feat: add memory system and troubleshoot agent
Memory System: - Add category-based memory storage (company, tech, role, location, server) - Silent background saving via saveMemorySilently() - Category-based overwrite (same category replaces old memory) - Server-related pattern detection (AWS, GCP, k8s, traffic info) - Memory management tool (list, delete) Troubleshoot Agent: - Session-based troubleshooting conversation (KV, 1h TTL) - 20-year DevOps/SRE expert persona - Support for server/infra, domain/DNS, code/deploy, network, database issues - Internal tools: search_solution (Brave), lookup_docs (Context7) - Auto-trigger on error-related keywords - Session completion and cancellation support Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
140
src/tools/memory-tool.ts
Normal file
140
src/tools/memory-tool.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import type { Env, ManageMemoryArgs } from '../types';
|
||||
import {
|
||||
saveMemory,
|
||||
getMemories,
|
||||
deleteMemory,
|
||||
deleteMemoryByContent,
|
||||
} from '../services/memory-service';
|
||||
import { createLogger, maskUserId } from '../utils/logger';
|
||||
|
||||
const logger = createLogger('memory-tool');
|
||||
|
||||
export const manageMemoryTool = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'manage_memory',
|
||||
description:
|
||||
'사용자 기억 조회/삭제 전용. list: 사용자가 "내 기억", "뭘 기억해?" 요청 시. delete: 사용자가 "잊어줘" 요청 시. save는 시스템이 자동 처리하므로 호출하지 마세요.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
action: {
|
||||
type: 'string',
|
||||
enum: ['save', 'list', 'delete'],
|
||||
description: 'save=저장, list=조회, delete=삭제',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
description: '저장할 내용 또는 삭제할 내용 (검색어)',
|
||||
},
|
||||
memory_id: {
|
||||
type: 'number',
|
||||
description: '삭제할 기억의 ID (선택)',
|
||||
},
|
||||
},
|
||||
required: ['action'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 기억 관리 도구 실행
|
||||
*/
|
||||
export async function executeManageMemory(
|
||||
args: ManageMemoryArgs,
|
||||
_env?: Env,
|
||||
telegramUserId?: string,
|
||||
db?: D1Database
|
||||
): Promise<string> {
|
||||
const { action, content, memory_id } = args;
|
||||
logger.info('시작', {
|
||||
action,
|
||||
hasContent: !!content,
|
||||
memoryId: memory_id,
|
||||
userId: maskUserId(telegramUserId),
|
||||
});
|
||||
|
||||
if (!telegramUserId || !db) {
|
||||
return '🚫 기억 기능을 사용할 수 없습니다.';
|
||||
}
|
||||
|
||||
// 사용자 조회
|
||||
const user = await db
|
||||
.prepare('SELECT id FROM users WHERE telegram_id = ?')
|
||||
.bind(telegramUserId)
|
||||
.first<{ id: number }>();
|
||||
|
||||
if (!user) {
|
||||
return '🚫 사용자 정보를 찾을 수 없습니다.';
|
||||
}
|
||||
|
||||
const userId = user.id;
|
||||
|
||||
try {
|
||||
switch (action) {
|
||||
case 'save': {
|
||||
if (!content) {
|
||||
return '🚫 저장할 내용을 입력해주세요.';
|
||||
}
|
||||
|
||||
await saveMemory(db, userId, content);
|
||||
// 자동 저장 시 AI가 이 결과를 사용자에게 전달하지 않도록 내부 마커 사용
|
||||
return '[SAVED]';
|
||||
}
|
||||
|
||||
case 'list': {
|
||||
const memories = await getMemories(db, userId);
|
||||
|
||||
if (memories.length === 0) {
|
||||
return '📋 저장된 기억이 없습니다.';
|
||||
}
|
||||
|
||||
const memoryList = memories
|
||||
.map((m, index) => `${index + 1}. ${m.content} (ID: ${m.id})`)
|
||||
.join('\n');
|
||||
|
||||
return `📋 저장된 기억 (${memories.length}개)\n\n${memoryList}`;
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
// ID로 삭제
|
||||
if (memory_id) {
|
||||
const deletedCount = await deleteMemory(db, userId, memory_id);
|
||||
|
||||
if (deletedCount === 0) {
|
||||
return `🚫 ID ${memory_id}에 해당하는 기억을 찾을 수 없습니다.`;
|
||||
}
|
||||
|
||||
return `✅ 기억을 삭제했습니다 (ID: ${memory_id})`;
|
||||
}
|
||||
|
||||
// 내용 검색으로 삭제
|
||||
if (content) {
|
||||
const deletedContents = await deleteMemoryByContent(
|
||||
db,
|
||||
userId,
|
||||
content
|
||||
);
|
||||
|
||||
if (deletedContents.length === 0) {
|
||||
return `🚫 "${content}"와 일치하는 기억이 없습니다.`;
|
||||
}
|
||||
|
||||
const deletedList = deletedContents
|
||||
.map((c, i) => `${i + 1}. ${c}`)
|
||||
.join('\n');
|
||||
|
||||
return `✅ ${deletedContents.length}개의 기억을 삭제했습니다:\n\n${deletedList}`;
|
||||
}
|
||||
|
||||
return '🚫 삭제할 기억의 ID 또는 검색어를 입력해주세요.';
|
||||
}
|
||||
|
||||
default:
|
||||
return `🚫 알 수 없는 작업: ${action}`;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('기억 처리 오류', error as Error, { action });
|
||||
return '🚫 기억 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user