ui: Constants refactor (#26908)
* refactor: Constants * refactor: Constants/Enums cleanup * refactor: Constant objects instead of multiple single value constants * refactor: Cleanup constants
This commit is contained in:
@@ -5,10 +5,8 @@ import {
|
||||
API_CHAT,
|
||||
API_SLOTS,
|
||||
API_STREAM,
|
||||
ATTACHMENT_LABEL_MCP_PROMPT,
|
||||
ATTACHMENT_LABEL_MCP_RESOURCE,
|
||||
ATTACHMENT_LABEL_PDF_FILE,
|
||||
CONTROL_ACTION,
|
||||
HEADERS,
|
||||
LEGACY_AGENTIC_REGEX,
|
||||
REASONING_EFFORT_TOKENS,
|
||||
SETTINGS_KEYS,
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
STREAM_VISIBILITY_KICK_MS
|
||||
} from '$lib/constants';
|
||||
import {
|
||||
AttachmentLabel,
|
||||
AttachmentType,
|
||||
ContentPartType,
|
||||
MessageRole,
|
||||
@@ -341,7 +340,7 @@ export class ChatService {
|
||||
// server side replay buffer and powers discoverActiveStream on tab reopen. with an explicit
|
||||
// model the ::model suffix keeps the per model session distinct
|
||||
if (stream && conversationId) {
|
||||
headers['X-Conversation-Id'] = streamIdentity(conversationId, options.model);
|
||||
headers[HEADERS.X_CONVERSATION_ID_HEADER] = streamIdentity(conversationId, options.model);
|
||||
// persist the pending stream before the fetch: a reload during the model load or
|
||||
// the prompt processing must still find its way back to the session once it exists
|
||||
ChatService.saveStreamState(conversationId, 0, options.model ?? null);
|
||||
@@ -1291,7 +1290,7 @@ export class ChatService {
|
||||
|
||||
for (const textFile of textFiles) {
|
||||
contentParts.push({
|
||||
text: formatAttachmentText('File', textFile.name, textFile.content),
|
||||
text: formatAttachmentText(AttachmentLabel.FILE, textFile.name, textFile.content),
|
||||
type: ContentPartType.TEXT
|
||||
});
|
||||
}
|
||||
@@ -1304,7 +1303,11 @@ export class ChatService {
|
||||
|
||||
for (const legacyContextFile of legacyContextFiles) {
|
||||
contentParts.push({
|
||||
text: formatAttachmentText('File', legacyContextFile.name, legacyContextFile.content),
|
||||
text: formatAttachmentText(
|
||||
AttachmentLabel.FILE,
|
||||
legacyContextFile.name,
|
||||
legacyContextFile.content
|
||||
),
|
||||
type: ContentPartType.TEXT
|
||||
});
|
||||
}
|
||||
@@ -1382,7 +1385,7 @@ export class ChatService {
|
||||
}
|
||||
} else {
|
||||
contentParts.push({
|
||||
text: formatAttachmentText(ATTACHMENT_LABEL_PDF_FILE, pdfFile.name, pdfFile.content),
|
||||
text: formatAttachmentText(AttachmentLabel.PDF_FILE, pdfFile.name, pdfFile.content),
|
||||
type: ContentPartType.TEXT
|
||||
});
|
||||
}
|
||||
@@ -1396,7 +1399,7 @@ export class ChatService {
|
||||
for (const mcpPrompt of mcpPrompts) {
|
||||
contentParts.push({
|
||||
text: formatAttachmentText(
|
||||
ATTACHMENT_LABEL_MCP_PROMPT,
|
||||
AttachmentLabel.MCP_PROMPT,
|
||||
mcpPrompt.name,
|
||||
mcpPrompt.content,
|
||||
mcpPrompt.serverName
|
||||
@@ -1413,7 +1416,7 @@ export class ChatService {
|
||||
for (const mcpResource of mcpResources) {
|
||||
contentParts.push({
|
||||
text: formatAttachmentText(
|
||||
ATTACHMENT_LABEL_MCP_RESOURCE,
|
||||
AttachmentLabel.MCP_RESOURCE,
|
||||
mcpResource.name,
|
||||
mcpResource.content,
|
||||
mcpResource.serverName
|
||||
|
||||
@@ -276,7 +276,7 @@ export { MCPService } from './mcp.service';
|
||||
* - **toolsStore**: Exposes the tool definition when the sandbox is enabled
|
||||
* - **agenticStore**: Dispatches ToolSource.FRONTEND calls here
|
||||
*
|
||||
* @see buildSandboxToolDefinition in constants/sandbox.ts - tool schema sent to the LLM
|
||||
* @see buildSandboxToolDefinition in utils/sandbox-tool - tool schema sent to the LLM
|
||||
* @see agenticStore in stores/agentic.svelte.ts - tool dispatch
|
||||
*/
|
||||
export { SandboxService } from './sandbox.service';
|
||||
|
||||
@@ -13,12 +13,12 @@ import type {
|
||||
Tool
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import {
|
||||
CORS_PROXY,
|
||||
CORS_PROXY_ENDPOINT,
|
||||
CORS_PROXY_HEADER_PREFIX,
|
||||
DEFAULT_CLIENT_VERSION,
|
||||
DEFAULT_IMAGE_MIME_TYPE,
|
||||
DEFAULT_MCP_CONFIG,
|
||||
MCP_PARTIAL_REDACT_HEADERS
|
||||
HEADERS
|
||||
} from '$lib/constants';
|
||||
import {
|
||||
MCPConnectionPhase,
|
||||
@@ -120,7 +120,7 @@ export class MCPService {
|
||||
const details: DiagnosticRequestDetails = {
|
||||
body: summarizeRequestBody(body),
|
||||
credentials: init?.credentials ?? baseInit.credentials,
|
||||
headers: sanitizeHeaders(requestHeaders, extraRedactedHeaders, MCP_PARTIAL_REDACT_HEADERS),
|
||||
headers: sanitizeHeaders(requestHeaders, extraRedactedHeaders, HEADERS.PARTIAL_REDACT),
|
||||
method: getRequestMethod(input, init, baseInit).toUpperCase(),
|
||||
mode: init?.mode ?? baseInit.mode,
|
||||
url: getRequestUrl(input)
|
||||
@@ -141,8 +141,8 @@ export class MCPService {
|
||||
) {
|
||||
for (const [key, value] of new Headers(headers).entries()) {
|
||||
const proxiedKey =
|
||||
useProxy && !key.toLowerCase().startsWith(CORS_PROXY_HEADER_PREFIX)
|
||||
? `${CORS_PROXY_HEADER_PREFIX}${key}`
|
||||
useProxy && !key.toLowerCase().startsWith(CORS_PROXY.HEADER_PREFIX)
|
||||
? `${CORS_PROXY.HEADER_PREFIX}${key}`
|
||||
: key;
|
||||
|
||||
requestHeaders.set(proxiedKey, value);
|
||||
@@ -361,7 +361,7 @@ export class MCPService {
|
||||
{
|
||||
response: {
|
||||
durationMs,
|
||||
headers: sanitizeHeaders(response.headers, undefined, MCP_PARTIAL_REDACT_HEADERS),
|
||||
headers: sanitizeHeaders(response.headers, undefined, HEADERS.PARTIAL_REDACT),
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
url
|
||||
@@ -751,7 +751,7 @@ export class MCPService {
|
||||
headers: sanitizeHeaders(
|
||||
serverConfig.headers,
|
||||
Object.keys(serverConfig.headers ?? {}),
|
||||
MCP_PARTIAL_REDACT_HEADERS
|
||||
HEADERS.PARTIAL_REDACT
|
||||
),
|
||||
serverName,
|
||||
transportType,
|
||||
|
||||
@@ -22,12 +22,13 @@ import {
|
||||
DB_APP_NAME_DEPRECATED,
|
||||
IDXDB_STORES,
|
||||
IDXDB_TABLES,
|
||||
LEGACY_AGENTIC_REGEX,
|
||||
LEGACY_REASONING_TAGS,
|
||||
NEW_TO_DEPRECATED_MAP,
|
||||
SETTINGS_KEYS,
|
||||
STORAGE_APP_NAME,
|
||||
STORAGE_APP_NAME_DEPRECATED
|
||||
} from '$lib/constants';
|
||||
import { LEGACY_AGENTIC_REGEX, LEGACY_REASONING_TAGS } from '$lib/constants/agentic';
|
||||
import { SETTINGS_KEYS } from '$lib/constants/settings-keys';
|
||||
import { MessageRole } from '$lib/enums';
|
||||
import Dexie from 'dexie';
|
||||
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
import {
|
||||
API_MODELS,
|
||||
MODEL_ACTIVATED_PARAMS_RE,
|
||||
MODEL_CUSTOM_QUANTIZATION_PREFIX_RE,
|
||||
MODEL_ID_NOT_FOUND,
|
||||
MODEL_ID_ORG_SEPARATOR,
|
||||
MODEL_ID_QUANTIZATION_SEPARATOR,
|
||||
MODEL_ID_SEGMENT_SEPARATOR,
|
||||
MODEL_IGNORED_SEGMENTS,
|
||||
MODEL_PARAMS_RE,
|
||||
MODEL_QUANTIZATION_SEGMENT_RE,
|
||||
MODEL_WEIGHT_EXTENSION_RE
|
||||
} from '$lib/constants';
|
||||
import { API_MODELS, MODEL_ID } from '$lib/constants';
|
||||
import { ServerModelStatus } from '$lib/enums';
|
||||
import type { ParsedModelId } from '$lib/types/models';
|
||||
import { apiFetch, apiPost, normalizeModelName } from '$lib/utils';
|
||||
@@ -142,13 +130,13 @@ export class ModelsService {
|
||||
};
|
||||
// strip directory path and weight extension so a bare `-m /path/file.gguf`
|
||||
// parses like a clean repo id; the HF `org/model` form is preserved
|
||||
const source = normalizeModelName(modelId).replace(MODEL_WEIGHT_EXTENSION_RE, '');
|
||||
const source = normalizeModelName(modelId).replace(MODEL_ID.WEIGHT_EXTENSION_RE, '');
|
||||
// 1. Extract colon-separated quantization (e.g. `model:Q4_K_M`)
|
||||
const colonIdx = source.indexOf(MODEL_ID_QUANTIZATION_SEPARATOR);
|
||||
const colonIdx = source.indexOf(MODEL_ID.QUANTIZATION_SEPARATOR);
|
||||
|
||||
let modelPath: string;
|
||||
|
||||
if (colonIdx !== MODEL_ID_NOT_FOUND) {
|
||||
if (colonIdx !== MODEL_ID.NOT_FOUND) {
|
||||
result.quantization = source.slice(colonIdx + 1) || null;
|
||||
modelPath = source.slice(0, colonIdx);
|
||||
} else {
|
||||
@@ -156,11 +144,11 @@ export class ModelsService {
|
||||
}
|
||||
|
||||
// 2. Extract org name (e.g. `org/model` -> org = "org")
|
||||
const slashIdx = modelPath.indexOf(MODEL_ID_ORG_SEPARATOR);
|
||||
const slashIdx = modelPath.indexOf(MODEL_ID.ORG_SEPARATOR);
|
||||
|
||||
let modelStr: string;
|
||||
|
||||
if (slashIdx !== MODEL_ID_NOT_FOUND) {
|
||||
if (slashIdx !== MODEL_ID.NOT_FOUND) {
|
||||
result.orgName = modelPath.slice(0, slashIdx);
|
||||
modelStr = modelPath.slice(slashIdx + 1);
|
||||
} else {
|
||||
@@ -170,16 +158,16 @@ export class ModelsService {
|
||||
// 3. Handle dot-separated quantization (e.g. `model-name.Q4_K_M`)
|
||||
const dotIdx = modelStr.lastIndexOf('.');
|
||||
|
||||
if (dotIdx !== MODEL_ID_NOT_FOUND && !result.quantization) {
|
||||
if (dotIdx !== MODEL_ID.NOT_FOUND && !result.quantization) {
|
||||
const afterDot = modelStr.slice(dotIdx + 1);
|
||||
|
||||
if (MODEL_QUANTIZATION_SEGMENT_RE.test(afterDot)) {
|
||||
if (MODEL_ID.QUANTIZATION_SEGMENT_RE.test(afterDot)) {
|
||||
result.quantization = afterDot;
|
||||
modelStr = modelStr.slice(0, dotIdx);
|
||||
}
|
||||
}
|
||||
|
||||
const segments = modelStr.split(MODEL_ID_SEGMENT_SEPARATOR);
|
||||
const segments = modelStr.split(MODEL_ID.SEGMENT_SEPARATOR);
|
||||
|
||||
// 4. Detect trailing quantization from dash-separated segments
|
||||
// Handle UD-prefixed quantization (e.g. `UD-Q8_K_XL`) and
|
||||
@@ -188,8 +176,8 @@ export class ModelsService {
|
||||
const last = segments[segments.length - 1];
|
||||
const secondLast = segments.length > 2 ? segments[segments.length - 2] : null;
|
||||
|
||||
if (MODEL_QUANTIZATION_SEGMENT_RE.test(last)) {
|
||||
if (secondLast && MODEL_CUSTOM_QUANTIZATION_PREFIX_RE.test(secondLast)) {
|
||||
if (MODEL_ID.QUANTIZATION_SEGMENT_RE.test(last)) {
|
||||
if (secondLast && MODEL_ID.CUSTOM_QUANTIZATION_PREFIX_RE.test(secondLast)) {
|
||||
result.quantization = `${secondLast}-${last}`;
|
||||
segments.splice(segments.length - 2, 2);
|
||||
} else {
|
||||
@@ -200,33 +188,33 @@ export class ModelsService {
|
||||
}
|
||||
|
||||
// 5. Find params and activated params
|
||||
let paramsIdx = MODEL_ID_NOT_FOUND;
|
||||
let activatedParamsIdx = MODEL_ID_NOT_FOUND;
|
||||
let paramsIdx = MODEL_ID.NOT_FOUND;
|
||||
let activatedParamsIdx = MODEL_ID.NOT_FOUND;
|
||||
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const seg = segments[i];
|
||||
|
||||
if (paramsIdx === MODEL_ID_NOT_FOUND && MODEL_PARAMS_RE.test(seg)) {
|
||||
if (paramsIdx === MODEL_ID.NOT_FOUND && MODEL_ID.PARAMS_RE.test(seg)) {
|
||||
paramsIdx = i;
|
||||
result.params = seg.toUpperCase();
|
||||
} else if (paramsIdx !== MODEL_ID_NOT_FOUND && MODEL_ACTIVATED_PARAMS_RE.test(seg)) {
|
||||
} else if (paramsIdx !== MODEL_ID.NOT_FOUND && MODEL_ID.ACTIVATED_PARAMS_RE.test(seg)) {
|
||||
activatedParamsIdx = i;
|
||||
result.activatedParams = seg.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Model name = segments before params; tags = remaining segments after params
|
||||
const pivotIdx = paramsIdx !== MODEL_ID_NOT_FOUND ? paramsIdx : segments.length;
|
||||
const pivotIdx = paramsIdx !== MODEL_ID.NOT_FOUND ? paramsIdx : segments.length;
|
||||
|
||||
result.modelName = segments.slice(0, pivotIdx).join(MODEL_ID_SEGMENT_SEPARATOR) || null;
|
||||
result.modelName = segments.slice(0, pivotIdx).join(MODEL_ID.SEGMENT_SEPARATOR) || null;
|
||||
|
||||
if (paramsIdx !== MODEL_ID_NOT_FOUND) {
|
||||
if (paramsIdx !== MODEL_ID.NOT_FOUND) {
|
||||
result.tags = segments.slice(paramsIdx + 1).filter((_, relIdx) => {
|
||||
const absIdx = paramsIdx + 1 + relIdx;
|
||||
|
||||
if (absIdx === activatedParamsIdx) return false;
|
||||
|
||||
return !MODEL_IGNORED_SEGMENTS.has(segments[absIdx].toUpperCase());
|
||||
return !MODEL_ID.IGNORED_SEGMENTS.has(segments[absIdx].toUpperCase());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ROUTES } from '$lib/constants/routes';
|
||||
import { ROUTES } from '$lib/constants';
|
||||
|
||||
export class RouterService {
|
||||
static chat(id: string): string {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { base } from '$app/paths';
|
||||
import { API_TOOLS, X_RESP_TYPE_HEADER, X_TOOL_CWD_HEADER } from '$lib/constants';
|
||||
import { API_TOOLS, HEADERS } from '$lib/constants';
|
||||
import { ToolResponseField } from '$lib/enums';
|
||||
import type { ServerBuiltinToolInfo, ToolExecutionResult } from '$lib/types';
|
||||
import { apiFetch } from '$lib/utils';
|
||||
@@ -31,7 +31,7 @@ export class ToolsService {
|
||||
): Promise<ToolExecutionResult> {
|
||||
const result = await apiFetch<Record<string, unknown>>(API_TOOLS.EXECUTE, {
|
||||
body: JSON.stringify({ params, tool: toolName }),
|
||||
headers: cwd ? { [X_TOOL_CWD_HEADER]: cwd } : undefined,
|
||||
headers: cwd ? { [HEADERS.X_TOOL_CWD_HEADER]: cwd } : undefined,
|
||||
method: 'POST',
|
||||
signal
|
||||
});
|
||||
@@ -64,9 +64,9 @@ export class ToolsService {
|
||||
): Promise<Record<string, unknown>> {
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (cwd) headers[X_TOOL_CWD_HEADER] = cwd;
|
||||
if (cwd) headers[HEADERS.X_TOOL_CWD_HEADER] = cwd;
|
||||
|
||||
if (respType) headers[X_RESP_TYPE_HEADER] = respType;
|
||||
if (respType) headers[HEADERS.X_RESP_TYPE_HEADER] = respType;
|
||||
|
||||
return apiFetch<Record<string, unknown>>(API_TOOLS.EXECUTE, {
|
||||
body: JSON.stringify({ params, tool: toolName }),
|
||||
@@ -99,7 +99,7 @@ export class ToolsService {
|
||||
): AsyncGenerator<ToolStreamEvent> {
|
||||
const headers = getJsonHeaders();
|
||||
|
||||
if (cwd) headers[X_TOOL_CWD_HEADER] = cwd;
|
||||
if (cwd) headers[HEADERS.X_TOOL_CWD_HEADER] = cwd;
|
||||
|
||||
const response = await fetch(`${base}${API_TOOLS.EXECUTE}`, {
|
||||
body: JSON.stringify({ params, stream: true, tool: toolName }),
|
||||
|
||||
Reference in New Issue
Block a user