reduce the use of any, part 3

This commit is contained in:
perf3ct 2025-04-16 17:29:35 +00:00
parent 4601e3bfdb
commit 80ea2c3eef
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
4 changed files with 127 additions and 83 deletions

View File

@ -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,

View File

@ -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

View File

@ -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';
}
}

View File

@ -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>;
}