- 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,xhighvariant support, andgetModelFamily()fix for provider-prefixed versioned models. - 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.
- Default context limit corrected from 4096 to 128000 tokens to match OmniRoute API behavior.
- Structured observability for enrichment failures with per-attempt diagnostics and fallback decisions.
fetchModelsDevData()now uses a bounded retry loop:- Maximum 3 attempts with 250ms / 500ms backoff.
- Retries on: timeouts (
AbortError), network errors, HTTP 429, and HTTP 5xx. - Fail-fast on: HTTP 4xx (non-429) and structurally invalid responses.
- Stale in-memory cache fallback:
- If cached data exists but TTL expired, live refresh is attempted first.
- If all refresh attempts fail, the stale cached data is returned instead of
null. - If no cache exists and all attempts fail, returns
null(safe fail-open).
- Timeout budget increased from 1000ms to 5000ms per attempt.
- Failure classification:
timeout,network,http_retryable,http_non_retryable,parse,invalid_structure.
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.
Solution:
- Added
groupVariantModels()insrc/models.ts— a pure two-pass algorithm that:- Categorizes models into real bases and variants using
stripVariantSuffix() - Builds result: real bases pass through unchanged; for each base with variants, merges all variants under the base model with a
variantsRecord - Synthetic bases: when only variants are returned (no explicit base), creates a synthetic base from the first variant, copying all fields and setting
id/nameto the stripped base ID - Metadata merging: base inherits max
contextWindow, maxmaxTokens, and the union of supported capability flags across all variants
- Categorizes models into real bases and variants using
- Integrated into
fetchModels()pipeline:normalizeModel→deduplicateModels→groupVariantModels→enrichModelMetadata→toProviderModels - Fixed
toProviderModel()insrc/plugin.tsto prioritize pre-populatedmodel.variantsover generated{low, medium, high}defaults - Added
'xhigh'toOmniRouteModelVariant.reasoningEfforttype and generated variants
Edge Cases Handled:
| Scenario | Behavior |
|---|---|
| Only variants returned, no base model | Creates synthetic base from first variant |
| Base model + variants both returned | Uses real base; merges variant metadata (max limits) |
Non-reasoning suffix (e.g., -preview) |
stripVariantSuffix() ignores it; no grouping |
| Mixed provider prefixes post-dedup | Grouping operates on canonical IDs |
Variant without supportsReasoning=true |
Still grouped; base becomes true if any variant has it |
DEFAULT_CONTEXT_LIMITcorrected from4096to128000.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').
- Cache Isolation —
modelsDevCacheis now keyed by URL (Map<string, ModelsDevCache>) to prevent cross-config data leakage when different configs specify differentmodelsDev.urlvalues. - JSDoc Accuracy —
OmniRouteModelsDevConfig.timeoutMsJSDoc updated to reflect the new5000msdefault. - Lockfile Sync —
package-lock.jsonversion aligned withpackage.json(1.2.1). - Test Suite Speed — Eliminated real
setTimeoutsleeps fromtest/models-dev.test.mjsby usingcacheTtl: 0for stale-cache tests. Reduces test runtime and improves scalability. - Latency Documentation — Explicit JSDoc added on
fetchModelsDevData()documenting worst-case cold-start latency (~15.75s) as an accepted reliability trade-off. - models.dev Structural Validation — Fetched models.dev payloads now validate provider entries and nested
modelsrecords before accepting data, preventing malformed upstream objects from entering cache/index paths. - Variant Capability Union — Grouped variants now merge
supportsVision,supportsTools,supportsStreaming,supportsTemperature, andsupportsAttachmentinto the base model when any variant advertises those capabilities.
- Added 9 focused tests in
test/models-dev.test.mjscovering all retry, cache, fallback, and malformed-provider validation paths. - Added 1 unit test in
test/models.test.mjscovering capability union across grouped variants. - Added 2 regression tests in
test/plugin.test.mjsfor variant grouping and synthetic base model creation. - Added cache isolation (
clearModelCache(),clearModelsDevCache()) totest/plugin.test.mjsafterEachto prevent cross-test contamination. - Full regression suite: 54/54 tests pass (0 failures).
- Internal
docs/superpowers/planning/spec artifacts are kept local only and are excluded from the GitHub repository.
npm run prepublishOnlypasses (clean,build,check:exports).npm testpasses: 54 tests, 0 failures.- TypeScript strict mode compiles cleanly.
- No breaking changes. Plugin behavior remains safe when
models.devis fully unavailable. - Existing
modelsDev.timeoutMsandmodelsDev.cacheTtlconfig options continue to work as before.