From 72109acf9e722f28fea52be26a665f6a88e1b40f Mon Sep 17 00:00:00 2001 From: Fsocietyhhh <1211904451@qq.com> Date: Tue, 27 Oct 2026 22:04:21 -0700 Subject: [PATCH 1/2] fix: show newest models first within each provider --- package-lock.json | 8 +-- package.json | 2 +- src/gateway-models.ts | 2 + src/serve/model-list.ts | 43 ++++++++++++++ src/serve/server.ts | 39 +----------- src/ui/model-picker.ts | 111 ++++------------------------------- test/local.mjs | 10 ++-- test/model-catalog.local.mjs | 42 +++++++++++++ 8 files changed, 109 insertions(+), 148 deletions(-) create mode 100644 src/serve/model-list.ts diff --git a/package-lock.json b/package-lock.json index a95bc47c..da24bf33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ ], "dependencies": { "@blockrun/llm": "^3.19.1", - "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/b95efe2f025c9968742e6479bc9ec71b6a40c0f4", + "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/a9d7dd21e65c744104dd752a13d7bf5a71e27f01", "@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/fd6d03d035ff676642ba1683c333d929939f8a00", "@colbymchenry/codegraph": "^1.5.0", "@modelcontextprotocol/sdk": "^1.29.0", @@ -2100,9 +2100,9 @@ } }, "node_modules/@blockrun/model-catalog": { - "version": "0.2.0", - "resolved": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/b95efe2f025c9968742e6479bc9ec71b6a40c0f4", - "integrity": "sha512-xvqbo5mzcWVM1QJgQTYjcc04aque8QGzHkdDDwc3PecmOkgtJ5EU5oU/wxJkqioc86e1wYv1Xb9AA5NsMO0fYA==", + "version": "0.2.1", + "resolved": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/a9d7dd21e65c744104dd752a13d7bf5a71e27f01", + "integrity": "sha512-LEqJ2liNHBfL1hlc+6z7W9E4w0XTbkDih1nW+SqGTR2Grv/2wWNDNCKf8ABefODvZt4EFVDs1A4QHg6xALiotw==", "license": "MIT", "engines": { "node": ">=20.19.0" diff --git a/package.json b/package.json index 21d3d3bc..022e6c07 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ }, "dependencies": { "@blockrun/llm": "^3.19.1", - "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/b95efe2f025c9968742e6479bc9ec71b6a40c0f4", + "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/a9d7dd21e65c744104dd752a13d7bf5a71e27f01", "@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/fd6d03d035ff676642ba1683c333d929939f8a00", "@colbymchenry/codegraph": "^1.5.0", "@modelcontextprotocol/sdk": "^1.29.0", diff --git a/src/gateway-models.ts b/src/gateway-models.ts index cbc6db56..2b209cfa 100644 --- a/src/gateway-models.ts +++ b/src/gateway-models.ts @@ -66,6 +66,8 @@ export interface GatewayModel { name: string; description?: string; owned_by?: string; + available?: boolean; + release_date?: string; billing_mode: BillingMode; categories: string[]; context_window?: number; diff --git a/src/serve/model-list.ts b/src/serve/model-list.ts new file mode 100644 index 00000000..189f1d14 --- /dev/null +++ b/src/serve/model-list.ts @@ -0,0 +1,43 @@ +import { sortModelsNewestFirst } from '@blockrun/model-catalog'; +import type { GatewayModel } from '../gateway-models.js'; + +// Keep company sections in the established picker order. Recency within each +// section belongs to Model Core, shared with the expanded terminal picker. +const PROVIDER_LABEL: Record = { + anthropic: 'Anthropic', openai: 'OpenAI', azure: 'OpenAI', google: 'Google', 'google-vertex': 'Google', + xai: 'xAI', deepseek: 'DeepSeek', meta: 'Meta', 'meta-llama': 'Meta', nvidia: 'NVIDIA', + moonshot: 'Moonshot', moonshotai: 'Moonshot', qwen: 'Qwen', alibaba: 'Qwen', mistral: 'Mistral', + mistralai: 'Mistral', minimax: 'MiniMax', zhipu: 'Zhipu', bytedance: 'ByteDance', cohere: 'Cohere', + perplexity: 'Perplexity', amazon: 'Amazon', microsoft: 'Microsoft', '01-ai': 'Yi', ai21: 'AI21', +}; +const PROVIDER_ORDER = ['Anthropic', 'OpenAI', 'Google', 'xAI', 'DeepSeek', 'Qwen', 'Moonshot', 'Meta', 'Mistral', 'MiniMax', 'NVIDIA']; + +function providerLabel(id: string, ownedBy?: string): string { + const p = (id.split('/')[0] || ownedBy || '').toLowerCase(); + return PROVIDER_LABEL[p] || (p ? p.charAt(0).toUpperCase() + p.slice(1) : 'Other'); +} + +/** The models.list payload used by both Desktop and the browser UI. */ +export function buildModelList(models: GatewayModel[]) { + const groups = new Map(); + for (const model of models) { + if (model.available === false || !model.categories.includes('chat')) continue; + const provider = providerLabel(model.id, model.owned_by); + const group = groups.get(provider) ?? []; + group.push(model); + groups.set(provider, group); + } + const rank = (provider: string) => { + const index = PROVIDER_ORDER.indexOf(provider); + return index < 0 ? PROVIDER_ORDER.length : index; + }; + return [...groups].sort(([a], [b]) => rank(a) - rank(b) || a.localeCompare(b)) + .flatMap(([provider, rows]) => sortModelsNewestFirst(rows).map(model => ({ + id: model.id, + label: model.name, + free: model.billing_mode === 'free', + group: provider, + provider, + contextWindow: model.context_window, + }))); +} diff --git a/src/serve/server.ts b/src/serve/server.ts index 14a7dce7..3fea519c 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -31,6 +31,7 @@ import { assembleInstructions } from '../agent/context.js'; import { interactiveSession } from '../agent/loop.js'; import { allCapabilities, createSubAgentCapability } from '../tools/index.js'; import { getModelsByCategory } from '../gateway-models.js'; +import { buildModelList } from './model-list.js'; import { listSessions, loadSessionHistory } from '../session/storage.js'; import { loadSdkSettlements } from '../stats/cost-log.js'; import { readSwaps } from '../stats/swap-log.js'; @@ -140,26 +141,11 @@ function labelFor(name: string): string { return TOOL_LABELS[name] ?? name; } -// Model list grouping — by provider (company), like OpenRouter/Together. The -// provider is the id's vendor prefix (e.g. "anthropic/claude-…"); PROVIDER_ORDER -// puts the most-wanted vendors first, the rest fall in alphabetically. -const PROVIDER_LABEL: Record = { - anthropic: 'Anthropic', openai: 'OpenAI', azure: 'OpenAI', google: 'Google', 'google-vertex': 'Google', - xai: 'xAI', deepseek: 'DeepSeek', meta: 'Meta', 'meta-llama': 'Meta', nvidia: 'NVIDIA', - moonshot: 'Moonshot', moonshotai: 'Moonshot', qwen: 'Qwen', alibaba: 'Qwen', mistral: 'Mistral', - mistralai: 'Mistral', minimax: 'MiniMax', zhipu: 'Zhipu', bytedance: 'ByteDance', cohere: 'Cohere', - perplexity: 'Perplexity', amazon: 'Amazon', microsoft: 'Microsoft', '01-ai': 'Yi', ai21: 'AI21', -}; -const PROVIDER_ORDER = ['Anthropic', 'OpenAI', 'Google', 'xAI', 'DeepSeek', 'Qwen', 'Moonshot', 'Meta', 'Mistral', 'MiniMax', 'NVIDIA']; const MEDIA_MIME: Record = { mp3: 'audio/mpeg', wav: 'audio/wav', m4a: 'audio/mp4', ogg: 'audio/ogg', flac: 'audio/flac', mp4: 'video/mp4', webm: 'video/webm', png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', webp: 'image/webp', gif: 'image/gif', }; -function providerLabel(id: string, ownedBy?: string): string { - const p = (id.split('/')[0] || ownedBy || '').toLowerCase(); - return PROVIDER_LABEL[p] || (p ? p.charAt(0).toUpperCase() + p.slice(1) : 'Other'); -} // ─── Browser-attack surface gate ──────────────────────────────────────────── // Loopback binding alone is NOT an auth boundary: any web page the user has @@ -839,28 +825,7 @@ export async function startServer(opts: ServerOptions): Promise { case 'models.list': { try { const models = await getModelsByCategory('chat'); - const mapped = models.map((m) => { - const provider = providerLabel(m.id, m.owned_by); - return { - id: m.id, - label: m.name, - free: m.billing_mode === 'free', - group: provider, - provider, - contextWindow: m.context_window, - }; - }); - // Group by provider (PROVIDER_ORDER first, then alphabetical); free - // models surface first within each provider. The picker renders - // consecutive same-`group` items as one section, so sort accordingly. - const rank = (g: string) => { const i = PROVIDER_ORDER.indexOf(g); return i < 0 ? 999 : i; }; - mapped.sort((a, b) => - rank(a.group) - rank(b.group) || - a.group.localeCompare(b.group) || - (a.free === b.free ? 0 : a.free ? -1 : 1) || - a.label.localeCompare(b.label), - ); - send(ws, id, 'response', { models: mapped }); + send(ws, id, 'response', { models: buildModelList(models) }); } catch (err) { send(ws, id, 'error', { message: err instanceof Error ? err.message : 'models error' }); } diff --git a/src/ui/model-picker.ts b/src/ui/model-picker.ts index 134bf180..fd885884 100644 --- a/src/ui/model-picker.ts +++ b/src/ui/model-picker.ts @@ -5,6 +5,7 @@ import readline from 'node:readline'; import chalk from 'chalk'; +import { sortModelsNewestFirst } from '@blockrun/model-catalog'; import { getGatewayModels, type GatewayModel } from '../gateway-models.js'; import { FREE_DEFAULT_MODEL } from '../free-models.js'; import { getModelCatalog, onModelCatalogChange } from '../model-catalog.js'; @@ -490,94 +491,6 @@ function modelSuffix(id: string): string { return id.includes('/') ? id.slice(id.indexOf('/') + 1) : id; } -function versionScoreFrom(match: RegExpMatchArray | null): number { - if (!match) return 0; - const parts = match[1].split('.').map(part => Number.parseInt(part, 10) || 0); - return parts.slice(0, 3).reduce((score, part, index) => score + part * [1_000_000, 100_000, 1_000][index], 0); -} - -function providerVersionScore(provider: string, suffix: string): number { - switch (provider) { - case 'anthropic': - return versionScoreFrom(suffix.match(/claude-(?:fable|opus|sonnet|haiku)-(\d+(?:\.\d+)*)/)); - case 'openai': - if (suffix.startsWith('gpt-4o')) return versionScoreFrom(['', '4.0'] as RegExpMatchArray); - return versionScoreFrom(suffix.match(/(?:gpt-|o)(\d+(?:\.\d+)*)/)); - case 'google': - return versionScoreFrom(suffix.match(/gemini-(\d+(?:\.\d+)*)/)); - case 'xai': - return versionScoreFrom(suffix.match(/grok-(\d+(?:\.\d+)*)/)); - case 'zai': - return versionScoreFrom(suffix.match(/glm-(\d+(?:\.\d+)*)/)); - case 'moonshot': - return versionScoreFrom(suffix.match(/kimi-k(\d+(?:\.\d+)*)/)); - case 'minimax': - return versionScoreFrom(suffix.match(/minimax-m(\d+(?:\.\d+)*)/)); - case 'deepseek': - return versionScoreFrom(suffix.match(/deepseek-v(\d+(?:\.\d+)*)/)); - case 'nvidia': - return versionScoreFrom( - suffix.match(/deepseek-v(\d+(?:\.\d+)*)/) ?? - suffix.match(/qwen(\d+(?:\.\d+)*)/) ?? - suffix.match(/step-(\d+(?:\.\d+)*)/) ?? - suffix.match(/nemotron-(\d+(?:\.\d+)*)/) ?? - suffix.match(/mistral-large-(\d+(?:\.\d+)*)/) ?? - suffix.match(/v(\d+(?:\.\d+)*)/), - ); - default: - return versionScoreFrom(suffix.match(/(?:^|[^\d])(\d+(?:\.\d+)*)(?:[^\d]|$)/)); - } -} - -function expandedModelRank(model: GatewayModel): number { - const suffix = modelSuffix(model.id).toLowerCase(); - const provider = providerOf(model.id); - let score = providerVersionScore(provider, suffix); - - switch (provider) { - case 'anthropic': - score += suffix.includes('fable') ? 90_000 : suffix.includes('opus') ? 80_000 : suffix.includes('sonnet') ? 70_000 : suffix.includes('haiku') ? 40_000 : 0; - break; - case 'openai': - score += suffix.startsWith('gpt-') ? 80_000 : suffix.startsWith('o') ? 65_000 : 0; - if (suffix.includes('codex')) score += 8_000; - if (suffix.includes('pro') || suffix.includes('sol')) score += 3_000; - if (suffix.includes('terra')) score += 2_000; - if (suffix.includes('luna')) score += 1_000; - if (suffix.includes('mini')) score -= 8_000; - if (suffix.includes('nano')) score -= 12_000; - break; - case 'google': - score += suffix.includes('gemini') ? 80_000 : 0; - if (suffix.includes('pro')) score += 5_000; - if (suffix.includes('flash')) score -= 5_000; - break; - case 'xai': - score += suffix.includes('grok') ? 80_000 : 0; - if (suffix.includes('fast')) score -= 4_000; - if (suffix.includes('build')) score -= 8_000; - break; - case 'zai': - score += suffix.includes('glm') ? 80_000 : 0; - if (suffix.includes('turbo')) score -= 5_000; - break; - case 'moonshot': - score += suffix.includes('kimi') ? 80_000 : 0; - break; - case 'minimax': - score += suffix.includes('minimax') ? 80_000 : 0; - break; - case 'deepseek': - score += suffix.includes('v4-pro') ? 90_000 : suffix.includes('reasoner') ? 75_000 : suffix.includes('chat') ? 70_000 : 0; - break; - case 'nvidia': - score += suffix.includes('qwen3-next') ? 80_000 : suffix.includes('qwen') ? 70_000 : suffix.includes('nemotron') ? 60_000 : 0; - break; - } - - return score; -} - function cleanGatewayLabel(model: GatewayModel): string { return (model.name || modelSuffix(model.id)) .replace(/\s*\((?:free|paid)\)\s*$/i, '') @@ -698,28 +611,24 @@ export async function getExpandedPickerCategories(): Promise { export function reconcileExpandedPicker(catalog: GatewayModel[]): HydratedPicker { const categories: ModelCategory[] = [{ ...PICKER_CATEGORIES[0], models: [...PICKER_CATEGORIES[0].models] }]; - const curated = new Set(); const curatedRows = new Map(); for (const cat of PICKER_CATEGORIES) { for (const row of cat.models) { - curated.add(row.id); if (!isSyntheticId(row.id)) curatedRows.set(row.id, row); } } const shortcutById = buildShortcutById(); - const chatModels = catalog - .filter(m => m.categories?.includes('chat')) - .sort((a, b) => { - const providerDelta = providerRank(providerOf(a.id)) - providerRank(providerOf(b.id)); - if (providerDelta !== 0) return providerDelta; - const rankDelta = expandedModelRank(b) - expandedModelRank(a); - if (rankDelta !== 0) return rankDelta; - const curatedDelta = Number(!curated.has(a.id)) - Number(!curated.has(b.id)); - if (curatedDelta !== 0) return curatedDelta; - return modelSuffix(a.id).localeCompare(modelSuffix(b.id)); - }); + const byProviderModels = new Map(); + for (const model of catalog) { + if (model.available === false || !model.categories?.includes('chat')) continue; + const provider = providerOf(model.id); + const rows = byProviderModels.get(provider) ?? []; + rows.push(model); + byProviderModels.set(provider, rows); + } + const chatModels = [...byProviderModels.values()].flatMap(rows => sortModelsNewestFirst(rows)); const byProvider = new Map(); for (const model of chatModels) { diff --git a/test/local.mjs b/test/local.mjs index 43af039f..41fa1dcf 100644 --- a/test/local.mjs +++ b/test/local.mjs @@ -7687,7 +7687,7 @@ test('reconcileExpandedPicker: live catalog is grouped by provider after Auto', ); }); -test('reconcileExpandedPicker: provider groups rank newest and strongest models first', async () => { +test('reconcileExpandedPicker: provider groups use shared recency and preserve same-generation order', async () => { const { reconcileExpandedPicker } = await import('../dist/ui/model-picker.js'); const catalog = [ gwModel('anthropic/claude-haiku-4.5', { input: 1, output: 2 }), @@ -7732,13 +7732,13 @@ test('reconcileExpandedPicker: provider groups rank newest and strongest models 'anthropic/claude-haiku-4.5', ]); assert.deepEqual(idsFor('OpenAI / GPT'), [ + 'openai/gpt-5.6-luna', 'openai/gpt-5.6-sol', 'openai/gpt-5.6-terra', - 'openai/gpt-5.6-luna', 'openai/gpt-5.5', - 'openai/gpt-5.4-pro', 'openai/gpt-5.4-mini', 'openai/gpt-5.4-nano', + 'openai/gpt-5.4-pro', 'openai/gpt-5.3-codex', 'openai/gpt-5.3', 'openai/gpt-5.2', @@ -7747,8 +7747,8 @@ test('reconcileExpandedPicker: provider groups rank newest and strongest models ]); assert.deepEqual(idsFor('Google / Gemini'), [ 'google/gemini-3.5-flash', - 'google/gemini-3.1-pro', 'google/gemini-3.1-flash-lite', + 'google/gemini-3.1-pro', 'google/gemini-3-flash-preview', 'google/gemini-2.5-flash', ]); @@ -7760,8 +7760,8 @@ test('reconcileExpandedPicker: provider groups rank newest and strongest models assert.deepEqual(idsFor('Z.AI / GLM'), [ 'zai/glm-5.2', 'zai/glm-5.1', - 'zai/glm-5', 'zai/glm-5-turbo', + 'zai/glm-5', ]); assert.deepEqual(idsFor('MiniMax'), [ 'minimax/minimax-m3', diff --git a/test/model-catalog.local.mjs b/test/model-catalog.local.mjs index 5f993c3c..271df944 100644 --- a/test/model-catalog.local.mjs +++ b/test/model-catalog.local.mjs @@ -2,6 +2,48 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { createServer } from 'node:http'; import snapshot from '@blockrun/model-catalog/snapshot' with { type: 'json' }; +import { buildModelList } from '../dist/serve/model-list.js'; + +test('models.list groups every available chat model with the latest generations first', () => { + const row = (id, extra = {}) => ({ id, name: id, categories: ['chat'], billing_mode: 'paid', pricing: { input: 1, output: 2 }, ...extra }); + const rows = [ + row('google/gemini-2.5-pro'), + row('openai/gpt-4.1'), + row('anthropic/claude-haiku-4.5', { billing_mode: 'free' }), + row('google/gemini-3.1-pro'), + row('anthropic/claude-fable-5.1'), + row('openai/gpt-6.1-sol', { context_window: 1_000_000 }), + row('google/gemini-4-argon'), + row('openai/gpt-6-astra'), + row('google/gemini-3.8-flash'), + row('test/future-chat'), + row('google/image-model', { categories: ['image'] }), + row('openai/gpt-99', { available: false }), + ]; + const list = buildModelList(rows); + assert.deepEqual(list.map(m => m.id), [ + 'anthropic/claude-fable-5.1', 'anthropic/claude-haiku-4.5', + 'openai/gpt-6.1-sol', 'openai/gpt-6-astra', 'openai/gpt-4.1', + 'google/gemini-4-argon', 'google/gemini-3.8-flash', 'google/gemini-3.1-pro', 'google/gemini-2.5-pro', + 'test/future-chat', + ]); + assert.equal(list.find(m => m.id === 'anthropic/claude-haiku-4.5').free, true); + assert.equal(list.find(m => m.id === 'openai/gpt-6.1-sol').contextWindow, 1_000_000); + assert.deepEqual([...new Set(list.map(m => m.group))], ['Anthropic', 'OpenAI', 'Google', 'Test']); + assert.equal(rows[0].id, 'google/gemini-2.5-pro', 'input order is not mutated'); +}); + +test('Desktop and expanded terminal pickers share verified release-date ordering', async () => { + const { reconcileExpandedPicker } = await import('../dist/ui/model-picker.js'); + const rows = [ + { id: 'google/gemini-4-argon', name: 'Gemini 4 Argon', release_date: '2026-09-01' }, + { id: 'google/gemini-3.8-flash', name: 'Gemini 3.8 Flash', release_date: '2026-10-01' }, + ].map(m => ({ ...m, categories: ['chat'], billing_mode: 'paid', pricing: { input: 1, output: 2 } })); + const expected = ['google/gemini-3.8-flash', 'google/gemini-4-argon']; + assert.deepEqual(buildModelList(rows).map(m => m.id), expected); + const expanded = reconcileExpandedPicker(rows).categories.find(c => c.category === 'Google / Gemini'); + assert.deepEqual(expanded.models.map(m => m.id), expected); +}); process.env.RUNCODE_CHAIN = 'solana'; delete process.env.FRANKLIN_CATALOG_OFFLINE; From 846189ff85c2fd1deb186b678f3ecb80d3507e0d Mon Sep 17 00:00:00 2001 From: 1bcMax Date: Mon, 2 Nov 2026 12:53:49 -0600 Subject: [PATCH 2/2] fix: pin model-catalog to the merged #7 commit (aecf20b) a9d7dd2 was the head of a deleted branch; #7 was squash-merged as aecf20b, which also moves ordering into runtime/ordering.js and ranks the OpenAI o-series alongside GPT-4.x. Pin what actually shipped. --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index da24bf33..2e8e0a11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ ], "dependencies": { "@blockrun/llm": "^3.19.1", - "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/a9d7dd21e65c744104dd752a13d7bf5a71e27f01", + "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/aecf20b4d5ee51af4a38a69a1b9c81e3e64b955c", "@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/fd6d03d035ff676642ba1683c333d929939f8a00", "@colbymchenry/codegraph": "^1.5.0", "@modelcontextprotocol/sdk": "^1.29.0", @@ -2101,8 +2101,8 @@ }, "node_modules/@blockrun/model-catalog": { "version": "0.2.1", - "resolved": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/a9d7dd21e65c744104dd752a13d7bf5a71e27f01", - "integrity": "sha512-LEqJ2liNHBfL1hlc+6z7W9E4w0XTbkDih1nW+SqGTR2Grv/2wWNDNCKf8ABefODvZt4EFVDs1A4QHg6xALiotw==", + "resolved": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/aecf20b4d5ee51af4a38a69a1b9c81e3e64b955c", + "integrity": "sha512-bOHP8+xVSQcd7CYJEvP3CWjz9pBRukIveqF/nnYiynjxw1v/FeM5PVuU1MSQtpNFK60JDwBiU9H0OYDNvDnm1Q==", "license": "MIT", "engines": { "node": ">=20.19.0" diff --git a/package.json b/package.json index 022e6c07..2a5e7484 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ }, "dependencies": { "@blockrun/llm": "^3.19.1", - "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/a9d7dd21e65c744104dd752a13d7bf5a71e27f01", + "@blockrun/model-catalog": "https://codeload.github.com/BlockRunAI/model-catalog/tar.gz/aecf20b4d5ee51af4a38a69a1b9c81e3e64b955c", "@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/fd6d03d035ff676642ba1683c333d929939f8a00", "@colbymchenry/codegraph": "^1.5.0", "@modelcontextprotocol/sdk": "^1.29.0",