Skip to content

feat(tui): order the model picker by Kilo Gateway metadata - #15405

Merged
marius-kilocode merged 8 commits into
v2from
kilo-model-picker
Oct 23, 2026
Merged

marius-kilocode merged 8 commits into
v2from
kilo-model-picker

Conversation

@marius-kilocode

@marius-kilocode marius-kilocode commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #15242
Part of #15337 (the sidebar order item stays open, see Limits)

What Problem This Solves

The v2 TUI model picker (packages/tui/src/component/dialog-model.tsx) does not use the Kilo Gateway metadata that the kilocode.gateway models RPC already returns:

  • sortModelOptions puts opencode-go and opencode first, so Kilo Gateway models come after OpenCode and other providers.
  • recommendedIndex is ignored, so there is no Recommended section.
  • Free is inferred from the input price, and the v1 BYOK and May train labels are missing.
  • The v1 model info panel (description, pricing, context, Terminal Bench, training disclosure) is missing.

Why This Change Was Made

v1 (origin/main) is the reference:

  • packages/tui/src/component/dialog-model.tsx (lines 25-31, 66-72, 173): Gateway rank from recommendedIndex, BYOK and May train labels, and the details panel in a wide terminal.
  • packages/tui/src/kilocode/model-picker.ts (lines 156-166): Recommended section; search over title, section, provider name, provider ID and model ID, ranked inside each section; recents stay in their provider section.
  • packages/opencode/src/kilocode/components/model-info-panel.tsx (lines 79-86) and free-model-disclosure.ts: the BYOK and training disclosures and the price, context and benchmark rows.

The picker reads the metadata from the existing kilocode.gateway models RPC. No server or schema change is needed.

User Impact

  • The list order is: Favorites and Recent (stored order), then Recommended (Gateway recommendedIndex order), then Kilo Gateway (free first, then server order), then the other providers by name. OpenCode is no longer first. No provider is hidden.
  • A recent model also stays in its provider section, as on v1.
  • Search matches the provider name and the provider and model IDs (for example kilo, openai/gpt, amazon-bedrock), and section headers stay while searching.
  • Kilo rows show Free from Gateway isFree (not from the price), BYOK and May train. Other providers keep the upstream price rule for Free.
  • At 108 columns or more, a model info panel shows the highlighted model: name, provider, BYOK, "Data may be used for training", family, release date, input, output, cached and average price, context, Terminal Bench 2.0, reasoning, modalities and the Gateway description. As on v1, a free Gateway model shows no price or context rows.
  • Training policy: the picker lists only models of the model list. When hide_prompt_training_models is on, fix(gateway): restore enterprise policy and organization modes #15372 removes training models from that list, so they get no row and no May train label.
  • Model selection, the variant flow and the default model are not changed.

Evidence

Automated (pinned Bun 1.4.2, isolated OPENCODE_TEST_HOME and XDG paths):

  • packages/tui: bun typecheck passes.
  • bun test test/kilocode test/cli/cmd/tui/model-options.test.ts, upstream test/cli/tui/dialog-select.test.tsx and the other tests that render DialogSelect: 103 pass. Upstream model-options.test.ts passes unchanged.
    • test/kilocode/model-picker.test.ts (12): order with Favorites, Recent, Recommended, Kilo Gateway and other providers; signed out (no section headers, nothing hidden); no Gateway metadata; provider dialog; training-policy agreement; config alias; search by provider name, provider ID, model ID and title; labels from isFree, hasUserByokAvailable and mayTrainOnYourPrompts, and no Free inferred from a Kilo price.
    • test/kilocode/dialog-model.test.tsx (4): a recent model listed in Recent and in Kilo Gateway highlights one row, and hover moves the highlight to the row under the pointer (fails without the DialogSelect change). Also renders the real upstream DialogModel with the seam at 130 columns. It checks section order, row labels, the panel rows for a recommended model, that the panel follows the highlight (a regression check for stale rows), search with section headers, and the signed-out order.
    • free-model-disclosure.test.ts and model-info-panel-utils.test.ts: the v1 tests, ported.
  • The full bun test in packages/tui in one process: 1538 pass, 54 fail (same files and count as on the previous head). The 54 failures are in 15 files that are not related to the picker (session, diff viewer, stats). Each of these files passes when run alone (all 15 rerun: 0 fail). CI uses the sharded runner.
  • Root bun run check: pass. bun script/check-shared-patches.ts --worktree, bun script/check-opencode-annotations.ts --worktree, bun script/upstream/placement.ts --imports: pass. bun script/upstream/progress.ts twice (same output) and --check: pass.

Self-test: the real TUI through the vscode-self-test harness (--mode none), bun script/dev-isolated.ts --standalone, a fresh KILO_V2_PROFILE per run, and a clean env -i child environment. Team and personal runs used the local Gateway fixture (packages/kilo-gateway-core/src/testing.ts, with extra fixture models) through KILO_API_URL and a fake key. No real credential and no prompt were used.

Scenario Result
Signed out, real Gateway, ctrl+x m Pass. No section headers (no connected integration, as upstream). Kilo free models first with Free · May train; OpenCode free models after them (gone after the v2 merge with #15397). The panel shows the Auto Free description and the training disclosure
Signed out, search nemotron, opencode Pass. Kilo and OpenCode matches are both listed
Personal scope (fixture) Pass. Recommended: Kilo Auto Frontier (BYOK), Kilo Auto Free (Free), Claude Opus 4.6 (BYOK). Kilo Gateway: Kilo Auto Small (Free), Grok Code Fast 1 (Free · May train), GPT-5.4. Then OpenCode. The panel for Opus shows the prices, cache price, context 200K, Terminal Bench 61.0% and $2.10, Reasoning, Caps Image and the description
Personal scope, favorite and recent Pass. After ctrl+f on Opus and selecting Kilo Auto Small: Favorites (Opus), Recent (Kilo Auto Small), Recommended without Opus, and Kilo Auto Small still under Kilo Gateway
Personal scope, search openai/gpt, opus Pass. GPT-5.4 under the Kilo Gateway header; Opus under Favorites
After merging v2 (#15397, #15401): signed out and team scope Pass. Signed out: Kilo free models only, no OpenCode free models. Team: Recommended Claude Sonnet 4.6 (Team), now also the current model; Kilo Gateway GLM 5 (Team) and Kilo Auto Small
Team scope (fixture, KILO_ORG_ID) Pass. Recommended: Claude Sonnet 4.6 (Team). Kilo Gateway: GLM 5 (Team) (Free · May train), Kilo Auto Small (no Free, team catalog marks it paid). Then OpenCode

The self-test found one defect, which this PR fixes: panel rows kept the values of the previous model when the next model had the same rows. The rows are now a reactive component, and dialog-model.test.tsx covers it (the test fails with the old code).

Screenshots

Real TUI, local Gateway fixture (fixture models, no real account). Taken before the v2 merge: since #15397, the OpenCode free models below the Kilo sections are no longer listed.

Personal scope: Recommended, Kilo Gateway and other providers, with the info panel for a recommended model.

Model picker in personal scope with Recommended and Kilo Gateway sections and the model info panel

Free model that may train on prompts: Free · May train label and the training disclosure in the panel.

Model picker with a free model highlighted and the training disclosure in the info panel

Search by model ID keeps the section header.

Model picker search for openai/gpt with the Kilo Gateway section header

Team scope: the team catalog's Recommended and Kilo Gateway sections.

Model picker in team scope with team models

Placement

Change Rung Why not lower Proof
Picker options, order, labels, search (tui/src/kilocode/model-picker.ts) Kilo-owned n/a kilo_port(tui:c29e2d297ca2) and the v1 sort cells
Gateway metadata, preview, dialog size, panel frame (tui/src/kilocode/dialog-model.tsx) Kilo-owned n/a kilo_port(unattributed:tui/component:*)
Model info panel and disclosure (tui/src/kilocode/components/*) Kilo-owned n/a v1 file names
Seven call-out lines in tui/src/component/dialog-model.tsx (import, createKiloModelPicker, an early return kilo.options() in the options memo, onMove, flat={false}, kilo.frame( and its closing line) 4 The TUI plugin API has no model picker hook, and the host runs in the server process. A generic seam would need the same lines plus a new plugin API for one consumer kilocode_change(components:06ac8868d98e), kilocode_change(tui), shared-patches.json entry

| Row matching by reference in tui/src/ui/dialog-select.tsx (4 lines, as v1) | 3 | No plugin hook or host option reaches DialogSelect's private row matching. Generic, no Kilo value; same behavior for lists with unique values | kilocode_change(unattributed:tui/ui:*), shared-patches.json entry |

  • Shared upstream files: packages/tui/src/component/dialog-model.tsx (new entry, rung 4) and packages/tui/src/ui/dialog-select.tsx (added to the existing rung 4 entry from fix(tui): keep dialog footer mounted across action changes #15400; these 4 lines carry no Kilo value). Limits after merging current v2: files 43 to 44, markedLines 316 to 327.
  • Upstream code is not changed: the upstream options memo, sortModelOptions and prioritizeFavorites stay, so the upstream tests pass. The early return means the upstream list is not built or sorted. The v2.1.1 rewrite of this file (chore(upstream): sync v2.1.1 #15401) is merged into this branch: the call-out lines now sit in DialogConnectedModels, and createKiloModelPicker gets props.onSelect.
  • Core-internal imports added: none (@opencode/client and @opencode/schema types only). Mirrored files: none. No server plugin, so no startup budget change.

Progress map

95/9829 to 122/9828 cells done (25 to 26 dropped).

Done, and why:

  • by file name (7): components/model-info-panel.tsx, model-info-panel-utils.ts, free-model-disclosure.ts and their two tests; tui/src/kilocode/model-picker.ts and its test.
  • kilocode_change (1): components:06ac8868d98e, the v1 import hunk, on the seam import.
  • kilo_port (14): tui:c29e2d297ca2 (footer labels and preview) and 13 unattributed:tui/component hunks of the v1 picker (imports, terminal width, Gateway rank memo, preview and dialog size, panel frame, recommended sort) on the Kilo code that now does each of them.
  • kilocode_change (4): unattributed:tui/ui:acda41f897d2, 858635f51958, aac5db9863ac (2 cells), the v1 DialogSelect reference-identity lines, ported unchanged.
  • ported (1): model-info-panel.types.test.ts. The v2 panel takes the client ModelInfo type, so bun typecheck checks the same contract; dialog-model.test.tsx renders it.

Dropped, and why it is not needed:

  • unattributed:tui/component:902bf97fd9cb: v1 ranked the upstream "Popular providers" rows while searching. Upstream v2 removed those rows from the picker ("View all integrations" opens the integration dialog), so there is nothing to rank.

Still open:

  • cli cells module:.../cli/cmd/tui/component/dialog-provider.tsx and patch:cli:66a6b3781917: the v1 provider dialog module (provider priority, descriptions, failed-state gutter, local API key rules, Kilo auto method). This is the integration dialog, not the model picker. fix(gateway): promote Kilo and hide OpenCode free-tier models #15397 ports the priority part; the rest needs its own unit.

Limits

  • Sidebar order (Home and sidebar plugins: model picker, info panel, free/training disclosure #15337: pr 50, footer 99, usage 150, indexing 225, processes 250, memory 1000): none of these Kilo sidebar plugins exist on v2 yet, and the v2 TUI slot API (append: "sidebar.content", "sidebar.footer") has no numeric order. Nothing to apply in this PR. Missing: sidebar-pr, sidebar-footer (credits), sidebar-usage, sidebar-indexing, sidebar-background-processes, memory-status. They stay open in the plugin box.
  • Signed out there is no connected integration, so the picker shows no section headers (upstream v2 rule; v1 counted the anonymous Kilo provider as connected). The order is the same.
  • v1 "Popular providers" rows in the picker are not carried (see Dropped).
  • Under the newDesigns experiment the connected picker uses the Kilo list, so it has no upstream per-row detail line or separate Free group; the info panel shows those details. The experiment is off by default.
  • The Gateway description is shown in full; some descriptions already contain ... from the Gateway (for example NVIDIA Nemotron 3 Ultra), as on v1.
  • The panel shows "Reasoning" from Gateway metadata only; v2 model info has no reasoning flag for other providers.
  • The Gateway description is shown as plain text, as on v1 (Markdown is not rendered).
  • With the newDesigns experiment on and no connected integration, upstream's DialogFreeModels (from v2.1.1) is shown instead of this picker. The experiment is off by default.

Show Recommended and Kilo Gateway sections from the Gateway recommendedIndex,
Free from Gateway isFree, BYOK and May train labels, v1 search over provider
and model IDs, and the v1 model info panel. The logic is in Kilo-owned files;
the upstream picker gets seven marked call-out lines.
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

📈 v2 migration progress: 1.1% → 1.4% (+27 done, -1 total, +1 dropped; 137/9828 cells)

Placement: 11 new marked lines in shared files (11 patch), 15 new kilo_port annotations, 0 new core-internal imports.

Ratchets: 25 core-internal imports (base 25); shared patches by rung 24 seam, 20 patch (base 24 seam, 19 patch).

Feature Before After Change
components 0/22 7/22 +3 modules done; +1 patch done; +3 tests done
tui 1/45 4/45 +1 module done; +1 patch done; +1 test done
unattributed:tui/component 0/142 13/141 +13 patches done, -1 patch total; +1 dropped
unattributed:tui/ui 0/19 4/19 +4 patches done
26 cells closed
  • module:packages/opencode/src/kilocode/components/free-model-disclosure.ts
  • module:packages/opencode/src/kilocode/components/model-info-panel-utils.ts
  • module:packages/opencode/src/kilocode/components/model-info-panel.tsx
  • module:packages/opencode/test/kilocode/free-model-disclosure.test.ts
  • module:packages/opencode/test/kilocode/model-info-panel-utils.test.ts
  • module:packages/opencode/test/kilocode/model-info-panel.types.test.ts
  • module:packages/tui/src/kilocode/model-picker.ts
  • module:packages/tui/test/kilocode/model-picker.test.ts
  • patch:components:06ac8868d98e
  • patch:tui:c29e2d297ca2
  • patch:unattributed:tui/component:013e56c6e70d
  • patch:unattributed:tui/component:361708efa0db
  • patch:unattributed:tui/component:3bd2c832bb54
  • patch:unattributed:tui/component:442c6f2a6ad9
  • patch:unattributed:tui/component:5c55d556d8ae
  • patch:unattributed:tui/component:7fb2970f1e39
  • patch:unattributed:tui/component:8356b283bea4
  • patch:unattributed:tui/component:85b11084275d
  • patch:unattributed:tui/component:9a58930c75d8
  • patch:unattributed:tui/component:9e2836eb85dc
  • patch:unattributed:tui/component:a277acf3a84b
  • patch:unattributed:tui/component:c8cf17d43819
  • patch:unattributed:tui/component:d10b36aa74a5
  • patch:unattributed:tui/ui:858635f51958
  • patch:unattributed:tui/ui:aac5db9863ac
  • patch:unattributed:tui/ui:acda41f897d2
1 cells dropped
  • patch:unattributed:tui/component:902bf97fd9cb

v2 migration progress map at this commit

Full map · how cells close

@github-actions github-actions Bot added the area:cli CLI, TUI and core engine label Oct 23, 2026
# Conflicts:
#	migration-tracking/progress/README.md
#	migration-tracking/progress/history.svg
#	migration-tracking/progress/progress.json
#	packages/tui/src/component/dialog-model.tsx
#	script/upstream/shared-patches.json
Comment thread packages/tui/src/kilocode/model-picker.ts
searchInTitle
titlePlaceholder="Search models"
options={options()}
options={kilo.options()} // kilocode_change(tui) - Kilo: Gateway order and labels

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[SUGGESTION]: The upstream options memo is now unused but still computed

Only the type at line 200 reads options; the memo itself no longer feeds DialogSelect. Solid createMemo runs eagerly, so on every query, favorite or recent change it re-runs the upstream filter/sortModelOptions/fuzzysort.go pass in addition to kilo.options(). Removing or guarding the memo avoids the duplicate sort and fuzzy pass per keystroke. Separately, under experimental["new-designs"] that memo also supplied the per-row detail (the ModelDetail block is only shown when an option has detail), the Free group and the favoritesAtOpen order; the Kilo options do not carry those, so those users lose the detail row. If the experiment must keep it, pass those fields through.

@kilo-code-bot

kilo-code-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
packages/tui/src/kilocode/model-picker.ts 114 Recents are emitted both in the Recent section and in the provider list, producing two options with an identical value. The v2 DialogSelect resolves rows by isDeepEqual(option.value, ...), so both copies render as active and hover/mouse-down targets the first copy. v1 shipped a reference-identity kilocode_change in dialog-select.tsx for this duplicated-row case; the port does not carry it.

SUGGESTION

File Line Issue
packages/tui/src/component/dialog-model.tsx 203 The upstream options memo is now unused (only its type is referenced) but Solid still recomputes its filter/sort/fuzzysort pass on every query, favorite or recent change, duplicating kilo.options(). Under experimental["new-designs"] it also supplied the per-row detail, Free group and favoritesAtOpen order, which the Kilo options do not carry.
Files Reviewed (18 files)
  • migration-tracking/progress/README.md - generated, no issues
  • migration-tracking/progress/badge.svg - generated, no issues
  • migration-tracking/progress/dispositions.json - generated, no issues
  • migration-tracking/progress/history.svg - generated, no issues
  • migration-tracking/progress/progress.json - generated, no issues
  • migration-tracking/progress/progress.svg - generated, no issues
  • migration-tracking/technical-notes/baseline/model-sidebar-v2-parity.md - no issues
  • packages/tui/src/component/dialog-model.tsx - 1 suggestion
  • packages/tui/src/kilocode/components/free-model-disclosure.ts - no issues
  • packages/tui/src/kilocode/components/model-info-panel-utils.ts - no issues
  • packages/tui/src/kilocode/components/model-info-panel.tsx - no issues
  • packages/tui/src/kilocode/dialog-model.tsx - no issues
  • packages/tui/src/kilocode/model-picker.ts - 1 warning
  • packages/tui/test/kilocode/dialog-model.test.tsx - no issues
  • packages/tui/test/kilocode/free-model-disclosure.test.ts - no issues
  • packages/tui/test/kilocode/model-info-panel-utils.test.ts - no issues
  • packages/tui/test/kilocode/model-picker.test.ts - no issues
  • script/upstream/shared-patches.json - no issues

Reviewed the new TUI lifecycle (createResource, createEffect, useTerminalDimensions, scrollbox) for leaks; no listener, timer or subscription leak was found. The markdown files keep images in markdown form. Local typecheck/tests were not run in this read-only review.

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 151K · Output: 50.7K · Cached: 5.5M

Review guidance: REVIEW.md from base branch v2

Match the active DialogSelect row by reference, as on v1, so a recent model
in Recent and in its provider section highlights and targets one row. Return
the Kilo list from the first line of the upstream options memo so the
upstream list is not built and sorted on every keystroke.
…el-picker

# Conflicts:
#	migration-tracking/progress/README.md
#	migration-tracking/progress/progress.json
#	script/upstream/shared-patches.json
…el-picker

# Conflicts:
#	migration-tracking/progress/README.md
#	migration-tracking/progress/badge.svg
#	migration-tracking/progress/dispositions.json
#	migration-tracking/progress/history.svg
#	migration-tracking/progress/progress.json
#	migration-tracking/progress/progress.svg
#	script/upstream/shared-patches.json
…el-picker

# Conflicts:
#	migration-tracking/progress/README.md
#	migration-tracking/progress/history.svg
#	migration-tracking/progress/progress.json
#	migration-tracking/progress/progress.svg
@marius-kilocode
marius-kilocode merged commit 2af82ee into v2 Oct 23, 2026
22 checks passed
@marius-kilocode
marius-kilocode deleted the kilo-model-picker branch October 23, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:cli CLI, TUI and core engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants