feat: persist Antigravity model list across restarts
The antigravity provider list lived only in a module-scoped variable initialized from ANTG_PROVIDER_MODELS, so /agy:refresh-models updated the running process but the list silently reset to the static defaults on /reload or restart. - add ~/.config/agy-pi/models-cache.json (mode 0600, atomic write) storing version, refreshedAt, project and the fetched model definitions - load the cache at startup; fall back to ANTG_PROVIDER_MODELS when the file is missing, unreadable, corrupt or has an incompatible version - persist the live catalog in /agy:refresh-models and report the file path - add /agy:models-reset to drop the cache and restore the defaults Verified: extension loads with no cache (11 defaults), a valid cache is honored and registered, corrupt/invalid/version-mismatched caches fall back silently, and /agy:models-reset deletes the cache and re-registers the defaults end-to-end over RPC.
This commit is contained in:
+96
-4
@@ -1598,9 +1598,75 @@ const ANTG_PROVIDER_MODELS: AntgProviderModelDef[] = [
|
||||
{ id: "gpt-oss-120b-medium", name: "GPT-OSS 120B (Medium)", reasoning: false, images: false, contextWindow: 262144, maxTokens: 32768 },
|
||||
];
|
||||
|
||||
// Modelli attualmente registrati nel provider (statici all'avvio, aggiornabili
|
||||
// con /agy:refresh-models dal catalogo vivo fetchAvailableModels).
|
||||
let antgRegisteredModels: AntgProviderModelDef[] = ANTG_PROVIDER_MODELS;
|
||||
// ---------------------------------------------------------------------------
|
||||
// Cache persistente dei modelli (~/.config/agy-pi/models-cache.json)
|
||||
// Il catalogo vivo scaricato da /agy:refresh-models viene salvato qui, così la
|
||||
// lista sopravvive al riavvio dell'estensione. Se il file è assente, illeggibile
|
||||
// o corrotto si riparte da ANTG_PROVIDER_MODELS senza errori fatali.
|
||||
// ---------------------------------------------------------------------------
|
||||
const MODELS_CACHE_FILE = path.join(CONFIG_DIR, "models-cache.json");
|
||||
const MODELS_CACHE_VERSION = 1;
|
||||
|
||||
interface AntgModelsCache {
|
||||
version: number;
|
||||
refreshedAt: string;
|
||||
project?: string;
|
||||
models: AntgProviderModelDef[];
|
||||
}
|
||||
|
||||
function isAntgModelDef(value: any): value is AntgProviderModelDef {
|
||||
return (
|
||||
value !== null &&
|
||||
typeof value === "object" &&
|
||||
typeof value.id === "string" &&
|
||||
value.id.trim() !== "" &&
|
||||
typeof value.contextWindow === "number" &&
|
||||
value.contextWindow > 0 &&
|
||||
typeof value.maxTokens === "number" &&
|
||||
value.maxTokens > 0
|
||||
);
|
||||
}
|
||||
|
||||
function loadModelsCache(): AntgModelsCache | null {
|
||||
try {
|
||||
const raw = JSON.parse(fs.readFileSync(MODELS_CACHE_FILE, "utf8"));
|
||||
if (raw?.version !== MODELS_CACHE_VERSION) return null;
|
||||
if (!Array.isArray(raw.models) || raw.models.length === 0) return null;
|
||||
if (!raw.models.every(isAntgModelDef)) return null;
|
||||
return raw as AntgModelsCache;
|
||||
} catch {
|
||||
return null; // assente, illeggibile o corrotto → default
|
||||
}
|
||||
}
|
||||
|
||||
function saveModelsCache(models: AntgProviderModelDef[], projectId?: string) {
|
||||
try {
|
||||
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
const tmp = `${MODELS_CACHE_FILE}.tmp`;
|
||||
fs.writeFileSync(
|
||||
tmp,
|
||||
JSON.stringify(
|
||||
{
|
||||
version: MODELS_CACHE_VERSION,
|
||||
refreshedAt: new Date().toISOString(),
|
||||
project: projectId,
|
||||
models,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
fs.renameSync(tmp, MODELS_CACHE_FILE); // scrittura atomica
|
||||
} catch {
|
||||
/* ignora */
|
||||
}
|
||||
}
|
||||
|
||||
// Modelli attualmente registrati nel provider: cache persistente se presente,
|
||||
// altrimenti i default statici. Aggiornabili con /agy:refresh-models (che ora
|
||||
// salva su disco) e ripristinabili con /agy:models-reset.
|
||||
let antgRegisteredModels: AntgProviderModelDef[] = loadModelsCache()?.models ?? ANTG_PROVIDER_MODELS;
|
||||
|
||||
// Configurazione del provider "antigravity" (riusata all'avvio e al refresh).
|
||||
function antgProviderConfig(models: AntgProviderModelDef[]) {
|
||||
@@ -2618,10 +2684,11 @@ export default function agyExtension(pi: ExtensionAPI) {
|
||||
if (!models.length) throw new Error("Il catalogo non ha restituito modelli utilizzabili");
|
||||
antgRegisteredModels = models;
|
||||
pi.registerProvider("antigravity", antgProviderConfig(models));
|
||||
saveModelsCache(models, pid);
|
||||
ctx.ui.setStatus("agy:refresh-models", "");
|
||||
const lines = models.map((m) => ` ${m.id} — ${m.name}${m.reasoning ? " (thinking)" : ""}`).join("\n");
|
||||
ctx.ui.notify(
|
||||
`✅ Provider antigravity aggiornato: ${models.length} modelli (project ${pid})\n${lines}`,
|
||||
`✅ Provider antigravity aggiornato: ${models.length} modelli (project ${pid})\n${lines}\n\n💾 Lista salvata in ${MODELS_CACHE_FILE} (persistente al riavvio).`,
|
||||
"info",
|
||||
);
|
||||
} catch (e: any) {
|
||||
@@ -2631,6 +2698,31 @@ export default function agyExtension(pi: ExtensionAPI) {
|
||||
},
|
||||
});
|
||||
|
||||
// =========================================================================
|
||||
// Comando: /agy:models-reset — rimuove la cache persistente dei modelli e
|
||||
// ripristina la lista statica di default.
|
||||
// =========================================================================
|
||||
pi.registerCommand("agy:models-reset", {
|
||||
description:
|
||||
"Rimuove la cache persistente dei modelli (~/.config/agy-pi/models-cache.json) e ri-registra il provider con la lista di default.",
|
||||
handler: async (_args, ctx) => {
|
||||
let removed = false;
|
||||
try {
|
||||
removed = fs.existsSync(MODELS_CACHE_FILE);
|
||||
fs.rmSync(MODELS_CACHE_FILE, { force: true });
|
||||
} catch (e: any) {
|
||||
ctx.ui.notify(`Errore rimozione cache modelli: ${e.message}`, "error");
|
||||
return;
|
||||
}
|
||||
antgRegisteredModels = ANTG_PROVIDER_MODELS;
|
||||
pi.registerProvider("antigravity", antgProviderConfig(ANTG_PROVIDER_MODELS));
|
||||
ctx.ui.notify(
|
||||
`♻️ ${removed ? "Cache rimossa" : "Nessuna cache presente"}: provider antigravity ripristinato a ${ANTG_PROVIDER_MODELS.length} modelli di default.`,
|
||||
"info",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// =========================================================================
|
||||
// Comandi interattivi
|
||||
// =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user