feat(catalog): added cache invalidation for static model metadata
- Update `sakanaModelManagerOptions` to provide `dropCachedModelIdsOnStaticMismatch` configuration using identified static model IDs. - Add a test case to verify that stale cached model metadata is correctly cleared when bundled model specs are updated.
This commit is contained in:
@@ -2582,6 +2582,7 @@ export const SAKANA_FUGU_STATIC_MODELS: readonly ModelSpec<"openai-responses">[]
|
||||
];
|
||||
|
||||
const SAKANA_FUGU_STATIC_MODEL_BY_ID = new Map(SAKANA_FUGU_STATIC_MODELS.map(model => [model.id, model] as const));
|
||||
const SAKANA_FUGU_STATIC_MODEL_IDS = SAKANA_FUGU_STATIC_MODELS.map(model => model.id);
|
||||
|
||||
export interface SakanaModelManagerConfig {
|
||||
apiKey?: string;
|
||||
@@ -2596,6 +2597,7 @@ export function sakanaModelManagerOptions(config?: SakanaModelManagerConfig): Mo
|
||||
return {
|
||||
providerId: "sakana",
|
||||
dynamicModelsAuthoritative: true,
|
||||
dropCachedModelIdsOnStaticMismatch: SAKANA_FUGU_STATIC_MODEL_IDS,
|
||||
...(apiKey && {
|
||||
fetchDynamicModels: () =>
|
||||
fetchOpenAICompatibleModels({
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { afterEach, describe, expect, test, vi } from "bun:test";
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { getOAuthProviders } from "@oh-my-pi/pi-ai/registry/oauth";
|
||||
import { getEnvApiKey } from "@oh-my-pi/pi-ai/stream";
|
||||
import { Effort } from "@oh-my-pi/pi-catalog/effort";
|
||||
import { resolveProviderModels } from "@oh-my-pi/pi-catalog/model-manager";
|
||||
import { getBundledModels } from "@oh-my-pi/pi-catalog/models";
|
||||
import { DEFAULT_MODEL_PER_PROVIDER, PROVIDER_DESCRIPTORS } from "@oh-my-pi/pi-catalog/provider-models/descriptors";
|
||||
import { sakanaModelManagerOptions } from "@oh-my-pi/pi-catalog/provider-models/openai-compat";
|
||||
import type { FetchImpl, ResolvedOpenAIResponsesCompat } from "@oh-my-pi/pi-catalog/types";
|
||||
import type { FetchImpl, ModelSpec, ResolvedOpenAIResponsesCompat } from "@oh-my-pi/pi-catalog/types";
|
||||
|
||||
const ORIGINAL_ENV = {
|
||||
SAKANA_API_KEY: Bun.env.SAKANA_API_KEY,
|
||||
@@ -96,6 +100,52 @@ describe("Sakana AI provider support", () => {
|
||||
expect(fuguNext?.compat?.includeEncryptedReasoning).toBe(false);
|
||||
});
|
||||
|
||||
test("drops stale cached Fugu rows when bundled context metadata changes", async () => {
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "pi-catalog-sakana-stale-cache-"));
|
||||
const dbPath = path.join(tempDir, "models.db");
|
||||
const staleFugu: ModelSpec<"openai-responses"> = {
|
||||
id: "fugu",
|
||||
name: "Fugu",
|
||||
api: "openai-responses",
|
||||
provider: "sakana",
|
||||
baseUrl: "https://api.sakana.ai/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 272_000,
|
||||
maxTokens: null,
|
||||
};
|
||||
const correctedFugu: ModelSpec<"openai-responses"> = { ...staleFugu, contextWindow: 1_000_000 };
|
||||
|
||||
try {
|
||||
await resolveProviderModels(
|
||||
{
|
||||
providerId: "sakana",
|
||||
staticModels: [staleFugu],
|
||||
dynamicModelsAuthoritative: true,
|
||||
fetchDynamicModels: async () => [staleFugu],
|
||||
cacheDbPath: dbPath,
|
||||
},
|
||||
"online",
|
||||
);
|
||||
|
||||
const offline = await resolveProviderModels(
|
||||
{
|
||||
...sakanaModelManagerOptions({
|
||||
apiKey: "sakana-key",
|
||||
fetch: async () => new Response(null, { status: 503 }),
|
||||
}),
|
||||
staticModels: [correctedFugu],
|
||||
cacheDbPath: dbPath,
|
||||
},
|
||||
"offline",
|
||||
);
|
||||
|
||||
expect(offline.models.find(model => model.id === "fugu")?.contextWindow).toBe(1_000_000);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
test("prefers explicit Sakana model-manager base URL over environment aliases", async () => {
|
||||
Bun.env.SAKANA_BASE_URL = "https://env.sakana.test";
|
||||
const fetchMock: FetchImpl = vi.fn(
|
||||
|
||||
Reference in New Issue
Block a user