All notable changes to this project are documented in this file.
- Consolidated Agent Guidelines — Merged
CLAUDE.mdandAGENTS.mdinto a single canonicalAGENTS.mdfile.CLAUDE.mdis now a symlink toAGENTS.mdso both Claude Code and other agents read from the same source. - Release Process Documentation — Added complete release process steps to
AGENTS.md(version bump, changelog, tag, GitHub release, npm publish, verification).
- Model Metadata Overrides for Provider Models — Fixed model metadata overrides not being applied to provider models returned by the
providerhook. (src/plugin.ts) (@Alph4d0g)
- models.dev Reliability Pipeline — Complete rewrite of
fetchModelsDevData()with production-grade resilience:- Bounded retry loop (max 3 attempts) with exponential backoff (250ms, 500ms).
- Structured failure classification into 6 categories:
timeout,network,http_retryable,http_non_retryable,parse,invalid_structure. - Stale in-memory cache fallback: if live refresh fails, previously cached enrichment data is returned instead of skipping enrichment entirely.
- Fail-open cold-start behavior: returns
nullonly when no cache exists and all attempts fail, preserving plugin functionality. - Per-attempt structured logging: attempt number, failure class, HTTP status (when applicable), and elapsed duration.
- Success logging: total elapsed duration and provider count for observability.
- Timeout increase: default per-attempt timeout raised from 1000ms to 5000ms.
- 9 New Test Cases (
test/models-dev.test.mjs) covering:- Fresh cache hit (no redundant network call)
- Timeout recovery on retry
- 503 retryable HTTP failure recovery
- Stale cache fallback when all refresh attempts fail
- Null return on cold-start total failure
- 404 fail-fast behavior (no unnecessary retries)
- Invalid response structure with stale cache fallback
- Malformed provider entry rejection before cache update
- End-to-end integration with
getModelsDevIndex()
- Model Variant Support Fix — Comprehensive fix for variant-suffixed models (e.g.,
codex/gpt-5.5-xhigh,codex/gpt-5.5-high):- Added
groupVariantModels()insrc/models.ts— pure two-pass algorithm that merges variant-suffixed models under their base model ID - Added
variants?: Record<string, OmniRouteModelVariant>toOmniRouteModelinterface insrc/types.ts - Extended
OmniRouteModelVariant.reasoningEffortto include'xhigh'(was'low' | 'medium' | 'high') - 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, maxmaxTokens, unioned capability flags) - Pipeline integration:
fetchModels()now flowsnormalizeModel→deduplicateModels→groupVariantModels→enrichModelMetadata→toProviderModels toProviderModel()insrc/plugin.tsnow prioritizes pre-populatedmodel.variantsover generated{low, medium, high}defaults
- Added
- Test Cache Isolation (
test/plugin.test.mjs) — AddedclearModelCache()andclearModelsDevCache()toafterEachto prevent cross-test contamination from mutable in-memory caches - 2 New Regression Tests (
test/plugin.test.mjs) covering variant grouping and synthetic base model creation - 1 New Regression Test (
test/models.test.mjs) covering capability union across grouped variants
- Default Context Limit —
DEFAULT_CONTEXT_LIMITcorrected from4096to128000to match actual OmniRoute API defaults. - 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-.
- Internal Helpers — Extracted
fetchModelsDevOnce(),shouldRetryModelsDevFailure(), andsleep()helpers insrc/models-dev.tsto keep retry logic isolated from lookup/index logic.
- Test Config Artifacts — Removed
.opencode/config.jsonand.opencode/opencode.jsonfiles that were committed accidentally.
- Cache Isolation —
modelsDevCacheis now keyed by URL (Map<string, ModelsDevCache>) instead of a single global variable. Prevents cross-config data leakage when different configs specify differentmodelsDev.urlvalues. (src/models-dev.ts) - JSDoc Accuracy — Updated
OmniRouteModelsDevConfig.timeoutMsJSDoc comment from(default: 1000ms)to(default: 5000ms)to match the actual constant. (src/types.ts) - Lockfile Version Sync — Updated
package-lock.jsonversion from1.2.0to1.2.1to matchpackage.json. (package-lock.json) - Test Suite Speed — Eliminated real
setTimeoutsleeps fromtest/models-dev.test.mjsby usingcacheTtl: 0to mark cache immediately stale instead of waiting for TTL expiry. Reduces test runtime and improves scalability. - 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) - models.dev Structural Validation — Added runtime validation for provider entries and nested
modelsrecords before accepting fetched models.dev data. Prevents malformed upstream objects from being cached or indexed. (src/models-dev.ts) - Variant Capability Union — Grouped variant models now merge
supportsVision,supportsTools,supportsStreaming,supportsTemperature, andsupportsAttachmentinto the base model when any variant supports them. (src/models.ts)
- Comprehensive Model Metadata Normalization —
normalizeModel()now reads all OmniRoute field variants with proper precedence:- camelCase fields (e.g.,
contextWindow,supportsVision) - snake_case fields (e.g.,
context_length,max_output_tokens) - capabilities object (e.g.,
capabilities.vision,capabilities.tool_calling) - Precedence: camelCase > snake_case > capabilities object
- camelCase fields (e.g.,
- Provider Alias Deduplication — Generic deduplication system that groups alias and canonical model entries:
- Added
PROVIDER_ALIAS_TO_CANONICALmapping for known aliases (cx→codex,ollamacloud→ollama-cloud, etc.) - Added
deduplicateModels()function that prefers canonical IDs and merges alias metadata - Added
resolveProviderAliasForMetadata()andisProviderAlias()helpers - Only deduplicates known aliases; unknown provider prefixes are preserved as-is
- Added
- Model Capability Enrichment — Extended
OmniRouteModelinterface with native OmniRoute fields:- snake_case context limits:
context_length,max_input_tokens,max_output_tokens - Top-level capability flags:
vision,tool_calling - capabilities object:
vision,tool_calling,reasoning,thinking,attachment,temperature
- snake_case context limits:
- Array-based Metadata Validation — User-provided
modelMetadataarray blocks are now validated with warning logs for invalid entries - 4 New Test Cases covering normalization precedence, snake_case field reading, and deduplication behavior
- Array Metadata Merge Precedence — In array-based
modelMetadata, user config now comes before generated blocks to ensure user overrides take precedence in first-match-wins systems - Metadata Key Canonicalization — User metadata with alias keys (e.g.,
cx/gpt-5.5) is merged into canonical keys (e.g.,codex/gpt-5.5) to match deduplicated model IDs - Unknown Prefix Handling — Unknown provider prefixes now merge metadata instead of overwriting, preserving all available metadata
- Dead Code Removal — Eliminated unreachable
isAliascheck in deduplication logic - Alias Metadata Loss — Alias metadata is now merged into canonical entries instead of being dropped
- Review Feedback — Addressed all gemini-code-assist review comments from PR #20:
- Fixed array-based metadata merge precedence (userConfig first)
- Added validation for array-based user metadata blocks
- Fixed metadata merging for unknown provider prefixes
- Simplified deduplication logic and merged alias metadata into canonical
- Added
providerhook for OpenCode >=1.14.49 model listing API (ProviderHook), enabling dynamic model fetching when authentication is available. (@kkMihai) - Added
ProviderHook,ProviderHookContext,ProviderV2, andModelV2type definitions matching the@opencode-ai/pluginv1.14.50 API. (@kkMihai) - Added 3 regression tests covering provider hook behavior: live model fetch with auth, fallback without auth, and error recovery. (@kkMihai)
- Added
createMockFetch()test helper to isolate/v1/modelscall counting from enrichment endpoint mocks. (@kkMihai)
- Fixed model picker only showing 4 hardcoded fallback models on OpenCode >=1.14.49 by supplying models through the new
providerhookmodelscallback. (@kkMihai) - Fixed stale
provider.modelsfallback in no-auth branch of provider hook to always return plugin-native defaults with correctapi.urlandproviderIDmetadata. (@Alph4d0g) - Fixed misleading comment in fetch-failure recovery test to accurately describe the code path. (@Alph4d0g)
- Improved test coverage for unauthenticated state to explicitly verify that stale host-provided models are ignored. (@Alph4d0g)
- Improved formatting consistency in type definitions. (@Alph4d0g)
- Added proper logger module (
src/logger.ts) that writes to OpenCode's log file instead of the console.warn()always writes;debug()only writes whenOMNIROUTE_DEBUG=1.- Finds the most recent
.logfile in~/.local/share/opencode/log/bymtime. - Re-scans for new log files when the cached file is deleted (log rotation support).
- Silently fails on all I/O errors — never crashes the plugin.
- Added 13 unit tests for the logger module (
test/logger.test.mjs).
- Replaced all 46
console.log/console.warn/console.errorcalls across 4 source files with the new logger:src/plugin.ts(13 calls)src/models.ts(11 calls)src/models-dev.ts(7 calls)src/omniroute-combos.ts(15 calls)
- Log format now matches OpenCode's native format:
WARN 2026-05-14T12:34:56.789Z +0ms service=omniroute <message>.
- Fixed 2 pre-existing failing model cache tests that were incorrectly counting all
fetchcalls instead of only/v1/modelscalls.
- Fixed model picker only showing fallback models on OpenCode >=1.14.47 by eagerly fetching live models in the
confighook before OpenCode readsprovider.models. (@jms830) - Refactored
createRuntimeConfigto acceptoptionsdirectly for reuse across bothconfigandloaderhooks.
- Added
readAuthFromStore()helper to read the stored OmniRoute API key from~/.local/share/opencode/auth.jsonduring theconfighook. - Added regression test for eager model fetching in the config hook.
- Fixed combo model processing when the API returns model entries as objects instead of strings in the
modelsarray. (@hjasgr) - Hardened
resolveUnderlyingModelsagainst null/undefined entries and missing properties with runtime type narrowing.
- Updated
OmniRouteCombo.modelstype to accept objects from the API.
- Added models.dev capability enrichment for OmniRoute models via
provider.omniroute.options.modelsDev. - Added combo model support with automatic lowest-common-denominator capability calculation from
/api/combos. - Added
modelMetadataconfiguration option for custom/virtual model overrides viaprovider.omniroute.options.modelMetadata. - Added new runtime exports:
clearModelsDevCache,clearComboCache,fetchComboData,resolveUnderlyingModels,calculateModelCapabilities. - Added provider alias mapping (e.g.,
cx→openai,gemini→google) for models.dev lookups.
- Updated
fetchModelsto orchestrate enrichment pipeline (models.dev → combo capabilities). - Updated
clearModelCacheto also clear the combo cache. - Updated README with combo model documentation and new runtime API references.
- Added dual provider API mode support (
chatandresponses) throughprovider.omniroute.options.apiMode. - Added
OmniRouteApiModetype and re-exported it for consumers. - Added
OMNIROUTE_ENDPOINTS.RESPONSESconstant. - Added
runtimesubpath export (opencode-omniroute-auth/runtime) for helper APIs and runtime constants. - Added export validation script (
check:exports) to enforce plugin-loader-safe root exports before publish. - Added release planning and handover documentation (
docs/responses-api-evaluation-plan.md,docs/session-handover.md).
- Changed provider bootstrap logic to normalize and validate
apiModevalues, defaulting invalid values tochatwith warnings. - Changed package root runtime export shape to plugin-only exports (
default+OmniRouteAuthPlugin) for OpenCode loader compatibility. - Changed programmatic helper import path from package root to
opencode-omniroute-auth/runtime. - Updated README configuration and troubleshooting documentation to cover
apiMode, npm plugin loading behavior, and runtime helper import path. - Updated TypeScript build config to include
runtime.ts.
- Fixed npm plugin loading failure outside the repository caused by non-function root exports being treated as plugin functions by OpenCode loader.
- Verified
npm run prepublishOnlypasses (clean,build, andcheck:exports). - Verified built root module exports only callable plugin functions.
- Verified runtime helpers/constants remain available through
opencode-omniroute-auth/runtime. - Verified packed local tarball (
1.0.3) installs and exposes the expected export shape.
- Added initial export-shape validation check before publishing.
- Introduced default plugin export intended to improve compatibility with plugin loaders expecting default exports.
- Updated README troubleshooting notes for npm plugin loading.
- This version improved compatibility but did not fully resolve OpenCode loader behavior when non-function runtime exports were present at package root.
- Version bump and package republish metadata update after initial release.
- Initial OpenCode OmniRoute authentication plugin release.
/connectauthentication flow for storing and validating OmniRoute API keys.- Dynamic model discovery from
/v1/models. - TTL-based model caching with fallback model behavior.
- Request interception for Authorization header injection and safe base URL handling.
- OpenAI-compatible provider wiring for OmniRoute usage in OpenCode.