Fix web search

This commit is contained in:
Frederik Spirgi
2026-09-21 11:38:08 +02:00
parent daa754bac4
commit be28be1430
5 changed files with 123 additions and 23 deletions
+21 -4
View File
@@ -18,13 +18,14 @@ import {
retryStylePrompts
} from "./chatMessageHelpers.js";
import {SearXNGSearchProvider, WebSearchError, buildWebSearchContext} from "./webSearchService.js";
import {SearXNGSearchProvider, WebSearchError, buildWebSearchContext, buildWebSearchQuery} from "./webSearchService.js";
export function createChatService(repositories, modelService, config, webSearchProvider = new SearXNGSearchProvider(config)) {
const chatGenerationQueues = new Map();
const summaryQueues = new Map();
const activeGenerations = new Map();
const maxRetries = Number(config.chatMaxRetries ?? 5);
const now = typeof config.now === "function" ? config.now : () => new Date();
const insertChatMessage = (chatId, role, content, retryState = null, modelName = null, deliveryStatus = "complete", errorMessage = null) => {
const normalizedContent = String(content || "");
@@ -232,6 +233,10 @@ export function createChatService(repositories, modelService, config, webSearchP
: repositories.getRecentChatMessagesUpToId(chatId, upToMessageId).reverse();
const conversation = message == null ? history : [...history, {role: "user", content: message}];
const messagesPayload = [];
// Result material remains a separate untrusted user-context message. The
// grounding rule is added after mutable persona/chat prompts so it remains
// the final trusted instruction governing the supplied references.
const webSearchContext = sources === null ? null : buildWebSearchContext(sources, now());
if (activeSession.system_instruction) {
messagesPayload.push({role: "system", content: `CHAT-SPECIFIC INSTRUCTIONS:\n${activeSession.system_instruction}`});
}
@@ -254,12 +259,13 @@ export function createChatService(repositories, modelService, config, webSearchP
if (memoryPrompt) messagesPayload.push({role: "system", content: memoryPrompt});
const personaStatePrompt = buildPersonaStatePrompt(repositories.getPersonaChatState(chatId, user));
if (personaStatePrompt) messagesPayload.push({role: "system", content: personaStatePrompt});
if (sources) messagesPayload.push(...buildWebSearchContext(sources));
if (activePersona) messagesPayload.push({role: "system", content: buildRoleplayReplyGuardPrompt()});
if (webSearchContext) messagesPayload.push(webSearchContext[0]);
if (webSearchContext?.[1]) messagesPayload.push(webSearchContext[1]);
messagesPayload.push(...conversation.map((entry) => ({
role: entry.role === "bot" ? "assistant" : "user",
content: entry.content
})));
if (activePersona) messagesPayload.push({role: "system", content: buildRoleplayReplyGuardPrompt()});
return {session: activeSession, activePersona, activeUserPersona, messagesPayload};
};
@@ -333,7 +339,18 @@ export function createChatService(repositories, modelService, config, webSearchP
const fullReply = await withActiveGeneration(chatId, signal, async (activeSignal) => {
if (webSearch) {
onStatus?.({status: "searching"});
sources = await webSearchProvider.search(message, {signal: activeSignal, limit: 5});
const searchQuery = buildWebSearchQuery(message);
sources = await webSearchProvider.search(searchQuery, {signal: activeSignal, limit: 5});
if (config.structuredRequestLoggingEnabled) {
console.log(JSON.stringify({
event: "web_search",
enabled: true,
query: searchQuery,
resultCount: sources.length,
webContextSupplied: true,
model: effectiveModel
}));
}
onStatus?.({status: "generating", sourceCount: sources.length});
}
payload = buildConversationContext({user, chatId, session, message: null, sources});