mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-17 20:31:47 +02:00
ui : gate llama.cpp-only features by backend capabilities
Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { BackendPreset, BackendProtocol } from '$lib/types';
|
||||
import type { BackendCapabilities, BackendPreset, BackendProtocol } from '$lib/types';
|
||||
|
||||
/** Version sent with the Anthropic Messages API. */
|
||||
export const ANTHROPIC_API_VERSION = '2023-06-01';
|
||||
@@ -18,6 +18,34 @@ export const DEFAULT_BACKEND_MODELS_PATH = '/v1/models';
|
||||
/** Id of the built-in backend that points at the server serving this UI. */
|
||||
export const LOCAL_BACKEND_ID = 'local';
|
||||
|
||||
/** Capabilities of a full llama.cpp server. */
|
||||
const LLAMA_CPP_CAPABILITIES: BackendCapabilities = {
|
||||
corsProxy: true,
|
||||
loadUnload: true,
|
||||
props: true,
|
||||
router: true,
|
||||
slots: true,
|
||||
statusFeed: true,
|
||||
tools: true
|
||||
};
|
||||
/** Capabilities of a plain OpenAI- or Anthropic-compatible endpoint. */
|
||||
const COMPATIBLE_CAPABILITIES: BackendCapabilities = {
|
||||
corsProxy: false,
|
||||
loadUnload: false,
|
||||
props: false,
|
||||
router: false,
|
||||
slots: false,
|
||||
statusFeed: false,
|
||||
tools: false
|
||||
};
|
||||
|
||||
/** Capabilities per backend protocol. */
|
||||
export const BACKEND_CAPABILITIES: Record<BackendProtocol, BackendCapabilities> = {
|
||||
anthropic: COMPATIBLE_CAPABILITIES,
|
||||
'llama.cpp': LLAMA_CPP_CAPABILITIES,
|
||||
openai: COMPATIBLE_CAPABILITIES
|
||||
};
|
||||
|
||||
/**
|
||||
* Ready-made endpoints offered when adding a backend. `custom` intentionally
|
||||
* carries no URL so the user starts from an empty form.
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
StreamConnectionState
|
||||
} from '$lib/enums';
|
||||
import { modelsStore } from '$lib/stores/models/index.svelte';
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings/index.svelte';
|
||||
import type { DatabaseMessageExtraMcpPrompt, DatabaseMessageExtraMcpResource } from '$lib/types';
|
||||
import type {
|
||||
@@ -87,6 +88,9 @@ export class ChatService {
|
||||
* @returns {Promise<boolean>} Promise that resolves to true if all slots are idle, false if any is processing
|
||||
*/
|
||||
static async areAllSlotsIdle(model?: string | null, signal?: AbortSignal): Promise<boolean> {
|
||||
// the /slots endpoint only exists on llama.cpp servers
|
||||
if (!serverStore.capabilities.slots) return true;
|
||||
|
||||
try {
|
||||
const url = model ? `${API_SLOTS.LIST}?model=${encodeURIComponent(model)}` : API_SLOTS.LIST;
|
||||
const res = await fetch(apiUrl(url), { signal });
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
* PropsService for the /props fetch.
|
||||
*/
|
||||
|
||||
import { BACKEND_CAPABILITIES } from '$lib/constants';
|
||||
import { ServerRole } from '$lib/enums';
|
||||
import { PropsService } from '$lib/services/props.service';
|
||||
import type { BackendCapabilities } from '$lib/types';
|
||||
import { ApiError } from '$lib/utils';
|
||||
import { getBackend } from '$lib/utils/api-base';
|
||||
import { getBackendCapabilities } from '$lib/utils/backend';
|
||||
|
||||
const LOADING_RETRY_INTERVAL_MS = 1000;
|
||||
|
||||
@@ -21,6 +25,13 @@ class ServerStore {
|
||||
private fetchPromise: Promise<void> | null = null;
|
||||
private retryTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
/** Features of the active backend. Defaults to full llama.cpp support. */
|
||||
get capabilities(): BackendCapabilities {
|
||||
const backend = getBackend();
|
||||
|
||||
return backend ? getBackendCapabilities(backend) : BACKEND_CAPABILITIES['llama.cpp'];
|
||||
}
|
||||
|
||||
get contextSize(): number | null {
|
||||
const nCtx = this.props?.default_generation_settings?.n_ctx;
|
||||
|
||||
@@ -63,6 +74,15 @@ class ServerStore {
|
||||
|
||||
this.clearRetryTimer();
|
||||
|
||||
// External backends expose no /props endpoint. Keep MODEL-mode defaults so
|
||||
// role detection and generation defaults degrade instead of failing.
|
||||
if (!this.capabilities.props) {
|
||||
this.clear();
|
||||
this.role = ServerRole.MODEL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!background) {
|
||||
this.loading = true;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import { ToolsService } from '$lib/services/tools.service';
|
||||
// direct imports between stores, not via the barrel, to avoid circular deps
|
||||
import { mcpStore } from '$lib/stores/mcp/index.svelte';
|
||||
import { modelsStore } from '$lib/stores/models/index.svelte';
|
||||
import { serverStore } from '$lib/stores/server.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings/index.svelte';
|
||||
import type { OpenAIToolDefinition, ToolEntry, ToolGroup } from '$lib/types';
|
||||
import { ApiError, buildSandboxToolDefinition } from '$lib/utils';
|
||||
@@ -232,6 +233,14 @@ class ToolsStore {
|
||||
}
|
||||
|
||||
async fetchServerTools(): Promise<void> {
|
||||
// the /tools endpoint only exists on llama.cpp servers
|
||||
if (!serverStore.capabilities.tools) {
|
||||
this._serverTools = [];
|
||||
this.cwdAwareTools = new SvelteSet();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._loading) return;
|
||||
|
||||
this._loading = true;
|
||||
|
||||
Vendored
+22
@@ -10,6 +10,28 @@
|
||||
/** Request/response shape a backend speaks. */
|
||||
export type BackendProtocol = 'llama.cpp' | 'openai' | 'anthropic';
|
||||
|
||||
/**
|
||||
* Features a backend supports. A llama.cpp server exposes extra endpoints on
|
||||
* top of the OpenAI-compatible API; plain OpenAI- and Anthropic-compatible
|
||||
* endpoints only provide chat and model listing.
|
||||
*/
|
||||
export interface BackendCapabilities {
|
||||
/** llama-server's /cors-proxy endpoint for cross-origin MCP requests. */
|
||||
corsProxy: boolean;
|
||||
/** Router-mode model load/unload. */
|
||||
loadUnload: boolean;
|
||||
/** The /props endpoint with server role and generation defaults. */
|
||||
props: boolean;
|
||||
/** Multi-model router mode. */
|
||||
router: boolean;
|
||||
/** The /slots introspection endpoint. */
|
||||
slots: boolean;
|
||||
/** The /models/sse load and download progress feed. */
|
||||
statusFeed: boolean;
|
||||
/** The /tools listing and execution endpoint. */
|
||||
tools: boolean;
|
||||
}
|
||||
|
||||
/** One configured API endpoint. */
|
||||
export interface Backend {
|
||||
/** Bearer token / API key used for this backend. */
|
||||
|
||||
@@ -36,7 +36,7 @@ export type {
|
||||
} from './api';
|
||||
|
||||
// Backend types
|
||||
export type { Backend, BackendPreset, BackendProtocol } from './backend';
|
||||
export type { Backend, BackendCapabilities, BackendPreset, BackendProtocol } from './backend';
|
||||
|
||||
// HuggingFace types
|
||||
export type {
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
BACKEND_CAPABILITIES,
|
||||
BACKEND_ID_PREFIX,
|
||||
BACKEND_PROTOCOLS,
|
||||
DEFAULT_BACKEND_CHAT_PATH,
|
||||
DEFAULT_BACKEND_MODELS_PATH,
|
||||
LOCAL_BACKEND_ID
|
||||
} from '$lib/constants';
|
||||
import type { Backend, BackendProtocol } from '$lib/types';
|
||||
import type { Backend, BackendCapabilities, BackendProtocol } from '$lib/types';
|
||||
|
||||
/** Absolute chat completions URL for a backend. */
|
||||
export function backendChatUrl(backend: Backend): string {
|
||||
@@ -25,6 +26,11 @@ export function backendModelsUrl(backend: Backend): string {
|
||||
return joinBackendUrl(backend.baseUrl, backend.modelsPath ?? DEFAULT_BACKEND_MODELS_PATH);
|
||||
}
|
||||
|
||||
/** Features a backend supports, derived from its protocol. */
|
||||
export function getBackendCapabilities(backend: Backend): BackendCapabilities {
|
||||
return BACKEND_CAPABILITIES[backend.protocol] ?? BACKEND_CAPABILITIES.openai;
|
||||
}
|
||||
|
||||
/** The built-in backend pointing at the server that serves this UI. */
|
||||
export function createLocalBackend(apiKey?: string, enabled = true): Backend {
|
||||
return {
|
||||
|
||||
@@ -21,6 +21,7 @@ export {
|
||||
backendChatUrl,
|
||||
backendModelsUrl,
|
||||
createLocalBackend,
|
||||
getBackendCapabilities,
|
||||
parseBackendsSettings
|
||||
} from './backend';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user