improve reasoning toggle tests and refactor model capability checks

This commit is contained in:
2026-09-22 10:30:03 +02:00
parent a8e348e0c7
commit 3b6c8969cc
15 changed files with 201 additions and 23 deletions
+25 -8
View File
@@ -12,7 +12,7 @@ import {
buildMemoryPrompt,
buildPersonaStatePrompt,
clampRetryActiveIndex,
formatChatMessage,
formatChatMessage as formatBaseChatMessage,
formatMessagesForSummary,
parseSources,
retryStylePrompts
@@ -21,7 +21,12 @@ import {
import {SearXNGSearchProvider, WebSearchError, buildWebSearchContext, retrieveWebSearch} from "./webSearchService.js";
import {supportsReasoning} from "../../public/app/modelCapabilities.js";
export function createChatService(repositories, modelService, config, webSearchProvider = new SearXNGSearchProvider(config)) {
export function createChatService(repositories, modelService, config, webSearchProvider = new SearXNGSearchProvider(config), attachmentService = null) {
const formatChatMessage = row => {
const message = formatBaseChatMessage(row);
const attachments = row && attachmentService?.list(row.id);
return message && attachments?.length ? {...message, attachments} : message;
};
const chatGenerationQueues = new Map();
const summaryQueues = new Map();
const activeGenerations = new Map();
@@ -272,6 +277,8 @@ export function createChatService(repositories, modelService, config, webSearchP
content: entry.content
}));
messagesPayload.push(...conversationMessages.slice(0, -1));
const visionContext = attachmentService?.context(history);
if (visionContext) messagesPayload.push(visionContext);
if (webSearchContext) messagesPayload.push(webSearchContext[0]);
if (webSearchContext?.[1]) messagesPayload.push(webSearchContext[1]);
if (conversationMessages.length) messagesPayload.push(conversationMessages.at(-1));
@@ -307,6 +314,7 @@ export function createChatService(repositories, modelService, config, webSearchP
return {fullReply: opener, thinking, promptMessageId: null};
}
await attachmentService?.analyze(promptMessage.id, promptMessage.content, signal);
const {messagesPayload} = buildConversationContext({
user,
chatId,
@@ -327,7 +335,7 @@ export function createChatService(repositories, modelService, config, webSearchP
return {fullReply, thinking, promptMessageId: promptMessage.id};
};
const generateChatTurn = ({user, chatId, message, model, webSearch = false, reasoning = false, onStatus = null, onChunk = null, onThinking = null, signal = null, parentMessageId = undefined}) =>
const generateChatTurn = ({user, chatId, message, model, attachments = [], reuseChatId = null, webSearch = false, reasoning = false, onStatus = null, onChunk = null, onThinking = null, signal = null, parentMessageId = undefined}) =>
withChatGenerationLock(chatId, async () => {
await (summaryQueues.get(chatId) || Promise.resolve());
const session = repositories.getChat(chatId, user);
@@ -346,7 +354,8 @@ export function createChatService(repositories, modelService, config, webSearchP
const {model: effectiveModel, generation} = getGenerationSettings(session, model);
const useReasoning = reasoning === true && supportsReasoning(effectiveModel);
signal?.throwIfAborted();
const inserted = repositories.insertBranchChatMessage(chatId, "user", message, null, null, "pending", null, effectiveParentId);
const insert = () => repositories.insertBranchChatMessage(chatId, "user", message, null, null, "pending", null, effectiveParentId);
const inserted = attachmentService ? attachmentService.createMessage(attachments, user, chatId, insert, reuseChatId) : insert();
const userMessageId = Number(inserted?.lastInsertRowid);
try {
let sources = null;
@@ -361,8 +370,13 @@ export function createChatService(repositories, modelService, config, webSearchP
const fullReply = await withActiveGeneration(chatId, signal, async (activeSignal) => {
activeSignal.throwIfAborted();
onStatus?.({status: "accepted"});
if (attachments.length) {
onStatus?.({status: "analyzing"});
await attachmentService.analyze(userMessageId, message, activeSignal);
}
if (webSearch) {
const search = await retrieveWebSearch(message, webSearchProvider, {
referenceText: attachments.length ? attachmentService.searchContext(userMessageId) : "",
signal: activeSignal,
onSearching: () => onStatus?.({status: "searching"})
});
@@ -489,6 +503,7 @@ export function createChatService(repositories, modelService, config, webSearchP
parentMessageId
);
parentMessageId = Number(inserted.lastInsertRowid);
attachmentService?.copy(sourceMessage.id, parentMessageId);
if (sourceMessage.sources) repositories.updateChatMessageSources(clonedChat.id, parentMessageId, parseSources(sourceMessage.sources));
if (sourceMessage.thinking) repositories.updateChatMessageThinking(clonedChat.id, parentMessageId, sourceMessage.thinking);
}
@@ -515,11 +530,11 @@ export function createChatService(repositories, modelService, config, webSearchP
containsUserVoiceInRoleplayOpener,
persistChatMessageRetryState,
buildMessagesPayload: buildConversationContext,
async sendChatMessage({user, chatId, message, model, webSearch = false, reasoning = false}) {
return generateChatTurn({user, chatId, message, model, webSearch, reasoning});
async sendChatMessage({user, chatId, message, model, attachments = [], webSearch = false, reasoning = false}) {
return generateChatTurn({user, chatId, message, model, attachments, webSearch, reasoning});
},
async streamChatMessage({user, chatId, message, model, webSearch = false, reasoning = false, onStatus, onChunk, onThinking, signal = null}) {
return generateChatTurn({user, chatId, message, model, webSearch, reasoning, onStatus, onChunk, onThinking, signal});
async streamChatMessage({user, chatId, message, model, attachments = [], webSearch = false, reasoning = false, onStatus, onChunk, onThinking, signal = null}) {
return generateChatTurn({user, chatId, message, model, attachments, webSearch, reasoning, onStatus, onChunk, onThinking, signal});
},
async retryMessage({user, chatId, selectedModel, targetMessage, retryStyle = null}) {
return withChatGenerationLock(chatId, async () => {
@@ -574,6 +589,8 @@ export function createChatService(repositories, modelService, config, webSearchP
const generated = await generateChatTurn({
user,
chatId: cloned.chat.id,
attachments: attachmentService?.list(targetMessage.id).map(item => item.id) || [],
reuseChatId: chatId,
message: content,
model,
webSearch,