MemoryWriteTool.tsx
1 import { mkdirSync, writeFileSync } from 'fs' 2 import { Box, Text } from 'ink' 3 import { dirname, join } from 'path' 4 import * as React from 'react' 5 import { z } from 'zod' 6 import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage.js' 7 import { Tool } from '../../Tool.js' 8 import { MEMORY_DIR } from '../../utils/env.js' 9 import { DESCRIPTION, PROMPT } from './prompt.js' 10 11 const inputSchema = z.strictObject({ 12 file_path: z.string().describe('Path to the memory file to write'), 13 content: z.string().describe('Content to write to the file'), 14 }) 15 16 export const MemoryWriteTool = { 17 name: 'MemoryWrite', 18 async description() { 19 return DESCRIPTION 20 }, 21 async prompt() { 22 return PROMPT 23 }, 24 inputSchema, 25 userFacingName() { 26 return 'Write Memory' 27 }, 28 async isEnabled() { 29 // TODO: Use a statsig gate 30 // TODO: Figure out how to do that without regressing app startup perf 31 return false 32 }, 33 isReadOnly() { 34 return false 35 }, 36 needsPermissions() { 37 return false 38 }, 39 renderResultForAssistant(content) { 40 return content 41 }, 42 renderToolUseMessage(input) { 43 return Object.entries(input) 44 .map(([key, value]) => `${key}: ${JSON.stringify(value)}`) 45 .join(', ') 46 }, 47 renderToolUseRejectedMessage() { 48 return <FallbackToolUseRejectedMessage /> 49 }, 50 renderToolResultMessage() { 51 return ( 52 <Box justifyContent="space-between" overflowX="hidden" width="100%"> 53 <Box flexDirection="row"> 54 <Text>{' '}⎿ Updated memory</Text> 55 </Box> 56 </Box> 57 ) 58 }, 59 async validateInput({ file_path }) { 60 const fullPath = join(MEMORY_DIR, file_path) 61 if (!fullPath.startsWith(MEMORY_DIR)) { 62 return { result: false, message: 'Invalid memory file path' } 63 } 64 return { result: true } 65 }, 66 async *call({ file_path, content }) { 67 const fullPath = join(MEMORY_DIR, file_path) 68 mkdirSync(dirname(fullPath), { recursive: true }) 69 writeFileSync(fullPath, content, 'utf-8') 70 yield { 71 type: 'result', 72 data: 'Saved', 73 resultForAssistant: 'Saved', 74 } 75 }, 76 } satisfies Tool<typeof inputSchema, string>