diff --git a/packages/core/src/sync/index.ts b/packages/core/src/sync/index.ts index 19cc36af4..eaeb0ebe7 100644 --- a/packages/core/src/sync/index.ts +++ b/packages/core/src/sync/index.ts @@ -44,13 +44,17 @@ export interface SyncProvider { name: string; modelsDir: string; skipCreates?: boolean; + preserveMissing?: string[]; sourceID?(model: SourceModel): string; skippedNotice?(ids: string[]): string[]; fetchModels(): Promise; parseModels(raw: unknown): SourceModel[]; translateModel( model: SourceModel, - context: { existing(id: string): ExistingModel | undefined }, + context: { + existing(id: string): ExistingModel | undefined; + authored(id: string): ExistingModel | undefined; + }, ): { id: string; model: SyncedModel } | undefined; } @@ -106,6 +110,7 @@ export async function syncProvider( const existing = await readExisting(provider.modelsDir); const sourceModels = provider.parseModels(await provider.fetchModels()); const desired = new Map; content: string }>(); + const preserveMissing = new Set(provider.preserveMissing ?? []); const skippedRemote: string[] = []; for (const sourceModel of sourceModels) { @@ -113,6 +118,9 @@ export async function syncProvider( existing(id) { return existing.get(`${id}.toml`)?.toml; }, + authored(id) { + return existing.get(`${id}.toml`)?.authored; + }, }); if (translated === undefined) { if (provider.skipCreates) skippedRemote.push(provider.sourceID?.(sourceModel) ?? "unknown"); @@ -182,8 +190,10 @@ export async function syncProvider( for (const relativePath of existing.keys()) { if (desired.has(relativePath)) continue; - if (options.newOnly) { - console.log(`Skipping removal in new-only mode: ${relativePath}`); + const id = relativePath.slice(0, -5); + if (options.newOnly || preserveMissing.has(id)) { + const mode = options.newOnly ? "new-only mode" : "preserve list"; + console.log(`Skipping removal in ${mode}: ${relativePath}`); unchanged++; continue; } diff --git a/packages/core/src/sync/providers/google.ts b/packages/core/src/sync/providers/google.ts index bf79dac45..56920c962 100644 --- a/packages/core/src/sync/providers/google.ts +++ b/packages/core/src/sync/providers/google.ts @@ -32,6 +32,8 @@ export const google = { name: "Google", modelsDir: "providers/google/models", skipCreates: true, + // v1beta/models omits Gemini-TTS models served by Cloud TTS / Vertex AI. + preserveMissing: ["gemini-2.5-flash-tts"], sourceID(model) { return model.name.replace(/^models\//, ""); }, @@ -81,12 +83,16 @@ export const google = { return { id, - model: buildModel(model, existing), + model: buildModel(model, existing, context.authored(id)), }; }, } satisfies SyncProvider; -function buildModel(model: GoogleModel, existing: ExistingModel): SyncedModel { +function buildModel( + model: GoogleModel, + existing: ExistingModel, + authored: ExistingModel | undefined, +): SyncedModel { const name = existing.name; const releaseDate = existing.release_date; const lastUpdated = existing.last_updated; @@ -111,6 +117,27 @@ function buildModel(model: GoogleModel, existing: ExistingModel): SyncedModel { throw new Error(`Google model ${model.name} has incomplete local TOML metadata required for sync`); } + if (authored?.base_model !== undefined) { + const result: SyncedModel = { ...authored, base_model: authored.base_model }; + const limitOverride = { ...authored.limit }; + if (model.inputTokenLimit !== limit.context) { + limitOverride.context = model.inputTokenLimit; + } + if (model.outputTokenLimit !== limit.output) { + limitOverride.output = model.outputTokenLimit; + } + if ( + limitOverride.context !== undefined + || limitOverride.input !== undefined + || limitOverride.output !== undefined + ) { + result.limit = limitOverride; + } else { + delete result.limit; + } + return result; + } + return { base_model: existing.base_model, base_model_omit: existing.base_model_omit, diff --git a/providers/google/models/gemini-3-pro-image-preview.toml b/providers/google/models/gemini-3-pro-image-preview.toml index 98a4ae2c5..a68249299 100644 --- a/providers/google/models/gemini-3-pro-image-preview.toml +++ b/providers/google/models/gemini-3-pro-image-preview.toml @@ -3,3 +3,6 @@ base_model = "google/gemini-3-pro-image-preview" [cost] input = 2 output = 120 + +[limit] +context = 131_072