jeo-code 0.7.57 → 0.7.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/package.json +1 -1
- package/src/agent/prompt-router.ts +37 -10
- package/src/ai/model-catalog-compat.ts +20 -4
- package/src/ai/model-catalog.ts +110 -83
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
The README mirrors the latest 5 entries — regenerate with `bun run changelog:sync`.
|
|
8
8
|
|
|
9
|
+
## [0.7.58] - 2026-07-07
|
|
10
|
+
_Applied the previous entry's `routing.crossProviderPool` to the real live session config, then deep-researched every catalogued model's actual public release date (2026-07 sourced, per-provider parallel research with citations) to answer "모델 설정은 2026년도 기준으로 딥서치해서 모델리스트 최신순으로 정렬" — while researching, found and fixed a genuine ranking bug this surfaced: `strongestCredentialed`'s tiebreak on a full capability tie (identical thinking/output/context) fell through to a raw alphabetical canonical-id compare, which silently picked the OLDEST model in a same-spec family (`claude-opus-4-6` over `claude-opus-4-7`/`4-8`, purely because `"4-6" < "4-8"` as a string) — confirmed reproducible before the fix, confirmed corrected after._
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`CatalogModel.releaseDate`** (`"YYYY-MM"`) on every catalog entry — deep-research sourced from each provider's own announcement (Anthropic/OpenAI/Google/xAI/Moonshot direct web_search per family; Tencent-hosted rebrands (DeepSeek/MiniMax/Zhipu GLM/Hunyuan) traced to the ORIGINAL developer's release, not Tencent's hosting-catalog appearance date). `gpt-5.4-mini` was never added to the catalog — confirmed absent both before and after this pass, per explicit request.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **`MODEL_CATALOG` reordered newest-first within every provider block** for human readability (routing correctness never depended on array order — the ranking functions below now sort/tiebreak explicitly).
|
|
17
|
+
- **Recency tiebreak replaces the arbitrary alphabetical one** in `cheapestCredentialed`/`strongestCredentialed`/`compareStrengthAscending` (`src/agent/prompt-router.ts`) — on an exact capability/cost tie, the NEWER `releaseDate` now wins (a missing date always sorts as oldest, so an unconfirmed date can never silently outrank a verified-newer model). Fixes the confirmed opus-4-6/4-7/4-8 bug above.
|
|
18
|
+
- **`catalogForProvider`'s secondary sort** (`src/ai/model-catalog-compat.ts`) now orders by `releaseDate` (newest first) instead of alphabetical id — this is the actual list order `/model`'s live picker and `jeo setup` show a user, so "정렬" now reaches the real user-facing surface, not just the raw catalog array.
|
|
19
|
+
- **`RECOMMENDED` provider defaults refreshed** to the current (2026-07) general-availability flagship per provider: `claude-sonnet-5` (was `claude-sonnet-4-6`), `gpt-5.5` (was `gpt-4o`), `gemini-3-flash` (was `gemini-2.0-flash`), `antigravity/gpt-5.5` (was `antigravity/gemini-3-pro-low`).
|
|
20
|
+
|
|
21
|
+
### Verified
|
|
22
|
+
- `bun run typecheck` clean; full suite 2710/2710 pass across 281 files (1 pre-existing unrelated flaky test — `session.test.ts`'s global-`JSON.parse`-mock count assertion, confirmed passing in isolation and on rerun — not a regression from this change).
|
|
23
|
+
- Live-executed the exact reported bug before AND after the fix: `strongestCredentialed(anthropicOnlyConfig, m => m.canonical.startsWith("claude-opus"))` returned `claude-opus-4-6` (oldest) before, `claude-opus-4-8` (newest, correct) after.
|
|
24
|
+
- Re-applied `routing.crossProviderPool: true` to the live user config (a concurrent interactive session had reset it via an unrelated `/model` command mid-turn) and reconfirmed via `jeo doctor`: all 4 tiers correctly resolve through the cross-provider pool across anthropic/gemini/antigravity.
|
|
25
|
+
|
|
9
26
|
## [0.7.57] - 2026-07-07
|
|
10
27
|
_"동급모델간 크로스 프로바이더 라우팅이 동작하게 개선" — v0.7.56's tier auto-select was single-winner by design (always the one cheapest/strongest model), so a user with `roles.smol` pinned (or simply multiple credentialed providers) never saw actual distribution across equivalent-class models. Deep-research-informed redesign: production LLM routers (LiteLLM, Bifrost/VoidLLM) model this as a named "model group" spanning provider deployments with a distribution strategy, not a single deterministic pick — jeo now supports both, opt-in._
|
|
11
28
|
|
package/README.ja.md
CHANGED
|
@@ -259,11 +259,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
259
259
|
## 変更履歴 (Changelog)
|
|
260
260
|
|
|
261
261
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
262
|
+
- **[0.7.58]** (2026-07-07) — Applied the previous entry's `routing.crossProviderPool` to the real live session config, then deep-researched every catalogued model's actual public release date (2026-07 sourced, per-provider parallel research with citations) to answer "모델 설정은 2026년도 기준으로 딥서치해서 모델리스트 최신순으로 정렬" — while researching, found and fixed a genuine ranking bug this surfaced: `strongestCredentialed`'s tiebreak on a full capability tie (identical thinking/output/context) fell through to a raw alphabetical canonical-id compare, which silently picked the OLDEST model in a same-spec family (`claude-opus-4-6` over `claude-opus-4-7`/`4-8`, purely because `"4-6" < "4-8"` as a string) — confirmed reproducible before the fix, confirmed corrected after.
|
|
262
263
|
- **[0.7.57]** (2026-07-07) — "동급모델간 크로스 프로바이더 라우팅이 동작하게 개선" — v0.7.56's tier auto-select was single-winner by design (always the one cheapest/strongest model), so a user with `roles.smol` pinned (or simply multiple credentialed providers) never saw actual distribution across equivalent-class models. Deep-research-informed redesign: production LLM routers (LiteLLM, Bifrost/VoidLLM) model this as a named "model group" spanning provider deployments with a distribution strategy, not a single deterministic pick — jeo now supports both, opt-in.
|
|
263
264
|
- **[0.7.56]** (2026-07-07) — "서로다른 프로바이더로 급에 따라 나눠서 설정하도록 개선" — PromptRouter's `trivial`/`complex` tiers previously collapsed to `defaultModel` whenever `roles.smol`/`roles.slow`/`routing.tiers.*` were left unconfigured (the documented "safe no-op absent configuration" contract), which meant a user with multiple providers credentialed never actually got cross-provider routing without hand-picking a model per tier. Also the long-term ask: routing must stay correct as jeo's model catalog evolves, never a hand-maintained tier→model table that goes stale.
|
|
264
265
|
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
265
266
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
266
|
-
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
267
267
|
|
|
268
268
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
269
269
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -260,11 +260,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
260
260
|
## 변경 이력 (Changelog)
|
|
261
261
|
|
|
262
262
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
263
|
+
- **[0.7.58]** (2026-07-07) — Applied the previous entry's `routing.crossProviderPool` to the real live session config, then deep-researched every catalogued model's actual public release date (2026-07 sourced, per-provider parallel research with citations) to answer "모델 설정은 2026년도 기준으로 딥서치해서 모델리스트 최신순으로 정렬" — while researching, found and fixed a genuine ranking bug this surfaced: `strongestCredentialed`'s tiebreak on a full capability tie (identical thinking/output/context) fell through to a raw alphabetical canonical-id compare, which silently picked the OLDEST model in a same-spec family (`claude-opus-4-6` over `claude-opus-4-7`/`4-8`, purely because `"4-6" < "4-8"` as a string) — confirmed reproducible before the fix, confirmed corrected after.
|
|
263
264
|
- **[0.7.57]** (2026-07-07) — "동급모델간 크로스 프로바이더 라우팅이 동작하게 개선" — v0.7.56's tier auto-select was single-winner by design (always the one cheapest/strongest model), so a user with `roles.smol` pinned (or simply multiple credentialed providers) never saw actual distribution across equivalent-class models. Deep-research-informed redesign: production LLM routers (LiteLLM, Bifrost/VoidLLM) model this as a named "model group" spanning provider deployments with a distribution strategy, not a single deterministic pick — jeo now supports both, opt-in.
|
|
264
265
|
- **[0.7.56]** (2026-07-07) — "서로다른 프로바이더로 급에 따라 나눠서 설정하도록 개선" — PromptRouter's `trivial`/`complex` tiers previously collapsed to `defaultModel` whenever `roles.smol`/`roles.slow`/`routing.tiers.*` were left unconfigured (the documented "safe no-op absent configuration" contract), which meant a user with multiple providers credentialed never actually got cross-provider routing without hand-picking a model per tier. Also the long-term ask: routing must stay correct as jeo's model catalog evolves, never a hand-maintained tier→model table that goes stale.
|
|
265
266
|
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
266
267
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
267
|
-
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
268
268
|
|
|
269
269
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
270
270
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -264,11 +264,11 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
|
|
|
264
264
|
## Changelog
|
|
265
265
|
|
|
266
266
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
267
|
+
- **[0.7.58]** (2026-07-07) — Applied the previous entry's `routing.crossProviderPool` to the real live session config, then deep-researched every catalogued model's actual public release date (2026-07 sourced, per-provider parallel research with citations) to answer "모델 설정은 2026년도 기준으로 딥서치해서 모델리스트 최신순으로 정렬" — while researching, found and fixed a genuine ranking bug this surfaced: `strongestCredentialed`'s tiebreak on a full capability tie (identical thinking/output/context) fell through to a raw alphabetical canonical-id compare, which silently picked the OLDEST model in a same-spec family (`claude-opus-4-6` over `claude-opus-4-7`/`4-8`, purely because `"4-6" < "4-8"` as a string) — confirmed reproducible before the fix, confirmed corrected after.
|
|
267
268
|
- **[0.7.57]** (2026-07-07) — "동급모델간 크로스 프로바이더 라우팅이 동작하게 개선" — v0.7.56's tier auto-select was single-winner by design (always the one cheapest/strongest model), so a user with `roles.smol` pinned (or simply multiple credentialed providers) never saw actual distribution across equivalent-class models. Deep-research-informed redesign: production LLM routers (LiteLLM, Bifrost/VoidLLM) model this as a named "model group" spanning provider deployments with a distribution strategy, not a single deterministic pick — jeo now supports both, opt-in.
|
|
268
269
|
- **[0.7.56]** (2026-07-07) — "서로다른 프로바이더로 급에 따라 나눠서 설정하도록 개선" — PromptRouter's `trivial`/`complex` tiers previously collapsed to `defaultModel` whenever `roles.smol`/`roles.slow`/`routing.tiers.*` were left unconfigured (the documented "safe no-op absent configuration" contract), which meant a user with multiple providers credentialed never actually got cross-provider routing without hand-picking a model per tier. Also the long-term ask: routing must stay correct as jeo's model catalog evolves, never a hand-maintained tier→model table that goes stale.
|
|
269
270
|
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
270
271
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
271
|
-
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
272
272
|
|
|
273
273
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
274
274
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -259,11 +259,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
259
259
|
## 更新日志 (Changelog)
|
|
260
260
|
|
|
261
261
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
262
|
+
- **[0.7.58]** (2026-07-07) — Applied the previous entry's `routing.crossProviderPool` to the real live session config, then deep-researched every catalogued model's actual public release date (2026-07 sourced, per-provider parallel research with citations) to answer "모델 설정은 2026년도 기준으로 딥서치해서 모델리스트 최신순으로 정렬" — while researching, found and fixed a genuine ranking bug this surfaced: `strongestCredentialed`'s tiebreak on a full capability tie (identical thinking/output/context) fell through to a raw alphabetical canonical-id compare, which silently picked the OLDEST model in a same-spec family (`claude-opus-4-6` over `claude-opus-4-7`/`4-8`, purely because `"4-6" < "4-8"` as a string) — confirmed reproducible before the fix, confirmed corrected after.
|
|
262
263
|
- **[0.7.57]** (2026-07-07) — "동급모델간 크로스 프로바이더 라우팅이 동작하게 개선" — v0.7.56's tier auto-select was single-winner by design (always the one cheapest/strongest model), so a user with `roles.smol` pinned (or simply multiple credentialed providers) never saw actual distribution across equivalent-class models. Deep-research-informed redesign: production LLM routers (LiteLLM, Bifrost/VoidLLM) model this as a named "model group" spanning provider deployments with a distribution strategy, not a single deterministic pick — jeo now supports both, opt-in.
|
|
263
264
|
- **[0.7.56]** (2026-07-07) — "서로다른 프로바이더로 급에 따라 나눠서 설정하도록 개선" — PromptRouter's `trivial`/`complex` tiers previously collapsed to `defaultModel` whenever `roles.smol`/`roles.slow`/`routing.tiers.*` were left unconfigured (the documented "safe no-op absent configuration" contract), which meant a user with multiple providers credentialed never actually got cross-provider routing without hand-picking a model per tier. Also the long-term ask: routing must stay correct as jeo's model catalog evolves, never a hand-maintained tier→model table that goes stale.
|
|
264
265
|
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
265
266
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
266
|
-
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
267
267
|
|
|
268
268
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
269
269
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
|
@@ -233,6 +233,21 @@ function sizeClassFor(canonical: string): "small" | "mid" | "large" | null {
|
|
|
233
233
|
|
|
234
234
|
const TIER_TO_SIZE_CLASS: Record<PromptTier, "small" | "mid" | "large"> = { trivial: "small", standard: "mid", high: "mid", complex: "large" };
|
|
235
235
|
|
|
236
|
+
/** Compares `releaseDate` ("YYYY-MM", lexicographically sortable). `>0` when `a`
|
|
237
|
+
* is NEWER than `b`. A missing date sorts as OLDEST on that side — an
|
|
238
|
+
* unconfirmed date can never silently outrank a verified-newer model. Shared
|
|
239
|
+
* recency tiebreak for `compareStrengthAscending`/`cheapestCredentialed`/
|
|
240
|
+
* `strongestCredentialed`, replacing the arbitrary alphabetical canonical-id
|
|
241
|
+
* tiebreak those used before (which, on a full capability tie, picked the
|
|
242
|
+
* OLDEST id alphabetically — e.g. `claude-opus-4-6` beating `claude-opus-4-8`
|
|
243
|
+
* as "strongest" purely because "4-6" < "4-8" as a string). */
|
|
244
|
+
function compareRecency(a: CatalogModel, b: CatalogModel): number {
|
|
245
|
+
if (a.releaseDate === b.releaseDate) return 0;
|
|
246
|
+
if (!a.releaseDate) return -1;
|
|
247
|
+
if (!b.releaseDate) return 1;
|
|
248
|
+
return a.releaseDate < b.releaseDate ? -1 : 1;
|
|
249
|
+
}
|
|
250
|
+
|
|
236
251
|
/** Multi-key strength comparator (ascending: weakest first) — same ranking signals
|
|
237
252
|
* as `strongestCredentialed`'s single-winner tiebreak, reused here to bucket
|
|
238
253
|
* UNCLASSIFIED (no size-suffix) models into a tercile fallback. */
|
|
@@ -242,6 +257,8 @@ function compareStrengthAscending(a: CatalogModel, b: CatalogModel): number {
|
|
|
242
257
|
if (xhighA !== xhighB) return xhighA - xhighB;
|
|
243
258
|
if (a.maxOutputTokens !== b.maxOutputTokens) return a.maxOutputTokens - b.maxOutputTokens;
|
|
244
259
|
if (a.contextTokens !== b.contextTokens) return a.contextTokens - b.contextTokens;
|
|
260
|
+
const recency = compareRecency(a, b);
|
|
261
|
+
if (recency !== 0) return recency;
|
|
245
262
|
return a.canonical < b.canonical ? -1 : a.canonical > b.canonical ? 1 : 0;
|
|
246
263
|
}
|
|
247
264
|
|
|
@@ -297,8 +314,10 @@ export function selectFromPool(pool: readonly string[], sessionId: string | unde
|
|
|
297
314
|
/** Cheapest cloud model jeo has a credential for, computed LIVE off
|
|
298
315
|
* `MODEL_CATALOG`/`priceForModel` — picks up new/repriced catalog entries
|
|
299
316
|
* automatically, never a hand-maintained id. `null` when no credentialed
|
|
300
|
-
* model has a known price (caller falls back to `defaultModel`). Tiebreak
|
|
301
|
-
*
|
|
317
|
+
* model has a known price (caller falls back to `defaultModel`). Tiebreak on
|
|
318
|
+
* an exact cost tie: NEWER `releaseDate` wins (a same-priced newer model is
|
|
319
|
+
* likely a refined successor), then canonical id (deterministic fallback
|
|
320
|
+
* when recency also ties or is unconfirmed on both sides). */
|
|
302
321
|
export function cheapestCredentialed(config: RoutingConfig): string | null {
|
|
303
322
|
let best: CatalogModel | null = null;
|
|
304
323
|
let bestCost = Infinity;
|
|
@@ -312,9 +331,12 @@ export function cheapestCredentialed(config: RoutingConfig): string | null {
|
|
|
312
331
|
const price = priceForModel(m.canonical);
|
|
313
332
|
if (!price) continue;
|
|
314
333
|
const cost = price.inPerM + price.outPerM;
|
|
315
|
-
if (cost < bestCost
|
|
334
|
+
if (cost < bestCost) {
|
|
316
335
|
best = m;
|
|
317
336
|
bestCost = cost;
|
|
337
|
+
} else if (cost === bestCost && best) {
|
|
338
|
+
const recency = compareRecency(m, best);
|
|
339
|
+
if (recency > 0 || (recency === 0 && m.canonical < best.canonical)) best = m;
|
|
318
340
|
}
|
|
319
341
|
}
|
|
320
342
|
return best?.canonical ?? null;
|
|
@@ -322,13 +344,16 @@ export function cheapestCredentialed(config: RoutingConfig): string | null {
|
|
|
322
344
|
|
|
323
345
|
/** Most capable cloud model jeo has a credential for, computed LIVE off
|
|
324
346
|
* `MODEL_CATALOG` — ranks by full (xhigh) thinking support first, then max
|
|
325
|
-
* output tokens, then context window,
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
347
|
+
* output tokens, then context window, then NEWER `releaseDate` (a same-specs
|
|
348
|
+
* model with a later release date is presumptively a refined successor — e.g.
|
|
349
|
+
* `claude-opus-4-8` over `claude-opus-4-6`, which the OLD alphabetical
|
|
350
|
+
* canonical-id tiebreak got backwards, since `"4-6" < "4-8"` picked the
|
|
351
|
+
* OLDEST opus as "strongest"), then canonical id (final deterministic
|
|
352
|
+
* fallback). `null` when no credentialed model qualifies (caller falls back
|
|
353
|
+
* to `defaultModel`). Excludes `limitedAvailability` models (e.g.
|
|
354
|
+
* `claude-mythos-5`) — a provider credential doesn't imply access to a
|
|
355
|
+
* specific invite-only model; explicit `/model`/`routing.tiers` can still
|
|
356
|
+
* target one by id for approved accounts. */
|
|
332
357
|
export function strongestCredentialed(
|
|
333
358
|
config: RoutingConfig,
|
|
334
359
|
filter?: (m: CatalogModel) => boolean
|
|
@@ -344,6 +369,8 @@ export function strongestCredentialed(
|
|
|
344
369
|
if (xhighM !== xhighBest) { if (xhighM > xhighBest) best = m; continue; }
|
|
345
370
|
if (m.maxOutputTokens !== best.maxOutputTokens) { if (m.maxOutputTokens > best.maxOutputTokens) best = m; continue; }
|
|
346
371
|
if (m.contextTokens !== best.contextTokens) { if (m.contextTokens > best.contextTokens) best = m; continue; }
|
|
372
|
+
const recency = compareRecency(m, best);
|
|
373
|
+
if (recency !== 0) { if (recency > 0) best = m; continue; }
|
|
347
374
|
if (m.canonical < best.canonical) best = m;
|
|
348
375
|
}
|
|
349
376
|
return best?.canonical ?? null;
|
|
@@ -19,10 +19,18 @@ export interface ModelCatalogEntry {
|
|
|
19
19
|
recommended?: boolean;
|
|
20
20
|
note?: string;
|
|
21
21
|
company?: string;
|
|
22
|
+
/** Public release date, `"YYYY-MM"` — see `CatalogModel.releaseDate`. Drives
|
|
23
|
+
* `catalogForProvider`'s newest-first secondary sort. */
|
|
24
|
+
releaseDate?: string;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
/** Canonical ids
|
|
25
|
-
|
|
27
|
+
/** Canonical ids surfaced as a provider's recommended default — the current
|
|
28
|
+
* (2026-07 deep-research verified) general-availability flagship per provider,
|
|
29
|
+
* NOT necessarily the single most expensive/most-capable model (e.g. Anthropic's
|
|
30
|
+
* actual top tier, claude-fable-5, is pricier than the "recommended" sonnet-5 —
|
|
31
|
+
* recommended means "solid everyday default", not "strongest"). Re-verify and
|
|
32
|
+
* update whenever a provider ships a new default-tier release. */
|
|
33
|
+
const RECOMMENDED: Record<string, true> = { "claude-sonnet-5": true, "gpt-5.5": true, "gemini-3-flash": true, "antigravity/gpt-5.5": true, "qwen2.5": true };
|
|
26
34
|
|
|
27
35
|
export function normalizeModelId(id: string): string {
|
|
28
36
|
return (id ?? "").trim().toLowerCase();
|
|
@@ -35,9 +43,10 @@ function adapt(m: CatalogModel): ModelCatalogEntry {
|
|
|
35
43
|
provider: m.provider,
|
|
36
44
|
contextWindow: m.contextTokens,
|
|
37
45
|
reasoning,
|
|
38
|
-
recommended: RECOMMENDED
|
|
46
|
+
recommended: !!RECOMMENDED[m.canonical],
|
|
39
47
|
note: `${formatTokens(m.contextTokens)} ctx${reasoning ? ", reasoning" : ""}`,
|
|
40
48
|
company: m.company,
|
|
49
|
+
releaseDate: m.releaseDate,
|
|
41
50
|
};
|
|
42
51
|
}
|
|
43
52
|
|
|
@@ -50,12 +59,19 @@ export function findCatalogEntry(id: string): ModelCatalogEntry | undefined {
|
|
|
50
59
|
return hit ? adapt(hit) : undefined;
|
|
51
60
|
}
|
|
52
61
|
|
|
53
|
-
/** Entries for a provider, recommended first then by
|
|
62
|
+
/** Entries for a provider, recommended first, then NEWEST-FIRST by `releaseDate`
|
|
63
|
+
* (undated entries sort last, tiebroken by id) — this is the actual list order
|
|
64
|
+
* `/model`'s live picker and `jeo setup`'s recommendation prompt show a user. */
|
|
54
65
|
export function catalogForProvider(provider: ProviderName): ModelCatalogEntry[] {
|
|
55
66
|
return catalogByProvider(provider)
|
|
56
67
|
.map(adapt)
|
|
57
68
|
.sort((a, b) => {
|
|
58
69
|
if (!!b.recommended !== !!a.recommended) return b.recommended ? 1 : -1;
|
|
70
|
+
if (a.releaseDate !== b.releaseDate) {
|
|
71
|
+
if (!a.releaseDate) return 1;
|
|
72
|
+
if (!b.releaseDate) return -1;
|
|
73
|
+
return b.releaseDate.localeCompare(a.releaseDate);
|
|
74
|
+
}
|
|
59
75
|
return a.id.localeCompare(b.id);
|
|
60
76
|
});
|
|
61
77
|
}
|
package/src/ai/model-catalog.ts
CHANGED
|
@@ -36,35 +36,59 @@ export interface CatalogModel {
|
|
|
36
36
|
* selection) excludes these; explicit `/model` or `routing.tiers.*.model`
|
|
37
37
|
* can still target them by id for approved accounts. */
|
|
38
38
|
limitedAvailability?: boolean;
|
|
39
|
+
/** Public release date, `"YYYY-MM"` (lexicographically sortable) — deep-research
|
|
40
|
+
* sourced from each provider's own announcement. Drives newest-first catalog
|
|
41
|
+
* ordering and recency-based tiebreaks in prompt-router.ts's ranking functions
|
|
42
|
+
* (`compareStrengthAscending`, `cheapestCredentialed`, `strongestCredentialed`)
|
|
43
|
+
* so a genuinely newer same-tier model wins a tie instead of an arbitrary
|
|
44
|
+
* alphabetical pick. Omitted (undefined) for ids with no confirmed public
|
|
45
|
+
* date — these sort AFTER every dated entry within their block, never before,
|
|
46
|
+
* so an unconfirmed date can never silently outrank a verified-newer model. */
|
|
47
|
+
releaseDate?: string;
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
const FULL: ThinkLevel[] = ["low", "medium", "high", "xhigh"];
|
|
42
51
|
const STD: ThinkLevel[] = ["low", "medium", "high"];
|
|
43
52
|
|
|
53
|
+
// [canonical model id, release YYYY-MM] tuples, deep-research sourced (Anthropic/
|
|
54
|
+
// OpenAI/Google base-model announcement dates — antigravity is a hosting layer over
|
|
55
|
+
// the SAME underlying models, not a separate release). Newest-first per family below;
|
|
56
|
+
// -thinking/-high/-low suffixes are reasoning-effort variants of the SAME release.
|
|
44
57
|
export const ANTIGRAVITY_MODELS = [
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"claude-opus-4-8",
|
|
49
|
-
"claude-opus-4-8-thinking",
|
|
50
|
-
"claude-
|
|
51
|
-
"claude-
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"gemini-3-flash",
|
|
56
|
-
"gemini-3-pro-high",
|
|
57
|
-
"gemini-3-pro-low",
|
|
58
|
-
"
|
|
59
|
-
"gemini-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
58
|
+
["gpt-5.5", "2026-04"],
|
|
59
|
+
["gemini-3.1-pro-high", "2026-02"],
|
|
60
|
+
["gemini-3.1-pro-low", "2026-02"],
|
|
61
|
+
["claude-opus-4-8", "2026-05"],
|
|
62
|
+
["claude-opus-4-8-thinking", "2026-05"],
|
|
63
|
+
["claude-opus-4-7", "2026-04"],
|
|
64
|
+
["claude-opus-4-7-thinking", "2026-04"],
|
|
65
|
+
["claude-sonnet-4-6", "2026-02"],
|
|
66
|
+
["claude-sonnet-4-6-thinking", "2026-02"],
|
|
67
|
+
["claude-opus-4-6-thinking", "2026-02"],
|
|
68
|
+
["gemini-3-flash", "2025-12"],
|
|
69
|
+
["gemini-3-pro-high", "2025-11"],
|
|
70
|
+
["gemini-3-pro-low", "2025-11"],
|
|
71
|
+
["gpt-oss-120b-medium", "2025-08"],
|
|
72
|
+
["gemini-2.5-flash", "2025-06"],
|
|
73
|
+
["gemini-2.5-flash-thinking", "2025-06"],
|
|
74
|
+
["gemini-2.5-pro", "2025-03"],
|
|
62
75
|
] as const;
|
|
63
76
|
|
|
64
|
-
/** A curated set of common public models with their documented capabilities.
|
|
77
|
+
/** A curated set of common public models with their documented capabilities.
|
|
78
|
+
* Ordered NEWEST-FIRST within each provider block per `releaseDate`
|
|
79
|
+
* (deep-research sourced from each provider's own announcement — see the
|
|
80
|
+
* v0.7.58 CHANGELOG entry for the full per-model source list). Purely for
|
|
81
|
+
* human readability / "what's current" at a glance — routing correctness
|
|
82
|
+
* does not depend on array order: `prompt-router.ts`'s ranking functions
|
|
83
|
+
* (`cheapestCredentialed`/`strongestCredentialed`/`compareStrengthAscending`)
|
|
84
|
+
* now tiebreak on `releaseDate` directly rather than relying on position. */
|
|
65
85
|
export const MODEL_CATALOG: readonly CatalogModel[] = [
|
|
66
|
-
// Anthropic
|
|
67
|
-
{ canonical: "claude-
|
|
86
|
+
// Anthropic (newest first: sonnet-5 > fable-5 > opus-4-8 > opus-4-7 > sonnet-4-6 > opus-4-6 > haiku-4-5)
|
|
87
|
+
{ canonical: "claude-sonnet-5", provider: "anthropic", providerModel: "claude-sonnet-5", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-06" },
|
|
88
|
+
// Fable 5 = Anthropic's most capable widely-released model (adaptive thinking always on);
|
|
89
|
+
// Mythos 5 is limited-availability (Project Glasswing) but callable by id for approved accounts.
|
|
90
|
+
{ canonical: "claude-fable-5", provider: "anthropic", providerModel: "claude-fable-5", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-06" },
|
|
91
|
+
{ canonical: "claude-mythos-5", provider: "anthropic", providerModel: "claude-mythos-5", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, limitedAvailability: true, releaseDate: "2026-06" },
|
|
68
92
|
// NOTE: opus 4.6+ use Anthropic ADAPTIVE thinking (type:"adaptive" + output_config.effort).
|
|
69
93
|
// opus 4.7/4.8 OMIT visible thought unless the request opts into `display: "summarized"` —
|
|
70
94
|
// anthropic.ts sets that on the adaptive transport so reasoning streams again (gjc parity).
|
|
@@ -72,50 +96,54 @@ export const MODEL_CATALOG: readonly CatalogModel[] = [
|
|
|
72
96
|
// The 4.6 generation onward is 1M context / 128k sync max output (Anthropic docs:
|
|
73
97
|
// Opus 4.8 & Sonnet 5 comparison table; Opus 4.6/4.7, Sonnet 4.6 share the gen's
|
|
74
98
|
// dateless-snapshot 1M/128k + 300k batch-output beta). Dated pre-4.6 ids keep 200k/64k.
|
|
75
|
-
{ canonical: "claude-opus-4-
|
|
76
|
-
{ canonical: "claude-opus-4-7", provider: "anthropic", providerModel: "claude-opus-4-7", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true },
|
|
77
|
-
{ canonical: "claude-
|
|
78
|
-
{ canonical: "claude-
|
|
79
|
-
{ canonical: "claude-
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
{ canonical: "
|
|
83
|
-
{ canonical: "
|
|
84
|
-
|
|
85
|
-
{ canonical: "gpt-
|
|
86
|
-
{ canonical: "
|
|
87
|
-
{ canonical: "gpt-
|
|
88
|
-
{ canonical: "
|
|
89
|
-
|
|
90
|
-
{ canonical: "
|
|
91
|
-
{ canonical: "
|
|
92
|
-
{ canonical: "
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
{ canonical: "
|
|
96
|
-
{ canonical: "
|
|
97
|
-
{ canonical: "
|
|
98
|
-
|
|
99
|
-
{ canonical: "kimi-k2-0711-preview", provider: "kimi", providerModel: "kimi-k2-0711-preview", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: false },
|
|
100
|
-
{ canonical: "kimi-thinking-preview", provider: "kimi", providerModel: "kimi-thinking-preview", contextTokens: 128_000, maxOutputTokens: 32_000, thinking: FULL, images: true },
|
|
101
|
-
{ canonical: "kimi-latest", provider: "kimi", providerModel: "kimi-latest", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: true },
|
|
102
|
-
{ canonical: "moonshot-v1-128k", provider: "kimi", providerModel: "moonshot-v1-128k", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: false },
|
|
99
|
+
{ canonical: "claude-opus-4-8", provider: "anthropic", providerModel: "claude-opus-4-8", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-05" },
|
|
100
|
+
{ canonical: "claude-opus-4-7", provider: "anthropic", providerModel: "claude-opus-4-7", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-04" },
|
|
101
|
+
{ canonical: "claude-sonnet-4-6", provider: "anthropic", providerModel: "claude-sonnet-4-6", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-02" },
|
|
102
|
+
{ canonical: "claude-opus-4-6", provider: "anthropic", providerModel: "claude-opus-4-6", contextTokens: 1_000_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-02" },
|
|
103
|
+
{ canonical: "claude-haiku-4-5", provider: "anthropic", providerModel: "claude-haiku-4-5-20251001", contextTokens: 200_000, maxOutputTokens: 64_000, thinking: FULL, images: true, releaseDate: "2025-10" },
|
|
104
|
+
// OpenAI (newest first: gpt-5.5 > gpt-5.4 > o4-mini/o3/gpt-4.1 > o3-mini > gpt-4o-mini > gpt-4o)
|
|
105
|
+
{ canonical: "gpt-5.5", provider: "openai", providerModel: "gpt-5.5", contextTokens: 400_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-04" },
|
|
106
|
+
{ canonical: "gpt-5.4", provider: "openai", providerModel: "gpt-5.4", contextTokens: 400_000, maxOutputTokens: 128_000, thinking: FULL, images: true, releaseDate: "2026-03" },
|
|
107
|
+
{ canonical: "o4-mini", provider: "openai", providerModel: "o4-mini", contextTokens: 200_000, maxOutputTokens: 100_000, thinking: STD, images: true, releaseDate: "2025-04" },
|
|
108
|
+
{ canonical: "o3", provider: "openai", providerModel: "o3", contextTokens: 200_000, maxOutputTokens: 100_000, thinking: STD, images: true, releaseDate: "2025-04" },
|
|
109
|
+
{ canonical: "gpt-4.1", provider: "openai", providerModel: "gpt-4.1", contextTokens: 1_000_000, maxOutputTokens: 32_768, thinking: [], images: true, releaseDate: "2025-04" },
|
|
110
|
+
{ canonical: "o3-mini", provider: "openai", providerModel: "o3-mini", contextTokens: 200_000, maxOutputTokens: 100_000, thinking: STD, images: false, releaseDate: "2025-01" },
|
|
111
|
+
{ canonical: "gpt-4o-mini", provider: "openai", providerModel: "gpt-4o-mini", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: true, releaseDate: "2024-07" },
|
|
112
|
+
{ canonical: "gpt-4o", provider: "openai", providerModel: "gpt-4o", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: true, releaseDate: "2024-05" },
|
|
113
|
+
// xAI (Grok) — OpenAI-compatible at https://api.x.ai/v1 (XAI_API_KEY). Newest first.
|
|
114
|
+
{ canonical: "grok-4.3", provider: "xai", providerModel: "grok-4.3", contextTokens: 256_000, maxOutputTokens: 64_000, thinking: FULL, images: true, releaseDate: "2026-04" },
|
|
115
|
+
{ canonical: "grok-4-fast-reasoning", provider: "xai", providerModel: "grok-4-fast-reasoning", contextTokens: 2_000_000, maxOutputTokens: 64_000, thinking: FULL, images: true, releaseDate: "2025-09" },
|
|
116
|
+
{ canonical: "grok-4-fast-non-reasoning", provider: "xai", providerModel: "grok-4-fast-non-reasoning", contextTokens: 2_000_000, maxOutputTokens: 64_000, thinking: [], images: true, releaseDate: "2025-09" },
|
|
117
|
+
{ canonical: "grok-code-fast-1", provider: "xai", providerModel: "grok-code-fast-1", contextTokens: 256_000, maxOutputTokens: 64_000, thinking: FULL, images: false, releaseDate: "2025-08" },
|
|
118
|
+
// Kimi (Moonshot) — OpenAI-compatible at https://api.moonshot.ai/v1 (KIMI_API_KEY). Newest first.
|
|
119
|
+
{ canonical: "kimi-k2-0711-preview", provider: "kimi", providerModel: "kimi-k2-0711-preview", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: false, releaseDate: "2025-07" },
|
|
120
|
+
{ canonical: "kimi-thinking-preview", provider: "kimi", providerModel: "kimi-thinking-preview", contextTokens: 128_000, maxOutputTokens: 32_000, thinking: FULL, images: true, releaseDate: "2025-05" },
|
|
121
|
+
{ canonical: "kimi-latest", provider: "kimi", providerModel: "kimi-latest", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: true, releaseDate: "2025-02" },
|
|
122
|
+
{ canonical: "moonshot-v1-128k", provider: "kimi", providerModel: "moonshot-v1-128k", contextTokens: 128_000, maxOutputTokens: 16_384, thinking: [], images: false, releaseDate: "2024-01" },
|
|
103
123
|
// Kimi Code (Moonshot coding subscription, device-code OAuth) — Anthropic-compatible
|
|
104
124
|
// at https://api.kimi.com/coding. Provider-qualified (`kimi/…`) to avoid canonical
|
|
105
125
|
// collisions (kimi-k2.5 also exists under tencent). gjc catalog parity: kimi-code.
|
|
106
|
-
|
|
107
|
-
{ canonical: "kimi-k2.7-code", provider: "kimi", providerModel: "kimi/kimi-k2.7-code", contextTokens: 262_144, maxOutputTokens: 65_536, thinking: FULL, images: true, company: "Moonshot (Kimi Code)" },
|
|
108
|
-
{ canonical: "kimi
|
|
109
|
-
{ canonical: "kimi/kimi-k2
|
|
110
|
-
{ canonical: "kimi/kimi-k2", provider: "kimi", providerModel: "kimi/kimi-k2", contextTokens: 262_144, maxOutputTokens:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{ canonical: "gemini-
|
|
114
|
-
{ canonical: "gemini-
|
|
115
|
-
{ canonical: "gemini-
|
|
126
|
+
// Newest first.
|
|
127
|
+
{ canonical: "kimi-k2.7-code", provider: "kimi", providerModel: "kimi/kimi-k2.7-code", contextTokens: 262_144, maxOutputTokens: 65_536, thinking: FULL, images: true, company: "Moonshot (Kimi Code)", releaseDate: "2026-06" },
|
|
128
|
+
{ canonical: "kimi-for-coding", provider: "kimi", providerModel: "kimi/kimi-for-coding", contextTokens: 262_144, maxOutputTokens: 32_000, thinking: FULL, images: true, company: "Moonshot (Kimi Code)", releaseDate: "2026-01" }, // [INFERENCE] alias-registration date approximated from Kimi CLI's 2026-01 launch — no primary-source changelog entry found
|
|
129
|
+
{ canonical: "kimi/kimi-k2.5", provider: "kimi", providerModel: "kimi/kimi-k2.5", contextTokens: 262_144, maxOutputTokens: 65_536, thinking: FULL, images: true, company: "Moonshot (Kimi Code)", releaseDate: "2026-01" },
|
|
130
|
+
{ canonical: "kimi/kimi-k2-turbo-preview", provider: "kimi", providerModel: "kimi/kimi-k2-turbo-preview", contextTokens: 262_144, maxOutputTokens: 32_000, thinking: FULL, images: false, company: "Moonshot (Kimi Code)", releaseDate: "2025-08" },
|
|
131
|
+
{ canonical: "kimi/kimi-k2", provider: "kimi", providerModel: "kimi/kimi-k2", contextTokens: 262_144, maxOutputTokens: 262_144, thinking: [], images: false, company: "Moonshot (Kimi Code)", releaseDate: "2025-07" },
|
|
132
|
+
// Google (newest first: gemini-3.1-pro > gemini-3-* > gemini-2.5-* > gemini-2.0-flash > gemini-1.5-pro)
|
|
133
|
+
{ canonical: "gemini-3.1-pro-high", provider: "gemini", providerModel: "gemini-3.1-pro-high", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: FULL, images: true, releaseDate: "2026-02" },
|
|
134
|
+
{ canonical: "gemini-3.1-pro-low", provider: "gemini", providerModel: "gemini-3.1-pro-low", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: FULL, images: true, releaseDate: "2026-02" },
|
|
135
|
+
{ canonical: "gemini-3-flash", provider: "gemini", providerModel: "gemini-3-flash", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: FULL, images: true, releaseDate: "2025-12" },
|
|
136
|
+
{ canonical: "gemini-3-pro-high", provider: "gemini", providerModel: "gemini-3-pro-high", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: FULL, images: true, releaseDate: "2025-11" },
|
|
137
|
+
{ canonical: "gemini-3-pro-low", provider: "gemini", providerModel: "gemini-3-pro-low", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: FULL, images: true, releaseDate: "2025-11" },
|
|
138
|
+
{ canonical: "gemini-2.5-flash", provider: "gemini", providerModel: "gemini-2.5-flash", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: STD, images: true, releaseDate: "2025-06" },
|
|
139
|
+
{ canonical: "gemini-2.5-pro", provider: "gemini", providerModel: "gemini-2.5-pro", contextTokens: 1_000_000, maxOutputTokens: 65_536, thinking: STD, images: true, releaseDate: "2025-03" },
|
|
140
|
+
{ canonical: "gemini-2.0-flash", provider: "gemini", providerModel: "gemini-2.0-flash", contextTokens: 1_000_000, maxOutputTokens: 8_192, thinking: [], images: true, releaseDate: "2025-02" },
|
|
141
|
+
{ canonical: "gemini-1.5-pro", provider: "gemini", providerModel: "gemini-1.5-pro", contextTokens: 1_000_000, maxOutputTokens: 8_192, thinking: [], images: true, releaseDate: "2024-02" },
|
|
116
142
|
// Google Antigravity / Gemini CLI (Cloud Code Assist) — provider-qualified to avoid
|
|
117
|
-
// collisions with public Gemini, Anthropic, and OpenAI/Codex ids.
|
|
118
|
-
|
|
143
|
+
// collisions with public Gemini, Anthropic, and OpenAI/Codex ids. A hosting layer
|
|
144
|
+
// over the SAME underlying models researched above, not a separate release —
|
|
145
|
+
// releaseDate comes from the [id, date] tuple, not re-derived.
|
|
146
|
+
...ANTIGRAVITY_MODELS.map(([id, releaseDate]): CatalogModel => ({
|
|
119
147
|
canonical: `antigravity/${id}`,
|
|
120
148
|
provider: "antigravity",
|
|
121
149
|
providerModel: id,
|
|
@@ -124,31 +152,30 @@ export const MODEL_CATALOG: readonly CatalogModel[] = [
|
|
|
124
152
|
thinking: id.includes("thinking") || id.includes("-high") || id.includes("-low") || id.includes("gemini-3") || id.startsWith("gpt-5") ? FULL : STD,
|
|
125
153
|
images: !id.includes("gpt-oss"),
|
|
126
154
|
company: id.includes("claude") ? "Anthropic via Antigravity" : id.includes("gpt") ? "OpenAI via Antigravity" : "Google Antigravity",
|
|
155
|
+
releaseDate,
|
|
127
156
|
})),
|
|
128
|
-
// Tencent
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
{ canonical: "
|
|
133
|
-
{ canonical: "
|
|
134
|
-
{ canonical: "deepseek-
|
|
135
|
-
|
|
136
|
-
{ canonical: "
|
|
137
|
-
{ canonical: "
|
|
138
|
-
{ canonical: "
|
|
139
|
-
|
|
140
|
-
{ canonical: "
|
|
141
|
-
{ canonical: "
|
|
142
|
-
{ canonical: "glm-5", provider: "tencent", providerModel: "glm-5", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent" },
|
|
143
|
-
{ canonical: "glm-5-turbo", provider: "tencent", providerModel: "glm-5-turbo", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent" },
|
|
144
|
-
{ canonical: "
|
|
145
|
-
|
|
146
|
-
{ canonical: "kimi-k2.
|
|
147
|
-
{ canonical: "
|
|
148
|
-
// Tencent — Hunyuan MT
|
|
149
|
-
{ canonical: "hy-mt2-plus", provider: "tencent", providerModel: "hy-mt2-plus", contextTokens: 128_000, maxOutputTokens: 8192, thinking: STD, images: false, company: "Tencent" },
|
|
157
|
+
// Tencent — hosts the same underlying models under its own cloud brand; dates
|
|
158
|
+
// below are the ORIGINAL developer's release (DeepSeek/MiniMax/Zhipu/Moonshot),
|
|
159
|
+
// not Tencent's hosting-catalog appearance date, except where the id itself pins
|
|
160
|
+
// a Tencent-specific snapshot (the two `-2026XX` suffixed DeepSeek ids). Newest first overall.
|
|
161
|
+
{ canonical: "glm-5.2", provider: "tencent", providerModel: "glm-5.2", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-06" },
|
|
162
|
+
{ canonical: "hy-mt2-plus", provider: "tencent", providerModel: "hy-mt2-plus", contextTokens: 128_000, maxOutputTokens: 8192, thinking: STD, images: false, company: "Tencent", releaseDate: "2026-06" },
|
|
163
|
+
{ canonical: "deepseek-v4-pro-202606", provider: "tencent", providerModel: "deepseek-v4-pro-202606", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-06" },
|
|
164
|
+
{ canonical: "minimax-m3", provider: "tencent", providerModel: "minimax-m3", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-06" },
|
|
165
|
+
{ canonical: "deepseek-v4-flash-202605", provider: "tencent", providerModel: "deepseek-v4-flash-202605", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-05" },
|
|
166
|
+
{ canonical: "glm-5v-turbo", provider: "tencent", providerModel: "glm-5v-turbo", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: true, company: "Tencent", releaseDate: "2026-04" },
|
|
167
|
+
{ canonical: "deepseek-v4-pro", provider: "tencent", providerModel: "deepseek-v4-pro", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-04" },
|
|
168
|
+
{ canonical: "deepseek-v4-flash", provider: "tencent", providerModel: "deepseek-v4-flash", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-04" },
|
|
169
|
+
{ canonical: "kimi-k2.6", provider: "tencent", providerModel: "kimi-k2.6", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-04" },
|
|
170
|
+
{ canonical: "minimax-m2.7", provider: "tencent", providerModel: "minimax-m2.7", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-03" },
|
|
171
|
+
{ canonical: "glm-5.1", provider: "tencent", providerModel: "glm-5.1", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-03" },
|
|
172
|
+
{ canonical: "glm-5-turbo", provider: "tencent", providerModel: "glm-5-turbo", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-03" },
|
|
173
|
+
{ canonical: "minimax-m2.5", provider: "tencent", providerModel: "minimax-m2.5", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-02" },
|
|
174
|
+
{ canonical: "glm-5", provider: "tencent", providerModel: "glm-5", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-02" },
|
|
175
|
+
{ canonical: "kimi-k2.5", provider: "tencent", providerModel: "kimi-k2.5", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2026-01" },
|
|
176
|
+
{ canonical: "deepseek-v3.2", provider: "tencent", providerModel: "deepseek-v3.2", contextTokens: 128_000, maxOutputTokens: 8192, thinking: FULL, images: false, company: "Tencent", releaseDate: "2025-12" },
|
|
150
177
|
// Ollama (local)
|
|
151
|
-
{ canonical: "qwen2.5", provider: "ollama", providerModel: "ollama/qwen2.5:0.5b", contextTokens: 32_768, maxOutputTokens: 8_192, thinking: [], images: false },
|
|
178
|
+
{ canonical: "qwen2.5", provider: "ollama", providerModel: "ollama/qwen2.5:0.5b", contextTokens: 32_768, maxOutputTokens: 8_192, thinking: [], images: false, releaseDate: "2024-09" },
|
|
152
179
|
];
|
|
153
180
|
|
|
154
181
|
/**
|