diff --git a/apps/server/src/services/i18n.ts b/apps/server/src/services/i18n.ts index 3bdf6f9cd..3e1f4d1a6 100644 --- a/apps/server/src/services/i18n.ts +++ b/apps/server/src/services/i18n.ts @@ -51,7 +51,7 @@ export function getLocales(): Locale[] { } function getCurrentLanguage(): LOCALE_IDS { - let language: string; + let language: string | null = null; if (sql_init.isDbInitialized()) { language = options.getOptionOrNull("locale"); } diff --git a/apps/server/src/services/import/opml.ts b/apps/server/src/services/import/opml.ts index cdc01011f..934578c70 100644 --- a/apps/server/src/services/import/opml.ts +++ b/apps/server/src/services/import/opml.ts @@ -84,7 +84,7 @@ async function importOpml(taskContext: TaskContext, fileBuffer: string | Buffer, } const outlines = xml.opml.body[0].outline || []; - let returnNote = null; + let returnNote: BNote | null = null; for (const outline of outlines) { const note = importOutline(outline, parentNote.noteId); diff --git a/apps/server/src/services/llm/ai_interface.ts b/apps/server/src/services/llm/ai_interface.ts index b8349b5b2..df8cc6914 100644 --- a/apps/server/src/services/llm/ai_interface.ts +++ b/apps/server/src/services/llm/ai_interface.ts @@ -9,7 +9,7 @@ export interface Message { content: string; name?: string; tool_call_id?: string; - tool_calls?: ToolCall[]; + tool_calls?: ToolCall[] | null; sessionId?: string; // Optional session ID for WebSocket communication } @@ -210,7 +210,7 @@ export interface ChatResponse { stream?: (callback: (chunk: StreamChunk) => Promise | void) => Promise; /** Tool calls from the LLM (if tools were used and the model supports them) */ - tool_calls?: ToolCall[]; + tool_calls?: ToolCall[] | null; } export interface AIService { diff --git a/apps/server/src/services/llm/embeddings/embeddings_interface.ts b/apps/server/src/services/llm/embeddings/embeddings_interface.ts index b1fa333bf..1db6c5099 100644 --- a/apps/server/src/services/llm/embeddings/embeddings_interface.ts +++ b/apps/server/src/services/llm/embeddings/embeddings_interface.ts @@ -22,20 +22,24 @@ export interface NoteEmbeddingContext { title: string; mime: string; }[]; - backlinks?: { - sourceNoteId: string; - sourceTitle: string; - relationName: string; - }[]; - relatedNotes?: { - targetNoteId: string; - targetTitle: string; - relationName: string; - }[]; + backlinks?: Backlink[]; + relatedNotes?: RelatedNote[]; labelValues?: Record; templateTitles?: string[]; } +export interface Backlink { + sourceNoteId: string; + sourceTitle: string; + relationName: string; +} + +export interface RelatedNote { + targetNoteId: string; + targetTitle: string; + relationName: string; +} + /** * Information about an embedding model's capabilities */ diff --git a/apps/server/src/services/llm/embeddings/storage.ts b/apps/server/src/services/llm/embeddings/storage.ts index 67063e63b..675047a76 100644 --- a/apps/server/src/services/llm/embeddings/storage.ts +++ b/apps/server/src/services/llm/embeddings/storage.ts @@ -8,6 +8,14 @@ import entityChangesService from "../../../services/entity_changes.js"; import type { EntityChange } from "../../../services/entity_changes_interface.js"; import { EMBEDDING_CONSTANTS } from "../constants/embedding_constants.js"; import { SEARCH_CONSTANTS } from '../constants/search_constants.js'; + +interface Similarity { + noteId: string; + similarity: number; + contentType: string; + bonuses?: Record; // Optional for debugging +} + /** * Creates or updates an embedding for a note */ @@ -434,7 +442,7 @@ async function processEmbeddings(queryEmbedding: Float32Array, embeddings: any[] return { bonuses, totalBonus }; } - const similarities = []; + const similarities: Similarity[] = []; try { // Try to extract the original query text if it was added to the metadata diff --git a/apps/server/src/services/llm/providers/anthropic_service.ts b/apps/server/src/services/llm/providers/anthropic_service.ts index 955ef494a..cbdbb6814 100644 --- a/apps/server/src/services/llm/providers/anthropic_service.ts +++ b/apps/server/src/services/llm/providers/anthropic_service.ts @@ -7,6 +7,21 @@ import { getAnthropicOptions } from './providers.js'; import log from '../../log.js'; import Anthropic from '@anthropic-ai/sdk'; import { SEARCH_CONSTANTS } from '../constants/search_constants.js'; +import type { ToolCall } from '../tools/tool_interfaces.js'; + +interface AnthropicMessage extends Omit { + content: MessageContent[] | string; +} + +interface MessageContent { + type: "text" | "tool_use" | "tool_result"; + text?: string; + id?: string; + name?: string; + content?: string; + tool_use_id?: string; + input?: string | Record; +} export class AnthropicService extends BaseAIService { private client: any = null; @@ -130,7 +145,7 @@ export class AnthropicService extends BaseAIService { .join(''); // Process tool calls if any are present in the response - let toolCalls = null; + let toolCalls: ToolCall[] | null = null; if (response.content) { const toolBlocks = response.content.filter((block: any) => block.type === 'tool_use' || @@ -157,7 +172,7 @@ export class AnthropicService extends BaseAIService { return null; }).filter(Boolean); - log.info(`Extracted ${toolCalls.length} tool calls from Anthropic response`); + log.info(`Extracted ${toolCalls?.length} tool calls from Anthropic response`); } } @@ -406,8 +421,8 @@ export class AnthropicService extends BaseAIService { /** * Format messages for the Anthropic API */ - private formatMessages(messages: Message[]): any[] { - const anthropicMessages: any[] = []; + private formatMessages(messages: Message[]): AnthropicMessage[] { + const anthropicMessages: AnthropicMessage[] = []; // Process each message for (const msg of messages) { @@ -424,7 +439,7 @@ export class AnthropicService extends BaseAIService { // Assistant messages need special handling for tool_calls if (msg.tool_calls && msg.tool_calls.length > 0) { // Create content blocks array for tool calls - const content = []; + const content: MessageContent[] = []; // Add text content if present if (msg.content) { diff --git a/apps/server/src/services/llm/providers/providers.ts b/apps/server/src/services/llm/providers/providers.ts index 5fcd4286a..91295ffe0 100644 --- a/apps/server/src/services/llm/providers/providers.ts +++ b/apps/server/src/services/llm/providers/providers.ts @@ -181,7 +181,7 @@ export async function updateEmbeddingProviderConfig( } // Build update query parts - const updates = []; + const updates: string[] = []; const params: any[] = []; if (priority !== undefined) { diff --git a/apps/server/src/services/llm/tools/content_extraction_tool.ts b/apps/server/src/services/llm/tools/content_extraction_tool.ts index 0a1a18cd7..52c1409e9 100644 --- a/apps/server/src/services/llm/tools/content_extraction_tool.ts +++ b/apps/server/src/services/llm/tools/content_extraction_tool.ts @@ -8,6 +8,26 @@ import type { Tool, ToolHandler } from './tool_interfaces.js'; import log from '../../log.js'; import becca from '../../../becca/becca.js'; +interface CodeBlock { + code: string; + language?: string; +} + +interface Heading { + text: string; + level: number; // 1 for H1, 2 for H2, etc. +} + +interface List { + type: "unordered" | "ordered"; + items: string[]; +} + +interface Table { + headers: string[]; + rows: string[][]; +} + /** * Definition of the content extraction tool */ @@ -137,8 +157,8 @@ export class ContentExtractionTool implements ToolHandler { /** * Extract lists from HTML content */ - private extractLists(content: string): Array<{ type: string, items: string[] }> { - const lists = []; + private extractLists(content: string): List[] { + const lists: List[] = []; // Extract unordered lists const ulRegex = /]*>([\s\S]*?)<\/ul>/gi; @@ -179,7 +199,7 @@ export class ContentExtractionTool implements ToolHandler { * Extract list items from list content */ private extractListItems(listContent: string): string[] { - const items = []; + const items: string[] = []; const itemRegex = /]*>([\s\S]*?)<\/li>/gi; let itemMatch; @@ -196,15 +216,15 @@ export class ContentExtractionTool implements ToolHandler { /** * Extract tables from HTML content */ - private extractTables(content: string): Array<{ headers: string[], rows: string[][] }> { - const tables = []; + private extractTables(content: string): Table[] { + const tables: Table[] = []; const tableRegex = /]*>([\s\S]*?)<\/table>/gi; - let tableMatch; + let tableMatch: RegExpExecArray | null; while ((tableMatch = tableRegex.exec(content)) !== null) { const tableContent = tableMatch[1]; - const headers = []; - const rows = []; + const headers: string[] = []; + const rows: string[][] = []; // Extract table headers const headerRegex = /]*>([\s\S]*?)<\/th>/gi; @@ -218,7 +238,7 @@ export class ContentExtractionTool implements ToolHandler { let rowMatch; while ((rowMatch = rowRegex.exec(tableContent)) !== null) { const rowContent = rowMatch[1]; - const cells = []; + const cells: string[] = []; const cellRegex = /]*>([\s\S]*?)<\/td>/gi; let cellMatch; @@ -246,7 +266,7 @@ export class ContentExtractionTool implements ToolHandler { * Extract headings from HTML content */ private extractHeadings(content: string): Array<{ level: number, text: string }> { - const headings = []; + const headings: Heading[] = []; for (let i = 1; i <= 6; i++) { const headingRegex = new RegExp(`]*>([\\s\\S]*?)<\/h${i}>`, 'gi'); @@ -270,7 +290,7 @@ export class ContentExtractionTool implements ToolHandler { * Extract code blocks from HTML content */ private extractCodeBlocks(content: string): Array<{ language?: string, code: string }> { - const codeBlocks = []; + const codeBlocks: CodeBlock[] = []; // Look for
 and  blocks
         const preRegex = /]*>([\s\S]*?)<\/pre>/gi;
diff --git a/apps/server/src/services/llm/tools/note_creation_tool.ts b/apps/server/src/services/llm/tools/note_creation_tool.ts
index 9633880e4..41e608029 100644
--- a/apps/server/src/services/llm/tools/note_creation_tool.ts
+++ b/apps/server/src/services/llm/tools/note_creation_tool.ts
@@ -9,6 +9,7 @@ import log from '../../log.js';
 import becca from '../../../becca/becca.js';
 import notes from '../../notes.js';
 import attributes from '../../attributes.js';
+import type { BNote } from '../../backend_script_entrypoint.js';
 
 /**
  * Definition of the note creation tool
@@ -89,7 +90,7 @@ export class NoteCreationTool implements ToolHandler {
             log.info(`Executing create_note tool - Title: "${title}", Type: ${type}, ParentNoteId: ${parentNoteId || 'root'}`);
 
             // Validate parent note exists if specified
-            let parent = null;
+            let parent: BNote | null = null;
             if (parentNoteId) {
                 parent = becca.notes[parentNoteId];
                 if (!parent) {
diff --git a/apps/server/src/services/llm/tools/relationship_tool.ts b/apps/server/src/services/llm/tools/relationship_tool.ts
index 09e16f72c..a7023981d 100644
--- a/apps/server/src/services/llm/tools/relationship_tool.ts
+++ b/apps/server/src/services/llm/tools/relationship_tool.ts
@@ -10,6 +10,14 @@ import becca from '../../../becca/becca.js';
 import attributes from '../../attributes.js';
 import aiServiceManager from '../ai_service_manager.js';
 import { SEARCH_CONSTANTS } from '../constants/search_constants.js';
+import type { Backlink, RelatedNote } from '../embeddings/embeddings_interface.js';
+
+interface Suggestion {
+    targetNoteId: string;
+    targetTitle: string;
+    similarity: number;
+    suggestedRelation: string;
+}
 
 /**
  * Definition of the relationship tool
@@ -180,7 +188,7 @@ export class RelationshipTool implements ToolHandler {
                 .filter((attr: any) => attr.type === 'relation')
                 .slice(0, limit);
 
-            const outgoingRelations = [];
+            const outgoingRelations: RelatedNote[] = [];
 
             for (const attr of outgoingAttributes) {
                 const targetNote = becca.notes[attr.value];
@@ -196,7 +204,7 @@ export class RelationshipTool implements ToolHandler {
 
             // Get incoming relationships (where this note is the target)
             // Since becca.findNotesWithRelation doesn't exist, use attributes to find notes with relation
-            const incomingRelations = [];
+            const incomingRelations: Backlink[] = [];
 
             // Find all attributes of type relation that point to this note
             const relationAttributes = sourceNote.getTargetRelations();
@@ -321,7 +329,7 @@ export class RelationshipTool implements ToolHandler {
             const sourceContent = await sourceNote.getContent();
 
             // Prepare suggestions
-            const suggestions = [];
+            const suggestions: Suggestion[] = [];
 
             for (const relatedNote of relatedResult.relatedNotes) {
                 try {
diff --git a/apps/server/src/services/notes.ts b/apps/server/src/services/notes.ts
index cbb3c90c1..f06e07ed8 100644
--- a/apps/server/src/services/notes.ts
+++ b/apps/server/src/services/notes.ts
@@ -755,7 +755,7 @@ function updateNoteData(noteId: string, content: string, attachments: Attachment
 function undeleteNote(noteId: string, taskContext: TaskContext) {
     const noteRow = sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
 
-    if (!noteRow.isDeleted) {
+    if (!noteRow.isDeleted || !noteRow.deleteId) {
         log.error(`Note '${noteId}' is not deleted and thus cannot be undeleted.`);
         return;
     }
diff --git a/apps/server/src/services/script.ts b/apps/server/src/services/script.ts
index aedab83bf..1afc3b763 100644
--- a/apps/server/src/services/script.ts
+++ b/apps/server/src/services/script.ts
@@ -118,7 +118,7 @@ function getParams(params?: ScriptParams) {
 }
 
 function getScriptBundleForFrontend(note: BNote, script?: string, params?: ScriptParams) {
-    let overrideContent = null;
+    let overrideContent: string | null = null;
 
     if (script) {
         overrideContent = `return (${script}\r\n)(${getParams(params)})`;
@@ -170,7 +170,7 @@ function getScriptBundle(note: BNote, root: boolean = true, scriptEnv: string |
 
     includedNoteIds.push(note.noteId);
 
-    const modules = [];
+    const modules: BNote[] = [];
 
     for (const child of note.getChildNotes()) {
         const childBundle = getScriptBundle(child, false, scriptEnv, includedNoteIds);
diff --git a/apps/server/src/services/search/services/parse.ts b/apps/server/src/services/search/services/parse.ts
index c454aef7e..6cfaad6e6 100644
--- a/apps/server/src/services/search/services/parse.ts
+++ b/apps/server/src/services/search/services/parse.ts
@@ -294,11 +294,11 @@ function getExpression(tokens: TokenData[], searchContext: SearchContext, level
             valueExtractor: ValueExtractor;
             direction: string;
         }[] = [];
-        let limit;
+        let limit: number | undefined = undefined;
 
         if (tokens[i].token === "orderby") {
             do {
-                const propertyPath = [];
+                const propertyPath: string[] = [];
                 let direction = "asc";
 
                 do {
diff --git a/apps/server/src/services/search/services/search.ts b/apps/server/src/services/search/services/search.ts
index 3e1020e7a..7c53546e7 100644
--- a/apps/server/src/services/search/services/search.ts
+++ b/apps/server/src/services/search/services/search.ts
@@ -36,7 +36,7 @@ function searchFromNote(note: BNote): SearchNoteResult {
 
     const searchScript = note.getRelationValue("searchScript");
     const searchString = note.getLabelValue("searchString") || "";
-    let error = null;
+    let error: string | null = null;
 
     if (searchScript) {
         searchResultNoteIds = searchFromRelation(note, "searchScript");
diff --git a/apps/server/src/share/shaca/shaca-interface.ts b/apps/server/src/share/shaca/shaca-interface.ts
index 65b0585b7..1d796b302 100644
--- a/apps/server/src/share/shaca/shaca-interface.ts
+++ b/apps/server/src/share/shaca/shaca-interface.ts
@@ -43,7 +43,7 @@ export default class Shaca {
     }
 
     getNotes(noteIds: string[], ignoreMissing = false) {
-        const filteredNotes = [];
+        const filteredNotes: SNote[] = [];
 
         for (const noteId of noteIds) {
             const note = this.notes[noteId];