Skip to content

Commit e9f9483

Browse files
authored
Use OpenAI-compatible /v1/models endpoint by default (#17689)
* refactor: Data fetching via stores * chore: update webui build output * refactor: Use OpenAI compat `/v1/models` endpoint by default to list models * chore: update webui build output * chore: update webui build output
1 parent 41c5e02 commit e9f9483

File tree

11 files changed

+45
-90
lines changed

11 files changed

+45
-90
lines changed

tools/server/public/index.html.gz

-194 Bytes
Binary file not shown.

tools/server/webui/docs/flows/data-flow-simplified-router-mode.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ sequenceDiagram
1515
Stores->>DB: load conversations
1616
Stores->>API: GET /props
1717
API-->>Stores: {role: "router"}
18-
Stores->>API: GET /models
18+
Stores->>API: GET /v1/models
1919
API-->>Stores: models[] with status (loaded/available)
2020
loop each loaded model
2121
Stores->>API: GET /props?model=X
@@ -28,7 +28,7 @@ sequenceDiagram
2828
alt model not loaded
2929
Stores->>API: POST /models/load
3030
loop poll status
31-
Stores->>API: GET /models
31+
Stores->>API: GET /v1/models
3232
API-->>Stores: check if loaded
3333
end
3434
Stores->>API: GET /props?model=X

tools/server/webui/docs/flows/models-flow.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ sequenceDiagram
5656
UI->>modelsStore: fetchRouterModels()
5757
activate modelsStore
5858
modelsStore->>ModelsSvc: listRouter()
59-
ModelsSvc->>API: GET /models
59+
ModelsSvc->>API: GET /v1/models
6060
API-->>ModelsSvc: ApiRouterModelsListResponse
6161
Note right of API: {data: [{id, status, path, in_cache}]}
6262
modelsStore->>modelsStore: routerModels = $state(data)
@@ -132,7 +132,7 @@ sequenceDiagram
132132
loop poll every 500ms (max 60 attempts)
133133
modelsStore->>modelsStore: fetchRouterModels()
134134
modelsStore->>ModelsSvc: listRouter()
135-
ModelsSvc->>API: GET /models
135+
ModelsSvc->>API: GET /v1/models
136136
API-->>ModelsSvc: models[]
137137
modelsStore->>modelsStore: getModelStatus(modelId)
138138
alt status === LOADED
@@ -165,7 +165,7 @@ sequenceDiagram
165165
modelsStore->>modelsStore: pollForModelStatus(modelId, UNLOADED)
166166
loop poll until unloaded
167167
modelsStore->>ModelsSvc: listRouter()
168-
ModelsSvc->>API: GET /models
168+
ModelsSvc->>API: GET /v1/models
169169
end
170170
171171
modelsStore->>modelsStore: modelLoadingStates.set(modelId, false)

tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script lang="ts">
22
import { ChatMessage } from '$lib/components/app';
3-
import { DatabaseService } from '$lib/services/database';
43
import { chatStore } from '$lib/stores/chat.svelte';
54
import { conversationsStore, activeConversation } from '$lib/stores/conversations.svelte';
65
import { getMessageSiblings } from '$lib/utils';
@@ -19,7 +18,7 @@
1918
const conversation = activeConversation();
2019
2120
if (conversation) {
22-
DatabaseService.getConversationMessages(conversation.id).then((messages) => {
21+
conversationsStore.getConversationMessages(conversation.id).then((messages) => {
2322
allConversationMessages = messages;
2423
});
2524
} else {

tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsFields.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import { Textarea } from '$lib/components/ui/textarea';
88
import { SETTING_CONFIG_DEFAULT, SETTING_CONFIG_INFO } from '$lib/constants/settings-config';
99
import { settingsStore } from '$lib/stores/settings.svelte';
10-
import { ParameterSyncService } from '$lib/services/parameter-sync';
1110
import { ChatSettingsParameterSourceIndicator } from '$lib/components/app';
1211
import type { Component } from 'svelte';
1312
@@ -22,7 +21,7 @@
2221
2322
// Helper function to get parameter source info for syncable parameters
2423
function getParameterSourceInfo(key: string) {
25-
if (!ParameterSyncService.canSyncParameter(key)) {
24+
if (!settingsStore.canSyncParameter(key)) {
2625
return null;
2726
}
2827

tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsImportExportTab.svelte

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
import { Download, Upload } from '@lucide/svelte';
33
import { Button } from '$lib/components/ui/button';
44
import { DialogConversationSelection } from '$lib/components/app';
5-
import { DatabaseService } from '$lib/services/database';
65
import { createMessageCountMap } from '$lib/utils';
7-
import { conversationsStore } from '$lib/stores/conversations.svelte';
6+
import { conversationsStore, conversations } from '$lib/stores/conversations.svelte';
87
98
let exportedConversations = $state<DatabaseConversation[]>([]);
109
let importedConversations = $state<DatabaseConversation[]>([]);
@@ -21,15 +20,15 @@
2120
2221
async function handleExportClick() {
2322
try {
24-
const allConversations = await DatabaseService.getAllConversations();
23+
const allConversations = conversations();
2524
if (allConversations.length === 0) {
2625
alert('No conversations to export');
2726
return;
2827
}
2928
3029
const conversationsWithMessages = await Promise.all(
31-
allConversations.map(async (conv) => {
32-
const messages = await DatabaseService.getConversationMessages(conv.id);
30+
allConversations.map(async (conv: DatabaseConversation) => {
31+
const messages = await conversationsStore.getConversationMessages(conv.id);
3332
return { conv, messages };
3433
})
3534
);
@@ -47,7 +46,7 @@
4746
try {
4847
const allData: ExportedConversations = await Promise.all(
4948
selectedConversations.map(async (conv) => {
50-
const messages = await DatabaseService.getConversationMessages(conv.id);
49+
const messages = await conversationsStore.getConversationMessages(conv.id);
5150
return { conv: $state.snapshot(conv), messages: $state.snapshot(messages) };
5251
})
5352
);
@@ -135,9 +134,7 @@
135134
.snapshot(fullImportData)
136135
.filter((item) => selectedIds.has(item.conv.id));
137136
138-
await DatabaseService.importConversations(selectedData);
139-
140-
await conversationsStore.loadConversations();
137+
await conversationsStore.importConversationsData(selectedData);
141138
142139
importedConversations = selectedConversations;
143140
showImportSummary = true;

tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import * as Table from '$lib/components/ui/table';
44
import { BadgeModality, CopyToClipboardIcon } from '$lib/components/app';
55
import { serverStore } from '$lib/stores/server.svelte';
6-
import { modelsStore } from '$lib/stores/models.svelte';
7-
import { ChatService } from '$lib/services/chat';
6+
import { modelsStore, modelOptions, modelsLoading } from '$lib/stores/models.svelte';
87
import { formatFileSize, formatParameters, formatNumber } from '$lib/utils';
98
109
interface Props {
@@ -16,38 +15,24 @@
1615
1716
let serverProps = $derived(serverStore.props);
1817
let modelName = $derived(modelsStore.singleModelName);
18+
let models = $derived(modelOptions());
19+
let isLoadingModels = $derived(modelsLoading());
20+
21+
// Get the first model for single-model mode display
22+
let firstModel = $derived(models[0] ?? null);
1923
2024
// Get modalities from modelStore using the model ID from the first model
21-
// For now it supports only for single-model mode, will be extended with further improvements for multi-model functioanlities
2225
let modalities = $derived.by(() => {
23-
if (!modelsData?.data?.[0]?.id) return [];
24-
25-
return modelsStore.getModelModalitiesArray(modelsData.data[0].id);
26+
if (!firstModel?.id) return [];
27+
return modelsStore.getModelModalitiesArray(firstModel.id);
2628
});
2729
28-
let modelsData = $state<ApiModelListResponse | null>(null);
29-
let isLoadingModels = $state(false);
30-
31-
// Fetch models data when dialog opens
30+
// Ensure models are fetched when dialog opens
3231
$effect(() => {
33-
if (open && !modelsData) {
34-
loadModelsData();
32+
if (open && models.length === 0) {
33+
modelsStore.fetch();
3534
}
3635
});
37-
38-
async function loadModelsData() {
39-
isLoadingModels = true;
40-
41-
try {
42-
modelsData = await ChatService.getModels();
43-
} catch (error) {
44-
console.error('Failed to load models data:', error);
45-
// Set empty data to prevent infinite loading
46-
modelsData = { object: 'list', data: [] };
47-
} finally {
48-
isLoadingModels = false;
49-
}
50-
}
5136
</script>
5237

5338
<Dialog.Root bind:open {onOpenChange}>
@@ -70,8 +55,8 @@
7055
<div class="flex items-center justify-center py-8">
7156
<div class="text-sm text-muted-foreground">Loading model information...</div>
7257
</div>
73-
{:else if modelsData && modelsData.data.length > 0}
74-
{@const modelMeta = modelsData.data[0].meta}
58+
{:else if firstModel}
59+
{@const modelMeta = firstModel.meta}
7560

7661
{#if serverProps}
7762
<Table.Root>

tools/server/webui/src/lib/services/chat.ts

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -677,48 +677,6 @@ export class ChatService {
677677
// Utilities
678678
// ─────────────────────────────────────────────────────────────────────────────
679679

680-
/**
681-
* Get server properties - static method for API compatibility (to be refactored)
682-
*/
683-
static async getServerProps(): Promise<ApiLlamaCppServerProps> {
684-
try {
685-
const response = await fetch(`./props`, {
686-
headers: getJsonHeaders()
687-
});
688-
689-
if (!response.ok) {
690-
throw new Error(`Failed to fetch server props: ${response.status}`);
691-
}
692-
693-
const data = await response.json();
694-
return data;
695-
} catch (error) {
696-
console.error('Error fetching server props:', error);
697-
throw error;
698-
}
699-
}
700-
701-
/**
702-
* Get model information from /models endpoint (to be refactored)
703-
*/
704-
static async getModels(): Promise<ApiModelListResponse> {
705-
try {
706-
const response = await fetch(`./models`, {
707-
headers: getJsonHeaders()
708-
});
709-
710-
if (!response.ok) {
711-
throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`);
712-
}
713-
714-
const data = await response.json();
715-
return data;
716-
} catch (error) {
717-
console.error('Error fetching models:', error);
718-
throw error;
719-
}
720-
}
721-
722680
/**
723681
* Injects a system message at the beginning of the conversation if provided.
724682
* Checks for existing system messages to avoid duplication.

tools/server/webui/src/lib/services/models.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getJsonHeaders } from '$lib/utils';
77
*
88
* This service handles communication with model-related endpoints:
99
* - `/v1/models` - OpenAI-compatible model list (MODEL + ROUTER mode)
10-
* - `/models` - Router-specific model management (ROUTER mode only)
10+
* - `/models/load`, `/models/unload` - Router-specific model management (ROUTER mode only)
1111
*
1212
* **Responsibilities:**
1313
* - List available models
@@ -43,7 +43,7 @@ export class ModelsService {
4343
* Returns models with load status, paths, and other metadata
4444
*/
4545
static async listRouter(): Promise<ApiRouterModelsListResponse> {
46-
const response = await fetch(`${base}/models`, {
46+
const response = await fetch(`${base}/v1/models`, {
4747
headers: getJsonHeaders()
4848
});
4949

tools/server/webui/src/lib/stores/conversations.svelte.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,19 @@ class ConversationsStore {
519519
return await DatabaseService.getConversationMessages(convId);
520520
}
521521

522+
/**
523+
* Imports conversations from provided data (without file picker)
524+
* @param data - Array of conversation data with messages
525+
* @returns Import result with counts
526+
*/
527+
async importConversationsData(
528+
data: ExportedConversations
529+
): Promise<{ imported: number; skipped: number }> {
530+
const result = await DatabaseService.importConversations(data);
531+
await this.loadConversations();
532+
return result;
533+
}
534+
522535
/**
523536
* Adds a message to the active messages array
524537
* Used by chatStore when creating new messages

0 commit comments

Comments
 (0)