add JSDoc comments because yes

This commit is contained in:
2026-09-25 17:14:56 +02:00
parent 9020356e62
commit 0a24035b27
62 changed files with 197 additions and 0 deletions
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Validiert und speichert Bildanhänge und bereitet zwischengespeicherte Bildanalysen für den Chat vor.
*/
import sharp from "sharp";
import {createHash, randomUUID} from "node:crypto";
import {attachmentMetadata} from "../db/attachments.js";
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Normalisiert Nachrichten und erstellt Kontexttexte für Erinnerungen, Zusammenfassungen und Personas.
*/
import {normalizeSources} from "./webSearchService.js";
export function parseSources(value) {
+7
View File
@@ -1,3 +1,6 @@
/**
* @file Koordiniert Chat-Antworten, Modellkontext, Websuche, Anhänge, Antwortvarianten und Gesprächsverzweigungen.
*/
import {
buildPersonaPrompt,
buildRoleplayDirectionPrompt,
@@ -95,15 +98,18 @@ export function createChatService(repositories, modelService, config, webSearchP
const withChatGenerationLock = (chatId, operation) => {
const previous = chatGenerationQueues.get(chatId) || Promise.resolve();
// Ein fehlgeschlagener Vorgänger darf die Warteschlange dieses Chats nicht blockieren.
const current = previous.catch(() => undefined).then(operation);
chatGenerationQueues.set(chatId, current);
return current.finally(() => {
// Nur den eigenen Eintrag entfernen: Inzwischen könnte bereits ein Folgeauftrag warten.
if (chatGenerationQueues.get(chatId) === current) chatGenerationQueues.delete(chatId);
});
};
const withActiveGeneration = async (chatId, externalSignal, operation) => {
const controller = new AbortController();
// Verbindungsabbruch und manuelles Stoppen wirken auf denselben Generierungsauftrag.
const abortFromCaller = () => controller.abort(externalSignal?.reason);
if (externalSignal?.aborted) abortFromCaller();
else externalSignal?.addEventListener("abort", abortFromCaller, { once: true });
@@ -157,6 +163,7 @@ export function createChatService(repositories, modelService, config, webSearchP
const allMessages = repositories.listActiveBranchMessages(chatId)
.filter((message) => !message.delivery_status || message.delivery_status === "complete");
const keepRecent = Math.max(0, config.chatHistoryLimit);
// Die neuesten Nachrichten bleiben vollständig im Kontext; nur ältere werden zusammengefasst.
const cutoffIndex = allMessages.length - keepRecent - 1;
if (cutoffIndex < 0) return;
const cutoffMessage = allMessages[cutoffIndex];
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Speichert, liest und löscht hochgeladene Dateien in einem lokalen Speicherverzeichnis.
*/
import fs from "node:fs";
import path from "node:path";
import {randomUUID} from "node:crypto";
+5
View File
@@ -1,3 +1,6 @@
/**
* @file Kommuniziert mit Ollama und verwaltet Antwortstreams, Zeitlimits, Modellstatus und Modell-Caches.
*/
import { supportsReasoning } from "../../public/js/modelCapabilities.js";
import { AttachmentError } from "./attachmentService.js";
@@ -147,6 +150,7 @@ export function createModelService(config, overrides = {}) {
touch();
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
// Netzwerkblöcke können mitten in einer JSON-Zeile enden; den Rest für den nächsten Block behalten.
buffer = lines.pop() || "";
for (const line of lines) {
const trimmed = line.trim();
@@ -160,6 +164,7 @@ export function createModelService(config, overrides = {}) {
if (!completed && buffer.trim()) {
consume(buffer.trim());
}
// Erst das Abschlussereignis bestätigt eine vollständige Antwort; ein Stream-Ende allein genügt nicht.
if (!completed) throw new ModelServiceError("MODEL_INTERRUPTED", "Model response was interrupted.", 502);
onRawReply?.(fullReply);
return fullReply.trim();
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Validiert Persona-Daten und erstellt Rollenspielanweisungen sowie Prüfungen für die Rollenverteilung.
*/
const PERSONA_FIELD_LIMITS = {
name: 200,
pronouns: 40,
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Definiert Anweisungen, Antwortschema und Normalisierung für Bildanalysen und deren Nutzung im Chat.
*/
// Bump whenever the perception prompt, schema, or interpretation contract changes.
export const VISION_PROMPT_VERSION = 4;
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Sammelt begrenzte Diagnosedaten zur Bildverarbeitung und kontrolliert deren benutzerbezogenen Zugriff.
*/
const RAW_VISION_LIMIT = 12000;
const EVIDENCE_LIMIT = 100000;
const ANSWER_LIMIT = 30000;
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Entscheidet über Websuchen, fragt SearXNG ab und bereitet relevante Quellen als Modellkontext auf.
*/
/** @typedef {{title: string, url: string, snippet: string, score?: number, engine?: string, category?: string, publishedDate?: string}} RawSearchResult */
/** @typedef {{title: string, url: string, snippet: string}} SearchResult */
/** @typedef {{signal?: AbortSignal, limit?: number, category?: string}} SearchOptions */
+3
View File
@@ -1,3 +1,6 @@
/**
* @file Prüft und normalisiert importierte Arbeitsbereiche mit Personas, Chats und Nachrichtenbeziehungen.
*/
import {parseSources} from "./chatMessageHelpers.js";
const VALID_PERSONA_TYPES = new Set(["assistant", "user"]);