diff --git a/apps/server/src/services/llm/pipeline/stages/tool_calling_stage.ts b/apps/server/src/services/llm/pipeline/stages/tool_calling_stage.ts index a2eaa00fb..86bad8066 100644 --- a/apps/server/src/services/llm/pipeline/stages/tool_calling_stage.ts +++ b/apps/server/src/services/llm/pipeline/stages/tool_calling_stage.ts @@ -490,43 +490,9 @@ export class ToolCallingStage extends BasePipelineStage this.isEmptyToolResult(msg.content, msg.name || '')) - .map(msg => msg.name); - - directiveMessage = `CRITICAL INSTRUCTION: YOU MUST NOT STOP AFTER EMPTY RESULTS!\n\n`; - directiveMessage += `REQUIRED ACTIONS:\n`; - - if (emptyToolNames.includes('search_notes')) { - directiveMessage += `1. IMMEDIATELY use keyword_search_notes with specific terms\n`; - directiveMessage += `2. Try attribute_search if content might be tagged/categorized\n`; - directiveMessage += `3. Use discover_tools to find alternative approaches\n`; - } - - if (emptyToolNames.includes('keyword_search_notes')) { - directiveMessage += `1. IMMEDIATELY use search_notes for semantic matching\n`; - directiveMessage += `2. Try broader or alternative keyword terms\n`; - directiveMessage += `3. Use workflow_helper for guidance on next steps\n`; - } - - if (emptyToolNames.includes('attribute_search')) { - directiveMessage += `1. Use search_notes to find content about the attribute topic\n`; - directiveMessage += `2. Try different attribute names or types\n`; - directiveMessage += `3. Use search_suggestion to see available attributes\n`; - } - - directiveMessage += `\nFORBIDDEN: Do NOT ask user for clarification or offer general information!\n`; - directiveMessage += `REQUIRED: CONTINUE with alternative tools and approaches immediately!`; + directiveMessage = `No results found. Try alternative search approaches: use different search tools, broader terms, or alternative keywords. Continue searching - don't ask the user for guidance.`; } else { - // Has results - encourage follow-up actions - directiveMessage = `EXCELLENT! You found results. Now CONTINUE the workflow:\n\n`; - directiveMessage += `NEXT REQUIRED ACTIONS:\n`; - directiveMessage += `1. Use read_note to examine the most relevant results\n`; - directiveMessage += `2. Use workflow_helper to plan next steps based on your findings\n`; - directiveMessage += `3. Consider using related tools for deeper analysis\n\n`; - directiveMessage += `GOAL: Provide comprehensive information by using multiple tools in sequence.\n`; - directiveMessage += `CONTINUE with tool usage - don't stop at just search results!`; + directiveMessage = `You found results! Use read_note with the noteId values to get full content and continue your analysis.`; } updatedMessages.push({ @@ -638,14 +604,8 @@ export class ToolCallingStage extends BasePipelineStage 0 ? suggestions.join('\n') : ''} - -EXAMPLES: -• Find notes with #important tag: { "attributeType": "label", "attributeName": "important" } -• Find notes with ~relatedTo relation: { "attributeType": "relation", "attributeName": "relatedTo" }`; + const errorMessage = `Invalid attributeType: "${attributeType}". Must be exactly "label" or "relation" (lowercase). Example: {"attributeType": "label", "attributeName": "important"}`; return errorMessage; } diff --git a/apps/server/src/services/llm/tools/keyword_search_tool.ts b/apps/server/src/services/llm/tools/keyword_search_tool.ts index d32f87303..f27b3a17b 100644 --- a/apps/server/src/services/llm/tools/keyword_search_tool.ts +++ b/apps/server/src/services/llm/tools/keyword_search_tool.ts @@ -17,41 +17,13 @@ export const keywordSearchToolDefinition: Tool = { type: 'function', function: { name: 'keyword_search_notes', - description: `EXACT KEYWORD search for notes. Finds notes containing specific words, phrases, or attribute filters. - - BEST FOR: Finding notes with specific words/phrases you know exist - USE WHEN: You need exact text matches, specific terms, or attribute-based filtering - DIFFERENT FROM: search_notes (which finds conceptual/semantic matches) - - SEARCH TYPES: - • Simple: "machine learning" (finds notes containing both words) - • Phrase: "\"exact phrase\"" (finds this exact phrase) - • Attributes: "#label" or "~relation" (notes with specific labels/relations) - • Complex: "AI #project ~relatedTo" (combines keywords with attributes) - - NEXT STEPS: Use read_note with returned noteId values for full content`, + description: 'Keyword search for exact text matches. Supports phrases in quotes, #labels, ~relations, and search operators like OR.', parameters: { type: 'object', properties: { query: { type: 'string', - description: `Keyword search query using Trilium search syntax. - - SIMPLE EXAMPLES: - - "machine learning" (both words anywhere) - - "\"project management\"" (exact phrase) - - "python OR javascript" (either word) - - ATTRIBUTE EXAMPLES: - - "#important" (notes with 'important' label) - - "~project" (notes with 'project' relation) - - "#status = completed" (specific label value) - - COMBINED EXAMPLES: - - "AI #project #status = active" (AI content with project label and active status) - - "note.title *= \"weekly\"" (titles containing 'weekly') - - AVOID: Conceptual queries better suited for search_notes` + description: 'Search query. Examples: "machine learning", "#important", "python OR javascript", "note.title *= weekly"' }, maxResults: { type: 'number', @@ -59,7 +31,7 @@ export const keywordSearchToolDefinition: Tool = { }, includeArchived: { type: 'boolean', - description: 'INCLUDE ARCHIVED: Search archived notes too (default: false). Use true for complete historical search.' + description: 'Include archived notes in search (default: false).' } }, required: ['query'] @@ -130,21 +102,7 @@ export class KeywordSearchTool implements ToolHandler { count: 0, results: [], query: query, - searchType: 'keyword', - message: 'No exact keyword matches found.', - nextSteps: { - immediate: [ - `Try search_notes for semantic/conceptual search: "${this.convertToSemanticQuery(query)}"`, - `Use attribute_search if looking for specific labels or relations`, - `Try simpler keywords or check spelling` - ], - queryHelp: [ - 'Remove quotes for broader matching', - 'Try individual words instead of phrases', - 'Use OR operator: "word1 OR word2"', - 'Check if content might be in archived notes (set includeArchived: true)' - ] - } + message: `No keyword matches. Try: search_notes with "${this.convertToSemanticQuery(query)}" or check spelling/try simpler terms.` }; } @@ -153,12 +111,7 @@ export class KeywordSearchTool implements ToolHandler { totalFound: searchResults.length, query: query, searchType: 'keyword', - message: 'Found exact keyword matches. Use noteId values with other tools.', - nextSteps: { - examine: `Use read_note with any noteId (e.g., "${limitedResults[0].noteId}") to get full content`, - refine: limitedResults.length < searchResults.length ? `Found ${searchResults.length} total matches (showing ${limitedResults.length}). Increase maxResults for more.` : null, - related: 'Use search_notes for conceptually related content beyond exact keywords' - }, + message: `Found ${limitedResults.length} keyword matches. Use read_note with noteId for full content.`, results: limitedResults.map(note => { // Get a preview of the note content with highlighted search terms let contentPreview = ''; diff --git a/apps/server/src/services/llm/tools/read_note_tool.ts b/apps/server/src/services/llm/tools/read_note_tool.ts index ddb8ce589..98dd4bd5f 100644 --- a/apps/server/src/services/llm/tools/read_note_tool.ts +++ b/apps/server/src/services/llm/tools/read_note_tool.ts @@ -34,37 +34,17 @@ export const readNoteToolDefinition: Tool = { type: 'function', function: { name: 'read_note', - description: `READ FULL CONTENT of a specific note by its ID. Get complete note content and metadata. - - BEST FOR: Getting complete content after finding notes through search tools - USE WHEN: You have a noteId from search results and need the full content - IMPORTANT: Must use noteId (like "abc123def456") from search results - NOT note titles - - TIP: This is typically used after search_notes, keyword_search_notes, or attribute_search - - NEXT STEPS: Use note_update or attribute_manager tools to modify the note if needed`, + description: 'Read the full content of a note by its ID. Use noteId from search results, not note titles.', parameters: { type: 'object', properties: { noteId: { type: 'string', - description: `SYSTEM ID of the note to read. - - CRITICAL: Must be a noteId (like "abc123def456") - NOT a note title! - - CORRECT: "abc123def456" (from search results) - WRONG: "My Note Title" (this will fail) - - WHERE TO GET: From noteId field in search tool results` + description: 'The noteId of the note to read (e.g., "abc123def456"). Get this from search results, not note titles.' }, includeAttributes: { type: 'boolean', - description: `INCLUDE METADATA: Get note attributes (labels, relations) in response. - - • true = Get full note with all attributes/metadata - • false = Get just note content (default) - - Use true when you need to see tags, labels, relations, or other metadata` + description: 'Include note attributes/metadata in response (default: false).' } }, required: ['noteId'] diff --git a/apps/server/src/services/llm/tools/search_notes_tool.ts b/apps/server/src/services/llm/tools/search_notes_tool.ts index 5da23b728..f943daae5 100644 --- a/apps/server/src/services/llm/tools/search_notes_tool.ts +++ b/apps/server/src/services/llm/tools/search_notes_tool.ts @@ -17,50 +17,25 @@ export const searchNotesToolDefinition: Tool = { type: 'function', function: { name: 'search_notes', - description: `SEMANTIC/CONCEPTUAL search for notes. Finds notes related to concepts, topics, or themes even without exact keyword matches. - - BEST FOR: Finding notes about ideas, concepts, or topics described in various ways - USE WHEN: Looking for conceptual relationships, thematic content, or related ideas - DIFFERENT FROM: keyword_search (which finds exact text matches) - - TIPS: - - Use descriptive phrases like "project management methodologies" rather than single words - - Think conceptually: "machine learning classification" vs just "ML" - - Results include noteId values - ALWAYS use these IDs (not titles) with other tools - - NEXT STEPS: Use read_note with returned noteId values to get full content`, + description: 'Semantic search for notes. Finds conceptually related content. Use descriptive phrases, not single words. Returns noteId values to use with other tools.', parameters: { type: 'object', properties: { query: { type: 'string', - description: `Descriptive search query for semantic matching. - - GOOD EXAMPLES: - - "machine learning algorithms for classification" - - "personal productivity and time management techniques" - - "software development best practices" - - AVOID: - - Single words: "ML", "productivity" - - Overly broad: "work", "notes" - - Overly specific: exact phrases that might not exist` + description: 'Search query for finding conceptually related notes. Use descriptive phrases like "machine learning classification" rather than single words.' }, parentNoteId: { type: 'string', - description: `SCOPE LIMITER: Search only within children of this note. - - IMPORTANT: Must be a noteId (like "abc123def456") from previous search results - NOT a note title. - - USE FOR: Searching within specific projects, categories, or sections.` + description: 'Optional noteId to limit search to children of this note. Must be a noteId from search results, not a title.' }, maxResults: { type: 'number', - description: 'Number of results (1-20, default: 5). Use 10-15 for comprehensive exploration, 3-5 for quick lookup.' + description: 'Maximum number of results to return (default: 5, max: 20).' }, summarize: { type: 'boolean', - description: 'AI SUMMARIES: Get intelligent summaries instead of truncated text (default: false). Use true for cleaner result overview.' + description: 'Get AI-generated summaries instead of truncated previews (default: false).' } }, required: ['query'] @@ -324,33 +299,14 @@ export class SearchNotesTool implements ToolHandler { count: 0, results: [], query: query, - searchType: 'semantic', - message: 'No semantic matches found for your query.', - nextSteps: { - immediate: [ - `Try keyword_search with specific terms: "${this.extractKeywords(query)}"`, - `Use attribute_search if looking for labeled/categorized notes`, - `Try broader search terms like "${this.suggestBroaderTerms(query)}"` - ], - tips: [ - 'Semantic search finds conceptual matches - try describing the topic differently', - 'If you know specific words that appear in the notes, use keyword_search instead', - 'Check if the content might be tagged with labels using attribute_search' - ] - } + message: `No results found. Try: keyword_search_notes with "${this.extractKeywords(query)}" or attribute_search for tagged notes.` }; } else { return { count: enhancedResults.length, results: enhancedResults, query: query, - searchType: 'semantic', - message: 'Found semantic matches. Use noteId values with other tools.', - nextSteps: { - examine: `Use read_note with any noteId (e.g., "${enhancedResults[0].noteId}") to get full content`, - refine: parentNoteId ? 'Remove parentNoteId to search all notes' : `Add parentNoteId: "${enhancedResults[0].noteId}" to search within the first result's children`, - related: 'Search for related concepts or use different descriptive terms' - } + message: `Found ${enhancedResults.length} matches. Use read_note with noteId to get full content.` }; } } catch (error: unknown) { diff --git a/apps/server/src/services/llm/tools/tool_discovery_helper.ts b/apps/server/src/services/llm/tools/tool_discovery_helper.ts index 530bcb977..384a0e8bb 100644 --- a/apps/server/src/services/llm/tools/tool_discovery_helper.ts +++ b/apps/server/src/services/llm/tools/tool_discovery_helper.ts @@ -16,37 +16,21 @@ export const toolDiscoveryHelperDefinition: Tool = { type: 'function', function: { name: 'discover_tools', - description: `DISCOVER AVAILABLE TOOLS and get guidance on which tools to use for your task. - - BEST FOR: Understanding what tools are available and getting usage recommendations - USE WHEN: You're unsure which tool to use, want to see all options, or need workflow guidance - HELPS WITH: Tool selection, parameter guidance, workflow planning - - TIP: Use this when you have a task but aren't sure which tools can help accomplish it - - NEXT STEPS: Use the recommended tools based on the guidance provided`, + description: 'Get recommendations for which tools to use for your task. Helps when you\'re unsure which tool is best.', parameters: { type: 'object', properties: { taskDescription: { type: 'string', - description: `📝 DESCRIBE YOUR TASK: What are you trying to accomplish? - - ✅ GOOD EXAMPLES: - - "Find notes about machine learning" - - "Create a new project planning note" - - "Find all notes tagged as important" - - "Read the content of a specific note" - - 💡 Be specific about your goal for better tool recommendations` + description: 'Describe what you want to accomplish (e.g., "find notes about machine learning", "read a specific note").' }, includeExamples: { type: 'boolean', - description: 'INCLUDE EXAMPLES: Get specific usage examples for recommended tools (default: true)' + description: 'Include usage examples for recommended tools (default: true).' }, showAllTools: { type: 'boolean', - description: 'SHOW ALL TOOLS: List all available tools, not just recommended ones (default: false)' + description: 'Show all available tools instead of just recommendations (default: false).' } }, required: ['taskDescription'] diff --git a/apps/server/src/services/llm/tools/tool_initializer.ts b/apps/server/src/services/llm/tools/tool_initializer.ts index 2245470d1..304a71ef6 100644 --- a/apps/server/src/services/llm/tools/tool_initializer.ts +++ b/apps/server/src/services/llm/tools/tool_initializer.ts @@ -18,7 +18,6 @@ import { AttributeManagerTool } from './attribute_manager_tool.js'; import { CalendarIntegrationTool } from './calendar_integration_tool.js'; import { NoteSummarizationTool } from './note_summarization_tool.js'; import { ToolDiscoveryHelper } from './tool_discovery_helper.js'; -import { WorkflowHelper } from './workflow_helper.js'; import log from '../../log.js'; // Error type guard @@ -54,9 +53,8 @@ export async function initializeTools(): Promise { toolRegistry.registerTool(new ContentExtractionTool()); // Extract info from note content toolRegistry.registerTool(new CalendarIntegrationTool()); // Calendar-related operations - // Register helper and guidance tools + // Register helper tools (simplified) toolRegistry.registerTool(new ToolDiscoveryHelper()); // Tool discovery and usage guidance - toolRegistry.registerTool(new WorkflowHelper()); // Multi-step workflow guidance // Log registered tools const toolCount = toolRegistry.getAllTools().length;