src / tools.ts
import { tool, type ToolsProviderController } from "@lmstudio/sdk";
import { z } from "zod";
import { deleteMemory, listMemories, saveMemory, searchMemories } from "./store";
export async function toolsProvider(_ctl: ToolsProviderController) {
return [
tool({
name: "alexiel_remember",
description:
"Save or update a durable memory. Use this when the user shares a fact, decision, or " +
"project detail worth keeping across sessions — not for transient chat content. " +
"If the key already exists, its content is overwritten.",
parameters: {
key: z
.string()
.min(1)
.max(200)
.describe("Unique hierarchical key, e.g. 'project:zombieland:status' or 'preference:code-style'"),
content: z.string().min(1).describe("The information to remember"),
tags: z.string().optional().describe("Optional space/comma separated tags"),
},
implementation: async ({ key, content, tags }) => {
const action = saveMemory(key, content, tags ?? "");
return `${action === "created" ? "Saved" : "Updated"} memory "${key}".`;
},
}),
tool({
name: "alexiel_recall",
description:
"Explicitly search saved memories. Usually unnecessary since relevant memories are " +
"auto-injected already — use this only if you need to dig for something not surfaced " +
"automatically, or need more results than were injected.",
parameters: {
query: z.string().min(1).max(300).describe("Search terms"),
limit: z.number().int().min(1).max(50).optional().describe("Max results (default 10)"),
},
implementation: async ({ query, limit }) => {
const results = searchMemories(query, limit ?? 10);
if (results.length === 0) return `No memories found matching "${query}".`;
return results
.map((r) => `[${r.key}]${r.tags ? ` (${r.tags})` : ""}\n${r.content}`)
.join("\n\n---\n\n");
},
}),
tool({
name: "alexiel_list_memories",
description: "List saved memory keys, optionally filtered by a key prefix. Does not return full content.",
parameters: {
prefix: z.string().max(200).optional().describe("Optional key prefix filter, e.g. 'project:zombieland:'"),
limit: z.number().int().min(1).max(200).optional().describe("Max results (default 50)"),
},
implementation: async ({ prefix, limit }) => {
const rows = listMemories(prefix, limit ?? 50);
if (rows.length === 0) return prefix ? `No memories found with prefix "${prefix}".` : "No memories stored yet.";
return rows.map((r) => `${r.key}${r.tags ? ` (${r.tags})` : ""} — updated ${r.updated_at}`).join("\n");
},
}),
tool({
name: "alexiel_forget",
description: "Permanently delete a memory by its exact key. Cannot be undone.",
parameters: {
key: z.string().min(1).max(200).describe("Exact memory key to delete"),
},
implementation: async ({ key }) => {
const deleted = deleteMemory(key);
return deleted ? `Deleted memory "${key}".` : `No memory found for key "${key}" — nothing deleted.`;
},
}),
];
}