mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
refactor: replace ListVaultFiles with content-based SearchVaultFiles
Replace list_vault_files function with search_vault_files that performs regex-based content search instead of listing all files. Add escapeRegex helper for search term sanitization. Remove unused edit mode CSS.
This commit is contained in:
parent
92d3bc5a31
commit
f2a7a41705
9 changed files with 64 additions and 34 deletions
|
|
@ -1,11 +1,11 @@
|
|||
import type { IAIFunctionDefinition } from "./IAIFunctionDefinition";
|
||||
import { ListVaultFiles } from "./Functions/ListVaultFiles";
|
||||
import { SearchVaultFiles } from "./Functions/SearchVaultFiles";
|
||||
import { ReadFile } from "./Functions/ReadFile";
|
||||
|
||||
export class AIFunctionDefinitions {
|
||||
public getQueryActions(destructive: boolean): IAIFunctionDefinition[] {
|
||||
const actions = [
|
||||
ListVaultFiles,
|
||||
SearchVaultFiles,
|
||||
ReadFile
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
import { AIFunction } from "Enums/AIFunction";
|
||||
import type { IAIFunctionDefinition } from "../IAIFunctionDefinition";
|
||||
|
||||
export const ListVaultFiles: IAIFunctionDefinition = {
|
||||
name: AIFunction.ListVaultFiles,
|
||||
description: `Returns complete list of vault files with metadata (names, paths, sizes).
|
||||
Call this whenever you need to know what files exist in the vault to answer questions,
|
||||
verify file presence, or to perform further agentic functions. Use proactively
|
||||
when vault contents would inform your response.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
user_message: {
|
||||
type: "string",
|
||||
description: "A short message to be displayed to the user that explains the action being taken"
|
||||
}
|
||||
},
|
||||
required: ["user_message"]
|
||||
}
|
||||
}
|
||||
26
AIClasses/FunctionDefinitions/Functions/SearchVaultFiles.ts
Normal file
26
AIClasses/FunctionDefinitions/Functions/SearchVaultFiles.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { AIFunction } from "Enums/AIFunction";
|
||||
import type { IAIFunctionDefinition } from "../IAIFunctionDefinition";
|
||||
|
||||
export const SearchVaultFiles: IAIFunctionDefinition = {
|
||||
name: AIFunction.SearchVaultFiles,
|
||||
description: `Searches through all files in the user's Obsidian vault for the given search term.
|
||||
Uses regex pattern matching to search both file names and file content.
|
||||
Returns list of matching vault files with metadata (names, paths) and contextual snippets showing matched content with surrounding text.
|
||||
Call this whenever you need to know what files exist in the vault to answer questions,
|
||||
verify file presence, or to perform further agentic functions.
|
||||
Use proactively when vault contents would inform your response.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
search_term: {
|
||||
type: "string",
|
||||
description: "The regex pattern to search for in vault files. Supports both simple text (e.g., 'todo') and regex patterns (e.g., '(urgent|important)'). The search is performed on both file names and content."
|
||||
},
|
||||
user_message: {
|
||||
type: "string",
|
||||
description: "A short message to be displayed to the user that explains the action being taken"
|
||||
}
|
||||
},
|
||||
required: ["search_term", "user_message"]
|
||||
}
|
||||
}
|
||||
|
|
@ -300,11 +300,6 @@
|
|||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
#edit-mode-button.edit-mode {
|
||||
box-shadow: 0px 0px 1px 1px var(--color-blue);
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
#submit-button:not(:disabled):hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--interactive-accent-hover);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export enum AIFunction {
|
||||
ListVaultFiles = "list_vault_files",
|
||||
SearchVaultFiles = "search_vault_files",
|
||||
ReadFile = "read_file",
|
||||
|
||||
// used by gemini
|
||||
|
|
|
|||
|
|
@ -33,4 +33,8 @@ export function dateToString(date: Date, includeTime: boolean = true): string {
|
|||
day: '2-digit'
|
||||
}).replace(/[:\s]/g, '-');
|
||||
}
|
||||
}
|
||||
|
||||
export function escapeRegex(string: string): string {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
|
@ -12,8 +12,8 @@ export class AIFunctionService {
|
|||
|
||||
public async performAIFunction(functionCall: AIFunctionCall): Promise<AIFunctionResponse> {
|
||||
switch (functionCall.name) {
|
||||
case AIFunction.ListVaultFiles:
|
||||
return new AIFunctionResponse(functionCall.name, await this.listVaultFiles());
|
||||
case AIFunction.SearchVaultFiles:
|
||||
return new AIFunctionResponse(functionCall.name, await this.searchVaultFiles(functionCall.arguments.search_term));
|
||||
|
||||
case AIFunction.ReadFile:
|
||||
return new AIFunctionResponse(functionCall.name, await this.readFile(functionCall.arguments.file_path));
|
||||
|
|
@ -32,12 +32,11 @@ export class AIFunctionService {
|
|||
}
|
||||
}
|
||||
|
||||
private async listVaultFiles(): Promise<object> {
|
||||
const files: TFile[] = await this.fileSystemService.listFilesInDirectory("/");
|
||||
private async searchVaultFiles(searchTerm: string): Promise<object> {
|
||||
const files: TFile[] = await this.fileSystemService.searchVaultFiles(searchTerm);
|
||||
return files.map((file) => ({
|
||||
name: file.basename,
|
||||
path: file.path,
|
||||
size_bytes: file.stat.size
|
||||
path: file.path
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ export class FileSystemService {
|
|||
}
|
||||
}
|
||||
|
||||
public async searchVaultFiles(searchTerm: string): Promise<TFile[]> {
|
||||
return await this.vaultService.searchVaultFiles(searchTerm);
|
||||
}
|
||||
|
||||
private async createDirectories(vaultService: VaultService, filePath: string, allowAccessToPluginRoot: boolean = false) {
|
||||
const dirPath: string = filePath.substring(0, filePath.lastIndexOf('/'));
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Resolve } from "./DependencyService";
|
|||
import { Services } from "./Services";
|
||||
import type AIAgentPlugin from "main";
|
||||
import { Path } from "Enums/Path";
|
||||
import { escapeRegex } from "Helpers/Helpers";
|
||||
|
||||
/* This service protects the users vault through their exclusions. The plugin root is excluded by default */
|
||||
export class VaultService {
|
||||
|
|
@ -90,6 +91,27 @@ export class VaultService {
|
|||
return files.filter(file => !this.isExclusion(file.path, allowAccessToPluginRoot));
|
||||
}
|
||||
|
||||
public async searchVaultFiles(searchTerm: string): Promise<TFile[]> {
|
||||
let regex: RegExp;
|
||||
try {
|
||||
regex = new RegExp(searchTerm, "i");
|
||||
} catch {
|
||||
regex = new RegExp(escapeRegex(searchTerm), "i");
|
||||
}
|
||||
|
||||
const files: TFile[] = this.vault.getFiles().filter(file => !this.isExclusion(file.path));
|
||||
|
||||
const matches: TFile[] = [];
|
||||
for (const file of files) {
|
||||
const content = await this.vault.cachedRead(file);
|
||||
if (regex.test(content)) {
|
||||
matches.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private isExclusion(filePath: string, allowAccessToPluginRoot: boolean = false): boolean {
|
||||
// the ai should never be able to edit the user instruction
|
||||
const exclusions = allowAccessToPluginRoot
|
||||
|
|
|
|||
Loading…
Reference in a new issue