Files
clawdbot/src/auto-reply/reply/directive-handling.auth.ts
Peter Steinberger c379191f80 chore: migrate to oxlint and oxfmt
Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
2026-01-14 15:02:19 +00:00

223 lines
7.7 KiB
TypeScript

import {
isProfileInCooldown,
resolveAuthProfileDisplayLabel,
resolveAuthStorePathForDisplay,
} from "../../agents/auth-profiles.js";
import {
ensureAuthProfileStore,
getCustomProviderApiKey,
resolveAuthProfileOrder,
resolveEnvApiKey,
} from "../../agents/model-auth.js";
import { normalizeProviderId } from "../../agents/model-selection.js";
import type { ClawdbotConfig } from "../../config/config.js";
import { shortenHomePath } from "../../utils.js";
export type ModelAuthDetailMode = "compact" | "verbose";
const maskApiKey = (value: string): string => {
const trimmed = value.trim();
if (!trimmed) return "missing";
if (trimmed.length <= 16) return trimmed;
return `${trimmed.slice(0, 8)}...${trimmed.slice(-8)}`;
};
export const resolveAuthLabel = async (
provider: string,
cfg: ClawdbotConfig,
modelsPath: string,
agentDir?: string,
mode: ModelAuthDetailMode = "compact",
): Promise<{ label: string; source: string }> => {
const formatPath = (value: string) => shortenHomePath(value);
const store = ensureAuthProfileStore(agentDir, {
allowKeychainPrompt: false,
});
const order = resolveAuthProfileOrder({ cfg, store, provider });
const providerKey = normalizeProviderId(provider);
const lastGood = (() => {
const map = store.lastGood;
if (!map) return undefined;
for (const [key, value] of Object.entries(map)) {
if (normalizeProviderId(key) === providerKey) return value;
}
return undefined;
})();
const nextProfileId = order[0];
const now = Date.now();
const formatUntil = (timestampMs: number) => {
const remainingMs = Math.max(0, timestampMs - now);
const minutes = Math.round(remainingMs / 60_000);
if (minutes < 1) return "soon";
if (minutes < 60) return `${minutes}m`;
const hours = Math.round(minutes / 60);
if (hours < 48) return `${hours}h`;
const days = Math.round(hours / 24);
return `${days}d`;
};
if (order.length > 0) {
if (mode === "compact") {
const profileId = nextProfileId;
if (!profileId) return { label: "missing", source: "missing" };
const profile = store.profiles[profileId];
const configProfile = cfg.auth?.profiles?.[profileId];
const missing =
!profile ||
(configProfile?.provider && configProfile.provider !== profile.provider) ||
(configProfile?.mode &&
configProfile.mode !== profile.type &&
!(configProfile.mode === "oauth" && profile.type === "token"));
const more = order.length > 1 ? ` (+${order.length - 1})` : "";
if (missing) return { label: `${profileId} missing${more}`, source: "" };
if (profile.type === "api_key") {
return {
label: `${profileId} api-key ${maskApiKey(profile.key)}${more}`,
source: "",
};
}
if (profile.type === "token") {
const exp =
typeof profile.expires === "number" &&
Number.isFinite(profile.expires) &&
profile.expires > 0
? profile.expires <= now
? " expired"
: ` exp ${formatUntil(profile.expires)}`
: "";
return {
label: `${profileId} token ${maskApiKey(profile.token)}${exp}${more}`,
source: "",
};
}
const display = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
const label = display === profileId ? profileId : display;
const exp =
typeof profile.expires === "number" &&
Number.isFinite(profile.expires) &&
profile.expires > 0
? profile.expires <= now
? " expired"
: ` exp ${formatUntil(profile.expires)}`
: "";
return { label: `${label} oauth${exp}${more}`, source: "" };
}
const labels = order.map((profileId) => {
const profile = store.profiles[profileId];
const configProfile = cfg.auth?.profiles?.[profileId];
const flags: string[] = [];
if (profileId === nextProfileId) flags.push("next");
if (lastGood && profileId === lastGood) flags.push("lastGood");
if (isProfileInCooldown(store, profileId)) {
const until = store.usageStats?.[profileId]?.cooldownUntil;
if (typeof until === "number" && Number.isFinite(until) && until > now) {
flags.push(`cooldown ${formatUntil(until)}`);
} else {
flags.push("cooldown");
}
}
if (
!profile ||
(configProfile?.provider && configProfile.provider !== profile.provider) ||
(configProfile?.mode &&
configProfile.mode !== profile.type &&
!(configProfile.mode === "oauth" && profile.type === "token"))
) {
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
return `${profileId}=missing${suffix}`;
}
if (profile.type === "api_key") {
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
return `${profileId}=${maskApiKey(profile.key)}${suffix}`;
}
if (profile.type === "token") {
if (
typeof profile.expires === "number" &&
Number.isFinite(profile.expires) &&
profile.expires > 0
) {
flags.push(profile.expires <= now ? "expired" : `exp ${formatUntil(profile.expires)}`);
}
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
return `${profileId}=token:${maskApiKey(profile.token)}${suffix}`;
}
const display = resolveAuthProfileDisplayLabel({
cfg,
store,
profileId,
});
const suffix =
display === profileId
? ""
: display.startsWith(profileId)
? display.slice(profileId.length).trim()
: `(${display})`;
if (
typeof profile.expires === "number" &&
Number.isFinite(profile.expires) &&
profile.expires > 0
) {
flags.push(profile.expires <= now ? "expired" : `exp ${formatUntil(profile.expires)}`);
}
const suffixLabel = suffix ? ` ${suffix}` : "";
const suffixFlags = flags.length > 0 ? ` (${flags.join(", ")})` : "";
return `${profileId}=OAuth${suffixLabel}${suffixFlags}`;
});
return {
label: labels.join(", "),
source: `auth-profiles.json: ${formatPath(resolveAuthStorePathForDisplay(agentDir))}`,
};
}
const envKey = resolveEnvApiKey(provider);
if (envKey) {
const isOAuthEnv =
envKey.source.includes("ANTHROPIC_OAUTH_TOKEN") ||
envKey.source.toLowerCase().includes("oauth");
const label = isOAuthEnv ? "OAuth (env)" : maskApiKey(envKey.apiKey);
return { label, source: mode === "verbose" ? envKey.source : "" };
}
const customKey = getCustomProviderApiKey(cfg, provider);
if (customKey) {
return {
label: maskApiKey(customKey),
source: mode === "verbose" ? `models.json: ${formatPath(modelsPath)}` : "",
};
}
return { label: "missing", source: "missing" };
};
export const formatAuthLabel = (auth: { label: string; source: string }) => {
if (!auth.source || auth.source === auth.label || auth.source === "missing") {
return auth.label;
}
return `${auth.label} (${auth.source})`;
};
export const resolveProfileOverride = (params: {
rawProfile?: string;
provider: string;
cfg: ClawdbotConfig;
agentDir?: string;
}): { profileId?: string; error?: string } => {
const raw = params.rawProfile?.trim();
if (!raw) return {};
const store = ensureAuthProfileStore(params.agentDir, {
allowKeychainPrompt: false,
});
const profile = store.profiles[raw];
if (!profile) {
return { error: `Auth profile "${raw}" not found.` };
}
if (profile.provider !== params.provider) {
return {
error: `Auth profile "${raw}" is for ${profile.provider}, not ${params.provider}.`,
};
}
return { profileId: raw };
};