Repository navigation
feat(dashboard): "New models" inbox across connected providers - #16864
Open
diegosouzapw wants to merge 10 commits into
Open
diegosouzapw wants to merge 10 commits into
diegosouzapw wants to merge 10 commits into
Conversation
Every successful model sync now records the provider's listing in a new seen_models table (migration 206, src/lib/db/seenModels.ts). The first sync of a provider seeds its baseline as already read, so existing installs and freshly connected providers never flood the inbox; models that show up in later syncs stay unread until acknowledged. Rows are never deleted, so a model that drops out of a listing and comes back is not flagged again. - GET /api/models/new returns the unread models grouped by provider (read from the table only, no catalog rebuild per request). - POST /api/models/new/acknowledge marks a selection, or everything, read (Zod-validated body; errors sanitized via createErrorResponse). - The Providers toolbar gets a "New models" button with an unread badge and a modal grouped by provider, with Free tags from the shared free-model knowledge and per-provider / mark-all-read actions. - Recording is best-effort and never fails a sync; it runs for the regular discovery path and the Volcano Ark console path, so the 6h auto-sync scheduler fills the inbox too. - New UI strings translated in all 66 locales. Co-authored-by: ErfanBagheri404 <mrenmityerf@gmail.com> Inspired-by: decolua/9router#3604
Contributor
CI Coverage Report
Coverage artifact was not available for this run. |
Collaborator
Author
|
Re-homed to |
…pr-3604-new-models-inbox # Conflicts: # src/app/(dashboard)/dashboard/providers/components/ProviderSummaryCard.tsx
The seen_models migration was renumbered 206 -> 215 on the merge with release/v3.8.53 (206 is taken by 206_codex_wakeup_tasks), which makes the shipped SQL file count 212. AGENTS.md and llm.txt carry the same count but are protected agent-instruction surfaces and are left for the operator.
README Database row resolved to 214 migrations (213 on the release + this PR's seen_models). docs/i18n mirrors take the release side; they are refreshed after merge. Co-authored-by: ErfanBagheri404 <mrenmityerf@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
… 215/216 release/v3.8.53 shipped 215_team_cost_centers.sql and 216_team_cost_shapes.sql, so this PR's 215_seen_models.sql collided. The migration body is unchanged (idempotent CREATE ... IF NOT EXISTS). Co-authored-by: ErfanBagheri404 <mrenmityerf@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: ErfanBagheri404 <mrenmityerf@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
… 217 release/v3.8.53 shipped 217_quota_recovery_tickets.sql (#14982) after the previous renumber, so 217_seen_models.sql collided again. README Database row now reflects the 215 SQL migrations on the merged tree. Migration body unchanged. Co-authored-by: ErfanBagheri404 <mrenmityerf@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
# Conflicts: # src/app/(dashboard)/dashboard/providers/components/ProviderSummaryCard.tsx # src/i18n/messages/am.json # src/i18n/messages/ar.json # src/i18n/messages/az.json # src/i18n/messages/bg.json # src/i18n/messages/bn.json # src/i18n/messages/bs.json # src/i18n/messages/cs.json # src/i18n/messages/da.json # src/i18n/messages/de.json # src/i18n/messages/el.json # src/i18n/messages/en.json # src/i18n/messages/es.json # src/i18n/messages/et.json # src/i18n/messages/fa.json # src/i18n/messages/fi.json # src/i18n/messages/fr.json # src/i18n/messages/ga.json # src/i18n/messages/gu.json # src/i18n/messages/ha.json # src/i18n/messages/he.json # src/i18n/messages/hi.json # src/i18n/messages/hr.json # src/i18n/messages/hu.json # src/i18n/messages/hy.json # src/i18n/messages/id.json # src/i18n/messages/ig.json # src/i18n/messages/it.json # src/i18n/messages/ja.json # src/i18n/messages/ka.json # src/i18n/messages/km.json # src/i18n/messages/kn.json # src/i18n/messages/ko.json # src/i18n/messages/lt.json # src/i18n/messages/lv.json # src/i18n/messages/ml.json # src/i18n/messages/mr.json # src/i18n/messages/ms.json # src/i18n/messages/mt.json # src/i18n/messages/my.json # src/i18n/messages/ne.json # src/i18n/messages/nl.json # src/i18n/messages/no.json # src/i18n/messages/or.json # src/i18n/messages/pa.json # src/i18n/messages/phi.json # src/i18n/messages/pl.json # src/i18n/messages/pt-BR.json # src/i18n/messages/pt.json # src/i18n/messages/ro.json # src/i18n/messages/ru.json # src/i18n/messages/si.json # src/i18n/messages/sk.json # src/i18n/messages/sl.json # src/i18n/messages/sr.json # src/i18n/messages/sv.json # src/i18n/messages/sw.json # src/i18n/messages/ta.json # src/i18n/messages/te.json # src/i18n/messages/th.json # src/i18n/messages/tr.json # src/i18n/messages/uk-UA.json # src/i18n/messages/ur.json # src/i18n/messages/uz.json # src/i18n/messages/vi.json # src/i18n/messages/yo.json # src/i18n/messages/zh-CN.json # src/i18n/messages/zh-TW.json
…ase 217) Co-authored-by: ErfanBagheri404 <mrenmityerf@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
seen_modelstable, and models that appear in a later sync stay unread until acknowledged.GET /api/models/new(unread models grouped by provider) andPOST /api/models/new/acknowledge(selection or all), both management routes.Attribution
Thanks to @ErfanBagheri404 for the original implementation.
Changes
src/lib/db/migrations/206_seen_models.sql— new idempotent tableseen_models(provider, model_id, is_free, first_seen_at, acknowledged_at)+ index (next free number on the tip;check:migration-numberingOK).src/lib/db/seenModels.ts—reconcileSeenModels,listUnseenModels,countUnseenModels,acknowledgeSeenModels. Seeding is per provider: the first reconcile of a provider records its whole listing as read, so an existing install, or a provider connected later, never floods the inbox. Rows are never deleted, so a model that disappears and comes back is not flagged again.src/lib/newModelsInbox.ts— best-effort recorder used by the sync route (never throws, never fails a sync; free flag viaisFreeModel()fromsrc/shared/utils/freeModels.ts) and the grouped read model (provider names throughgetProviderById/getProviderDisplayName, compatible nodes resolved fromprovider_nodes).src/app/api/providers/[id]/sync-models/route.ts— +3 lines: records the fetched listing on the regular discovery path and on the Volcano Ark console path, so the 6h auto-sync scheduler fills the inbox too.src/app/api/models/new/route.ts,src/app/api/models/new/acknowledge/route.ts—requireManagementAuth, Zod.safeParsebody ({ models: [{provider, modelId}] },{ all: true }or empty = all), errors throughcreateErrorResponse(sanitized)./api/models/*already classifies as MANAGEMENT; no process spawn, so not local-only.src/app/(dashboard)/dashboard/providers/components/NewModelsButton.tsx+ 2-line mount inProviderSummaryCard.tsx(keepsproviders/page.tsxuntouched).src/i18n/messages/*.json— 10 newproviders.newModels*keys, translated in all 66 locales (inserted in place, no key reordering).Design note: the GET reads the table only instead of rebuilding the unified
/v1/modelscatalog on every request, so it is cheap and needs no in-memory cache; the sync path is the single writer.Test plan
node --import tsx/esm --test tests/unit/seen-models.test.ts— 13 tests: seed-on-first-reconcile, later model flagged, acknowledge + re-reconcile not re-flagged, disappear/reappear not re-flagged, per-provider seeding, blank/duplicate ids, acknowledge-all, raw-payload recorder, recorder never throws on DB failure, GET grouping, POST selection/all, POST 400 on invalid body, GET 500 error path leaks neither the DB path nor a stack frame. Failed before the port (modules missing).node --import tsx/esm --test tests/unit/seen-models-sync-route.test.ts— realPOST /api/providers/[id]/sync-modelstwice: first sync seeds (0 unread), second sync with one extra model leaves exactly that model unread. Verified it FAILS with the original route (ℹ pass 0 ℹ fail 1) and passes with the hook.seen-models,seen-models-sync-route,model-sync-route,model-sync-custom-preservation,model-sync-keeps-imported-media-models,siliconflow-model-sync,zai-web-model-sync-route,openference-sync-e2e-15762,sync-models-degraded-cached-catalog-9683,combo-stale-model-refs-13505,i18n-vi-completeness,i18n-placeholder-parity,i18n-key-completeness,i18n-locale-surfaces-parity→ℹ tests 139 ℹ pass 139 ℹ fail 0.npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files>→ clean;npx prettier --check→ clean.npm run typecheck:core→ 57 errors, all pre-existing on the base (none in the changed files).npm run check:migration-numbering→ OK (203 migrations);check:route-validation:t06→ PASS;check:openapi-coverage→ PASS;check:openapi-routes→ OK;check:route-guard-membership→ OK;check:file-size→ OK.npm run i18n:check-keys→ OK (66 locales, all 13765 keys);i18n:check-ratio→ OK;check-new-key-coverage→ PASS;i18n:check-ui-coverage→ PASS.check-pr-test-policy→ PASS;check:test-masking→ OK.