Skip to content

Commit 5771b7c

Browse files
authored
Release v1.2.1 (#24)
* fix: correct DEFAULT_CONTEXT_LIMIT from 4096 to 128000 OmniRoute 3.7.9 does not expose contextWindow/context_length/max_input_tokens in /v1/models responses. When these fields are missing, the plugin falls back to DEFAULT_CONTEXT_LIMIT. The previous value of 4096 was incorrect - that's a reasonable output token limit, but context windows for modern LLMs are 128K+. This caused OpenCode to display 4096 token context windows for models like kmc/kimi-k2.6. Changed DEFAULT_CONTEXT_LIMIT to 128000 to match the plugin's own default models (gpt-4o, gpt-4o-mini, llama-3.1-405b all use 128000). Fixes #19 * feat(models.dev): improve enrichment reliability with retries and stale cache fallback - Increase default timeout from 1000ms to 5000ms - Add bounded retry loop (max 3 attempts, backoff 250ms/500ms) - Add stale in-memory cache fallback when live refresh fails - Add structured failure classification (timeout, network, http_retryable, http_non_retryable, parse, invalid_structure) - Add improved logging for fetch attempts, failures, and fallback decisions - Keep all changes localized to src/models-dev.ts - Add 8 focused tests covering fresh cache, retries, stale fallback, fail-fast, and integration paths All 50 tests pass (0 regressions). * chore: remove opencode test config * chore(release): bump version to 1.4.1 and update changelog - Update package.json version from 1.2.0 to 1.4.1 - Add CHANGELOG.md entry for v1.4.1 - Add docs/release-notes-v1.4.1.md with release highlights and verification steps * fix(review): address PR #22 code review feedback - Cache isolation: key models.dev cache by URL (Map) to prevent cross-config data leakage when different configs specify different modelsDev.url values - Update outdated JSDoc comment for timeoutMs default (1000ms -> 5000ms) - Eliminate real setTimeout sleeps from tests by using cacheTtl: 0 for stale-cache scenarios instead of waiting for TTL expiry - Document worst-case cold-start latency (~15.75s) in fetchModelsDevData JSDoc - Update package-lock.json version to 1.4.1 (file is .gitignored but kept in sync locally) - Update CHANGELOG.md and release notes with code review fixes section All 50 tests pass (0 regressions). * docs: add model variant support fix design spec * feat: model variant support fix — grouping, xhigh🧠, synthetic bases 🎸, getModelFamily🧑‍🧑‍🧒‍🧒 fix (#23) * docs: add model variant support fix design spec * feat(types,models): add variant grouping and xhigh support - Add variants field to OmniRouteModel interface - Add xhigh to reasoningEffort type - Implement groupVariantModels() pure function - Integrate grouping into fetchModels() pipeline between dedup and enrich * feat(plugin): use model.variants in toProviderModel and fix getModelFamily - toProviderModel() now prioritizes pre-populated model.variants over generated defaults - getModelFamily() strips provider prefix before extracting family name - Fixes incorrect family extraction for provider-prefixed versioned models * test(plugin): add variant grouping tests and fix cache isolation - Add cache clearing (clearModelCache, clearModelsDevCache) to afterEach - Add test: provider hook groups variant models under base model - Add test: provider hook creates synthetic base model when only variants are returned - Prevents cross-test contamination from mutable in-memory caches * docs: update CHANGELOG and release notes for model variant support fix - Add Model Variant Support Fix section to CHANGELOG.md (grouped under Added/Fixed) - Update docs/release-notes-v1.4.1.md with: - New highlight for variant grouping - Detailed Model Variant Support Fix section with edge cases table - getModelFamily() fix for provider-prefixed models - Updated test count (52 tests) - New design spec reference * refactor(models): remove redundant toLowerCase and drop docs/superpowers - Remove redundant suffix.toLowerCase() in groupVariantModels() — suffix is already lowercased when extracted from the model ID via slice() at line 184. Replaced with direct string literal comparison which also narrows the type for TypeScript. (gemini-code-assist review feedback) - Remove docs/superpowers/ directory from repository — design specs are development artifacts that don't need to be in the source tree. - Update release notes to remove design spec file references. * chore(release): keep superpowers artifacts local * chore(release): correct version to 1.2.1 * fix(review): address release PR feedback
1 parent 4362383 commit 5771b7c

18 files changed

Lines changed: 882 additions & 2468 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ temp/
4343

4444
# Worktrees
4545
.worktrees/
46+
47+
# Local planning artifacts
48+
docs/superpowers/

.opencode/config.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

.opencode/opencode.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,62 @@
22

33
All notable changes to this project are documented in this file.
44

5+
## [1.2.1] - 2026-05-19
6+
7+
### Added
8+
9+
- **models.dev Reliability Pipeline** — Complete rewrite of `fetchModelsDevData()` with production-grade resilience:
10+
- Bounded retry loop (max 3 attempts) with exponential backoff (250ms, 500ms).
11+
- Structured failure classification into 6 categories: `timeout`, `network`, `http_retryable`, `http_non_retryable`, `parse`, `invalid_structure`.
12+
- Stale in-memory cache fallback: if live refresh fails, previously cached enrichment data is returned instead of skipping enrichment entirely.
13+
- Fail-open cold-start behavior: returns `null` only when no cache exists and all attempts fail, preserving plugin functionality.
14+
- Per-attempt structured logging: attempt number, failure class, HTTP status (when applicable), and elapsed duration.
15+
- Success logging: total elapsed duration and provider count for observability.
16+
- Timeout increase: default per-attempt timeout raised from 1000ms to 5000ms.
17+
- **9 New Test Cases** (`test/models-dev.test.mjs`) covering:
18+
- Fresh cache hit (no redundant network call)
19+
- Timeout recovery on retry
20+
- 503 retryable HTTP failure recovery
21+
- Stale cache fallback when all refresh attempts fail
22+
- Null return on cold-start total failure
23+
- 404 fail-fast behavior (no unnecessary retries)
24+
- Invalid response structure with stale cache fallback
25+
- Malformed provider entry rejection before cache update
26+
- End-to-end integration with `getModelsDevIndex()`
27+
- **Model Variant Support Fix** — Comprehensive fix for variant-suffixed models (e.g., `codex/gpt-5.5-xhigh`, `codex/gpt-5.5-high`):
28+
- Added `groupVariantModels()` in `src/models.ts` — pure two-pass algorithm that merges variant-suffixed models under their base model ID
29+
- Added `variants?: Record<string, OmniRouteModelVariant>` to `OmniRouteModel` interface in `src/types.ts`
30+
- Extended `OmniRouteModelVariant.reasoningEffort` to include `'xhigh'` (was `'low' | 'medium' | 'high'`)
31+
- Synthetic base model creation: when only variants are returned (no explicit base), creates a synthetic base from the first variant with merged metadata (max `contextWindow`, max `maxTokens`, unioned capability flags)
32+
- Pipeline integration: `fetchModels()` now flows `normalizeModel``deduplicateModels``groupVariantModels``enrichModelMetadata``toProviderModels`
33+
- `toProviderModel()` in `src/plugin.ts` now prioritizes pre-populated `model.variants` over generated `{low, medium, high}` defaults
34+
- **Test Cache Isolation** (`test/plugin.test.mjs`) — Added `clearModelCache()` and `clearModelsDevCache()` to `afterEach` to prevent cross-test contamination from mutable in-memory caches
35+
- **2 New Regression Tests** (`test/plugin.test.mjs`) covering variant grouping and synthetic base model creation
36+
- **1 New Regression Test** (`test/models.test.mjs`) covering capability union across grouped variants
37+
38+
### Fixed
39+
40+
- **Default Context Limit**`DEFAULT_CONTEXT_LIMIT` corrected from `4096` to `128000` to match actual OmniRoute API defaults.
41+
- **getModelFamily() for Provider-Prefixed Models** — Fixed incorrect family extraction for versioned models with provider prefixes. Before: `getModelFamily('codex/gpt-5.5-xhigh')``'codex/gpt'`. After: → `'gpt'`. Implementation now strips provider prefix before splitting on `-`.
42+
43+
### Changed
44+
45+
- **Internal Helpers** — Extracted `fetchModelsDevOnce()`, `shouldRetryModelsDevFailure()`, and `sleep()` helpers in `src/models-dev.ts` to keep retry logic isolated from lookup/index logic.
46+
47+
### Removed
48+
49+
- **Test Config Artifacts** — Removed `.opencode/config.json` and `.opencode/opencode.json` files that were committed accidentally.
50+
51+
### Fixed (Code Review)
52+
53+
- **Cache Isolation**`modelsDevCache` is now keyed by URL (`Map<string, ModelsDevCache>`) instead of a single global variable. Prevents cross-config data leakage when different configs specify different `modelsDev.url` values. (`src/models-dev.ts`)
54+
- **JSDoc Accuracy** — Updated `OmniRouteModelsDevConfig.timeoutMs` JSDoc comment from `(default: 1000ms)` to `(default: 5000ms)` to match the actual constant. (`src/types.ts`)
55+
- **Lockfile Version Sync** — Updated `package-lock.json` version from `1.2.0` to `1.2.1` to match `package.json`. (`package-lock.json`)
56+
- **Test Suite Speed** — Eliminated real `setTimeout` sleeps from `test/models-dev.test.mjs` by using `cacheTtl: 0` to mark cache immediately stale instead of waiting for TTL expiry. Reduces test runtime and improves scalability.
57+
- **Latency Documentation** — Added explicit JSDoc on `fetchModelsDevData()` documenting worst-case cold-start latency (~15.75s) as an accepted reliability trade-off per design spec. (`src/models-dev.ts`)
58+
- **models.dev Structural Validation** — Added runtime validation for provider entries and nested `models` records before accepting fetched models.dev data. Prevents malformed upstream objects from being cached or indexed. (`src/models-dev.ts`)
59+
- **Variant Capability Union** — Grouped variant models now merge `supportsVision`, `supportsTools`, `supportsStreaming`, `supportsTemperature`, and `supportsAttachment` into the base model when any variant supports them. (`src/models.ts`)
60+
561
## [1.2.0] - 2026-05-17
662

763
### Added

docs/release-notes-v1.2.1.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Release v1.2.1
2+
3+
## Highlights
4+
5+
- **Model Variant Support Fix** — Variant-suffixed models (e.g., `codex/gpt-5.5-xhigh`, `codex/gpt-5.5-high`) are now grouped under their base model ID instead of appearing as duplicate top-level entries. Includes synthetic base model creation, `xhigh` variant support, and `getModelFamily()` fix for provider-prefixed versioned models.
6+
- **models.dev enrichment no longer fails on transient network slowness.** The fetch pipeline now retries up to 3 times with exponential backoff and falls back to stale cached data if live refresh fails.
7+
- **Default context limit corrected** from 4096 to 128000 tokens to match OmniRoute API behavior.
8+
- **Structured observability** for enrichment failures with per-attempt diagnostics and fallback decisions.
9+
10+
## What Changed
11+
12+
### Reliability
13+
14+
- `fetchModelsDevData()` now uses a bounded retry loop:
15+
- Maximum 3 attempts with 250ms / 500ms backoff.
16+
- Retries on: timeouts (`AbortError`), network errors, HTTP 429, and HTTP 5xx.
17+
- Fail-fast on: HTTP 4xx (non-429) and structurally invalid responses.
18+
- Stale in-memory cache fallback:
19+
- If cached data exists but TTL expired, live refresh is attempted first.
20+
- If all refresh attempts fail, the stale cached data is returned instead of `null`.
21+
- If no cache exists and all attempts fail, returns `null` (safe fail-open).
22+
- Timeout budget increased from 1000ms to 5000ms per attempt.
23+
- Failure classification: `timeout`, `network`, `http_retryable`, `http_non_retryable`, `parse`, `invalid_structure`.
24+
25+
### Model Variant Support Fix
26+
27+
**Problem:** When OmniRoute lists variant-suffixed models separately (e.g., `codex/gpt-5.5-xhigh`, `codex/gpt-5.5-high`), each variant appeared as an independent top-level entry with incorrect generated variants (`{low, medium, high}`), causing duplicate/confusing model entries in OpenCode's model picker.
28+
29+
**Solution:**
30+
- Added `groupVariantModels()` in `src/models.ts` — a pure two-pass algorithm that:
31+
1. **Categorizes** models into real bases and variants using `stripVariantSuffix()`
32+
2. **Builds result**: real bases pass through unchanged; for each base with variants, merges all variants under the base model with a `variants` Record
33+
3. **Synthetic bases**: when only variants are returned (no explicit base), creates a synthetic base from the first variant, copying all fields and setting `id`/`name` to the stripped base ID
34+
4. **Metadata merging**: base inherits **max** `contextWindow`, **max** `maxTokens`, and the union of supported capability flags across all variants
35+
- Integrated into `fetchModels()` pipeline: `normalizeModel``deduplicateModels``groupVariantModels``enrichModelMetadata``toProviderModels`
36+
- Fixed `toProviderModel()` in `src/plugin.ts` to prioritize pre-populated `model.variants` over generated `{low, medium, high}` defaults
37+
- Added `'xhigh'` to `OmniRouteModelVariant.reasoningEffort` type and generated variants
38+
39+
**Edge Cases Handled:**
40+
| Scenario | Behavior |
41+
|----------|----------|
42+
| Only variants returned, no base model | Creates synthetic base from first variant |
43+
| Base model + variants both returned | Uses real base; merges variant metadata (max limits) |
44+
| Non-reasoning suffix (e.g., `-preview`) | `stripVariantSuffix()` ignores it; no grouping |
45+
| Mixed provider prefixes post-dedup | Grouping operates on canonical IDs |
46+
| Variant without `supportsReasoning=true` | Still grouped; base becomes `true` if any variant has it |
47+
48+
### Fixes
49+
50+
- `DEFAULT_CONTEXT_LIMIT` corrected from `4096` to `128000`.
51+
- **`getModelFamily()` for Provider-Prefixed Models** — Fixed incorrect family extraction for versioned models with provider prefixes. `getModelFamily('codex/gpt-5.5-xhigh')` now correctly returns `'gpt'` (was `'codex/gpt'`).
52+
53+
### Code Review Fixes
54+
55+
- **Cache Isolation**`modelsDevCache` is now keyed by URL (`Map<string, ModelsDevCache>`) to prevent cross-config data leakage when different configs specify different `modelsDev.url` values.
56+
- **JSDoc Accuracy**`OmniRouteModelsDevConfig.timeoutMs` JSDoc updated to reflect the new `5000ms` default.
57+
- **Lockfile Sync**`package-lock.json` version aligned with `package.json` (`1.2.1`).
58+
- **Test Suite Speed** — Eliminated real `setTimeout` sleeps from `test/models-dev.test.mjs` by using `cacheTtl: 0` for stale-cache tests. Reduces test runtime and improves scalability.
59+
- **Latency Documentation** — Explicit JSDoc added on `fetchModelsDevData()` documenting worst-case cold-start latency (~15.75s) as an accepted reliability trade-off.
60+
- **models.dev Structural Validation** — Fetched models.dev payloads now validate provider entries and nested `models` records before accepting data, preventing malformed upstream objects from entering cache/index paths.
61+
- **Variant Capability Union** — Grouped variants now merge `supportsVision`, `supportsTools`, `supportsStreaming`, `supportsTemperature`, and `supportsAttachment` into the base model when any variant advertises those capabilities.
62+
63+
### Testing
64+
65+
- Added 9 focused tests in `test/models-dev.test.mjs` covering all retry, cache, fallback, and malformed-provider validation paths.
66+
- Added 1 unit test in `test/models.test.mjs` covering capability union across grouped variants.
67+
- Added 2 regression tests in `test/plugin.test.mjs` for variant grouping and synthetic base model creation.
68+
- Added cache isolation (`clearModelCache()`, `clearModelsDevCache()`) to `test/plugin.test.mjs` `afterEach` to prevent cross-test contamination.
69+
- Full regression suite: 54/54 tests pass (0 failures).
70+
71+
### Documentation
72+
73+
- Internal `docs/superpowers/` planning/spec artifacts are kept local only and are excluded from the GitHub repository.
74+
75+
## Verification
76+
77+
- `npm run prepublishOnly` passes (`clean`, `build`, `check:exports`).
78+
- `npm test` passes: 54 tests, 0 failures.
79+
- TypeScript strict mode compiles cleanly.
80+
81+
## Upgrade Notes
82+
83+
- No breaking changes. Plugin behavior remains safe when `models.dev` is fully unavailable.
84+
- Existing `modelsDev.timeoutMs` and `modelsDev.cacheTtl` config options continue to work as before.

0 commit comments

Comments
 (0)