Skip to content

feat(models): archived model display and URL encoding fix#77

Merged
pescn merged 3 commits intomainfrom
feat/archived-models-and-url-encoding
Mar 1, 2026
Merged

feat(models): archived model display and URL encoding fix#77
pescn merged 3 commits intomainfrom
feat/archived-models-and-url-encoding

Conversation

@pescn
Copy link
Contributor

@pescn pescn commented Mar 1, 2026

Summary

  • Archived models in registry: Models that have been deleted but still have historical completion/embedding records now appear as grayed-out "Archived" entries in the global model registry page. Users can click the history button to navigate to past requests for traceability.
  • URL encoding fix: Eden Treaty does not URL-encode dynamic path segments, causing 404 errors for model names containing slashes (e.g. Qwen/Qwen3-8B). All by-system-name path params are now wrapped with encodeURIComponent().

Changes

Backend

  • listUniqueSystemNames() now returns { active: string[], archived: string[] } instead of string[]
  • Archived names are derived via SQL UNION on completions + embeddings tables, excluding active model names

Frontend

  • New ArchivedModelRow component with archive icon, opacity-50, and strikethrough styling
  • ModelsSettingsPage accepts activeSystemNames and archivedSystemNames props
  • Added encodeURIComponent(systemName) to all Eden Treaty by-system-name calls
  • i18n keys added for both en-US and zh-CN

Test plan

  • Delete all providers for a model that has historical requests → model appears as archived in registry
  • Click history button on archived model → navigates to requests page filtered by that model
  • Model names with slashes (e.g. Qwen/Qwen3-8B) display providers correctly
  • Active models continue to work as before (weight editing, history navigation)
  • Type check passes (bun run check)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新功能

    • 模型列表现在区分并显示“已归档”模型,已归档项带淡化样式、归档标签与历史记录入口。
  • 改进

    • 后端返回将活跃与归档模型分组,前端据此分别展示。
    • 对模型系统名的 API 请求进行了编码处理以提升健壮性。
  • 本地化

    • 增加“Archived”及其提示的中/英本地化文本。

pescn and others added 2 commits March 1, 2026 12:49
Models that have been deleted but still have historical completion/embedding
records now appear as grayed-out "Archived" entries in the global model
registry. Users can click the history button to trace past requests.

- Backend: `listUniqueSystemNames()` returns `{ active, archived }` using
  SQL UNION query on completions/embeddings tables
- Frontend: new `ArchivedModelRow` component with archive icon, opacity,
  and strikethrough styling
- i18n: added Archived/ArchivedTooltip keys for en-US and zh-CN

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Eden Treaty does not URL-encode dynamic path segments, causing 404 errors
for model names containing slashes (e.g. `Qwen/Qwen3-8B`). Wrap all
`by-system-name` path params with `encodeURIComponent()`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

📝 Walkthrough

Walkthrough

后端将 listUniqueSystemNames 的返回值从字符串数组改为包含 activearchived 两部分的对象。前端适配该结构,分离并显示活跃与已归档模型行,所有按 systemName 的 API 路径均改为使用 URL 编码;新增两处国际化文案。

Changes

Cohort / File(s) Summary
后端 - 模型名称查询
backend/src/db/index.ts
listUniqueSystemNames 返回类型由 string[] 改为 `{ active: string[]; archived: { systemName: string; modelType: "chat"
国际化 - 翻译文件
frontend/src/i18n/locales/en-US.json, frontend/src/i18n/locales/zh-CN.json
新增两条翻译键:pages.models.registry.Archivedpages.models.registry.ArchivedTooltip(英文/中文均已添加)。
前端 - 模型注册表
frontend/src/pages/models/models-registry-table.tsx
在构造按 systemName 查询的 API 路径时使用 encodeURIComponent(systemName),以确保特殊字符被正确编码。
前端 - 模型设置页面
frontend/src/pages/settings/models-settings-page.tsx
组件 props 从单一 systemNames 改为 { activeSystemNames: string[]; archivedSystemNames: ArchivedModel[] };新增 ArchivedModelRow 用于渲染已归档项(带 ArchiveIcon、删除样式和“历史”跳转),对相关 API 路径均使用 URL 编码;更新条件渲染与表格分组。
前端 - 路由层
frontend/src/routes/models/registry.tsx
调用处由 systemNames={data} 改为 activeSystemNames={data.active}archivedSystemNames={data.archived},以匹配后端新返回结构与 ModelsSettingsPage 新签名。

Sequence Diagram(s)

sequenceDiagram
    participant Route as 路由层 (registry.tsx)
    participant Backend as 后端 (listUniqueSystemNames)
    participant SettingsPage as 模型设置页面 (ModelsSettingsPage)
    participant API as 模型 API (admin.models)

    Route->>Backend: 请求模型名称列表
    Backend->>Backend: 计算 active 与 archived 集合
    Backend-->>Route: 返回 { active: [...], archived: [...] }

    Route->>SettingsPage: 传入 activeSystemNames 与 archivedSystemNames
    SettingsPage->>SettingsPage: 渲染活跃行与已归档行
    SettingsPage->>API: GET /models/by-system-name/{encodeURIComponent(systemName)}
    API-->>SettingsPage: 返回模型详情
Loading

评估代码审查工作量

🎯 3 (中等) | ⏱️ ~35 分钟

🐰 已归档的模型静静躺,
活跃的在阳光下忙忙,
名称分组清清楚楚,
路径编码稳稳当当,
小兔拍手庆贺此方光!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: archived model display functionality and URL encoding fix for system names.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/archived-models-and-url-encoding

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the model management experience by enhancing data traceability and application robustness. It introduces the capability to visualize models that have been deleted but still possess historical usage data, ensuring that no valuable historical context is lost. Concurrently, it addresses a critical bug by correctly handling URL encoding for model names, which prevents errors and ensures seamless interaction with the API for all model identifiers.

Highlights

  • Archived Model Display: Implemented a feature to display 'archived' models in the global model registry, allowing users to see models that have been deleted but still have historical usage records. These models are visually distinguished with grayed-out text and a strikethrough, and provide a direct link to their request history.
  • URL Encoding Fix: Resolved an issue where model names containing special characters (like slashes, e.g., 'Qwen/Qwen3-8B') caused 404 errors in API requests. All dynamic path segments for model system names are now properly URL-encoded using encodeURIComponent().
Changelog
  • backend/src/db/index.ts
    • Updated the listUniqueSystemNames function to return an object containing separate arrays for active and archived model system names, instead of a single string array.
    • Added new SQL logic to identify archived models by performing a UNION on completions and embeddings tables and excluding models that are currently active.
  • frontend/src/i18n/locales/en-US.json
    • Added new English translation keys: pages.models.registry.Archived and pages.models.registry.ArchivedTooltip.
  • frontend/src/i18n/locales/zh-CN.json
    • Added new Chinese translation keys: pages.models.registry.Archived and pages.models.registry.ArchivedTooltip.
  • frontend/src/pages/models/models-registry-table.tsx
    • Applied encodeURIComponent to the systemName parameter in API calls for fetching models and updating weights to ensure proper URL handling.
  • frontend/src/pages/settings/models-settings-page.tsx
    • Imported ArchiveIcon for use in the UI.
    • Modified the ModelsSettingsPage component to accept activeSystemNames and archivedSystemNames as distinct props.
    • Updated the rendering logic to display active models using ModelRow and archived models using a newly introduced ArchivedModelRow component.
    • Created the ArchivedModelRow component, which displays archived models with an ArchiveIcon, opacity-50 styling, a strikethrough on the name, and a button to navigate to their history.
    • Applied encodeURIComponent to the systemName parameter in API calls within the LoadBalancingDialog.
  • frontend/src/routes/models/registry.tsx
    • Updated the ModelsSettingsPage component call to pass activeSystemNames and archivedSystemNames separately, based on the data received from the backend query.
Activity
  • No specific human activity (comments, reviews, or progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a feature to display archived models and fixes a URL encoding issue. The implementation is mostly solid, but I have a couple of suggestions. In the backend, the query for archived models can be simplified to improve readability and avoid duplicating logic. On the frontend, there's a bug in the new ArchivedModelRow component where the history link is incorrect for embedding models. This will require a backend change to resolve properly. The URL encoding fix looks correct.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/src/db/index.ts (1)

952-994: ⚠️ Potential issue | 🟠 Major

modelType 在归档查询中被忽略,归档结果会与请求类型不一致

这里 activemodelType 过滤,但 archived 仍固定查询 completions+embeddings,并且排除 active 时也未按 model_type 对齐。传入 chatembedding 时会出现归档集合不准确的问题。

🔧 建议修复(按 modelType 对齐 archived 源与排除条件)
 export async function listUniqueSystemNames(
   modelType?: ModelTypeEnumType,
 ): Promise<{ active: string[]; archived: string[] }> {
   logger.debug("listUniqueSystemNames", modelType);

   // Get active model names (non-deleted models with non-deleted providers)
   const r = await db
@@
     .orderBy(asc(schema.ModelsTable.systemName));
   const active = r.map((x) => x.systemName);

+  const archivedSourceSql =
+    modelType === "chat"
+      ? sql`SELECT DISTINCT model FROM completions WHERE deleted = false`
+      : modelType === "embedding"
+        ? sql`SELECT DISTINCT model FROM embeddings WHERE deleted = false`
+        : sql`SELECT DISTINCT model FROM completions WHERE deleted = false
+              UNION
+              SELECT DISTINCT model FROM embeddings WHERE deleted = false`;
+
   // Get archived model names: exist in completions/embeddings but not in active models
   const archivedResult = await db.execute(sql`
-    SELECT DISTINCT model AS name FROM (
-      SELECT DISTINCT model FROM completions WHERE deleted = false
-      UNION
-      SELECT DISTINCT model FROM embeddings WHERE deleted = false
-    ) AS all_models
-    WHERE model NOT IN (
+    SELECT DISTINCT src.model AS name
+    FROM (${archivedSourceSql}) AS src
+    WHERE src.model NOT IN (
       SELECT DISTINCT m.system_name
       FROM models m
       INNER JOIN providers p ON m.provider_id = p.id
-      WHERE m.deleted = false AND p.deleted = false
+      WHERE m.deleted = false
+        AND p.deleted = false
+        ${modelType ? sql`AND m.model_type = ${modelType}` : sql``}
     )
     ORDER BY name ASC
   `);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/db/index.ts` around lines 952 - 994, The archived query in
listUniqueSystemNames ignores modelType, causing mismatched archived results;
update the archivedResult SQL so when modelType is provided it (1) filters the
UNION source to only the relevant table(s) (e.g., only embeddings for embedding
type, only completions for chat/type that maps to completions) or includes a
WHERE model_type = :modelType in each source, and (2) adds the same model_type
filter to the exclusion subquery that selects DISTINCT m.system_name from models
(aliases m and p) so the NOT IN comparison aligns with the active query; modify
the archivedResult construction (and its parameterization) to pass modelType
into the SQL and then map archived from the returned name column as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/pages/settings/models-settings-page.tsx`:
- Around line 173-176: handleHistoryClick currently always navigates to
'/requests' which breaks access for archived models that only have embedding
history; update the click handler (handleHistoryClick) to read a model type
indicator (e.g., modelType on the archived model alongside systemName) and route
conditionally using navigate: if modelType === 'request' go to '/requests', if
modelType === 'embedding' go to the embeddings history route (e.g.,
'/embeddings'), passing model and modelType in search; preserve
e.stopPropagation() and add a safe fallback to '/requests' if modelType is
missing or unknown while ensuring the archived data includes the modelType field
for future use.

---

Outside diff comments:
In `@backend/src/db/index.ts`:
- Around line 952-994: The archived query in listUniqueSystemNames ignores
modelType, causing mismatched archived results; update the archivedResult SQL so
when modelType is provided it (1) filters the UNION source to only the relevant
table(s) (e.g., only embeddings for embedding type, only completions for
chat/type that maps to completions) or includes a WHERE model_type = :modelType
in each source, and (2) adds the same model_type filter to the exclusion
subquery that selects DISTINCT m.system_name from models (aliases m and p) so
the NOT IN comparison aligns with the active query; modify the archivedResult
construction (and its parameterization) to pass modelType into the SQL and then
map archived from the returned name column as before.

ℹ️ Review info

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3121a7b and 3eaea5d.

📒 Files selected for processing (6)
  • backend/src/db/index.ts
  • frontend/src/i18n/locales/en-US.json
  • frontend/src/i18n/locales/zh-CN.json
  • frontend/src/pages/models/models-registry-table.tsx
  • frontend/src/pages/settings/models-settings-page.tsx
  • frontend/src/routes/models/registry.tsx

…ting

- Backend: archived query now respects `modelType` param and returns
  `{ systemName, modelType }` per archived entry (instead of plain string)
- Backend: simplified SQL by fetching all historical names and filtering
  in TypeScript, avoiding duplicated active-model logic in NOT IN subquery
- Frontend: `ArchivedModelRow` routes to `/embeddings` for embedding
  models instead of hardcoding `/requests`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
frontend/src/pages/settings/models-settings-page.tsx (1)

64-66: ⚠️ Potential issue | 🟡 Minor

React key 存在潜在冲突风险。

如果后端将来返回相同 systemName 但不同 modelType 的归档模型,当前仅使用 item.systemName 作为 key 会导致 React 渲染异常。建议使用复合 key 以确保唯一性。

🛡️ 建议使用复合 key
-                {archivedSystemNames.map((item) => (
-                  <ArchivedModelRow key={item.systemName} systemName={item.systemName} modelType={item.modelType} />
+                {archivedSystemNames.map((item) => (
+                  <ArchivedModelRow key={`${item.modelType}:${item.systemName}`} systemName={item.systemName} modelType={item.modelType} />
                 ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/settings/models-settings-page.tsx` around lines 64 - 66,
The list rendering uses item.systemName alone as the React key which can collide
if two archived entries share systemName but differ in modelType; update the map
to use a composite key (e.g., combine item.systemName and item.modelType) when
rendering ArchivedModelRow so each element has a unique key (refer to
archivedSystemNames, ArchivedModelRow, item.systemName and item.modelType).
🧹 Nitpick comments (1)
frontend/src/pages/settings/models-settings-page.tsx (1)

195-197: 可考虑显示归档模型的类型标签。

当前 modelType 列显示 "-",但组件已接收 modelType 属性。显示实际类型(带归档样式)可提升用户体验,便于区分 chat 和 embedding 模型的历史记录。

💡 可选:显示带样式的模型类型
       <TableCell>
-        <span className="text-muted-foreground text-sm">-</span>
+        <Badge variant="outline" className="text-muted-foreground text-xs opacity-70">
+          {modelType === 'chat'
+            ? t('pages.settings.models.columns.Chat')
+            : t('pages.settings.models.columns.Embedding')}
+        </Badge>
       </TableCell>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/settings/models-settings-page.tsx` around lines 195 - 197,
Replace the hardcoded "-" in the TableCell with the actual modelType value
passed into the component (use the modelType prop or model.modelType used
elsewhere in this file) and render it as a styled archived tag (e.g., a small
badge/span with classes like "text-sm px-2 rounded bg-muted-foreground/10
text-muted-foreground" or similar) so archived models show "chat" or "embedding"
visibly; update the TableCell containing the dash to display this styled model
type badge instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@frontend/src/pages/settings/models-settings-page.tsx`:
- Around line 64-66: The list rendering uses item.systemName alone as the React
key which can collide if two archived entries share systemName but differ in
modelType; update the map to use a composite key (e.g., combine item.systemName
and item.modelType) when rendering ArchivedModelRow so each element has a unique
key (refer to archivedSystemNames, ArchivedModelRow, item.systemName and
item.modelType).

---

Nitpick comments:
In `@frontend/src/pages/settings/models-settings-page.tsx`:
- Around line 195-197: Replace the hardcoded "-" in the TableCell with the
actual modelType value passed into the component (use the modelType prop or
model.modelType used elsewhere in this file) and render it as a styled archived
tag (e.g., a small badge/span with classes like "text-sm px-2 rounded
bg-muted-foreground/10 text-muted-foreground" or similar) so archived models
show "chat" or "embedding" visibly; update the TableCell containing the dash to
display this styled model type badge instead.

ℹ️ Review info

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3eaea5d and 2ad744d.

📒 Files selected for processing (2)
  • backend/src/db/index.ts
  • frontend/src/pages/settings/models-settings-page.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/src/db/index.ts

@pescn pescn merged commit 80cc1ef into main Mar 1, 2026
2 checks passed
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.

1 participant