Files
Trilium/apps/server/src/services/llm/tools/read_note_tool.ts
T
2025-04-22 17:16:41 +03:00

122 lines
3.8 KiB
TypeScript

/**
* Read Note Tool
*
* This tool allows the LLM to read the content of a specific note.
*/
import type { Tool, ToolHandler } from './tool_interfaces.js';
import log from '../../log.js';
import becca from '../../../becca/becca.js';
// Define type for note response
interface NoteResponse {
noteId: string;
title: string;
type: string;
content: string | Buffer;
attributes?: Array<{
name: string;
value: string;
type: string;
}>;
}
// Error type guard
function isError(error: unknown): error is Error {
return error instanceof Error || (typeof error === 'object' &&
error !== null && 'message' in error);
}
/**
* Definition of the read note tool
*/
export const readNoteToolDefinition: Tool = {
type: 'function',
function: {
name: 'read_note',
description: 'Read the content of a specific note by its ID',
parameters: {
type: 'object',
properties: {
noteId: {
type: 'string',
description: 'The system ID of the note to read (not the title). This is a unique identifier like "abc123def456" that must be used to access a specific note.'
},
includeAttributes: {
type: 'boolean',
description: 'Whether to include note attributes in the response (default: false)'
}
},
required: ['noteId']
}
}
};
/**
* Read note tool implementation
*/
export class ReadNoteTool implements ToolHandler {
public definition: Tool = readNoteToolDefinition;
/**
* Execute the read note tool
*/
public async execute(args: { noteId: string, includeAttributes?: boolean }): Promise<string | object> {
try {
const { noteId, includeAttributes = false } = args;
log.info(`Executing read_note tool - NoteID: "${noteId}", IncludeAttributes: ${includeAttributes}`);
// Get the note from becca
const note = becca.notes[noteId];
if (!note) {
log.info(`Note with ID ${noteId} not found - returning error`);
return `Error: Note with ID ${noteId} not found`;
}
log.info(`Found note: "${note.title}" (Type: ${note.type})`);
// Get note content
const startTime = Date.now();
const content = await note.getContent();
const duration = Date.now() - startTime;
log.info(`Retrieved note content in ${duration}ms, content length: ${content?.length || 0} chars`);
// Prepare the response
const response: NoteResponse = {
noteId: note.noteId,
title: note.title,
type: note.type,
content: content || ''
};
// Include attributes if requested
if (includeAttributes) {
const attributes = note.getOwnedAttributes();
log.info(`Including ${attributes.length} attributes in response`);
response.attributes = attributes.map(attr => ({
name: attr.name,
value: attr.value,
type: attr.type
}));
if (attributes.length > 0) {
// Log some example attributes
attributes.slice(0, 3).forEach((attr, index) => {
log.info(`Attribute ${index + 1}: ${attr.name}=${attr.value} (${attr.type})`);
});
}
}
return response;
} catch (error: unknown) {
const errorMessage = isError(error) ? error.message : String(error);
log.error(`Error executing read_note tool: ${errorMessage}`);
return `Error: ${errorMessage}`;
}
}
}