ui: Linting & Formatting scripts (#26819)

This commit is contained in:
Aleksander Grygier
2026-08-10 08:38:37 +02:00
committed by GitHub
parent 1e396e72a8
commit 92d1bb0c99
538 changed files with 8806 additions and 6036 deletions
+44 -22
View File
@@ -1,15 +1,8 @@
import {
AgenticSectionType,
AttachmentType,
ContinueIntentKind,
MessageRole,
ToolResultKind
} from '$lib/enums';
import {
ATTACHMENT_SAVED_REGEX,
MARKDOWN_ATX_HEADING_REGEX,
MARKDOWN_BOLD_REGEX,
MARKDOWN_BLOCKQUOTE_REGEX,
MARKDOWN_BOLD_REGEX,
MARKDOWN_CODE_FENCE_REGEX,
MARKDOWN_LINK_REGEX,
MARKDOWN_LIST_BULLET_REGEX,
@@ -21,6 +14,13 @@ import {
SEARCH_SUMMARY_TOTAL_REGEX,
TOOL_RESULT_JSON_OPEN_REGEX
} from '$lib/constants';
import {
AgenticSectionType,
AttachmentType,
ContinueIntentKind,
MessageRole,
ToolResultKind
} from '$lib/enums';
import type { ApiChatCompletionToolCall } from '$lib/types/api';
import type {
DatabaseMessage,
@@ -78,9 +78,10 @@ function deriveSingleTurnSections(
const hasContentAfterReasoning =
!!message.content?.trim() || toolCalls.length > 0 || streamingToolCalls.length > 0;
const isPending = isStreaming && !hasContentAfterReasoning;
sections.push({
type: isPending ? AgenticSectionType.REASONING_PENDING : AgenticSectionType.REASONING,
content: message.reasoningContent,
type: isPending ? AgenticSectionType.REASONING_PENDING : AgenticSectionType.REASONING,
wasInterrupted: !isStreaming && !hasContentAfterReasoning
});
}
@@ -88,16 +89,16 @@ function deriveSingleTurnSections(
// 2. Text content
if (message.content?.trim()) {
sections.push({
type: AgenticSectionType.TEXT,
content: message.content
content: message.content,
type: AgenticSectionType.TEXT
});
}
// 3. Persisted tool calls (from message.toolCalls field)
const toolCalls = parseToolCalls(message.toolCalls);
// Index tool messages by toolCallId for O(1) lookup instead of O(n) find()
const toolMsgById = new Map<string, DatabaseMessage>();
for (const tm of toolMessages) {
if (tm.toolCallId && !toolMsgById.has(tm.toolCallId)) {
toolMsgById.set(tm.toolCallId, tm);
@@ -112,29 +113,32 @@ function deriveSingleTurnSections(
: isStreaming
? AgenticSectionType.TOOL_CALL_PENDING
: AgenticSectionType.TOOL_CALL;
sections.push({
type,
content: resultMsg?.content || '',
toolName: tc.function?.name,
toolArgs: tc.function?.arguments,
toolCallId: tc.id,
toolCwd: resultMsg?.toolCwd,
toolName: tc.function?.name,
toolResult: resultMsg?.content,
toolResultExtras: resultMsg?.extra,
toolCwd: resultMsg?.toolCwd,
toolCallId: tc.id
type
});
}
// 4. Streaming tool calls (not yet persisted - currently being received)
const persistedIds = new Set(toolCalls.map((t) => t.id).filter(Boolean));
for (const tc of streamingToolCalls) {
// Skip if already in persisted tool calls
if (tc.id && persistedIds.has(tc.id)) continue;
sections.push({
type: AgenticSectionType.TOOL_CALL_STREAMING,
content: '',
toolName: tc.function?.name,
toolArgs: tc.function?.arguments,
toolCallId: tc.id
toolCallId: tc.id,
toolName: tc.function?.name,
type: AgenticSectionType.TOOL_CALL_STREAMING
});
}
@@ -168,8 +172,8 @@ export function deriveAgenticSections(
}
const sections: AgenticSection[] = [];
const firstTurnToolMsgs = collectToolMessages(toolMessages, 0);
sections.push(...deriveSingleTurnSections(message, firstTurnToolMsgs));
let i = firstTurnToolMsgs.length;
@@ -212,10 +216,12 @@ export function buildAssistantRawOutput(sections: AgenticSection[]): string {
case AgenticSectionType.REASONING:
case AgenticSectionType.REASONING_PENDING:
parts.push(`${REASONING_TAGS.START}${NEWLINE}${section.content}${REASONING_TAGS.END}`);
break;
case AgenticSectionType.TEXT:
parts.push(section.content);
break;
case AgenticSectionType.TOOL_CALL:
@@ -281,8 +287,8 @@ export function splitSearchSummaryList(
const matchesText = separatorIndex === -1 ? text : text.slice(0, separatorIndex);
const summaryText =
separatorIndex === -1 ? '' : text.slice(separatorIndex + SEARCH_SUMMARY_SEPARATOR.length);
const totalMatch = summaryText.match(SEARCH_SUMMARY_TOTAL_REGEX);
if (totalMatch) {
captureTotal(parseInt(totalMatch[1], 10));
}
@@ -316,11 +322,13 @@ export function parseToolResultWithImages(
.join(NEWLINE);
const cacheKey = `${imageNames}:${toolResult}`;
const cached = toolResultLinesCache.get(cacheKey);
if (cached !== undefined) return cached;
const lines = toolResult.split(NEWLINE);
const result = lines.map((line) => {
const match = line.match(ATTACHMENT_SAVED_REGEX);
if (!match || !extras) return { text: line };
const attachmentName = match[1];
@@ -329,12 +337,13 @@ export function parseToolResultWithImages(
e.type === AttachmentType.IMAGE && e.name === attachmentName
);
return { text: line, image };
return { image, text: line };
});
if (toolResultLinesCache.size >= TOOL_RESULT_LINES_CACHE_MAX_SIZE) {
toolResultLinesCache.delete(toolResultLinesCache.keys().next().value!);
}
toolResultLinesCache.set(cacheKey, result);
return result;
@@ -359,9 +368,11 @@ export function classifyToolResult(content: string | undefined): ToolResultKind
if (!content) return ToolResultKind.TEXT;
const cached = classifyCache.get(content);
if (cached !== undefined) return cached;
const trimmed = content.trim();
if (!trimmed) return ToolResultKind.TEXT;
let result: ToolResultKind = ToolResultKind.TEXT;
@@ -383,6 +394,7 @@ export function classifyToolResult(content: string | undefined): ToolResultKind
if (classifyCache.size >= CLASSIFY_CACHE_MAX_SIZE) {
classifyCache.delete(classifyCache.keys().next().value!);
}
classifyCache.set(content, result);
return result;
@@ -405,13 +417,17 @@ function looksLikeMarkdown(content: string): boolean {
for (const line of lines) {
if (MARKDOWN_ATX_HEADING_REGEX.test(line)) return true;
if (MARKDOWN_BLOCKQUOTE_REGEX.test(line)) return true;
if (MARKDOWN_LIST_BULLET_REGEX.test(line)) return true;
if (MARKDOWN_LIST_NUMBERED_REGEX.test(line)) return true;
}
// Inline structural markers anywhere in the body.
if (MARKDOWN_LINK_REGEX.test(content)) return true;
if (MARKDOWN_BOLD_REGEX.test(content)) return true;
// Tables: a pipe-bearing header line followed by a separator row.
@@ -438,11 +454,14 @@ function parseToolCalls(toolCallsJson?: string): ApiChatCompletionToolCall[] {
if (!toolCallsJson) return [];
const cached = toolCallsParseCache.get(toolCallsJson);
if (cached) return cached;
let result: ApiChatCompletionToolCall[];
try {
const parsed = JSON.parse(toolCallsJson);
result = Array.isArray(parsed) ? parsed : [];
} catch {
result = [];
@@ -451,6 +470,7 @@ function parseToolCalls(toolCallsJson?: string): ApiChatCompletionToolCall[] {
if (toolCallsParseCache.size >= TOOL_CALLS_CACHE_MAX_SIZE) {
toolCallsParseCache.delete(toolCallsParseCache.keys().next().value!);
}
toolCallsParseCache.set(toolCallsJson, result);
return result;
@@ -508,6 +528,7 @@ export function classifyContinueIntent(messages: DatabaseMessage[], idx: number)
}
const hasToolCalls = parseToolCalls(target.toolCalls).length > 0;
if (!hasToolCalls) {
return { kind: ContinueIntentKind.APPEND_TEXT };
}
@@ -516,6 +537,7 @@ export function classifyContinueIntent(messages: DatabaseMessage[], idx: number)
// messages directly after the assistant turn that owns them, so the first
// non tool message marks the boundary.
let lastTrailingTool = idx;
for (let i = idx + 1; i < messages.length; i++) {
if (messages[i].role === MessageRole.TOOL) {
lastTrailingTool = i;