diff --git a/AIClasses/Claude/Claude.ts b/AIClasses/Claude/Claude.ts index 9acc56a..4b4d427 100644 --- a/AIClasses/Claude/Claude.ts +++ b/AIClasses/Claude/Claude.ts @@ -175,12 +175,20 @@ export class Claude implements IAIClass { if (isValidJson(content.functionCall)) { try { const parsedContent = JSON.parse(content.functionCall) as StoredFunctionCall; - contentBlocks.push({ - type: "tool_use", - id: parsedContent.functionCall.id, - name: parsedContent.functionCall.name, - input: parsedContent.functionCall.args - }); + + if (parsedContent.functionCall.id && parsedContent.functionCall.id.trim() !== "") { + contentBlocks.push({ + type: "tool_use", + id: parsedContent.functionCall.id, + name: parsedContent.functionCall.name, + input: parsedContent.functionCall.args + }); + } else { + contentBlocks.push({ + type: "text", + text: this.convertFunctionCallToText(parsedContent) + }); + } } catch (error) { console.error("Failed to parse function call:", error); // Fall back to treating as text @@ -208,11 +216,19 @@ export class Claude implements IAIClass { if (isValidJson(contentToExtract)) { try { const parsedContent = JSON.parse(contentToExtract) as StoredFunctionResponse; - contentBlocks.push({ - type: "tool_result", - tool_use_id: parsedContent.id, - content: JSON.stringify(parsedContent.functionResponse.response) - }); + + if (parsedContent.id && parsedContent.id.trim() !== "") { + contentBlocks.push({ + type: "tool_result", + tool_use_id: parsedContent.id, + content: JSON.stringify(parsedContent.functionResponse.response) + }); + } else { + contentBlocks.push({ + type: "text", + text: this.convertFunctionResponseToText(parsedContent) + }); + } } catch (error) { console.error("Failed to parse function response:", error); contentBlocks.push({ @@ -248,4 +264,19 @@ export class Claude implements IAIClass { } })); } + + /* + If a conversation used another provider it may not have function id's required by Claude. + Instead provide the function call and response as plain text to preserve context without breaking. + */ + + private convertFunctionCallToText(parsedContent: StoredFunctionCall): string { + const inputJson = JSON.stringify(parsedContent.functionCall.args); + return `[Legacy Tool Call] ${parsedContent.functionCall.name}\nInput: ${inputJson}`; + } + + private convertFunctionResponseToText(parsedContent: StoredFunctionResponse): string { + const resultJson = JSON.stringify(parsedContent.functionResponse.response); + return `[Legacy Tool Result] ${parsedContent.functionResponse.name}\nResult: ${resultJson}`; + } } diff --git a/AIClasses/SystemPrompt.ts b/AIClasses/SystemPrompt.ts index b522d9f..9a92bb1 100644 --- a/AIClasses/SystemPrompt.ts +++ b/AIClasses/SystemPrompt.ts @@ -26,6 +26,34 @@ Examples: **The cost of an unnecessary search is negligible. Missing relevant information is costly.** +**Regex Pattern Matching - POWERFUL PRIMARY TOOL** +Regex is your most versatile search capability. Use it aggressively and creatively: + + +- **Case-insensitive partial matching**: \`/maui/i\` finds MAUI, Maui, maui anywhere +- **Word boundary patterns**: \`/\bmaui\b/i\` matches whole words only +- **Prefix/suffix patterns**: \`/maui.*dev/i\` or \`/.*mobile.*app.*/i\` +- **Alternative spellings**: \`/gr(a|e)y/i\` matches gray or grey +- **Optional characters**: \`/dockers?/i\` matches docker or dockers +- **Wildcard sequences**: \`/proj.*alpha/i\` matches "project alpha", "proj_alpha", etc. +- **Multiple alternatives**: \`/(kubernetes|k8s|kube)/i\` catches all variations +- **Character classes**: \`/[Dd]ocker/\` for case variations +- **Numeric patterns**: \`/vd+.d+/\` for version numbers like v1.2 + + +When to deploy regex (use frequently): +1. **Initial search fails** → Immediately try regex pattern +2. **Abbreviations likely** → Search both full term and abbreviated pattern +3. **Multiple spellings** → Use alternation patterns +4. **Partial name known** → Use wildcard matching +5. **Version/date references** → Use numeric patterns +6. **Technical terms** → Search with common abbreviations + +Example workflow: +- Search "kubernetes" fails → Try \`/k8s|kubernetes|kube/i\` +- Search "Docker" fails → Try \`/docker.*/i\` to catch "Docker-compose", "Dockerfile" +- Search "Project Alpha" fails → Try \`/proj.*alpha/i\` for flexible matching + #### IMMEDIATE VAULT SEARCH Required When: - Query contains definite articles suggesting specific reference ("the project", "the prices", "the data") - Query uses possessive pronouns ("my ideas", "our plans", "my notes about") @@ -48,6 +76,8 @@ Acknowledge the search, then provide general assistance: **NEVER accept a failed search as final. Always try multiple approaches before concluding information doesn't exist.** +#### Multi-Tier Search Approach + When searching the vault, use a progressive strategy that automatically escalates: **Tier 1: Entity Extraction & Broad Search** @@ -74,44 +104,73 @@ When searching the vault, use a progressive strategy that automatically escalate ## Multi-Tool Workflow Architecture -### Planning Phase (for complex queries) -Establish a clear execution strategy: +### Planning Phase (Essential for Complex Queries) -1. **Intent Analysis**: Determine query scope and required information depth -2. **Tool Selection**: Identify which search approaches are needed -3. **Search Strategy Design**: Plan progressive search tiers and fallbacks -4. **Execution Order**: Sequence operations for optimal information gathering +Modern agentic AI systems succeed through orchestrated multi-step workflows where tasks are decomposed into subgoals, with each step building on the previous one. Before executing any complex query: + +1. **Intent Analysis**: Determine scope, depth, and complexity level +2. **Query Decomposition**: Break into searchable components +3. **Strategy Design**: Plan search progression (entity → regex → domain → relationships) +4. **Tool Selection**: Identify which searches need regex, which need domain expansion +5. **Execution Sequence**: Order operations for optimal information flow +6. **Success Criteria**: Define what "complete" looks like + +**Key Principle**: Agents that plan multi-step workflows autonomously before executing outperform those using single-step approaches. ### Execution Phase -Execute with adaptive intelligence: -1. **Initial Broad Search**: Start with core entities extracted from query -2. **Progressive Refinement**: Apply Tier 1 → Tier 2 → Tier 3 → Tier 4 as needed -3. **Dynamic Evaluation**: After each result, reason about next action -4. **Cross-Reference**: Look for connections between different information sources +Execute systematically with adaptive intelligence: + +1. **Entity Extraction**: Extract core entities, remove query noise +2. **Initial Search**: Broad search with clean entities +3. **Regex Deployment**: If initial search weak, immediately apply regex patterns +4. **Domain Expansion**: Apply knowledge for related concepts (search with regex alternations) +5. **Relationship Inference**: Read found content, infer connections +6. **Cross-Reference**: Link findings, identify patterns +7. **Adaptive Strategy**: Evaluate after each step, adjust approach as needed + + +**Regex Usage Throughout Execution:** +- After any failed exact match → Deploy regex pattern immediately +- When searching tech terms → Include abbreviation patterns from start +- For people/project names → Use flexible matching patterns +- With version numbers → Use numeric patterns +- When multiple spellings possible → Use alternation patterns + +Example execution with regex: +1. Search "docker" → Limited results +2. Immediately search \`/docker.*/i\` → Finds "Docker-compose", "Dockerfile", "docker-notes" +3. Search \`/container|docker|k8s/i\` → Domain expansion with regex +4. Success: Comprehensive results through regex flexibility + ### Synthesis Phase -Aggregate findings and construct response: + +Integrate all findings into cohesive response: 1. **Information Integration**: Combine results from all search attempts -2. **Relationship Mapping**: Identify connections between different sources -3. **Wiki-Link Application**: Link ALL vault references in final response -4. **Gap Identification**: Suggest missing connections or new notes when appropriate +2. **Relationship Mapping**: Identify connections between sources +3. **Universal Wiki-Linking**: Apply [[wiki-links]] to ALL vault references +4. **Gap Identification**: Note missing connections or suggest new notes +5. **Structured Response**: Present findings clearly with proper [[wiki-links]] -### Workflow Scaling Guidelines -**Simple queries** (1 search): Direct factual lookups with clear, single source -**Moderate queries** (2-4 searches): Comparisons, validations, or multi-source synthesis -**Complex queries** (5-10 searches): Comprehensive research requiring multiple angles -**Deep research** (10+ searches): Extensive cross-domain synthesis with relationship mapping +### Workflow Scaling by Complexity -## Query Decomposition Strategy +**Simple (1-3 operations)**: Direct lookup + optional regex +- "What did I write about React?" +- Entity extraction → Search → Done -Transform complex queries into actionable search components: -- "Who is X's Y?" → Search X first, infer Y from context in found content -- "Compare X and Y" → Search X, search Y, then synthesize findings -- "What did I learn about X?" → Search X + related tags + check backlinks +**Moderate (4-7 operations)**: Multiple searches with regex and domain expansion +- "Find all my notes about Docker and Kubernetes" +- Search "docker" → Regex \`/docker.*/i\` → Domain search "container" → Regex \`/k8s|kubernetes/i\` → Cross-reference -**Critical**: Extract key entities and search broadly first. Never search exact literal phrases. +**Complex (8-15 operations)**: Full multi-step planning with progressive strategy +- "Compare my approaches to microservices vs monoliths and relate to current projects" +- Plan: 5-step strategy → Execute: Search microservices (regex) → Search monoliths (regex) → Search projects (directory) → Read each → Infer relationships → Synthesize + +**Research-Grade (15+ operations)**: Comprehensive analysis across vault +- "Create a comprehensive overview of my learning journey in machine learning" +- Full planning framework → Systematic search across tags, dates, topics → Regex patterns for all variations → Deep synthesis with temporal analysis ## Core Capabilities diff --git a/Enums/Copy.ts b/Enums/Copy.ts index 52e37b4..8d69cd8 100644 --- a/Enums/Copy.ts +++ b/Enums/Copy.ts @@ -199,6 +199,9 @@ Each AI provider has their own data policies: - [Google (Gemini)](https://policies.google.com/privacy) - [OpenAI (ChatGPT)](https://openai.com/privacy/)`, + // Conversation Modal Copy + NoConversationsFound = "No conversations match your search.", + // Help Modal Additional Copy HelpModalCloseAriaLabel = "Close Help Modal", PluginVersionPrefix = "Plugin version: ", diff --git a/Modals/ConversationHistoryModal.ts b/Modals/ConversationHistoryModal.ts index 0033cd5..715d0cd 100644 --- a/Modals/ConversationHistoryModal.ts +++ b/Modals/ConversationHistoryModal.ts @@ -37,31 +37,27 @@ export class ConversationHistoryModal extends Modal { super(plugin.app); } - private async loadConversations() { + onOpen() { + void this.initializeContent(); + } + + private async initializeContent() { this.conversations = await this.conversationFileSystemService.getAllConversations(); this.items = this.conversations - .sort((a, b) => b.updated.getTime() - a.updated.getTime()) - .map((conversation) => { - const filePath = this.conversationFileSystemService.generateConversationPath(conversation); - return { - id: filePath, - date: dateToString(conversation.created, false), - updated: conversation.updated, - title: conversation.title, - selected: false, - filePath: filePath - }; - }); + .sort((a, b) => b.updated.getTime() - a.updated.getTime()) + .map((conversation) => { + const filePath = this.conversationFileSystemService.generateConversationPath(conversation); + return { + id: filePath, + date: dateToString(conversation.created, false), + updated: conversation.updated, + title: conversation.title, + selected: false, + filePath: filePath + }; + }); - // Update the component with loaded items if it's already mounted - if (this.component) { - this.component.items = this.items; - } - } - - onOpen() { - void this.loadConversations(); const { contentEl, modalEl, containerEl } = this; containerEl.addClass(Selector.ConversationHistoryModal); diff --git a/Modals/ConversationHistoryModalSvelte.svelte b/Modals/ConversationHistoryModalSvelte.svelte index 305b72a..5f45492 100644 --- a/Modals/ConversationHistoryModalSvelte.svelte +++ b/Modals/ConversationHistoryModalSvelte.svelte @@ -1,4 +1,5 @@