From b1bbce5375b3ffc470f4db504d3ee9c0bd02011b Mon Sep 17 00:00:00 2001 From: kappa Date: Tue, 27 Jan 2026 11:26:54 +0900 Subject: [PATCH] fix: allow session cancellation in all states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously cancellation only worked in 'selecting' or 'ordering' states. Now users can cancel server consultation at any stage using keywords: 취소, 다시, 처음, 리셋, 초기화, 다시 시작, 처음부터 Co-Authored-By: Claude Opus 4.5 --- .tasks/task_1769153089612.md | 91 ++++++++++++++++++++++++++++++++++++ src/server-agent.ts | 13 ++++-- vitest.config.ts | 12 +---- 3 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 .tasks/task_1769153089612.md diff --git a/.tasks/task_1769153089612.md b/.tasks/task_1769153089612.md new file mode 100644 index 0000000..c6ed1ae --- /dev/null +++ b/.tasks/task_1769153089612.md @@ -0,0 +1,91 @@ +# Server Recommendation Output Format Improvement + +## Objective +Improve server recommendation display to table format with provider column and region preference handling. + +## Files to Modify + +### 1. /Users/kaffa/telegram-bot-workers/src/tools/server-tool.ts + +**Location:** `recommendServer()` function around lines 279-294 + +**Current Format:** +``` +1. vc2-2c-4gb + • 2 vCPUs, 4.0GB RAM, 80GB SSD + • 리전: 서울, 한국 + • 42,100원/월 +``` + +**New Format:** +``` +🎯 **게임서버** 추천 + +📊 **분석 결과:** 게임서버 기본 요구사항 / 동시 접속자 50명 + +| # | 제공자 | 사양 | vCPU | RAM | 스토리지 | 리전 | 가격/월 | +|---|--------|------|------|-----|----------|------|--------| +| 1 | Vultr | vc2-2c-4gb | 2 | 4GB | 80GB | 서울 | 35,100원 | +| 2 | Linode | 4GB Plan | 4 | 4GB | 160GB | 도쿄 | 42,100원 | +| 3 | Linode | 4GB Plan | 4 | 4GB | 160GB | 싱가포르 | 42,100원 | + +💡 주문: "사양 #70455 주문" +``` + +**Code Change (results.forEach part around line 283-290):** +```typescript +// 표 헤더 +let response = `🎯 **${args.purpose || "범용"}** 서버 추천\n\n`; +response += `📊 **분석 결과:** ${requirements.reason}\n\n`; +response += `| # | 제공자 | 사양 | vCPU | RAM | 스토리지 | 리전 | 가격/월 |\n`; +response += `|---|--------|------|------|-----|----------|------|--------|\n`; + +results.forEach((spec, idx) => { + const ramGB = (spec.memory_mb / 1024).toFixed(0); + // 리전에서 국가 부분만 추출 (예: "서울, 한국" → "서울") + const shortRegion = spec.region_name.split(',')[0].trim(); + response += `| ${idx + 1} | ${spec.provider_name} | ${spec.instance_name} | ${spec.vcpu} | ${ramGB}GB | ${spec.storage_gb}GB | ${shortRegion} | ${spec.monthly_price_krw.toLocaleString()}원 |\n`; +}); + +response += `\n💡 주문하시려면 "사양 #${results[0].id} 주문"이라고 말씀해주세요.`; + +return response; +``` + +**Notes:** +- provider_name is already in query results (line 239: `prov.name as provider_name`) +- Extract city only from region_name (before comma) +- RAM should be whole number (0 decimals) + +### 2. /Users/kaffa/telegram-bot-workers/src/summary-service.ts + +**Location:** System prompt around lines 390-393 (server recommendation section) + +**Current:** +```typescript +- 서버 추천 요청 시: + 1. 새로운 추천 요청은 이전 대화와 무관하게 처리 + 2. 용도만 알면 바로 추천 가능. 용도 모르면 한 번만 질문 +``` + +**Change To:** +```typescript +- 서버 추천 요청 시: + 1. 새로운 추천 요청은 이전 대화와 무관하게 처리 + 2. 용도와 선호 위치(서울/도쿄/싱가포르)를 모르면 한 번에 질문: "어떤 용도로, 어느 지역 서버를 원하시나요? (서울/도쿄/싱가포르)" + 3. 위치 선호가 있으면 region 파라미터로 전달 (예: region="Seoul" 또는 region="Tokyo") +``` + +## Testing + +1. Build: `npm run dev` +2. Test message: "게임서버 추천해줘" +3. Verify table format renders correctly in Telegram +4. Test region preference: "서울 서버로 웹서버 추천" + +## Requirements + +- TypeScript strict mode +- No `any` types +- Preserve existing functionality +- Follow project conventions (kebab-case files, camelCase functions) diff --git a/src/server-agent.ts b/src/server-agent.ts index 40b1174..6d3ae59 100644 --- a/src/server-agent.ts +++ b/src/server-agent.ts @@ -479,11 +479,16 @@ export async function processServerConsultation( status: session.status }); - // 취소 키워드 처리 (selecting 또는 ordering 상태에서) - if ((session.status === 'selecting' || session.status === 'ordering') && - /취소|다시|처음/.test(userMessage)) { + // 취소 키워드 처리 (모든 상태에서 작동) + // "취소", "다시", "처음", "리셋", "초기화" 등 + if (/^(취소|다시|처음|리셋|초기화)/.test(userMessage.trim()) || + /취소할[게래]|다시\s*시작|처음부터/.test(userMessage)) { await deleteServerSession(env.SESSION_KV, session.telegramUserId); - logger.info('사용자 요청으로 상담 취소', { userId: session.telegramUserId }); + logger.info('사용자 요청으로 상담 취소', { + userId: session.telegramUserId, + previousStatus: session.status, + trigger: userMessage.slice(0, 20) + }); return '상담이 취소되었습니다. 다시 시작하려면 "서버 추천"이라고 말씀해주세요.'; } diff --git a/vitest.config.ts b/vitest.config.ts index b5d3bef..9d67557 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -4,17 +4,7 @@ import path from 'path'; export default defineConfig({ test: { globals: true, - environment: 'miniflare', - environmentOptions: { - bindings: { - BOT_TOKEN: 'test-bot-token', - WEBHOOK_SECRET: 'test-webhook-secret', - OPENAI_API_KEY: 'test-openai-key', - DEPOSIT_ADMIN_ID: '999999999', - }, - kvNamespaces: ['RATE_LIMIT_KV'], - d1Databases: ['DB'], - }, + environment: 'node', setupFiles: ['./tests/setup.ts'], coverage: { provider: 'v8',