Skip to content

feat: expose an explicit tier override for any provider connection (#7818) - #7838

Merged
diegosouzapw merged 1 commit into
release/v3.8.49from
feat/7818-custom-provider-tier
Jul 20, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.49from
feat/7818-custom-provider-tier

Conversation

@diegosouzapw

@diegosouzapw diegosouzapw commented Jul 20, 2026 •

Copy link
Copy Markdown
Owner

Summary

Closes the actual gap behind #7818/#7763: classifyTier() (open-sse/services/tierResolver.ts) already honored a DB-backed providerOverrides list keyed by an arbitrary provider-id string — it worked identically for a built-in or custom provider — but nothing exposed that mechanism through any UI or API route, for any provider. This PR is that missing surface.

  • New GET/PUT /api/settings/tier-config route: reads/writes a single provider's tier override in the existing tier_config table (loadTierConfig()/saveTierConfig()), validated with a z.enum(["free","cheap","premium"]) schema, and busts the in-process routing cache via setTierConfig() so a change applies immediately.
  • New generic tier-override <Select> wired into EditConnectionModal.tsx's Advanced Settings section (ProviderTierField.tsx + providerTierField.ts helpers, mirroring the existing m365Tier.ts pattern in the same directory) — applies uniformly to every connection, built-in or custom, no capability gate.
  • TierCoverageWidget.tsx::classifyConnection() now consults the same override before falling back to its existing registry-membership check, so a tiered custom provider shows up in the correct bucket instead of always landing in "Cheap".
  • i18n keys added to en.json + pt-BR.json under the providers namespace (tierOverride*).

No database migration — tier_config already exists via migration 059_manifest_routing.sql; verified via grep -rln "loadTierConfig\|saveTierConfig" src/app/api/ returning empty before this PR.

Scope decision (owner-confirmed): the original report says "4 tiers", but the actual ProviderTier machine enum (open-sse/services/tierTypes.ts) has exactly 3 values (free/cheap/premium) — the "4" is README.md marketing copy conflating two separate 3-bucket classifiers. This PR implements the override for the 3 real machine values and does not extend the enum. Nothing else is deferred; the feature is complete against the amended (3-tier) scope, so this closes the issue.

How validated (Hard Rule #18 — TDD, proved red before green)

Added 4 new top-level test files (26 assertions across 14 test cases):

  • tests/unit/tier-config-provider-override-route.test.ts — exercises the route's GET/PUT against a real isolated SQLite test DB (DATA_DIR temp dir + resetDbInstance() in beforeEach/after). Covers: set override for a custom (non-registry) provider id, clear via tier: null without touching other providers, reject an invalid tier with 400 (and assert the error body doesn't leak a stack trace), reject an empty provider string, and round-trip cleanly against an already-populated tier_config row (no-migration scenario).
  • tests/unit/tier-resolver-provider-override.test.ts — proves the setTierConfig() cache-bust actually matters: calls classifyTier() directly before and after a PUT, asserting the routing side picks up the override on the very next call (using a fresh model key so a stale per-key cache entry can't fake the result).
  • tests/unit/tier-coverage-widget-provider-override.test.ts — classifyConnection() unit tests (override-before-registry precedence, case-insensitive lookup, fallback to registry membership).
  • tests/unit/provider-tier-field-helpers.test.ts — fetchProviderTierOverride/saveProviderTierOverride/normalizeTierValue against a stubbed global.fetch.

Proved the red (not a placebo): deleted src/app/api/settings/tier-config/ entirely (backed up first, restored after) and re-ran the route + resolver test files — both failed with ERR_MODULE_NOT_FOUND (the route genuinely didn't exist before this PR). Also reverted classifyConnection() to drop the override lookup and re-ran the widget test — it failed with 'tier2' !== 'tier1' / 'tier2' !== 'tier3' assertion errors, proving that test isn't a DOM-less placebo either. Restored both files and reran green afterward.

Gates run (all green)

  • node scripts/check/check-test-discovery.mjs
  • npm run typecheck:core — clean
  • npm run typecheck:noimplicit:core — pre-existing errors only in open-sse/services/combo.ts, open-sse/utils/usageTracking.ts, src/shared/services/cliRuntime.ts (confirmed identical against origin/release/v3.8.49, untouched by this diff)
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files> — clean
  • npm run check:complexity-ratchets — cyclomatic 2076 (baseline 2130), cognitive 901 (baseline 950), both OK
  • node scripts/check/check-file-size.mjs — OK; EditConnectionModal.tsx frozen baseline bumped 1286→1288 (net +2 lines: one import + one <ProviderTierField .../> render call, justified in config/quality/file-size-baseline.json's new _rebaseline_2026_07_20_7818_provider_tier_field entry, mirroring the existing m365Tier.ts/AgentRouter precedents)
  • npm run check:mutation-test-coverage — no drift (tierResolver.ts/tierConfig.ts/the new route are not in Stryker's mutate set, confirmed before writing tests, so no tap.testFiles registration was needed)
  • node scripts/check/check-dashboard-typecheck.mjs — 2 pre-existing failures (AgentEmoji.tsx, GheConfigStep.tsx), confirmed via git diff --stat origin/release/v3.8.49...HEAD to be untouched by this PR
  • npm run check:cycles — no new cycles
  • New tests run directly — 14/14 pass

npm run test:coverage intentionally not run locally (heaviest gate, shared box) — CI runs it authoritatively.

What was deferred

Nothing from the confirmed (3-tier) scope. The only thing explicitly out of scope is extending ProviderTier to a 4th machine value (subscription vs. API-key), which the plan's Open Question flagged as a materially larger, separately-scoped change — the owner confirmed the 3-value scope for this issue.

Closes #7818

…nnection (#7818)

classifyTier() already honored a DB-backed providerOverrides list keyed
by an arbitrary provider-id string (built-in or custom), but nothing
exposed it through the UI or API. Adds GET/PUT /api/settings/tier-config,
a generic Advanced Settings tier selector wired into EditConnectionModal,
and makes TierCoverageWidget consult the same override before falling
back to registry-membership classification.

Owner decision: scope is the 3 real ProviderTier machine values
(free/cheap/premium) — the enum is not extended to 4.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@diegosouzapw

Copy link
Copy Markdown
Owner Author

Reviewed and verified this against a clean worktree off release/v3.8.49:

  • All 4 new test files (15 assertions) pass for real — including the two subtler ones: proving the setTierConfig() cache-bust actually matters (not just that the override array gets persisted), and proving classifyConnection()'s override-before-registry precedence.
  • Pre-existing touched-area tests (db-tier-config.test.ts, m365-tier-selector-6334.test.ts — the precedent this PR's ProviderTierField mirrors) still pass, no regressions.
  • Targeted ESLint on the 5 changed files is clean.
  • Clean merge against current release/v3.8.49, no conflicts, diff is exactly the 13 files / +591/-6 the PR claims — not a bloated branch.
  • The CI reds on this PR (Fast Quality Gates, No new ESLint warnings, Unit Tests fast-path 1-4, dast-smoke) are the known base-red TICK_MS is not defined cascade from perf(memory): mitigate event-loop starvation under 3000+ provider connections #7719 — confirmed identical on unrelated open PRs on the same base, unrelated to any file this PR touches.

Good use of the existing providerOverrides mechanism — the backend half was already there and untested through any real surface; this closes that gap cleanly with the right auth/Zod/error-sanitization wiring on the first pass. Merge-ready once CI reflects the release/v3.8.49 base-red fix.

@diegosouzapw

Copy link
Copy Markdown
Owner Author

Validated in local merge-train on tomni-proxmox-113 @ 19bcf534352e24cdd2448cdfdfd64d5bd9695c74 (FAST gates green: static + changed tests + vitest)

@diegosouzapw
diegosouzapw merged commit 6770a57 into release/v3.8.49 Jul 20, 2026
9 of 10 checks passed
diegosouzapw added a commit that referenced this pull request Jul 20, 2026
…llision + stryker 7806 registration

(1) #7838 added providerTierField.ts next to ProviderTierField.tsx in the same
directory — a case-only collision that breaks webpack on case-insensitive
filesystems; the #6584 guard fails Unit shard 4/4 on every fresh PR run.
Rename the helper to providerTierFieldApi.ts (import + test path adjusted).
(2) check:mutation-test-coverage --strict fails on the tip because merged
#7806's combo-skip-conn-disable-plugin-block test was never registered in
stryker tap.testFiles. Register it.
diegosouzapw added a commit that referenced this pull request Jul 20, 2026
…base-red)

#7838 added six providers.tierOverride* keys to en.json without the Vietnamese
counterparts; i18n-vi-completeness (key parity + both ICU checks) fails on the
release tip for every fresh PR run. Translated using the locale's existing tier
vocabulary and inserted at the mirrored position.
diegosouzapw added a commit to backryun/OmniRoute that referenced this pull request Jul 20, 2026
release/v3.8.49 tip took slot 129 via diegosouzapw#7843 (usage_history_codex_strong_identity,
itself renumbered from 128 during the diegosouzapw#7838/diegosouzapw#7840 base-red cleanup) after this
branch forked; renumber remove_unregistered_qwen_data to 130.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
diegosouzapw added a commit that referenced this pull request Jul 20, 2026
…rovider (#7866)

* refactor(cli): remove legacy Qwen Code integration

* refactor(qwen): remove deprecated Qwen OAuth provider

* feat(cli): rebuild Qwen Code integration for upstream V4

* fix(qwen): clear stale CLI auth on reset

* test(qwen): align retired provider coverage

* fix(db): renumber qwen-cleanup migration 129 -> 130

release/v3.8.49 tip took slot 129 via #7843 (usage_history_codex_strong_identity,
itself renumbered from 128 during the #7838/#7840 base-red cleanup) after this
branch forked; renumber remove_unregistered_qwen_data to 130.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
@diegosouzapw
diegosouzapw deleted the feat/7818-custom-provider-tier branch July 23, 2026 00:24
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…nnection (diegosouzapw#7818) (diegosouzapw#7838)

classifyTier() already honored a DB-backed providerOverrides list keyed
by an arbitrary provider-id string (built-in or custom), but nothing
exposed it through the UI or API. Adds GET/PUT /api/settings/tier-config,
a generic Advanced Settings tier selector wired into EditConnectionModal,
and makes TierCoverageWidget consult the same override before falling
back to registry-membership classification.

Owner decision: scope is the 3 real ProviderTier machine values
(free/cheap/premium) — the enum is not extended to 4.
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…llision + stryker 7806 registration

(1) diegosouzapw#7838 added providerTierField.ts next to ProviderTierField.tsx in the same
directory — a case-only collision that breaks webpack on case-insensitive
filesystems; the diegosouzapw#6584 guard fails Unit shard 4/4 on every fresh PR run.
Rename the helper to providerTierFieldApi.ts (import + test path adjusted).
(2) check:mutation-test-coverage --strict fails on the tip because merged
diegosouzapw#7806's combo-skip-conn-disable-plugin-block test was never registered in
stryker tap.testFiles. Register it.
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…ouzapw#7838 base-red)

diegosouzapw#7838 added six providers.tierOverride* keys to en.json without the Vietnamese
counterparts; i18n-vi-completeness (key parity + both ICU checks) fails on the
release tip for every fresh PR run. Translated using the locale's existing tier
vocabulary and inserted at the mirrored position.
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…rovider (diegosouzapw#7866)

* refactor(cli): remove legacy Qwen Code integration

* refactor(qwen): remove deprecated Qwen OAuth provider

* feat(cli): rebuild Qwen Code integration for upstream V4

* fix(qwen): clear stale CLI auth on reset

* test(qwen): align retired provider coverage

* fix(db): renumber qwen-cleanup migration 129 -> 130

release/v3.8.49 tip took slot 129 via diegosouzapw#7843 (usage_history_codex_strong_identity,
itself renumbered from 128 during the diegosouzapw#7838/diegosouzapw#7840 base-red cleanup) after this
branch forked; renumber remove_unregistered_qwen_data to 130.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…nnection (diegosouzapw#7818) (diegosouzapw#7838)

classifyTier() already honored a DB-backed providerOverrides list keyed
by an arbitrary provider-id string (built-in or custom), but nothing
exposed it through the UI or API. Adds GET/PUT /api/settings/tier-config,
a generic Advanced Settings tier selector wired into EditConnectionModal,
and makes TierCoverageWidget consult the same override before falling
back to registry-membership classification.

Owner decision: scope is the 3 real ProviderTier machine values
(free/cheap/premium) — the enum is not extended to 4.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…llision + stryker 7806 registration

(1) diegosouzapw#7838 added providerTierField.ts next to ProviderTierField.tsx in the same
directory — a case-only collision that breaks webpack on case-insensitive
filesystems; the diegosouzapw#6584 guard fails Unit shard 4/4 on every fresh PR run.
Rename the helper to providerTierFieldApi.ts (import + test path adjusted).
(2) check:mutation-test-coverage --strict fails on the tip because merged
diegosouzapw#7806's combo-skip-conn-disable-plugin-block test was never registered in
stryker tap.testFiles. Register it.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…ouzapw#7838 base-red)

diegosouzapw#7838 added six providers.tierOverride* keys to en.json without the Vietnamese
counterparts; i18n-vi-completeness (key parity + both ICU checks) fails on the
release tip for every fresh PR run. Translated using the locale's existing tier
vocabulary and inserted at the mirrored position.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…rovider (diegosouzapw#7866)

* refactor(cli): remove legacy Qwen Code integration

* refactor(qwen): remove deprecated Qwen OAuth provider

* feat(cli): rebuild Qwen Code integration for upstream V4

* fix(qwen): clear stale CLI auth on reset

* test(qwen): align retired provider coverage

* fix(db): renumber qwen-cleanup migration 129 -> 130

release/v3.8.49 tip took slot 129 via diegosouzapw#7843 (usage_history_codex_strong_identity,
itself renumbered from 128 during the diegosouzapw#7838/diegosouzapw#7840 base-red cleanup) after this
branch forked; renumber remove_unregistered_qwen_data to 130.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(providers): allow setting a tier on custom providers

1 participant