Skip to content

Upstream dialog: add models by hand in the Models section, for any upstream - #299

Merged
fylorn merged 1 commit into
devfrom
feat/dialog-manual-models
Oct 9, 2026
Merged

fylorn merged 1 commit into
devfrom
feat/dialog-manual-models

Conversation

@fylorn

@fylorn fylorn commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

What

The Edit / New upstream dialog's Models section now always lets models be added by hand, not only when the upstream returns no list. It uses the same list input as the model panel's Add models… dialog (Enter to add, several at once, checked on the spot: blank, */?, over 256 characters, already added, already listed by the upstream). The old free-text box is gone.

  • One table, the union. The upstream's own models (ModelRow.listed) plus the form's manual list (pending edits are the source of truth), deduplicated, listed first, manual ones after, like core merges them. Manual rows carry the Manual tag and a Remove word action; removing one the upstream also lists keeps the row, untagged. The input is the table's last row, aligned with the model IDs.
  • Works in every state: upstream with a list, without one (ollama-style: the note says why and that models can be added by hand), and a new upstream while its first fetch runs (skeleton above the input).
  • Scope for newly added models: with Selected models active, a model added by hand is checked right away (its exact ID is appended to models_only; a wildcard that already covers it is left alone), so it never ends up silently disabled; it can be unchecked like any row. All models needs nothing. Removing a manual model the upstream does not list also drops its exact entry from the scope, so "Selected models" cannot keep a check for a model that is gone (and an emptied scope blocks Save with "Select at least one model").
  • Counts read like the panel: 上游列出 4 个,手动添加 1 个 · 获取于 16:00; without a list, the badge follows the pending manual list (手动添加 / 未提供清单) and the count is just the number.
  • Save writes the manual list with the rest of the upstream (ProviderInput.models), no separate endpoint call. Text still in the input is added first; if it has a problem, the save stops and the dialog goes to the Models section where the problem is shown. Core's config.manual_model_* rejections surface in the dialog's error banner like any other save error (translated through core.zh.json).
  • After adding, the new row is revealed: the table scrolls to it, a filter that would hide it is cleared, and the input stays in view.
  • ModelCatalog / catalogOf carry only the IDs the upstream lists (listed) instead of flattening manual ones in.
  • Shared: ManualModelInput.tsx (entry hook, list box with the hint/problem line, ManualTag); ManualModelsDialog and ModelsPanel use it. Pure helpers: addToList, unionModels (manualModels.ts), inScope, withManualAdded, withManualRemoved (upstreamForm.ts).

Checks

  • pnpm typecheck, pnpm test (92 files, 953 tests; new tests for the union, tagging, in-dialog add checks, scope on add/remove, counts, catalogOf.listed, and the translated core rejection), pnpm build.
  • Preview harness (local): edit/new dialog with a list (chatgpt, anthropic, openrouter with wildcard scope), without one (ollama), new upstream during and after the first fetch, add/remove, every problem message, pending input on Save, a forced core rejection; zh/en, light/dark, 1100×720 and 820×560; no console errors. The panel's Add models… dialog still adds and saves as before.

🤖 Generated with Claude Code

…stream

The Edit / New upstream dialog only offered a free-text box for models added by
hand when the upstream returned no list. The Models section now always ends with
the same list input as the model panel's "Add models…" dialog (Enter to add,
several at once, checked on the spot), for an upstream with a list, without one,
and while a new upstream's first fetch runs.

- The section's table is the union of what the upstream lists and the form's
  manual list (pending edits are the source of truth), deduplicated, listed
  first. Manual rows are tagged Manual and have a Remove action; a removed model
  the upstream also lists stays, untagged.
- With "Selected models" active, a model added by hand is checked right away
  (its exact ID is appended to the scope; a wildcard that already covers it is
  left alone). Removing one the upstream does not list also drops its exact
  entry from the scope. "All models" needs nothing.
- The header counts read like the panel: "4 listed by the upstream, 1 added by
  hand"; the badge follows the pending manual list.
- Saving writes the manual list with the rest of the upstream. Text still in
  the input is added first; if it has a problem the save stops on the Models
  section. Core's config.manual_model_* rejections show in the dialog like
  any other save error.
- ModelCatalog carries only the IDs the upstream lists (ModelRow.listed)
  instead of flattening manual ones in.
- The list input, its checks' wording and the Manual tag are shared
  (ManualModelInput.tsx); ManualModelsDialog and ModelsPanel use them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fylorn
fylorn merged commit f613a41 into dev Oct 9, 2026
4 checks passed
@fylorn
fylorn deleted the feat/dialog-manual-models branch October 9, 2026 05:29
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