Sprint 0-2: TS plugin scaffolding, LanceDB utils, tooling updates
- Add index-tool.ts command implementation - Wire lancedb.ts vector search into plugin - Update src/tools/index.ts exports - Bump package deps (ts-jest, jest, typescript, lancedb) - Add .claude/settings.local.json Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,118 @@
|
||||
/** Tool registration — wires all 4 obsidian_rag_* tools into OpenClaw. */
|
||||
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
||||
import type { ObsidianRagConfig } from "../utils/config.js";
|
||||
import type { HealthState } from "../services/health.js";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { searchTool, type SearchParams } from "./search.js";
|
||||
import { runIndexTool, type IndexParams } from "./index-tool.js";
|
||||
import { statusTool } from "./status.js";
|
||||
import { memoryStoreTool, type MemoryStoreParams } from "./memory.js";
|
||||
|
||||
export async function registerTools(
|
||||
_config: ObsidianRagConfig,
|
||||
_health: { get: () => { state: HealthState } },
|
||||
): Promise<void> {
|
||||
// TODO: Wire into OpenClaw tool registry once SDK is available
|
||||
console.log("[obsidian-rag] Tools registered (stub — OpenClaw SDK TBD)");
|
||||
function textEnvelope<T>(text: string, details: T): AgentToolResult<T> {
|
||||
return { content: [{ type: "text", text }], details };
|
||||
}
|
||||
|
||||
export function registerTools(
|
||||
api: OpenClawPluginApi,
|
||||
config: ObsidianRagConfig,
|
||||
health: { get: () => { state: HealthState }; setActiveJob: (job: { id: string; mode: string; progress: number } | null) => void },
|
||||
): void {
|
||||
// obsidian_rag_search — primary semantic search
|
||||
api.registerTool({
|
||||
name: "obsidian_rag_search",
|
||||
description:
|
||||
"Primary semantic search tool. Given a natural language query, searches the Obsidian vault index and returns the most relevant note chunks ranked by semantic similarity. Supports filtering by directory, date range, and tags.",
|
||||
label: "Search Obsidian Vault",
|
||||
parameters: Type.Object({
|
||||
query: Type.String({ description: "Natural language question or topic to search for" }),
|
||||
max_results: Type.Optional(
|
||||
Type.Number({ minimum: 1, maximum: 50, description: "Maximum number of chunks to return" }),
|
||||
),
|
||||
directory_filter: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description: "Limit search to specific vault subdirectories (e.g. ['Journal', 'Finance'])",
|
||||
}),
|
||||
),
|
||||
date_range: Type.Optional(
|
||||
Type.Object({
|
||||
from: Type.Optional(Type.String({ description: "Start date (YYYY-MM-DD)" })),
|
||||
to: Type.Optional(Type.String({ description: "End date (YYYY-MM-DD)" })),
|
||||
}),
|
||||
),
|
||||
tags: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description: "Filter by hashtags found in notes (e.g. ['#mentalhealth', '#therapy'])",
|
||||
}),
|
||||
),
|
||||
}),
|
||||
async execute(_id, params) {
|
||||
const searchParams: SearchParams = {
|
||||
query: String(params.query),
|
||||
max_results: params.max_results != null ? Number(params.max_results) : undefined,
|
||||
directory_filter: params.directory_filter as string[] | undefined,
|
||||
date_range: params.date_range as { from?: string; to?: string } | undefined,
|
||||
tags: params.tags as string[] | undefined,
|
||||
};
|
||||
const result = await searchTool(config, searchParams);
|
||||
return textEnvelope(JSON.stringify(result), result);
|
||||
},
|
||||
});
|
||||
|
||||
// obsidian_rag_index — trigger indexing
|
||||
api.registerTool({
|
||||
name: "obsidian_rag_index",
|
||||
description:
|
||||
"Trigger indexing of the Obsidian vault. Use 'full' for first-time setup, 'sync' for incremental updates, 'reindex' to force a clean rebuild.",
|
||||
label: "Index Obsidian Vault",
|
||||
parameters: Type.Object({
|
||||
mode: Type.Union(
|
||||
[Type.Literal("full"), Type.Literal("sync"), Type.Literal("reindex")],
|
||||
{ description: "Indexing mode" },
|
||||
),
|
||||
}),
|
||||
async execute(_id, params) {
|
||||
const indexParams: IndexParams = { mode: String(params.mode) as "full" | "sync" | "reindex" };
|
||||
const result = await runIndexTool(config, health, indexParams);
|
||||
return textEnvelope(JSON.stringify(result), result);
|
||||
},
|
||||
});
|
||||
|
||||
// obsidian_rag_status — health check
|
||||
api.registerTool({
|
||||
name: "obsidian_rag_status",
|
||||
description:
|
||||
"Check the health of the Obsidian RAG plugin — index statistics, last sync time, unindexed files, and Ollama status. Call this first when unsure if the index is ready.",
|
||||
label: "Obsidian RAG Status",
|
||||
parameters: Type.Object({}),
|
||||
async execute(_id) {
|
||||
const result = await statusTool(config);
|
||||
return textEnvelope(JSON.stringify(result), result);
|
||||
},
|
||||
});
|
||||
|
||||
// obsidian_rag_memory_store — commit facts to memory
|
||||
api.registerTool({
|
||||
name: "obsidian_rag_memory_store",
|
||||
description:
|
||||
"Commit an important fact from search results to OpenClaw's memory for faster future retrieval. Use after finding significant information (e.g. 'I owe Sreenivas $50') that should be remembered.",
|
||||
label: "Store in Memory",
|
||||
parameters: Type.Object({
|
||||
key: Type.String({ description: "Identifier for the fact (e.g. 'debt_to_sreenivas')" }),
|
||||
value: Type.String({ description: "The fact to remember" }),
|
||||
source: Type.String({
|
||||
description: "Source file path in the vault (e.g. 'Journal/2025-03-15.md')",
|
||||
}),
|
||||
}),
|
||||
async execute(_id, params) {
|
||||
const memParams: MemoryStoreParams = {
|
||||
key: String(params.key),
|
||||
value: String(params.value),
|
||||
source: String(params.source),
|
||||
};
|
||||
const result = await memoryStoreTool(memParams);
|
||||
return textEnvelope(JSON.stringify(result), result);
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user