refactor: P3 low priority improvements
P3-1: Magic numbers to named constants - SMS_CONTENT_MAX_LENGTH = 500 (bank-sms-parser.ts) - DEFAULT_HISTORY_LIMIT = 10 (deposit-agent.ts) - LOG_RESULT_MAX_LENGTH = 200 (deposit-tool.ts) P3-2: Debug command admin-only access - Add DEPOSIT_ADMIN_ID check for /debug command - Return "관리자만 사용 가능" for non-admins P3-3: Stats query null handling - Replace || with ?? for COUNT results - Prevents 0 being overwritten incorrectly P3-4: Memory save error logging - Add logger.debug for saveMemorySilently failures - Non-critical but helps debug memory issues Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,9 +43,9 @@ export async function handleCommand(
|
|||||||
|
|
||||||
return `📊 <b>현재 컨텍스트</b>
|
return `📊 <b>현재 컨텍스트</b>
|
||||||
|
|
||||||
분석된 메시지: ${ctx.previousSummary?.message_count || 0}개
|
분석된 메시지: ${ctx.previousSummary?.message_count ?? 0}개
|
||||||
버퍼 메시지: ${ctx.recentMessages.length}개
|
버퍼 메시지: ${ctx.recentMessages.length}개
|
||||||
프로필 버전: ${ctx.previousSummary?.generation || 0}
|
프로필 버전: ${ctx.previousSummary?.generation ?? 0}
|
||||||
총 메시지: ${ctx.totalMessages}개
|
총 메시지: ${ctx.totalMessages}개
|
||||||
|
|
||||||
💡 ${remaining > 0 ? `${remaining}개 메시지 후 프로필 업데이트` : '업데이트 대기 중'}`;
|
💡 ${remaining > 0 ? `${remaining}개 메시지 후 프로필 업데이트` : '업데이트 대기 중'}`;
|
||||||
@@ -78,12 +78,18 @@ ${summary.summary}
|
|||||||
return `📈 <b>대화 통계</b>
|
return `📈 <b>대화 통계</b>
|
||||||
|
|
||||||
총 메시지: ${ctx.totalMessages}개
|
총 메시지: ${ctx.totalMessages}개
|
||||||
프로필 버전: ${ctx.previousSummary?.generation || 0}
|
프로필 버전: ${ctx.previousSummary?.generation ?? 0}
|
||||||
저장된 프로필: ${profileCount?.cnt || 0}개
|
저장된 프로필: ${profileCount?.cnt ?? 0}개
|
||||||
버퍼 대기: ${ctx.recentMessages.length}개`;
|
버퍼 대기: ${ctx.recentMessages.length}개`;
|
||||||
}
|
}
|
||||||
|
|
||||||
case '/debug': {
|
case '/debug': {
|
||||||
|
// Admin only - exposes internal debug info
|
||||||
|
const adminId = env.DEPOSIT_ADMIN_ID ? parseInt(env.DEPOSIT_ADMIN_ID, 10) : null;
|
||||||
|
if (!adminId || userId !== adminId) {
|
||||||
|
return '🔒 이 명령어는 관리자만 사용할 수 있습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
// 디버그용 명령어 (개발 시 유용)
|
// 디버그용 명령어 (개발 시 유용)
|
||||||
const ctx = await getConversationContext(env.DB, userId, chatId);
|
const ctx = await getConversationContext(env.DB, userId, chatId);
|
||||||
const recentMsgs = ctx.recentMessages.slice(-5).map((m, i) =>
|
const recentMsgs = ctx.recentMessages.slice(-5).map((m, i) =>
|
||||||
@@ -95,7 +101,7 @@ ${summary.summary}
|
|||||||
User ID: ${userId}
|
User ID: ${userId}
|
||||||
Chat ID: ${chatId}
|
Chat ID: ${chatId}
|
||||||
Buffer Count: ${ctx.recentMessages.length}
|
Buffer Count: ${ctx.recentMessages.length}
|
||||||
Summary Gen: ${ctx.previousSummary?.generation || 0}
|
Summary Gen: ${ctx.previousSummary?.generation ?? 0}
|
||||||
|
|
||||||
<b>최근 버퍼 (5개):</b>
|
<b>최근 버퍼 (5개):</b>
|
||||||
${recentMsgs || '(비어있음)'}`;
|
${recentMsgs || '(비어있음)'}`;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const logger = createLogger('deposit-agent');
|
|||||||
|
|
||||||
const MIN_DEPOSIT_AMOUNT = 1000; // 1,000원
|
const MIN_DEPOSIT_AMOUNT = 1000; // 1,000원
|
||||||
const MAX_DEPOSIT_AMOUNT = 100_000_000; // 1억원
|
const MAX_DEPOSIT_AMOUNT = 100_000_000; // 1억원
|
||||||
|
const DEFAULT_HISTORY_LIMIT = 10;
|
||||||
|
|
||||||
export interface DepositContext {
|
export interface DepositContext {
|
||||||
userId: number;
|
userId: number;
|
||||||
@@ -197,8 +198,8 @@ export async function executeDepositFunction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'get_transactions': {
|
case 'get_transactions': {
|
||||||
// LIMIT 값 검증: 1-100 범위, 기본값 10
|
// LIMIT 값 검증: 1-100 범위
|
||||||
const limit = Math.min(Math.max(parseInt(String(funcArgs.limit)) || 10, 1), 100);
|
const limit = Math.min(Math.max(parseInt(String(funcArgs.limit)) || DEFAULT_HISTORY_LIMIT, 1), 100);
|
||||||
|
|
||||||
const transactions = await db.prepare(
|
const transactions = await db.prepare(
|
||||||
`SELECT id, type, amount, status, depositor_name, description, created_at, confirmed_at
|
`SELECT id, type, amount, status, depositor_name, description, created_at, confirmed_at
|
||||||
|
|||||||
@@ -413,7 +413,9 @@ export async function generateOpenAIResponse(
|
|||||||
const saveableInfo = extractSaveableInfo(userMessage);
|
const saveableInfo = extractSaveableInfo(userMessage);
|
||||||
if (saveableInfo) {
|
if (saveableInfo) {
|
||||||
// 비동기로 저장, 응답 지연 없음
|
// 비동기로 저장, 응답 지연 없음
|
||||||
saveMemorySilently(db, telegramUserId, saveableInfo).catch(() => {});
|
saveMemorySilently(db, telegramUserId, saveableInfo).catch(err => {
|
||||||
|
logger.debug('Memory save failed (non-critical)', { error: (err as Error).message });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalResponse;
|
return finalResponse;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { createLogger } from '../utils/logger';
|
|||||||
|
|
||||||
const logger = createLogger('bank-sms-parser');
|
const logger = createLogger('bank-sms-parser');
|
||||||
|
|
||||||
|
const SMS_CONTENT_MAX_LENGTH = 500;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 은행 SMS 파싱 함수
|
* 은행 SMS 파싱 함수
|
||||||
*
|
*
|
||||||
@@ -52,7 +54,7 @@ function preprocessText(content: string): string {
|
|||||||
// [Web발신] 또는 은행 키워드가 있는 부분만 추출
|
// [Web발신] 또는 은행 키워드가 있는 부분만 추출
|
||||||
const smsStartMatch = text.match(/ \[Web발신\]| \[하나은행\]| \[KB\]| \[신한\]| \[우리\]| \[농협\]/);
|
const smsStartMatch = text.match(/ \[Web발신\]| \[하나은행\]| \[KB\]| \[신한\]| \[우리\]| \[농협\]/);
|
||||||
if (smsStartMatch && smsStartMatch.index !== undefined) {
|
if (smsStartMatch && smsStartMatch.index !== undefined) {
|
||||||
text = text.slice(smsStartMatch.index, smsStartMatch.index + 500);
|
text = text.slice(smsStartMatch.index, smsStartMatch.index + SMS_CONTENT_MAX_LENGTH);
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -68,7 +70,7 @@ function parseWithRegex(text: string): BankNotification | null {
|
|||||||
depositorName: depositor.trim(),
|
depositorName: depositor.trim(),
|
||||||
amount: parseInt(amountStr.replace(/,/g, '')),
|
amount: parseInt(amountStr.replace(/,/g, '')),
|
||||||
transactionTime: parseDateTime(date, time),
|
transactionTime: parseDateTime(date, time),
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ function parseWithRegex(text: string): BankNotification | null {
|
|||||||
amount: parseInt(amountStr.replace(/,/g, '')),
|
amount: parseInt(amountStr.replace(/,/g, '')),
|
||||||
balanceAfter: balanceStr ? parseInt(balanceStr.replace(/,/g, '')) : undefined,
|
balanceAfter: balanceStr ? parseInt(balanceStr.replace(/,/g, '')) : undefined,
|
||||||
transactionTime: parseDateTime(date, time),
|
transactionTime: parseDateTime(date, time),
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +99,7 @@ function parseWithRegex(text: string): BankNotification | null {
|
|||||||
depositorName: depositor,
|
depositorName: depositor,
|
||||||
amount: parseInt(amountStr.replace(/,/g, '')),
|
amount: parseInt(amountStr.replace(/,/g, '')),
|
||||||
transactionTime: date ? parseDateTime(date, time) : undefined,
|
transactionTime: date ? parseDateTime(date, time) : undefined,
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +113,7 @@ function parseWithRegex(text: string): BankNotification | null {
|
|||||||
depositorName: depositor,
|
depositorName: depositor,
|
||||||
amount: parseInt(amountStr.replace(/,/g, '')),
|
amount: parseInt(amountStr.replace(/,/g, '')),
|
||||||
transactionTime: date ? parseDateTime(date) : undefined,
|
transactionTime: date ? parseDateTime(date) : undefined,
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +127,7 @@ function parseWithRegex(text: string): BankNotification | null {
|
|||||||
bankName: '알수없음',
|
bankName: '알수없음',
|
||||||
depositorName: genericMatch1[2],
|
depositorName: genericMatch1[2],
|
||||||
amount: parseInt(genericMatch1[1].replace(/,/g, '')),
|
amount: parseInt(genericMatch1[1].replace(/,/g, '')),
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +137,7 @@ function parseWithRegex(text: string): BankNotification | null {
|
|||||||
bankName: '알수없음',
|
bankName: '알수없음',
|
||||||
depositorName: genericMatch2[1],
|
depositorName: genericMatch2[1],
|
||||||
amount: parseInt(genericMatch2[2].replace(/,/g, '')),
|
amount: parseInt(genericMatch2[2].replace(/,/g, '')),
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +151,7 @@ async function parseWithAI(text: string, env: Env): Promise<BankNotification | n
|
|||||||
|
|
||||||
텍스트:
|
텍스트:
|
||||||
"""
|
"""
|
||||||
${text.slice(0, 500)}
|
${text.slice(0, SMS_CONTENT_MAX_LENGTH)}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
요구사항:
|
요구사항:
|
||||||
@@ -227,7 +229,7 @@ ${text.slice(0, 500)}
|
|||||||
depositorName: result.depositorName,
|
depositorName: result.depositorName,
|
||||||
amount: typeof result.amount === 'string' ? parseInt(result.amount.replace(/,/g, '')) : result.amount,
|
amount: typeof result.amount === 'string' ? parseInt(result.amount.replace(/,/g, '')) : result.amount,
|
||||||
transactionTime: result.transactionTime ? new Date(result.transactionTime) : undefined,
|
transactionTime: result.transactionTime ? new Date(result.transactionTime) : undefined,
|
||||||
rawMessage: text.slice(0, 500),
|
rawMessage: text.slice(0, SMS_CONTENT_MAX_LENGTH),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { createLogger, maskUserId } from '../utils/logger';
|
|||||||
|
|
||||||
const logger = createLogger('deposit-tool');
|
const logger = createLogger('deposit-tool');
|
||||||
|
|
||||||
|
const LOG_RESULT_MAX_LENGTH = 200;
|
||||||
|
|
||||||
export const manageDepositTool = {
|
export const manageDepositTool = {
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
@@ -206,7 +208,7 @@ export async function executeManageDeposit(
|
|||||||
|
|
||||||
logger.info('executeDepositFunction 호출', { funcName, funcArgs });
|
logger.info('executeDepositFunction 호출', { funcName, funcArgs });
|
||||||
const result = await executeDepositFunction(funcName, funcArgs, context);
|
const result = await executeDepositFunction(funcName, funcArgs, context);
|
||||||
logger.info('결과', { result: JSON.stringify(result).slice(0, 200) });
|
logger.info('결과', { result: JSON.stringify(result).slice(0, LOG_RESULT_MAX_LENGTH) });
|
||||||
|
|
||||||
// 결과 포맷팅 (고정 형식)
|
// 결과 포맷팅 (고정 형식)
|
||||||
return formatDepositResult(action, result);
|
return formatDepositResult(action, result);
|
||||||
|
|||||||
Reference in New Issue
Block a user