mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-08-10 10:22:29 +08:00
reduce the use of any, part 3
This commit is contained in:
parent
4601e3bfdb
commit
80ea2c3eef
@ -18,6 +18,17 @@ import type {
|
||||
} from './interfaces/ai_service_interfaces.js';
|
||||
import type { NoteSearchResult } from './interfaces/context_interfaces.js';
|
||||
|
||||
/**
|
||||
* Interface representing relevant note context
|
||||
*/
|
||||
interface NoteContext {
|
||||
title: string;
|
||||
content?: string;
|
||||
noteId?: string;
|
||||
summary?: string;
|
||||
score?: number;
|
||||
}
|
||||
|
||||
export class AIServiceManager implements IAIServiceManager {
|
||||
private services: Record<ServiceProviders, AIService> = {
|
||||
openai: new OpenAIService(),
|
||||
@ -31,30 +42,30 @@ export class AIServiceManager implements IAIServiceManager {
|
||||
constructor() {
|
||||
// Initialize provider order immediately
|
||||
this.updateProviderOrder();
|
||||
|
||||
|
||||
// Initialize tools immediately
|
||||
this.initializeTools().catch(error => {
|
||||
log.error(`Error initializing LLM tools during AIServiceManager construction: ${error.message || String(error)}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize all LLM tools in one place
|
||||
*/
|
||||
private async initializeTools(): Promise<void> {
|
||||
try {
|
||||
log.info('Initializing LLM tools during AIServiceManager construction...');
|
||||
|
||||
|
||||
// Initialize agent tools
|
||||
await agentTools.initialize(true);
|
||||
await this.initializeAgentTools();
|
||||
log.info("Agent tools initialized successfully");
|
||||
|
||||
|
||||
// Initialize LLM tools
|
||||
const toolInitializer = await import('./tools/tool_initializer.js');
|
||||
await toolInitializer.default.initializeTools();
|
||||
log.info("LLM tools initialized successfully");
|
||||
} catch (error: any) {
|
||||
log.error(`Error initializing tools: ${error.message || String(error)}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error initializing tools: ${this.handleError(error)}`);
|
||||
// Don't throw, just log the error to prevent breaking construction
|
||||
}
|
||||
}
|
||||
@ -463,10 +474,8 @@ export class AIServiceManager implements IAIServiceManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get agent tools context for a specific note
|
||||
* This context enriches LLM prompts with tools that can interact with Trilium
|
||||
*
|
||||
* @param noteId - The note ID
|
||||
* Get enhanced context with available agent tools
|
||||
* @param noteId - The ID of the note
|
||||
* @param query - The user's query
|
||||
* @param showThinking - Whether to show LLM's thinking process
|
||||
* @param relevantNotes - Optional notes already found to be relevant
|
||||
@ -476,12 +485,12 @@ export class AIServiceManager implements IAIServiceManager {
|
||||
noteId: string,
|
||||
query: string,
|
||||
showThinking: boolean = false,
|
||||
relevantNotes: Array<any> = []
|
||||
relevantNotes: NoteSearchResult[] = []
|
||||
): Promise<string> {
|
||||
try {
|
||||
// Create agent tools message
|
||||
const toolsMessage = await this.getAgentToolsDescription();
|
||||
|
||||
|
||||
// Agent tools are already initialized in the constructor
|
||||
// No need to initialize them again
|
||||
|
||||
@ -508,7 +517,7 @@ export class AIServiceManager implements IAIServiceManager {
|
||||
|
||||
log.info(`Found ${contextNotes.length} relevant notes for context`);
|
||||
} catch (error) {
|
||||
log.error(`Failed to find relevant notes: ${error}`);
|
||||
log.error(`Failed to find relevant notes: ${this.handleError(error)}`);
|
||||
// Continue without context notes
|
||||
contextNotes = [];
|
||||
}
|
||||
@ -526,7 +535,7 @@ export class AIServiceManager implements IAIServiceManager {
|
||||
// Combine tool message with context
|
||||
return toolsMessage + contextStr;
|
||||
} catch (error) {
|
||||
log.error(`Error getting agent tools context: ${error}`);
|
||||
log.error(`Error getting agent tools context: ${this.handleError(error)}`);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -600,6 +609,16 @@ export class AIServiceManager implements IAIServiceManager {
|
||||
defaultModel: 'default'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler that properly types the error object
|
||||
*/
|
||||
private handleError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message || String(error);
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't create singleton immediately, use a lazy-loading pattern
|
||||
@ -662,7 +681,7 @@ export default {
|
||||
noteId: string,
|
||||
query: string,
|
||||
showThinking: boolean = false,
|
||||
relevantNotes: Array<any> = []
|
||||
relevantNotes: NoteSearchResult[] = []
|
||||
): Promise<string> {
|
||||
return getInstance().getAgentToolsContext(
|
||||
noteId,
|
||||
|
@ -6,17 +6,26 @@ import { ChatPipeline } from './pipeline/chat_pipeline.js';
|
||||
import type { ChatPipelineConfig, StreamCallback } from './pipeline/interfaces.js';
|
||||
import aiServiceManager from './ai_service_manager.js';
|
||||
import type { ChatPipelineInput } from './pipeline/interfaces.js';
|
||||
import type { NoteSearchResult } from './interfaces/context_interfaces.js';
|
||||
|
||||
// Update the ChatCompletionOptions interface to include the missing properties
|
||||
// TODO fix
|
||||
declare module './ai_interface.js' {
|
||||
interface ChatCompletionOptions {
|
||||
pipeline?: string;
|
||||
noteId?: string;
|
||||
useAdvancedContext?: boolean;
|
||||
showThinking?: boolean;
|
||||
enableTools?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a type for context extraction result
|
||||
interface ContextExtractionResult {
|
||||
context: string;
|
||||
sources?: NoteSearchResult[];
|
||||
thinking?: string;
|
||||
}
|
||||
|
||||
export interface ChatSession {
|
||||
id: string;
|
||||
title: string;
|
||||
@ -144,7 +153,7 @@ export class ChatService {
|
||||
...(options || session.options || {}),
|
||||
sessionId: session.id
|
||||
};
|
||||
|
||||
|
||||
// Execute the pipeline
|
||||
const response = await pipeline.execute({
|
||||
messages: session.messages,
|
||||
@ -156,7 +165,8 @@ export class ChatService {
|
||||
// Add assistant message
|
||||
const assistantMessage: Message = {
|
||||
role: 'assistant',
|
||||
content: response.text
|
||||
content: response.text,
|
||||
tool_calls: response.tool_calls
|
||||
};
|
||||
|
||||
session.messages.push(assistantMessage);
|
||||
@ -168,13 +178,13 @@ export class ChatService {
|
||||
provider: response.provider,
|
||||
usage: response.usage
|
||||
};
|
||||
|
||||
|
||||
// If there are tool calls, make sure they're stored in metadata
|
||||
if (response.tool_calls && response.tool_calls.length > 0) {
|
||||
// Let the storage service extract and save tool executions
|
||||
// The tool results are already in the messages
|
||||
}
|
||||
|
||||
|
||||
// Save the complete conversation with metadata
|
||||
await chatStorageService.updateChat(session.id, session.messages, undefined, metadata);
|
||||
|
||||
@ -187,9 +197,9 @@ export class ChatService {
|
||||
|
||||
return session;
|
||||
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
session.isStreaming = false;
|
||||
console.error('Error in AI chat:', error);
|
||||
console.error('Error in AI chat:', this.handleError(error));
|
||||
|
||||
// Add error message
|
||||
const errorMessage: Message = {
|
||||
@ -266,7 +276,8 @@ export class ChatService {
|
||||
// Add assistant message
|
||||
const assistantMessage: Message = {
|
||||
role: 'assistant',
|
||||
content: response.text
|
||||
content: response.text,
|
||||
tool_calls: response.tool_calls
|
||||
};
|
||||
|
||||
session.messages.push(assistantMessage);
|
||||
@ -279,13 +290,13 @@ export class ChatService {
|
||||
usage: response.usage,
|
||||
contextNoteId: noteId // Store the note ID used for context
|
||||
};
|
||||
|
||||
|
||||
// If there are tool calls, make sure they're stored in metadata
|
||||
if (response.tool_calls && response.tool_calls.length > 0) {
|
||||
// Let the storage service extract and save tool executions
|
||||
// The tool results are already in the messages
|
||||
}
|
||||
|
||||
|
||||
// Save the complete conversation with metadata
|
||||
await chatStorageService.updateChat(session.id, session.messages, undefined, metadata);
|
||||
|
||||
@ -298,9 +309,9 @@ export class ChatService {
|
||||
|
||||
return session;
|
||||
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
session.isStreaming = false;
|
||||
console.error('Error in context-aware chat:', error);
|
||||
console.error('Error in context-aware chat:', this.handleError(error));
|
||||
|
||||
// Add error message
|
||||
const errorMessage: Message = {
|
||||
@ -343,7 +354,7 @@ export class ChatService {
|
||||
noteId,
|
||||
query: lastUserMessage,
|
||||
useSmartContext
|
||||
});
|
||||
}) as ContextExtractionResult;
|
||||
|
||||
const contextMessage: Message = {
|
||||
role: 'user',
|
||||
@ -351,28 +362,27 @@ export class ChatService {
|
||||
};
|
||||
|
||||
session.messages.push(contextMessage);
|
||||
|
||||
|
||||
// Store the context note id in metadata
|
||||
const metadata = {
|
||||
contextNoteId: noteId
|
||||
};
|
||||
|
||||
|
||||
// Check if the context extraction result has sources
|
||||
// Note: We're adding a defensive check since TypeScript doesn't know about this property
|
||||
const contextSources = (contextResult as any).sources || [];
|
||||
if (contextSources && contextSources.length > 0) {
|
||||
// Convert the sources to the format expected by recordSources
|
||||
const sources = contextSources.map((source: any) => ({
|
||||
if (contextResult.sources && contextResult.sources.length > 0) {
|
||||
// Convert the sources to match expected format (handling null vs undefined)
|
||||
const sources = contextResult.sources.map(source => ({
|
||||
noteId: source.noteId,
|
||||
title: source.title,
|
||||
similarity: source.similarity,
|
||||
content: source.content
|
||||
// Replace null with undefined for content
|
||||
content: source.content === null ? undefined : source.content
|
||||
}));
|
||||
|
||||
|
||||
// Store these sources in metadata
|
||||
await chatStorageService.recordSources(session.id, sources);
|
||||
}
|
||||
|
||||
|
||||
await chatStorageService.updateChat(session.id, session.messages, undefined, metadata);
|
||||
|
||||
return session;
|
||||
@ -380,11 +390,6 @@ export class ChatService {
|
||||
|
||||
/**
|
||||
* Add semantically relevant context from a note based on a specific query
|
||||
*
|
||||
* @param sessionId - The ID of the chat session
|
||||
* @param noteId - The ID of the note to add context from
|
||||
* @param query - The specific query to find relevant information for
|
||||
* @returns The updated chat session
|
||||
*/
|
||||
async addSemanticNoteContext(sessionId: string, noteId: string, query: string): Promise<ChatSession> {
|
||||
const session = await this.getOrCreateSession(sessionId);
|
||||
@ -404,28 +409,27 @@ export class ChatService {
|
||||
};
|
||||
|
||||
session.messages.push(contextMessage);
|
||||
|
||||
|
||||
// Store the context note id and query in metadata
|
||||
const metadata = {
|
||||
contextNoteId: noteId
|
||||
};
|
||||
|
||||
|
||||
// Check if the semantic context extraction result has sources
|
||||
// Note: We're adding a defensive check since TypeScript doesn't know about this property
|
||||
const contextSources = (contextResult as any).sources || [];
|
||||
const contextSources = (contextResult as ContextExtractionResult).sources || [];
|
||||
if (contextSources && contextSources.length > 0) {
|
||||
// Convert the sources to the format expected by recordSources
|
||||
const sources = contextSources.map((source: any) => ({
|
||||
const sources = contextSources.map((source) => ({
|
||||
noteId: source.noteId,
|
||||
title: source.title,
|
||||
similarity: source.similarity,
|
||||
content: source.content
|
||||
content: source.content === null ? undefined : source.content
|
||||
}));
|
||||
|
||||
|
||||
// Store these sources in metadata
|
||||
await chatStorageService.recordSources(session.id, sources);
|
||||
}
|
||||
|
||||
|
||||
await chatStorageService.updateChat(session.id, session.messages, undefined, metadata);
|
||||
|
||||
return session;
|
||||
@ -456,7 +460,7 @@ export class ChatService {
|
||||
/**
|
||||
* Get pipeline performance metrics
|
||||
*/
|
||||
getPipelineMetrics(pipelineType: string = 'default'): any {
|
||||
getPipelineMetrics(pipelineType: string = 'default'): unknown {
|
||||
const pipeline = this.getPipeline(pipelineType);
|
||||
return pipeline.getMetrics();
|
||||
}
|
||||
@ -542,11 +546,21 @@ export class ChatService {
|
||||
|
||||
// If not using advanced context, use direct service call
|
||||
return await service.generateChatCompletion(messages, options);
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('Error in generateChatCompletion:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler utility
|
||||
*/
|
||||
private handleError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message || String(error);
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance
|
||||
|
@ -57,6 +57,16 @@ export class NoteNavigatorTool {
|
||||
private maxBreadth: number = SEARCH_CONSTANTS.HIERARCHY.MAX_BREADTH;
|
||||
private maxDepth: number = SEARCH_CONSTANTS.HIERARCHY.MAX_DEPTH;
|
||||
|
||||
/**
|
||||
* Error handler that properly types the error object
|
||||
*/
|
||||
private handleError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message || String(error);
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about a note
|
||||
*/
|
||||
@ -84,8 +94,8 @@ export class NoteNavigatorTool {
|
||||
attributeNames,
|
||||
hasChildren: note.children.length > 0
|
||||
};
|
||||
} catch (error: any) {
|
||||
log.error(`Error getting note info: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note info: ${this.handleError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -118,8 +128,8 @@ export class NoteNavigatorTool {
|
||||
notePathTitles: titles
|
||||
};
|
||||
}).sort((a, b) => a.notePath.length - b.notePath.length); // Sort by path length, shortest first
|
||||
} catch (error: any) {
|
||||
log.error(`Error getting note paths: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note paths: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -154,8 +164,8 @@ export class NoteNavigatorTool {
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
log.error(`Error getting note hierarchy: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note hierarchy: ${this.handleError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -185,7 +195,8 @@ export class NoteNavigatorTool {
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error in _getHierarchyLevel: ${this.handleError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -201,8 +212,8 @@ export class NoteNavigatorTool {
|
||||
}
|
||||
|
||||
return note.ownedAttributes;
|
||||
} catch (error: any) {
|
||||
log.error(`Error getting note attributes: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note attributes: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -280,8 +291,8 @@ export class NoteNavigatorTool {
|
||||
|
||||
// No path found
|
||||
return null;
|
||||
} catch (error: any) {
|
||||
log.error(`Error finding path between notes: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error finding path between notes: ${this.handleError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -312,8 +323,8 @@ export class NoteNavigatorTool {
|
||||
}
|
||||
|
||||
return results;
|
||||
} catch (error: any) {
|
||||
log.error(`Error searching notes by title: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error searching notes by title: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -338,8 +349,8 @@ export class NoteNavigatorTool {
|
||||
return parents
|
||||
.map(parent => this.getNoteInfo(parent.noteId))
|
||||
.filter((info): info is NoteInfo => info !== null);
|
||||
} catch (error: any) {
|
||||
log.error(`Error getting note clones: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note clones: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -429,8 +440,8 @@ export class NoteNavigatorTool {
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
log.error(`Error getting note context: ${error.message}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note context: ${this.handleError(error)}`);
|
||||
return "Error generating note context description.";
|
||||
}
|
||||
}
|
||||
@ -503,8 +514,8 @@ export class NoteNavigatorTool {
|
||||
attributes,
|
||||
parentPath
|
||||
};
|
||||
} catch (error) {
|
||||
log.error(`Error getting note structure: ${error}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note structure: ${this.handleError(error)}`);
|
||||
// Return a minimal structure with empty arrays to avoid null errors
|
||||
return {
|
||||
noteId,
|
||||
@ -534,8 +545,8 @@ export class NoteNavigatorTool {
|
||||
noteId: child.noteId,
|
||||
title: child.title
|
||||
}));
|
||||
} catch (error) {
|
||||
log.error(`Error getting child notes: ${error}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting child notes: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -555,8 +566,8 @@ export class NoteNavigatorTool {
|
||||
noteId: parent.noteId,
|
||||
title: parent.title
|
||||
}));
|
||||
} catch (error) {
|
||||
log.error(`Error getting parent notes: ${error}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting parent notes: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -613,8 +624,8 @@ export class NoteNavigatorTool {
|
||||
}
|
||||
|
||||
return [...outboundLinks, ...inboundLinks.slice(0, Math.floor(limit / 2))];
|
||||
} catch (error) {
|
||||
log.error(`Error getting linked notes: ${error}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting linked notes: ${this.handleError(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -629,8 +640,8 @@ export class NoteNavigatorTool {
|
||||
path.push(structure.title);
|
||||
|
||||
return path.join(' > ');
|
||||
} catch (error) {
|
||||
log.error(`Error getting note path: ${error}`);
|
||||
} catch (error: unknown) {
|
||||
log.error(`Error getting note path: ${this.handleError(error)}`);
|
||||
return 'Unknown path';
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export interface ToolCall {
|
||||
type?: string;
|
||||
function: {
|
||||
name: string;
|
||||
arguments: Record<string, any> | string;
|
||||
arguments: Record<string, unknown> | string;
|
||||
};
|
||||
}
|
||||
|
||||
@ -58,5 +58,5 @@ export interface ToolHandler {
|
||||
/**
|
||||
* Execute the tool with the given arguments
|
||||
*/
|
||||
execute(args: Record<string, any>): Promise<string | object>;
|
||||
execute(args: Record<string, unknown>): Promise<string | object>;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user