148 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * LLMemory Plugin for OpenCode
 | 
						|
 * 
 | 
						|
 * Provides a persistent memory/journal system for AI agents.
 | 
						|
 * Memories are stored in SQLite and searchable across sessions.
 | 
						|
 */
 | 
						|
import { tool } from "@opencode-ai/plugin";
 | 
						|
import { spawn } from "child_process";
 | 
						|
import { fileURLToPath } from 'url';
 | 
						|
import { dirname, join } from 'path';
 | 
						|
 | 
						|
const __filename = fileURLToPath(import.meta.url);
 | 
						|
const __dirname = dirname(__filename);
 | 
						|
const MEMORY_CLI = join(__dirname, '../llmemory/bin/llmemory');
 | 
						|
 | 
						|
function runMemoryCommand(args) {
 | 
						|
  return new Promise((resolve, reject) => {
 | 
						|
    const child = spawn('node', [MEMORY_CLI, ...args], {
 | 
						|
      env: { ...process.env }
 | 
						|
    });
 | 
						|
    
 | 
						|
    let stdout = '';
 | 
						|
    let stderr = '';
 | 
						|
    
 | 
						|
    child.stdout.on('data', (data) => {
 | 
						|
      stdout += data.toString();
 | 
						|
    });
 | 
						|
    
 | 
						|
    child.stderr.on('data', (data) => {
 | 
						|
      stderr += data.toString();
 | 
						|
    });
 | 
						|
    
 | 
						|
    child.on('close', (code) => {
 | 
						|
      if (code !== 0) {
 | 
						|
        reject(new Error(stderr || `Command failed with code ${code}`));
 | 
						|
      } else {
 | 
						|
        resolve(stdout);
 | 
						|
      }
 | 
						|
    });
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
export const LLMemoryPlugin = async (ctx) => {
 | 
						|
  const tools = {
 | 
						|
    memory_store: tool({
 | 
						|
      description: `Store a memory for future reference. Use this to remember important information across sessions.
 | 
						|
 | 
						|
Examples:
 | 
						|
- Store implementation decisions: "Decided to use JWT for auth instead of sessions"
 | 
						|
- Record completed work: "Implemented user authentication with email/password"
 | 
						|
- Save debugging insights: "Bug was caused by race condition in async handler"
 | 
						|
- Document project context: "Client prefers Material-UI over Tailwind"
 | 
						|
 | 
						|
Memories are searchable by content and tags.`,
 | 
						|
      args: {
 | 
						|
        content: tool.schema.string()
 | 
						|
          .describe("The memory content to store (required)"),
 | 
						|
        tags: tool.schema.string()
 | 
						|
          .optional()
 | 
						|
          .describe("Comma-separated tags for categorization (e.g., 'backend,auth,security')"),
 | 
						|
        expires: tool.schema.string()
 | 
						|
          .optional()
 | 
						|
          .describe("Optional expiration date (ISO format, e.g., '2026-12-31')"),
 | 
						|
        by: tool.schema.string()
 | 
						|
          .optional()
 | 
						|
          .describe("Agent/user identifier (defaults to 'agent')")
 | 
						|
      },
 | 
						|
      async execute(args) {
 | 
						|
        const cmdArgs = ['store', args.content];
 | 
						|
        if (args.tags) cmdArgs.push('--tags', args.tags);
 | 
						|
        if (args.expires) cmdArgs.push('--expires', args.expires);
 | 
						|
        if (args.by) cmdArgs.push('--by', args.by);
 | 
						|
        
 | 
						|
        try {
 | 
						|
          const result = await runMemoryCommand(cmdArgs);
 | 
						|
          return result;
 | 
						|
        } catch (error) {
 | 
						|
          return `Error storing memory: ${error.message}`;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }),
 | 
						|
 | 
						|
    memory_search: tool({
 | 
						|
      description: `Search stored memories by content and/or tags. Returns relevant memories from past sessions.
 | 
						|
 | 
						|
Use cases:
 | 
						|
- Find past decisions: "authentication"
 | 
						|
- Recall debugging insights: "race condition"
 | 
						|
- Look up project context: "client preferences"
 | 
						|
- Review completed work: "implemented"
 | 
						|
 | 
						|
Supports filtering by tags, date ranges, and limiting results.`,
 | 
						|
      args: {
 | 
						|
        query: tool.schema.string()
 | 
						|
          .describe("Search query (case-insensitive substring match)"),
 | 
						|
        tags: tool.schema.string()
 | 
						|
          .optional()
 | 
						|
          .describe("Filter by tags (AND logic, comma-separated)"),
 | 
						|
        any_tag: tool.schema.string()
 | 
						|
          .optional()
 | 
						|
          .describe("Filter by tags (OR logic, comma-separated)"),
 | 
						|
        limit: tool.schema.number()
 | 
						|
          .optional()
 | 
						|
          .describe("Maximum results to return (default: 10)")
 | 
						|
      },
 | 
						|
      async execute(args) {
 | 
						|
        const cmdArgs = ['search', args.query, '--json'];
 | 
						|
        if (args.tags) cmdArgs.push('--tags', args.tags);
 | 
						|
        if (args.any_tag) cmdArgs.push('--any-tag', args.any_tag);
 | 
						|
        if (args.limit) cmdArgs.push('--limit', String(args.limit));
 | 
						|
        
 | 
						|
        try {
 | 
						|
          const result = await runMemoryCommand(cmdArgs);
 | 
						|
          return result;
 | 
						|
        } catch (error) {
 | 
						|
          return `Error searching memories: ${error.message}`;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }),
 | 
						|
 | 
						|
    memory_list: tool({
 | 
						|
      description: `List recent memories, optionally filtered by tags. Useful for reviewing recent work or exploring stored context.`,
 | 
						|
      args: {
 | 
						|
        limit: tool.schema.number()
 | 
						|
          .optional()
 | 
						|
          .describe("Maximum results to return (default: 20)"),
 | 
						|
        tags: tool.schema.string()
 | 
						|
          .optional()
 | 
						|
          .describe("Filter by tags (comma-separated)")
 | 
						|
      },
 | 
						|
      async execute(args) {
 | 
						|
        const cmdArgs = ['list', '--json'];
 | 
						|
        if (args.limit) cmdArgs.push('--limit', String(args.limit));
 | 
						|
        if (args.tags) cmdArgs.push('--tags', args.tags);
 | 
						|
        
 | 
						|
        try {
 | 
						|
          const result = await runMemoryCommand(cmdArgs);
 | 
						|
          return result;
 | 
						|
        } catch (error) {
 | 
						|
          return `Error listing memories: ${error.message}`;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    })
 | 
						|
  };
 | 
						|
  
 | 
						|
  return { tool: tools };
 | 
						|
};
 |