← back to Exo
resolve issue #1070 (#1076)
6e6567a8022df8d4f3b2755e5d01a86cb32b8b91 · 2026-01-16 01:00:41 +0500 · Sami Khan
## Motivation
https://github.com/exo-explore/exo/issues/1070
## Changes
Added check in ChatForm.svelte to reset selectedChatModel when it no
longer matches any running instance.
## Why It Works
The $effect now detects when the selected model is stale (not in
availableModels()) and resets to the first available model.
## Test Plan
### Manual Testing
1. Create instance of Model A → Delete it → Create instance of Model B →
Chat
2. Verify request goes to Model B (not Model A)
---------
Co-authored-by: Alex Cheema <41707476+AlexCheema@users.noreply.github.com>
Files touched
M dashboard/src/lib/components/ChatForm.svelteM dashboard/src/routes/+page.svelte
Diff
commit 6e6567a8022df8d4f3b2755e5d01a86cb32b8b91
Author: Sami Khan <98742866+samiamjidkhan@users.noreply.github.com>
Date: Fri Jan 16 01:00:41 2026 +0500
resolve issue #1070 (#1076)
## Motivation
https://github.com/exo-explore/exo/issues/1070
## Changes
Added check in ChatForm.svelte to reset selectedChatModel when it no
longer matches any running instance.
## Why It Works
The $effect now detects when the selected model is stale (not in
availableModels()) and resets to the first available model.
## Test Plan
### Manual Testing
1. Create instance of Model A → Delete it → Create instance of Model B →
Chat
2. Verify request goes to Model B (not Model A)
---------
Co-authored-by: Alex Cheema <41707476+AlexCheema@users.noreply.github.com>
---
dashboard/src/lib/components/ChatForm.svelte | 33 +++++++++++++++++++++++++---
dashboard/src/routes/+page.svelte | 28 +++++++++++++++++++----
2 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/dashboard/src/lib/components/ChatForm.svelte b/dashboard/src/lib/components/ChatForm.svelte
index 3f622602..269c01f2 100644
--- a/dashboard/src/lib/components/ChatForm.svelte
+++ b/dashboard/src/lib/components/ChatForm.svelte
@@ -60,12 +60,39 @@
return models;
});
- // Auto-select the first available model if none is selected
+ // Track previous model IDs to detect newly added models (plain variable to avoid reactive loop)
+ let previousModelIds: Set<string> = new Set();
+
+ // Auto-select the first available model if none is selected, if current selection is stale, or if a new model is added
$effect(() => {
const models = availableModels();
- if (models.length > 0 && !currentModel) {
- setSelectedChatModel(models[0].id);
+ const currentModelIds = new Set(models.map(m => m.id));
+
+ if (models.length > 0) {
+ // Find newly added models (in current but not in previous)
+ const newModels = models.filter(m => !previousModelIds.has(m.id));
+
+ // If no model selected, select the first available
+ if (!currentModel) {
+ setSelectedChatModel(models[0].id);
+ }
+ // If current model is stale (no longer has a running instance), reset to first available
+ else if (!models.some(m => m.id === currentModel)) {
+ setSelectedChatModel(models[0].id);
+ }
+ // If a new model was just added, select it
+ else if (newModels.length > 0 && previousModelIds.size > 0) {
+ setSelectedChatModel(newModels[0].id);
+ }
+ } else {
+ // No instances running - clear the selected model
+ if (currentModel) {
+ setSelectedChatModel('');
+ }
}
+
+ // Update previous model IDs for next comparison
+ previousModelIds = currentModelIds;
});
function getInstanceModelId(instanceWrapped: unknown): string {
diff --git a/dashboard/src/routes/+page.svelte b/dashboard/src/routes/+page.svelte
index 1e57bcd9..1ad80171 100644
--- a/dashboard/src/routes/+page.svelte
+++ b/dashboard/src/routes/+page.svelte
@@ -400,10 +400,8 @@ function toggleInstanceDownloadDetails(nodeId: string): void {
const errorText = await response.text();
console.error('Failed to launch instance:', errorText);
} else {
- // Auto-select the launched model only if no model is currently selected
- if (!selectedChatModel()) {
- setSelectedChatModel(modelId);
- }
+ // Always auto-select the newly launched model so the user chats to what they just launched
+ setSelectedChatModel(modelId);
// Scroll to the bottom of instances container to show the new instance
// Use multiple attempts to ensure DOM has updated with the new instance
@@ -763,6 +761,10 @@ function toggleInstanceDownloadDetails(nodeId: string): void {
async function deleteInstance(instanceId: string) {
if (!confirm(`Delete instance ${instanceId.slice(0, 8)}...?`)) return;
+ // Get the model ID of the instance being deleted before we delete it
+ const deletedInstanceModelId = getInstanceModelId(instanceData[instanceId]);
+ const wasSelected = selectedChatModel() === deletedInstanceModelId;
+
try {
const response = await fetch(`/instance/${instanceId}`, {
method: 'DELETE',
@@ -771,6 +773,24 @@ function toggleInstanceDownloadDetails(nodeId: string): void {
if (!response.ok) {
console.error('Failed to delete instance:', response.status);
+ } else if (wasSelected) {
+ // If we deleted the currently selected model, switch to another available model
+ // Find another instance that isn't the one we just deleted
+ const remainingInstances = Object.entries(instanceData).filter(([id]) => id !== instanceId);
+ if (remainingInstances.length > 0) {
+ // Select the last instance (most recently added, since objects preserve insertion order)
+ const [, lastInstance] = remainingInstances[remainingInstances.length - 1];
+ const newModelId = getInstanceModelId(lastInstance);
+ if (newModelId && newModelId !== 'Unknown' && newModelId !== 'Unknown Model') {
+ setSelectedChatModel(newModelId);
+ } else {
+ // Clear selection if no valid model found
+ setSelectedChatModel('');
+ }
+ } else {
+ // No more instances, clear the selection
+ setSelectedChatModel('');
+ }
}
} catch (error) {
console.error('Error deleting instance:', error);
← a735dad6 Parse GPT OSS in runner (#1160)
·
back to Exo
·
quiet rust logs c8de3b90 →