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:
kappa
2026-01-27 14:28:22 +09:00
parent 6392a17d4f
commit 860e36a688
13 changed files with 1328 additions and 58 deletions

View File

@@ -9,6 +9,7 @@ import { searchWebTool, lookupDocsTool, executeSearchWeb, executeLookupDocs } fr
import { manageDomainTool, suggestDomainsTool, executeManageDomain, executeSuggestDomains } from './domain-tool';
import { manageDepositTool, executeManageDeposit } from './deposit-tool';
import { manageServerTool, executeManageServer } from './server-tool';
import { manageTroubleshootTool, executeManageTroubleshoot } from './troubleshoot-tool';
import { getCurrentTimeTool, calculateTool, executeGetCurrentTime, executeCalculate } from './utility-tools';
import { redditSearchTool, executeRedditSearch } from './reddit-tool';
import type { Env } from '../types';
@@ -78,6 +79,10 @@ const ManageServerArgsSchema = z.object({
message: z.string().min(1).max(500).optional(), // For continue_consultation
});
const ManageTroubleshootArgsSchema = z.object({
action: z.enum(['start', 'cancel']),
});
// All tools array (used by OpenAI API)
export const tools = [
weatherTool,
@@ -88,6 +93,7 @@ export const tools = [
manageDomainTool,
manageDepositTool,
manageServerTool,
manageTroubleshootTool,
suggestDomainsTool,
redditSearchTool,
];
@@ -97,6 +103,7 @@ export const TOOL_CATEGORIES: Record<string, string[]> = {
domain: [manageDomainTool.function.name, suggestDomainsTool.function.name],
deposit: [manageDepositTool.function.name],
server: [manageServerTool.function.name],
troubleshoot: [manageTroubleshootTool.function.name],
weather: [weatherTool.function.name],
search: [searchWebTool.function.name, lookupDocsTool.function.name],
reddit: [redditSearchTool.function.name],
@@ -108,6 +115,7 @@ export const CATEGORY_PATTERNS: Record<string, RegExp> = {
domain: /도메인|네임서버|whois|dns|tld|등록|\.com|\.net|\.io|\.kr|\.org/i,
deposit: /입금|충전|잔액|계좌|예치금|송금|돈/i,
server: /서버|VPS|클라우드|호스팅|인스턴스|linode|vultr/i,
troubleshoot: /문제|에러|오류|안[돼되]|느려|트러블|장애|버그|실패|안\s*됨/i,
weather: /날씨|기온|비|눈|맑|흐림|더워|추워/i,
search: /검색|찾아|뭐야|뉴스|최신/i,
reddit: /레딧|reddit|서브레딧|subreddit/i,
@@ -124,7 +132,7 @@ export function selectToolsForMessage(message: string): typeof tools {
}
// 패턴 매칭 없으면 전체 도구 사용 (폴백)
if (selectedCategories.size === 1) {
if (selectedCategories.size === 1) { // utility만 있으면 폴백
logger.info('패턴 매칭 없음 → 전체 도구 사용');
return tools;
}
@@ -244,6 +252,15 @@ export async function executeTool(
return executeRedditSearch(result.data, env);
}
case 'manage_troubleshoot': {
const result = ManageTroubleshootArgsSchema.safeParse(args);
if (!result.success) {
logger.error('Invalid troubleshoot args', new Error(result.error.message), { args });
return `❌ Invalid arguments: ${result.error.issues.map(e => e.message).join(', ')}`;
}
return executeManageTroubleshoot(result.data, env, telegramUserId);
}
default:
return `알 수 없는 도구: ${name}`;
}