refactor: Cleanup

This commit is contained in:
Aleksander Grygier 2026-02-03 14:11:43 +01:00
parent 4383644951
commit bb4253ae20
5 changed files with 35 additions and 18 deletions

View File

@ -32,3 +32,12 @@ export enum MessageType {
THINK = 'think',
SYSTEM = 'system'
}
/**
* Content part types for API chat message content.
*/
export enum ContentPartType {
TEXT = 'text',
IMAGE_URL = 'image_url',
INPUT_AUDIO = 'input_audio'
}

View File

@ -2,7 +2,13 @@ export { AttachmentType } from './attachment';
export { AgenticSectionType } from './agentic';
export { ChatMessageStatsView, MessageRole, MessageType, ReasoningFormat } from './chat';
export {
ChatMessageStatsView,
ContentPartType,
MessageRole,
MessageType,
ReasoningFormat
} from './chat';
export {
FileTypeCategory,

View File

@ -1,6 +1,6 @@
import { getJsonHeaders, formatAttachmentText, isAbortError } from '$lib/utils';
import { AGENTIC_REGEX } from '$lib/constants/agentic';
import { AttachmentType, MessageRole, ReasoningFormat } from '$lib/enums';
import { AttachmentType, ContentPartType, MessageRole, ReasoningFormat } from '$lib/enums';
import type { ApiChatMessageContentPart, ApiChatCompletionToolCall } from '$lib/types/api';
import type { DatabaseMessageExtraMcpPrompt } from '$lib/types';
import { modelsStore } from '$lib/stores/models.svelte';
@ -56,7 +56,7 @@ export class ChatService {
}
return content.map((part: ApiChatMessageContentPart) => {
if (part.type !== 'text' || !part.text) return part;
if (part.type !== ContentPartType.TEXT || !part.text) return part;
return {
...part,
text: part.text
@ -156,7 +156,7 @@ export class ChatService {
normalizedMessages.forEach((msg) => {
if (Array.isArray(msg.content)) {
msg.content = msg.content.filter((part: ApiChatMessageContentPart) => {
if (part.type === 'image_url') {
if (part.type === ContentPartType.IMAGE_URL) {
console.info(
`[ChatService] Skipping image attachment in message history (model "${options.model}" does not support vision)`
);
@ -165,7 +165,7 @@ export class ChatService {
return true;
});
// If only text remains and it's a single part, simplify to string
if (msg.content.length === 1 && msg.content[0].type === 'text') {
if (msg.content.length === 1 && msg.content[0].type === ContentPartType.TEXT) {
msg.content = msg.content[0].text;
}
}
@ -690,7 +690,7 @@ export class ChatService {
if (message.content) {
contentParts.push({
type: 'text',
type: ContentPartType.TEXT,
text: message.content
});
}
@ -703,7 +703,7 @@ export class ChatService {
for (const image of imageFiles) {
contentParts.push({
type: 'image_url',
type: ContentPartType.IMAGE_URL,
image_url: { url: image.base64Url }
});
}
@ -715,7 +715,7 @@ export class ChatService {
for (const textFile of textFiles) {
contentParts.push({
type: 'text',
type: ContentPartType.TEXT,
text: formatAttachmentText('File', textFile.name, textFile.content)
});
}
@ -728,7 +728,7 @@ export class ChatService {
for (const legacyContextFile of legacyContextFiles) {
contentParts.push({
type: 'text',
type: ContentPartType.TEXT,
text: formatAttachmentText('File', legacyContextFile.name, legacyContextFile.content)
});
}
@ -740,7 +740,7 @@ export class ChatService {
for (const audio of audioFiles) {
contentParts.push({
type: 'input_audio',
type: ContentPartType.INPUT_AUDIO,
input_audio: {
data: audio.base64Data,
format: audio.mimeType.includes('wav') ? 'wav' : 'mp3'
@ -757,13 +757,13 @@ export class ChatService {
if (pdfFile.processedAsImages && pdfFile.images) {
for (let i = 0; i < pdfFile.images.length; i++) {
contentParts.push({
type: 'image_url',
type: ContentPartType.IMAGE_URL,
image_url: { url: pdfFile.images[i] }
});
}
} else {
contentParts.push({
type: 'text',
type: ContentPartType.TEXT,
text: formatAttachmentText('PDF File', pdfFile.name, pdfFile.content)
});
}
@ -776,7 +776,7 @@ export class ChatService {
for (const mcpPrompt of mcpPrompts) {
contentParts.push({
type: 'text',
type: ContentPartType.TEXT,
text: formatAttachmentText(
'MCP Prompt',
mcpPrompt.name,

View File

@ -23,7 +23,7 @@ import { mcpStore } from '$lib/stores/mcp.svelte';
import { modelsStore } from '$lib/stores/models.svelte';
import { isAbortError } from '$lib/utils';
import { DEFAULT_AGENTIC_CONFIG, AGENTIC_TAGS } from '$lib/constants/agentic';
import { AttachmentType, MessageRole } from '$lib/enums';
import { AttachmentType, ContentPartType, MessageRole } from '$lib/enums';
import type {
AgenticFlowParams,
AgenticFlowResult,
@ -527,12 +527,14 @@ class AgenticStore {
this.emitToolCallResult(cleanedResult, maxToolPreviewLines, onChunk);
const contentParts: ApiChatMessageContentPart[] = [{ type: 'text', text: cleanedResult }];
const contentParts: ApiChatMessageContentPart[] = [
{ type: ContentPartType.TEXT, text: cleanedResult }
];
for (const attachment of attachments) {
if (attachment.type === AttachmentType.IMAGE) {
if (modelsStore.modelSupportsVision(options.model ?? '')) {
contentParts.push({
type: 'image_url',
type: ContentPartType.IMAGE_URL,
image_url: { url: (attachment as DatabaseMessageExtraImageFile).base64Url }
});
} else {

View File

@ -1,4 +1,4 @@
import type { ServerModelStatus, ServerRole } from '$lib/enums';
import type { ContentPartType, ServerModelStatus, ServerRole } from '$lib/enums';
import type { ChatMessagePromptProgress, ChatRole } from './chat';
export interface ApiChatCompletionToolFunction {
@ -13,7 +13,7 @@ export interface ApiChatCompletionTool {
}
export interface ApiChatMessageContentPart {
type: 'text' | 'image_url' | 'input_audio';
type: ContentPartType;
text?: string;
image_url?: {
url: string;