/** * Memory Search Tool * Searches past AgentActions (logs, toolLogs, inputs) for context. */ import { tool } from 'ai' import { z } from 'zod' import { toolRegistry } from './registry' import { prisma } from '@/lib/prisma' toolRegistry.register({ name: 'memory_search', description: 'Search past agent execution history for relevant information. Looks through previous logs, tool traces, and inputs.', isInternal: true, buildTool: (ctx) => tool({ description: 'Search past agent executions for context. Searches through logs and tool traces from previous runs.', inputSchema: z.object({ query: z.string().describe('What to search for in past executions'), limit: z.number().optional().describe('Max results (default 5)').default(5), }), execute: async ({ query, limit = 5 }) => { try { // Get past actions for this agent const actions = await prisma.agentAction.findMany({ where: { agentId: ctx.agentId, status: 'success', }, orderBy: { createdAt: 'desc' }, take: limit * 2, select: { id: true, log: true, input: true, toolLog: true, createdAt: true }, }) const keywords = query.toLowerCase().split(/\s+/).filter(w => w.length > 2) const results = actions .map(a => { const searchable = `${a.log || ''} ${a.input || ''} ${a.toolLog || ''}`.toLowerCase() const score = keywords.reduce((acc, kw) => acc + (searchable.includes(kw) ? 1 : 0), 0) return { ...a, score } }) .filter(r => r.score > 0) .sort((a, b) => b.score - a.score) .slice(0, limit) if (results.length === 0) { return { message: 'No matching past executions found.', query } } return results.map(r => ({ actionId: r.id, date: r.createdAt.toISOString(), log: (r.log || '').substring(0, 800), input: r.input ? (r.input).substring(0, 500) : null, })) } catch (e: any) { return { error: `Memory search failed: ${e.message}` } } }, }), })