refactor: Update Agentic and MCP config parsing to use new utils and constants

This commit is contained in:
Aleksander Grygier 2025-12-29 10:35:46 +01:00
parent 0c24db3178
commit 2325d2a50d
3 changed files with 35 additions and 115 deletions

View File

@ -4,14 +4,12 @@
import { Input } from '$lib/components/ui/input'; import { Input } from '$lib/components/ui/input';
import Label from '$lib/components/ui/label/label.svelte'; import Label from '$lib/components/ui/label/label.svelte';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { import { parseMcpServerSettings } from '$lib/config/mcp';
detectMcpTransportFromUrl, import { detectMcpTransportFromUrl } from '$lib/utils/mcp';
parseMcpServerSettings, import type { MCPServerSettingsEntry } from '$lib/types/mcp';
getDefaultMcpConfig,
type MCPServerSettingsEntry
} from '$lib/config/mcp';
import { MCPClient } from '$lib/mcp'; import { MCPClient } from '$lib/mcp';
import type { SettingsConfigType } from '$lib/types/settings'; import type { SettingsConfigType } from '$lib/types/settings';
import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp';
interface Props { interface Props {
localConfig: SettingsConfigType; localConfig: SettingsConfigType;
@ -20,8 +18,6 @@
let { localConfig, onConfigChange }: Props = $props(); let { localConfig, onConfigChange }: Props = $props();
const defaultMcpConfig = getDefaultMcpConfig();
type HealthCheckState = type HealthCheckState =
| { status: 'idle' } | { status: 'idle' }
| { status: 'loading' } | { status: 'loading' }
@ -44,7 +40,7 @@
id: crypto.randomUUID ? crypto.randomUUID() : `server-${Date.now()}`, id: crypto.randomUUID ? crypto.randomUUID() : `server-${Date.now()}`,
enabled: true, enabled: true,
url: '', url: '',
requestTimeoutSeconds: defaultMcpConfig.requestTimeoutSeconds requestTimeoutSeconds: DEFAULT_MCP_CONFIG.requestTimeoutSeconds
}; };
serializeServers([...servers, newServer]); serializeServers([...servers, newServer]);
@ -103,15 +99,15 @@
const timeoutMs = Math.round(server.requestTimeoutSeconds * 1000); const timeoutMs = Math.round(server.requestTimeoutSeconds * 1000);
const mcpClient = new MCPClient({ const mcpClient = new MCPClient({
protocolVersion: defaultMcpConfig.protocolVersion, protocolVersion: DEFAULT_MCP_CONFIG.protocolVersion,
capabilities: defaultMcpConfig.capabilities, capabilities: DEFAULT_MCP_CONFIG.capabilities,
clientInfo: defaultMcpConfig.clientInfo, clientInfo: DEFAULT_MCP_CONFIG.clientInfo,
requestTimeoutMs: timeoutMs, requestTimeoutMs: timeoutMs,
servers: { servers: {
[server.id]: { [server.id]: {
url: trimmedUrl, url: trimmedUrl,
transport: detectMcpTransportFromUrl(trimmedUrl), transport: detectMcpTransportFromUrl(trimmedUrl),
handshakeTimeoutMs: defaultMcpConfig.connectionTimeoutMs, handshakeTimeoutMs: DEFAULT_MCP_CONFIG.connectionTimeoutMs,
requestTimeoutMs: timeoutMs requestTimeoutMs: timeoutMs
} }
} }
@ -228,7 +224,7 @@
requestTimeoutSeconds: requestTimeoutSeconds:
Number.isFinite(parsed) && parsed > 0 Number.isFinite(parsed) && parsed > 0
? parsed ? parsed
: defaultMcpConfig.requestTimeoutSeconds : DEFAULT_MCP_CONFIG.requestTimeoutSeconds
}); });
}} }}
/> />

View File

@ -1,49 +1,29 @@
import { hasEnabledMcpServers } from './mcp'; import { hasEnabledMcpServers } from './mcp';
import type { SettingsConfigType } from '$lib/types/settings'; import type { SettingsConfigType } from '$lib/types/settings';
import type { AgenticConfig } from '$lib/types/agentic';
/** import { DEFAULT_AGENTIC_CONFIG } from '$lib/constants/agentic';
* Agentic orchestration configuration. import { normalizePositiveNumber } from '$lib/utils/number';
*/
export interface AgenticConfig {
enabled: boolean;
maxTurns: number;
maxToolPreviewLines: number;
filterReasoningAfterFirstTurn: boolean;
}
const defaultAgenticConfig: AgenticConfig = {
enabled: true,
maxTurns: 100,
maxToolPreviewLines: 25,
filterReasoningAfterFirstTurn: true
};
function normalizeNumber(value: unknown, fallback: number): number {
const parsed = typeof value === 'string' ? Number.parseFloat(value) : Number(value);
if (!Number.isFinite(parsed) || parsed <= 0) {
return fallback;
}
return parsed;
}
/** /**
* Gets the current agentic configuration. * Gets the current agentic configuration.
* Automatically disables agentic mode if no MCP servers are configured. * Automatically disables agentic mode if no MCP servers are configured.
*/ */
export function getAgenticConfig(settings: SettingsConfigType): AgenticConfig { export function getAgenticConfig(settings: SettingsConfigType): AgenticConfig {
const maxTurns = normalizeNumber(settings.agenticMaxTurns, defaultAgenticConfig.maxTurns); const maxTurns = normalizePositiveNumber(
const maxToolPreviewLines = normalizeNumber( settings.agenticMaxTurns,
DEFAULT_AGENTIC_CONFIG.maxTurns
);
const maxToolPreviewLines = normalizePositiveNumber(
settings.agenticMaxToolPreviewLines, settings.agenticMaxToolPreviewLines,
defaultAgenticConfig.maxToolPreviewLines DEFAULT_AGENTIC_CONFIG.maxToolPreviewLines
); );
const filterReasoningAfterFirstTurn = const filterReasoningAfterFirstTurn =
typeof settings.agenticFilterReasoningAfterFirstTurn === 'boolean' typeof settings.agenticFilterReasoningAfterFirstTurn === 'boolean'
? settings.agenticFilterReasoningAfterFirstTurn ? settings.agenticFilterReasoningAfterFirstTurn
: defaultAgenticConfig.filterReasoningAfterFirstTurn; : DEFAULT_AGENTIC_CONFIG.filterReasoningAfterFirstTurn;
return { return {
enabled: hasEnabledMcpServers(settings) && defaultAgenticConfig.enabled, enabled: hasEnabledMcpServers(settings) && DEFAULT_AGENTIC_CONFIG.enabled,
maxTurns, maxTurns,
maxToolPreviewLines, maxToolPreviewLines,
filterReasoningAfterFirstTurn filterReasoningAfterFirstTurn

View File

@ -1,68 +1,12 @@
import type { import type { MCPClientConfig, MCPServerConfig, MCPServerSettingsEntry } from '$lib/types/mcp';
MCPClientCapabilities,
MCPClientConfig,
MCPClientInfo,
MCPServerConfig
} from '../mcp/types';
import type { SettingsConfigType } from '$lib/types/settings'; import type { SettingsConfigType } from '$lib/types/settings';
import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp';
/** import { detectMcpTransportFromUrl, generateMcpServerId } from '$lib/utils/mcp';
* Raw MCP server configuration entry stored in settings. import { normalizePositiveNumber } from '$lib/utils/number';
*/
export type MCPServerSettingsEntry = {
id: string;
enabled: boolean;
url: string;
requestTimeoutSeconds: number;
};
const defaultMcpConfig = {
protocolVersion: '2025-06-18',
capabilities: { tools: { listChanged: true } } as MCPClientCapabilities,
clientInfo: { name: 'llama-webui-mcp', version: 'dev' } as MCPClientInfo,
requestTimeoutSeconds: 300, // 5 minutes for long-running tools
connectionTimeoutMs: 10_000 // 10 seconds for connection establishment
};
export function getDefaultMcpConfig() {
return defaultMcpConfig;
}
export function detectMcpTransportFromUrl(url: string): 'websocket' | 'streamable_http' {
const normalized = url.trim().toLowerCase();
return normalized.startsWith('ws://') || normalized.startsWith('wss://')
? 'websocket'
: 'streamable_http';
}
function normalizeRequestTimeoutSeconds(value: unknown, fallback: number): number {
const parsed = typeof value === 'string' ? Number.parseFloat(value) : Number(value);
if (!Number.isFinite(parsed) || parsed <= 0) {
return fallback;
}
return parsed;
}
function sanitizeId(id: unknown, index: number): string {
if (typeof id === 'string' && id.trim()) {
return id.trim();
}
return `server-${index + 1}`;
}
function sanitizeUrl(url: unknown): string {
if (typeof url === 'string') {
return url.trim();
}
return '';
}
export function parseMcpServerSettings( export function parseMcpServerSettings(
rawServers: unknown, rawServers: unknown,
fallbackRequestTimeoutSeconds = defaultMcpConfig.requestTimeoutSeconds fallbackRequestTimeoutSeconds = DEFAULT_MCP_CONFIG.requestTimeoutSeconds
): MCPServerSettingsEntry[] { ): MCPServerSettingsEntry[] {
if (!rawServers) return []; if (!rawServers) return [];
@ -84,15 +28,15 @@ export function parseMcpServerSettings(
if (!Array.isArray(parsed)) return []; if (!Array.isArray(parsed)) return [];
return parsed.map((entry, index) => { return parsed.map((entry, index) => {
const requestTimeoutSeconds = normalizeRequestTimeoutSeconds( const requestTimeoutSeconds = normalizePositiveNumber(
(entry as { requestTimeoutSeconds?: unknown })?.requestTimeoutSeconds, (entry as { requestTimeoutSeconds?: unknown })?.requestTimeoutSeconds,
fallbackRequestTimeoutSeconds fallbackRequestTimeoutSeconds
); );
const url = sanitizeUrl((entry as { url?: unknown })?.url); const url = typeof entry?.url === 'string' ? entry.url.trim() : '';
return { return {
id: sanitizeId((entry as { id?: unknown })?.id, index), id: generateMcpServerId((entry as { id?: unknown })?.id, index),
enabled: Boolean((entry as { enabled?: unknown })?.enabled), enabled: Boolean((entry as { enabled?: unknown })?.enabled),
url, url,
requestTimeoutSeconds requestTimeoutSeconds
@ -102,7 +46,7 @@ export function parseMcpServerSettings(
function buildServerConfig( function buildServerConfig(
entry: MCPServerSettingsEntry, entry: MCPServerSettingsEntry,
connectionTimeoutMs = defaultMcpConfig.connectionTimeoutMs connectionTimeoutMs = DEFAULT_MCP_CONFIG.connectionTimeoutMs
): MCPServerConfig | undefined { ): MCPServerConfig | undefined {
if (!entry?.url) { if (!entry?.url) {
return undefined; return undefined;
@ -133,7 +77,7 @@ export function buildMcpClientConfig(config: SettingsConfigType): MCPClientConfi
const normalized = buildServerConfig(entry); const normalized = buildServerConfig(entry);
if (normalized) { if (normalized) {
servers[sanitizeId(entry.id, index)] = normalized; servers[generateMcpServerId(entry.id, index)] = normalized;
} }
} }
@ -142,10 +86,10 @@ export function buildMcpClientConfig(config: SettingsConfigType): MCPClientConfi
} }
return { return {
protocolVersion: defaultMcpConfig.protocolVersion, protocolVersion: DEFAULT_MCP_CONFIG.protocolVersion,
capabilities: defaultMcpConfig.capabilities, capabilities: DEFAULT_MCP_CONFIG.capabilities,
clientInfo: defaultMcpConfig.clientInfo, clientInfo: DEFAULT_MCP_CONFIG.clientInfo,
requestTimeoutMs: Math.round(defaultMcpConfig.requestTimeoutSeconds * 1000), requestTimeoutMs: Math.round(DEFAULT_MCP_CONFIG.requestTimeoutSeconds * 1000),
servers servers
}; };
} }