From b3f7ba523f644224364d155b575fa3f9f13c5eb9 Mon Sep 17 00:00:00 2001
From: Adam Malczewski <github@tradam.dev>
Date: Wed, 10 Jun 2026 16:48:30 +0900
Subject: feat(chat,app): Model view in sidebar + split key/model selectors

- move the model picker out of the chat header into a dedicated "Model" sidebar
  view; sidebar now seeds two default panels (Model on top, Extensions below)
- split the single model dropdown into two stacked selects: a key selector
  (distinct credential keys) + a model selector (models under the current key)
- pure model-select helpers (splitModelName/joinModelName/modelKeys/modelsForKey),
  split on the FIRST slash so multi-slash model names stay intact
- onSelect still emits the full `<key>/<model>` string (ChatRequest.model unchanged)
---
 src/features/chat/ui/ModelSelector.svelte | 48 ++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 10 deletions(-)

(limited to 'src/features/chat/ui/ModelSelector.svelte')

diff --git a/src/features/chat/ui/ModelSelector.svelte b/src/features/chat/ui/ModelSelector.svelte
index 3e25ec3..a288cb8 100644
--- a/src/features/chat/ui/ModelSelector.svelte
+++ b/src/features/chat/ui/ModelSelector.svelte
@@ -1,4 +1,6 @@
 <script lang="ts">
+	import { joinModelName, modelKeys, modelsForKey, splitModelName } from "../model-select";
+
 	let {
 		models,
 		selected,
@@ -8,15 +10,41 @@
 		selected: string;
 		onSelect: (model: string) => void;
 	} = $props();
+
+	const keys = $derived(modelKeys(models));
+	const current = $derived(splitModelName(selected));
+	const keyModels = $derived(modelsForKey(models, current.key));
+
+	// Switching key jumps to the first model available under it.
+	function selectKey(key: string): void {
+		const first = modelsForKey(models, key)[0] ?? "";
+		onSelect(joinModelName(key, first));
+	}
+
+	function selectModel(model: string): void {
+		onSelect(joinModelName(current.key, model));
+	}
 </script>
 
-<select
-	class="select"
-	value={selected}
-	onchange={(e) => onSelect(e.currentTarget.value)}
-	aria-label="Model selector"
->
-	{#each models as model (model)}
-		<option value={model}>{model}</option>
-	{/each}
-</select>
+<div class="flex flex-col gap-2">
+	<select
+		class="select w-full"
+		value={current.key}
+		onchange={(e) => selectKey(e.currentTarget.value)}
+		aria-label="Key selector"
+	>
+		{#each keys as key (key)}
+			<option value={key}>{key}</option>
+		{/each}
+	</select>
+	<select
+		class="select w-full"
+		value={current.model}
+		onchange={(e) => selectModel(e.currentTarget.value)}
+		aria-label="Model selector"
+	>
+		{#each keyModels as model (model)}
+			<option value={model}>{model}</option>
+		{/each}
+	</select>
+</div>
-- 
cgit v1.2.3

