- Replace TypeBox + AgentToolResult with native OpenClaw AnyAgentTool pattern - Add id, openclaw, main fields to openclaw.plugin.json manifest - registerTools() now uses factory helpers returning typed AnyAgentTool objects - toAgentResult() adapter bridges search/index/status/memory results to AgentToolResult shape - Build clean — pi-agent-core peer dep not needed, openclaw exports all types - Task list updated: Phase 4 tools + plugin registration marked complete Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
113 lines
4.5 KiB
TypeScript
113 lines
4.5 KiB
TypeScript
/** Tool registration — wires all 4 obsidian_rag_* tools into OpenClaw. */
|
|
|
|
import type { AnyAgentTool, OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
import type { ObsidianRagConfig } from "../utils/config.js";
|
|
import type { HealthState } from "../services/health.js";
|
|
import { searchTool } from "./search.js";
|
|
import { runIndexTool } from "./index-tool.js";
|
|
import { statusTool } from "./status.js";
|
|
import { memoryStoreTool } from "./memory.js";
|
|
|
|
export function registerTools(
|
|
api: OpenClawPluginApi,
|
|
config: ObsidianRagConfig,
|
|
health: { get: () => { state: HealthState }; setActiveJob: (job: { id: string; mode: string; progress: number } | null) => void },
|
|
): void {
|
|
api.registerTool(makeSearchTool(config));
|
|
api.registerTool(makeIndexTool(config, health));
|
|
api.registerTool(makeStatusTool(config));
|
|
api.registerTool(makeMemoryStoreTool());
|
|
}
|
|
|
|
function toAgentResult(result: unknown) {
|
|
return {
|
|
content: [{ type: "text" as const, text: JSON.stringify(result) }],
|
|
details: result as Record<string, unknown>,
|
|
};
|
|
}
|
|
|
|
function makeSearchTool(config: ObsidianRagConfig): AnyAgentTool {
|
|
return {
|
|
name: "obsidian_rag_search",
|
|
description:
|
|
"Primary semantic search tool for querying the Obsidian vault. Use for natural language questions about journal entries, financial records, health data, project ideas, and more.",
|
|
label: "Obsidian RAG Search",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
query: { type: "string", description: "Natural language question or topic to search for" },
|
|
max_results: { type: "integer", description: "Maximum number of chunks to return (default: 5, range: 1-50)", default: 5, minimum: 1, maximum: 50 },
|
|
directory_filter: { type: "array", description: "Limit search to specific subdirectories", items: { type: "string" } },
|
|
date_range: {
|
|
type: "object",
|
|
properties: { from: { type: "string" }, to: { type: "string" } },
|
|
},
|
|
tags: { type: "array", description: "Filter by hashtags", items: { type: "string" } },
|
|
},
|
|
required: ["query"],
|
|
},
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
return toAgentResult(await searchTool(config, params as any));
|
|
},
|
|
} as AnyAgentTool;
|
|
}
|
|
|
|
function makeIndexTool(
|
|
config: ObsidianRagConfig,
|
|
health: { get: () => { state: HealthState }; setActiveJob: (job: { id: string; mode: string; progress: number } | null) => void },
|
|
): AnyAgentTool {
|
|
return {
|
|
name: "obsidian_rag_index",
|
|
description:
|
|
"Trigger indexing of the Obsidian vault. Use 'full' for initial index, 'sync' for incremental updates, 'reindex' to force full rebuild.",
|
|
label: "Obsidian RAG Index",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
mode: { type: "string", enum: ["full", "sync", "reindex"], description: "Indexing mode" },
|
|
},
|
|
required: ["mode"],
|
|
},
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
return toAgentResult(await runIndexTool(config, health, params as any));
|
|
},
|
|
} as AnyAgentTool;
|
|
}
|
|
|
|
function makeStatusTool(config: ObsidianRagConfig): AnyAgentTool {
|
|
return {
|
|
name: "obsidian_rag_status",
|
|
description:
|
|
"Check the health of the Obsidian RAG plugin: index statistics, last sync time, Ollama status, and active indexing job.",
|
|
label: "Obsidian RAG Status",
|
|
parameters: { type: "object", properties: {} },
|
|
async execute(_toolCallId: string) {
|
|
return toAgentResult(await statusTool(config));
|
|
},
|
|
} as AnyAgentTool;
|
|
}
|
|
|
|
function makeMemoryStoreTool(): AnyAgentTool {
|
|
return {
|
|
name: "obsidian_rag_memory_store",
|
|
description:
|
|
"Commit important facts from search results to OpenClaw's memory for faster future retrieval. Auto-suggested when search detects financial, health, or commitment content.",
|
|
label: "Obsidian RAG Memory Store",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
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" },
|
|
},
|
|
required: ["key", "value", "source"],
|
|
},
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
return toAgentResult(await memoryStoreTool(params as any));
|
|
},
|
|
} as AnyAgentTool;
|
|
}
|