diff --git a/src/services/llm/constants/hierarchy_constants.ts b/src/services/llm/constants/hierarchy_constants.ts new file mode 100644 index 000000000..0b577ee02 --- /dev/null +++ b/src/services/llm/constants/hierarchy_constants.ts @@ -0,0 +1,37 @@ +/** + * Hierarchy Context Constants + * + * This file centralizes all translatable strings used in the note hierarchy context + * functionality. These strings are used when displaying information about parent-child + * relationships and note relations in the LLM context building process. + */ + +import { t } from 'i18next'; + +export const HIERARCHY_STRINGS = { + // Parent context strings + PARENT_CONTEXT: { + NO_PARENT_CONTEXT: () => t('llm.hierarchy.no_parent_context', 'No parent context available.'), + CURRENT_NOTE: (title: string) => t('llm.hierarchy.current_note', '{{title}} (current note)', { title }), + }, + + // Child context strings + CHILD_CONTEXT: { + NO_CHILD_NOTES: () => t('llm.hierarchy.no_child_notes', 'No child notes.'), + CHILD_NOTES_HEADER: (count: number) => t('llm.hierarchy.child_notes_header', 'Child notes ({{count}} total)', { count }), + CHILD_SUMMARY_PREFIX: () => t('llm.hierarchy.child_summary_prefix', 'Summary: '), + MORE_CHILDREN: (count: number) => t('llm.hierarchy.more_children', '... and {{count}} more child notes not shown', { count }), + ERROR_RETRIEVING: () => t('llm.hierarchy.error_retrieving_children', 'Error retrieving child notes.') + }, + + // Linked notes context strings + LINKED_NOTES: { + NO_LINKED_NOTES: () => t('llm.hierarchy.no_linked_notes', 'No linked notes.'), + OUTGOING_RELATIONS_HEADER: (count: number) => t('llm.hierarchy.outgoing_relations_header', 'Outgoing relations ({{count}} total)', { count }), + INCOMING_RELATIONS_HEADER: (count: number) => t('llm.hierarchy.incoming_relations_header', 'Incoming relations ({{count}} total)', { count }), + DEFAULT_RELATION: () => t('llm.hierarchy.default_relation', 'relates to'), + MORE_OUTGOING: (count: number) => t('llm.hierarchy.more_outgoing', '... and {{count}} more outgoing relations not shown', { count }), + MORE_INCOMING: (count: number) => t('llm.hierarchy.more_incoming', '... and {{count}} more incoming relations not shown', { count }), + ERROR_RETRIEVING: () => t('llm.hierarchy.error_retrieving_linked', 'Error retrieving linked notes.') + } +}; diff --git a/src/services/llm/context/hierarchy.ts b/src/services/llm/context/hierarchy.ts index 08042e1fd..d2985b08c 100644 --- a/src/services/llm/context/hierarchy.ts +++ b/src/services/llm/context/hierarchy.ts @@ -1,5 +1,6 @@ import becca from '../../../becca/becca.js'; import { sanitizeHtmlContent } from './note_content.js'; +import { HIERARCHY_STRINGS } from '../constants/hierarchy_constants.js'; /** * Get a list of parent notes for a given note @@ -89,15 +90,15 @@ export async function getParentContext( if (context) { // If we have parent context, add the current note with proper indentation indentation = " ".repeat(1); // One level deeper than parents - context += `${indentation}> ${note.title} (current note)\n`; + context += `${indentation}> ${HIERARCHY_STRINGS.PARENT_CONTEXT.CURRENT_NOTE(note.title)}\n`; } else { // If no parents, just add the current note - context += `> ${note.title} (current note)\n`; + context += `> ${HIERARCHY_STRINGS.PARENT_CONTEXT.CURRENT_NOTE(note.title)}\n`; } } if (!context) { - return "No parent context available."; + return HIERARCHY_STRINGS.PARENT_CONTEXT.NO_PARENT_CONTEXT(); } return context; @@ -122,10 +123,10 @@ export async function getChildContext( const childNotes = note.getChildNotes(); if (!childNotes || childNotes.length === 0) { - return "No child notes."; + return HIERARCHY_STRINGS.CHILD_CONTEXT.NO_CHILD_NOTES(); } - let context = `Child notes (${childNotes.length} total):\n`; + let context = `${HIERARCHY_STRINGS.CHILD_CONTEXT.CHILD_NOTES_HEADER(childNotes.length)}\n`; // Limit the number of children included in context const limitedChildren = childNotes.slice(0, maxChildren); @@ -145,7 +146,7 @@ export async function getChildContext( .replace(/\n/g, ' '); if (truncatedContent) { - context += ` Summary: ${truncatedContent}${truncatedContent.length >= 100 ? '...' : ''}\n`; + context += ` ${HIERARCHY_STRINGS.CHILD_CONTEXT.CHILD_SUMMARY_PREFIX()}${truncatedContent}${truncatedContent.length >= 100 ? '...' : ''}\n`; } } catch (e) { // Silently skip content errors @@ -155,13 +156,13 @@ export async function getChildContext( // Add note about truncation if needed if (childNotes.length > maxChildren) { - context += `... and ${childNotes.length - maxChildren} more child notes not shown\n`; + context += `${HIERARCHY_STRINGS.CHILD_CONTEXT.MORE_CHILDREN(childNotes.length - maxChildren)}\n`; } return context; } catch (error) { console.error(`Error getting child context for ${noteId}:`, error); - return "Error retrieving child notes."; + return HIERARCHY_STRINGS.CHILD_CONTEXT.ERROR_RETRIEVING(); } } @@ -183,7 +184,7 @@ export async function getLinkedNotesContext( const relations = note.getRelations(); if (!relations || relations.length === 0) { - return "No linked notes."; + return HIERARCHY_STRINGS.LINKED_NOTES.NO_LINKED_NOTES(); } // Get incoming relations as well @@ -193,7 +194,7 @@ export async function getLinkedNotesContext( // Handle outgoing relations if (relations.length > 0) { - context += `Outgoing relations (${relations.length} total):\n`; + context += `${HIERARCHY_STRINGS.LINKED_NOTES.OUTGOING_RELATIONS_HEADER(relations.length)}\n`; // Limit the number of relations included in context const limitedRelations = relations.slice(0, maxRelations); @@ -201,14 +202,14 @@ export async function getLinkedNotesContext( for (const relation of limitedRelations) { const targetNote = becca.getNote(relation.value || ""); if (targetNote) { - const relationName = relation.name || 'relates to'; + const relationName = relation.name || HIERARCHY_STRINGS.LINKED_NOTES.DEFAULT_RELATION(); context += `- ${relationName} → ${targetNote.title}\n`; } } // Add note about truncation if needed if (relations.length > maxRelations) { - context += `... and ${relations.length - maxRelations} more outgoing relations not shown\n`; + context += `${HIERARCHY_STRINGS.LINKED_NOTES.MORE_OUTGOING(relations.length - maxRelations)}\n`; } } @@ -216,7 +217,7 @@ export async function getLinkedNotesContext( if (incomingRelations && incomingRelations.length > 0) { if (context) context += "\n"; - context += `Incoming relations (${incomingRelations.length} total):\n`; + context += `${HIERARCHY_STRINGS.LINKED_NOTES.INCOMING_RELATIONS_HEADER(incomingRelations.length)}\n`; // Limit the number of relations included in context const limitedIncoming = incomingRelations.slice(0, maxRelations); @@ -224,20 +225,20 @@ export async function getLinkedNotesContext( for (const relation of limitedIncoming) { const sourceNote = becca.getNote(relation.value || ""); if (sourceNote) { - const relationName = relation.name || 'relates to'; + const relationName = relation.name || HIERARCHY_STRINGS.LINKED_NOTES.DEFAULT_RELATION(); context += `- ${sourceNote.title} → ${relationName}\n`; } } // Add note about truncation if needed if (incomingRelations.length > maxRelations) { - context += `... and ${incomingRelations.length - maxRelations} more incoming relations not shown\n`; + context += `${HIERARCHY_STRINGS.LINKED_NOTES.MORE_INCOMING(incomingRelations.length - maxRelations)}\n`; } } - return context || "No linked notes."; + return context || HIERARCHY_STRINGS.LINKED_NOTES.NO_LINKED_NOTES(); } catch (error) { console.error(`Error getting linked notes context for ${noteId}:`, error); - return "Error retrieving linked notes."; + return HIERARCHY_STRINGS.LINKED_NOTES.ERROR_RETRIEVING(); } } diff --git a/translations/en/server.json b/translations/en/server.json index be6cb488d..a6c3d0dbb 100644 --- a/translations/en/server.json +++ b/translations/en/server.json @@ -196,6 +196,24 @@ "theme_group_light": "Light themes", "theme_group_dark": "Dark themes" }, + "llm": { + "hierarchy": { + "no_parent_context": "No parent context available.", + "current_note": "{{title}} (current note)", + "no_child_notes": "No child notes.", + "child_notes_header": "Child notes ({{count}} total)", + "child_summary_prefix": "Summary: ", + "more_children": "... and {{count}} more child notes not shown", + "error_retrieving_children": "Error retrieving child notes.", + "no_linked_notes": "No linked notes.", + "outgoing_relations_header": "Outgoing relations ({{count}} total)", + "incoming_relations_header": "Incoming relations ({{count}} total)", + "default_relation": "relates to", + "more_outgoing": "... and {{count}} more outgoing relations not shown", + "more_incoming": "... and {{count}} more incoming relations not shown", + "error_retrieving_linked": "Error retrieving linked notes." + } + }, "test_sync": { "not-configured": "Sync server host is not configured. Please configure sync first.", "successful": "Sync server handshake has been successful, sync has been started."