fix: clean model config typing
This commit is contained in:
@@ -143,10 +143,26 @@ export function loadAuthProfileStore(): AuthProfileStore {
|
||||
};
|
||||
for (const [provider, cred] of Object.entries(legacy)) {
|
||||
const profileId = `${provider}:default`;
|
||||
store.profiles[profileId] = {
|
||||
...cred,
|
||||
provider: cred.provider ?? (provider as OAuthProvider),
|
||||
};
|
||||
if (cred.type === "api_key") {
|
||||
store.profiles[profileId] = {
|
||||
type: "api_key",
|
||||
provider: cred.provider ?? (provider as OAuthProvider),
|
||||
key: cred.key,
|
||||
...(cred.email ? { email: cred.email } : {}),
|
||||
};
|
||||
} else {
|
||||
store.profiles[profileId] = {
|
||||
type: "oauth",
|
||||
provider: cred.provider ?? (provider as OAuthProvider),
|
||||
access: cred.access,
|
||||
refresh: cred.refresh,
|
||||
expires: cred.expires,
|
||||
...(cred.enterpriseUrl ? { enterpriseUrl: cred.enterpriseUrl } : {}),
|
||||
...(cred.projectId ? { projectId: cred.projectId } : {}),
|
||||
...(cred.accountId ? { accountId: cred.accountId } : {}),
|
||||
...(cred.email ? { email: cred.email } : {}),
|
||||
};
|
||||
}
|
||||
}
|
||||
return store;
|
||||
}
|
||||
@@ -162,17 +178,35 @@ export function ensureAuthProfileStore(): AuthProfileStore {
|
||||
|
||||
const legacyRaw = loadJsonFile(resolveLegacyAuthStorePath());
|
||||
const legacy = coerceLegacyStore(legacyRaw);
|
||||
const store = legacy
|
||||
? {
|
||||
version: AUTH_STORE_VERSION,
|
||||
profiles: Object.fromEntries(
|
||||
Object.entries(legacy).map(([provider, cred]) => [
|
||||
`${provider}:default`,
|
||||
{ ...cred, provider: cred.provider ?? (provider as OAuthProvider) },
|
||||
]),
|
||||
),
|
||||
const store: AuthProfileStore = {
|
||||
version: AUTH_STORE_VERSION,
|
||||
profiles: {},
|
||||
};
|
||||
if (legacy) {
|
||||
for (const [provider, cred] of Object.entries(legacy)) {
|
||||
const profileId = `${provider}:default`;
|
||||
if (cred.type === "api_key") {
|
||||
store.profiles[profileId] = {
|
||||
type: "api_key",
|
||||
provider: cred.provider ?? (provider as OAuthProvider),
|
||||
key: cred.key,
|
||||
...(cred.email ? { email: cred.email } : {}),
|
||||
};
|
||||
} else {
|
||||
store.profiles[profileId] = {
|
||||
type: "oauth",
|
||||
provider: cred.provider ?? (provider as OAuthProvider),
|
||||
access: cred.access,
|
||||
refresh: cred.refresh,
|
||||
expires: cred.expires,
|
||||
...(cred.enterpriseUrl ? { enterpriseUrl: cred.enterpriseUrl } : {}),
|
||||
...(cred.projectId ? { projectId: cred.projectId } : {}),
|
||||
...(cred.accountId ? { accountId: cred.accountId } : {}),
|
||||
...(cred.email ? { email: cred.email } : {}),
|
||||
};
|
||||
}
|
||||
: { version: AUTH_STORE_VERSION, profiles: {} };
|
||||
}
|
||||
}
|
||||
|
||||
const mergedOAuth = mergeOAuthFileIntoStore(store);
|
||||
const shouldWrite = legacy !== null || mergedOAuth;
|
||||
@@ -291,7 +325,7 @@ export function markAuthProfileGood(params: {
|
||||
const { store, provider, profileId } = params;
|
||||
const profile = store.profiles[profileId];
|
||||
if (!profile || profile.provider !== provider) return;
|
||||
store.lastGood = { ...(store.lastGood ?? {}), [provider]: profileId };
|
||||
store.lastGood = { ...store.lastGood, [provider]: profileId };
|
||||
saveAuthProfileStore(store);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,12 @@ export type EmbeddedPiRunMeta = {
|
||||
aborted?: boolean;
|
||||
};
|
||||
|
||||
type ApiKeyInfo = {
|
||||
apiKey: string;
|
||||
profileId?: string;
|
||||
source: string;
|
||||
};
|
||||
|
||||
export type EmbeddedPiRunResult = {
|
||||
payloads?: Array<{
|
||||
text?: string;
|
||||
@@ -396,8 +402,8 @@ export async function runEmbeddedPiAgent(params: {
|
||||
const initialThinkLevel = params.thinkLevel ?? "off";
|
||||
let thinkLevel = initialThinkLevel;
|
||||
const attemptedThinking = new Set<ThinkLevel>();
|
||||
let apiKeyInfo: Awaited<ReturnType<typeof getApiKeyForModel>> | null =
|
||||
null;
|
||||
let apiKeyInfo: ApiKeyInfo | null = null;
|
||||
let lastProfileId: string | undefined;
|
||||
|
||||
const resolveApiKeyForCandidate = async (candidate?: string) => {
|
||||
return getApiKeyForModel({
|
||||
@@ -411,6 +417,7 @@ export async function runEmbeddedPiAgent(params: {
|
||||
const applyApiKeyInfo = async (candidate?: string): Promise<void> => {
|
||||
apiKeyInfo = await resolveApiKeyForCandidate(candidate);
|
||||
authStorage.setRuntimeApiKey(model.provider, apiKeyInfo.apiKey);
|
||||
lastProfileId = apiKeyInfo.profileId;
|
||||
};
|
||||
|
||||
const advanceAuthProfile = async (): Promise<boolean> => {
|
||||
@@ -802,11 +809,11 @@ export async function runEmbeddedPiAgent(params: {
|
||||
log.debug(
|
||||
`embedded run done: runId=${params.runId} sessionId=${params.sessionId} durationMs=${Date.now() - started} aborted=${aborted}`,
|
||||
);
|
||||
if (apiKeyInfo?.profileId) {
|
||||
if (lastProfileId) {
|
||||
markAuthProfileGood({
|
||||
store: authStore,
|
||||
provider,
|
||||
profileId: apiKeyInfo.profileId,
|
||||
profileId: lastProfileId,
|
||||
});
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -337,7 +337,10 @@ export async function handleCommands(params: {
|
||||
const statusText = buildStatusMessage({
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model,
|
||||
model: {
|
||||
...cfg.agent?.model,
|
||||
primary: model,
|
||||
},
|
||||
contextTokens,
|
||||
thinkingDefault: cfg.agent?.thinkingDefault,
|
||||
verboseDefault: cfg.agent?.verboseDefault,
|
||||
|
||||
@@ -333,10 +333,13 @@ async function promptAuthConfig(
|
||||
agent: {
|
||||
...next.agent,
|
||||
model: {
|
||||
...((next.agent?.model as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(next.agent?.model &&
|
||||
"fallbacks" in (next.agent.model as Record<string, unknown>)
|
||||
? {
|
||||
fallbacks: (next.agent.model as { fallbacks?: string[] })
|
||||
.fallbacks,
|
||||
}
|
||||
: undefined),
|
||||
primary: "google-antigravity/claude-opus-4-5-thinking",
|
||||
},
|
||||
models: {
|
||||
@@ -392,10 +395,13 @@ async function promptAuthConfig(
|
||||
agent: {
|
||||
...next.agent,
|
||||
model: {
|
||||
...((next.agent?.model as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(next.agent?.model &&
|
||||
"fallbacks" in (next.agent.model as Record<string, unknown>)
|
||||
? {
|
||||
fallbacks: (next.agent.model as { fallbacks?: string[] })
|
||||
.fallbacks,
|
||||
}
|
||||
: undefined),
|
||||
primary: model,
|
||||
},
|
||||
models: {
|
||||
|
||||
@@ -64,15 +64,18 @@ export async function modelsFallbacksAddCommand(
|
||||
|
||||
if (existingKeys.includes(targetKey)) return cfg;
|
||||
|
||||
const existingModel = cfg.agent?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...((cfg.agent?.model as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: [...existing, targetKey],
|
||||
},
|
||||
models: nextModels,
|
||||
@@ -115,15 +118,18 @@ export async function modelsFallbacksRemoveCommand(
|
||||
throw new Error(`Fallback not found: ${targetKey}`);
|
||||
}
|
||||
|
||||
const existingModel = cfg.agent?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...((cfg.agent?.model as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: filtered,
|
||||
},
|
||||
},
|
||||
@@ -137,17 +143,23 @@ export async function modelsFallbacksRemoveCommand(
|
||||
}
|
||||
|
||||
export async function modelsFallbacksClearCommand(runtime: RuntimeEnv) {
|
||||
await updateConfig((cfg) => ({
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...((cfg.agent?.model as { primary?: string; fallbacks?: string[] }) ??
|
||||
{}),
|
||||
fallbacks: [],
|
||||
await updateConfig((cfg) => {
|
||||
const existingModel = cfg.agent?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
};
|
||||
});
|
||||
|
||||
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
|
||||
runtime.log("Fallback list cleared.");
|
||||
|
||||
@@ -64,15 +64,18 @@ export async function modelsImageFallbacksAddCommand(
|
||||
|
||||
if (existingKeys.includes(targetKey)) return cfg;
|
||||
|
||||
const existingModel = cfg.agent?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
imageModel: {
|
||||
...((cfg.agent?.imageModel as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: [...existing, targetKey],
|
||||
},
|
||||
models: nextModels,
|
||||
@@ -115,15 +118,18 @@ export async function modelsImageFallbacksRemoveCommand(
|
||||
throw new Error(`Image fallback not found: ${targetKey}`);
|
||||
}
|
||||
|
||||
const existingModel = cfg.agent?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
imageModel: {
|
||||
...((cfg.agent?.imageModel as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: filtered,
|
||||
},
|
||||
},
|
||||
@@ -137,19 +143,23 @@ export async function modelsImageFallbacksRemoveCommand(
|
||||
}
|
||||
|
||||
export async function modelsImageFallbacksClearCommand(runtime: RuntimeEnv) {
|
||||
await updateConfig((cfg) => ({
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
imageModel: {
|
||||
...((cfg.agent?.imageModel as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
fallbacks: [],
|
||||
await updateConfig((cfg) => {
|
||||
const existingModel = cfg.agent?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
imageModel: {
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
};
|
||||
});
|
||||
|
||||
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
|
||||
runtime.log("Image fallback list cleared.");
|
||||
|
||||
@@ -275,22 +275,28 @@ export async function modelsScanCommand(
|
||||
for (const entry of selectedImages) {
|
||||
if (!nextModels[entry]) nextModels[entry] = {};
|
||||
}
|
||||
const existingImageModel = cfg.agent?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
const nextImageModel =
|
||||
selectedImages.length > 0
|
||||
? {
|
||||
...((cfg.agent?.imageModel as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingImageModel?.primary
|
||||
? { primary: existingImageModel.primary }
|
||||
: undefined),
|
||||
fallbacks: selectedImages,
|
||||
...(opts.setImage ? { primary: selectedImages[0] } : {}),
|
||||
}
|
||||
: cfg.agent?.imageModel;
|
||||
const existingModel = cfg.agent?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
const agent = {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...((cfg.agent?.model as { primary?: string; fallbacks?: string[] }) ??
|
||||
{}),
|
||||
...(existingModel?.primary
|
||||
? { primary: existingModel.primary }
|
||||
: undefined),
|
||||
fallbacks: selected,
|
||||
...(opts.setDefault ? { primary: selected[0] } : {}),
|
||||
},
|
||||
|
||||
@@ -11,15 +11,17 @@ export async function modelsSetImageCommand(
|
||||
const key = `${resolved.provider}/${resolved.model}`;
|
||||
const nextModels = { ...cfg.agent?.models };
|
||||
if (!nextModels[key]) nextModels[key] = {};
|
||||
const existingModel = cfg.agent?.imageModel as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
imageModel: {
|
||||
...((cfg.agent?.imageModel as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingModel?.fallbacks
|
||||
? { fallbacks: existingModel.fallbacks }
|
||||
: undefined),
|
||||
primary: key,
|
||||
},
|
||||
models: nextModels,
|
||||
|
||||
@@ -8,15 +8,17 @@ export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) {
|
||||
const key = `${resolved.provider}/${resolved.model}`;
|
||||
const nextModels = { ...cfg.agent?.models };
|
||||
if (!nextModels[key]) nextModels[key] = {};
|
||||
const existingModel = cfg.agent?.model as
|
||||
| { primary?: string; fallbacks?: string[] }
|
||||
| undefined;
|
||||
return {
|
||||
...cfg,
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...((cfg.agent?.model as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(existingModel?.fallbacks
|
||||
? { fallbacks: existingModel.fallbacks }
|
||||
: undefined),
|
||||
primary: key,
|
||||
},
|
||||
models: nextModels,
|
||||
|
||||
@@ -94,8 +94,13 @@ export function applyMinimaxConfig(cfg: ClawdbotConfig): ClawdbotConfig {
|
||||
agent: {
|
||||
...cfg.agent,
|
||||
model: {
|
||||
...((cfg.agent?.model as { primary?: string; fallbacks?: string[] }) ??
|
||||
{}),
|
||||
...(cfg.agent?.model &&
|
||||
"fallbacks" in (cfg.agent.model as Record<string, unknown>)
|
||||
? {
|
||||
fallbacks: (cfg.agent.model as { fallbacks?: string[] })
|
||||
.fallbacks,
|
||||
}
|
||||
: undefined),
|
||||
primary: "lmstudio/minimax-m2.1-gs32",
|
||||
},
|
||||
models,
|
||||
|
||||
@@ -244,7 +244,8 @@ const LEGACY_CONFIG_MIGRATIONS: LegacyConfigMigration[] = [
|
||||
: {};
|
||||
|
||||
const ensureModel = (rawKey?: string) => {
|
||||
const key = String(rawKey ?? "").trim();
|
||||
if (typeof rawKey !== "string") return;
|
||||
const key = rawKey.trim();
|
||||
if (!key) return;
|
||||
if (!models[key]) models[key] = {};
|
||||
};
|
||||
@@ -255,11 +256,13 @@ const LEGACY_CONFIG_MIGRATIONS: LegacyConfigMigration[] = [
|
||||
for (const key of legacyModelFallbacks) ensureModel(key);
|
||||
for (const key of legacyImageModelFallbacks) ensureModel(key);
|
||||
for (const target of Object.values(legacyAliases)) {
|
||||
ensureModel(String(target ?? ""));
|
||||
if (typeof target !== "string") continue;
|
||||
ensureModel(target);
|
||||
}
|
||||
|
||||
for (const [alias, targetRaw] of Object.entries(legacyAliases)) {
|
||||
const target = String(targetRaw ?? "").trim();
|
||||
if (typeof targetRaw !== "string") continue;
|
||||
const target = targetRaw.trim();
|
||||
if (!target) continue;
|
||||
const entry =
|
||||
models[target] && typeof models[target] === "object"
|
||||
|
||||
@@ -49,7 +49,7 @@ vi.mock("discord.js", () => {
|
||||
}
|
||||
emit(event: string, ...args: unknown[]) {
|
||||
for (const handler of handlers.get(event) ?? []) {
|
||||
void Promise.resolve(handler(...args));
|
||||
Promise.resolve(handler(...args)).catch(() => {});
|
||||
}
|
||||
}
|
||||
login = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
@@ -337,10 +337,14 @@ export async function runOnboardingWizard(
|
||||
agent: {
|
||||
...nextConfig.agent,
|
||||
model: {
|
||||
...((nextConfig.agent?.model as {
|
||||
primary?: string;
|
||||
fallbacks?: string[];
|
||||
}) ?? {}),
|
||||
...(nextConfig.agent?.model &&
|
||||
"fallbacks" in (nextConfig.agent.model as Record<string, unknown>)
|
||||
? {
|
||||
fallbacks: (
|
||||
nextConfig.agent.model as { fallbacks?: string[] }
|
||||
).fallbacks,
|
||||
}
|
||||
: undefined),
|
||||
primary: "google-antigravity/claude-opus-4-5-thinking",
|
||||
},
|
||||
models: {
|
||||
|
||||
Reference in New Issue
Block a user