refactor(auth): share profile id dedupe helper

This commit is contained in:
Peter Steinberger
2026-02-16 22:51:42 +00:00
parent ff7a735115
commit 230e1d9962
5 changed files with 12 additions and 29 deletions

View File

@@ -5,6 +5,7 @@ export { resolveApiKeyForProfile } from "./auth-profiles/oauth.js";
export { resolveAuthProfileOrder } from "./auth-profiles/order.js"; export { resolveAuthProfileOrder } from "./auth-profiles/order.js";
export { resolveAuthStorePathForDisplay } from "./auth-profiles/paths.js"; export { resolveAuthStorePathForDisplay } from "./auth-profiles/paths.js";
export { export {
dedupeProfileIds,
listProfilesForProvider, listProfilesForProvider,
markAuthProfileGood, markAuthProfileGood,
setAuthProfileOrder, setAuthProfileOrder,

View File

@@ -1,7 +1,7 @@
import type { OpenClawConfig } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/config.js";
import type { AuthProfileStore } from "./types.js"; import type { AuthProfileStore } from "./types.js";
import { normalizeProviderId } from "../model-selection.js"; import { normalizeProviderId } from "../model-selection.js";
import { listProfilesForProvider } from "./profiles.js"; import { dedupeProfileIds, listProfilesForProvider } from "./profiles.js";
import { clearExpiredCooldowns, isProfileInCooldown } from "./usage.js"; import { clearExpiredCooldowns, isProfileInCooldown } from "./usage.js";
function resolveProfileUnusableUntil(stats: { function resolveProfileUnusableUntil(stats: {
@@ -110,12 +110,7 @@ export function resolveAuthProfileOrder(params: {
} }
return false; return false;
}); });
const deduped: string[] = []; const deduped = dedupeProfileIds(filtered);
for (const entry of filtered) {
if (!deduped.includes(entry)) {
deduped.push(entry);
}
}
// If user specified explicit order (store override or config), respect it // If user specified explicit order (store override or config), respect it
// exactly, but still apply cooldown sorting to avoid repeatedly selecting // exactly, but still apply cooldown sorting to avoid repeatedly selecting

View File

@@ -7,6 +7,10 @@ import {
updateAuthProfileStoreWithLock, updateAuthProfileStoreWithLock,
} from "./store.js"; } from "./store.js";
export function dedupeProfileIds(profileIds: string[]): string[] {
return [...new Set(profileIds)];
}
export async function setAuthProfileOrder(params: { export async function setAuthProfileOrder(params: {
agentDir?: string; agentDir?: string;
provider: string; provider: string;
@@ -17,13 +21,7 @@ export async function setAuthProfileOrder(params: {
params.order && Array.isArray(params.order) params.order && Array.isArray(params.order)
? params.order.map((entry) => String(entry).trim()).filter(Boolean) ? params.order.map((entry) => String(entry).trim()).filter(Boolean)
: []; : [];
const deduped = dedupeProfileIds(sanitized);
const deduped: string[] = [];
for (const entry of sanitized) {
if (!deduped.includes(entry)) {
deduped.push(entry);
}
}
return await updateAuthProfileStoreWithLock({ return await updateAuthProfileStoreWithLock({
agentDir: params.agentDir, agentDir: params.agentDir,

View File

@@ -2,7 +2,7 @@ import type { OpenClawConfig } from "../../config/config.js";
import type { AuthProfileConfig } from "../../config/types.js"; import type { AuthProfileConfig } from "../../config/types.js";
import type { AuthProfileIdRepairResult, AuthProfileStore } from "./types.js"; import type { AuthProfileIdRepairResult, AuthProfileStore } from "./types.js";
import { normalizeProviderId } from "../model-selection.js"; import { normalizeProviderId } from "../model-selection.js";
import { listProfilesForProvider } from "./profiles.js"; import { dedupeProfileIds, listProfilesForProvider } from "./profiles.js";
function getProfileSuffix(profileId: string): string { function getProfileSuffix(profileId: string): string {
const idx = profileId.indexOf(":"); const idx = profileId.indexOf(":");
@@ -139,12 +139,7 @@ export function repairOAuthProfileIdMismatch(params: {
const replaced = existing const replaced = existing
.map((id) => (id === legacyProfileId ? toProfileId : id)) .map((id) => (id === legacyProfileId ? toProfileId : id))
.filter((id): id is string => typeof id === "string" && id.trim().length > 0); .filter((id): id is string => typeof id === "string" && id.trim().length > 0);
const deduped: string[] = []; const deduped = dedupeProfileIds(replaced);
for (const entry of replaced) {
if (!deduped.includes(entry)) {
deduped.push(entry);
}
}
return { ...order, [resolvedKey]: deduped }; return { ...order, [resolvedKey]: deduped };
})(); })();

View File

@@ -3,6 +3,7 @@ import os from "node:os";
import path from "node:path"; import path from "node:path";
import type { UsageProviderId } from "./provider-usage.types.js"; import type { UsageProviderId } from "./provider-usage.types.js";
import { import {
dedupeProfileIds,
ensureAuthProfileStore, ensureAuthProfileStore,
listProfilesForProvider, listProfilesForProvider,
resolveApiKeyForProfile, resolveApiKeyForProfile,
@@ -144,14 +145,7 @@ async function resolveOAuthToken(params: {
store, store,
provider: params.provider, provider: params.provider,
}); });
const deduped = dedupeProfileIds(order);
const candidates = order;
const deduped: string[] = [];
for (const entry of candidates) {
if (!deduped.includes(entry)) {
deduped.push(entry);
}
}
for (const profileId of deduped) { for (const profileId of deduped) {
const cred = store.profiles[profileId]; const cred = store.profiles[profileId];