feat: v2.2.92 → v2.2.158 — god-file 분해 + Stocks feature + 대화 연속성

R56–R59: agent.ts 2731→1529줄 god-file 분해 (25 modules)
  · attrParsers + LLM 메서드 8개 (callNonStreaming, streamChatOnce 등)
  · executeActions 415줄 → 8 handler 그룹 (file/run/list/brain/calendar/sheets/tasks)
  · handlePrompt 1100줄 → 7 phase 모듈 (system prompt + budget + autoContinue 등)

R50–R55: extension.ts 1145→349줄 (telegram/settings/provider commands 분리)

Stocks feature 신규: /stocks slash command (v2.2.152~158)
  · .astra/stocks.json 저장소 + Yahoo Finance 현재가 갱신
  · 8 키워드 필터 (ROE/성장성/유동성/수익성/영업효율/기술력/안정성/PBR)
  · Naver 시가총액 페이지 JSON API (m.stock.naver.com) 발굴
  · LLM Top 5 매력도 분석 + Telegram 자동 보고서
  · KST 09:00/15:00 watcher 자동 모니터링

대화 연속성 (v2.2.150~157):
  · [PRIOR TURN CONCLUSION] block 으로 직전 결론 anchor
  · thin follow-up 분류 → boilerplate 헤더 suppression
  · slash 명령 결과 chatHistory mirror (capture wrapper)
  · echo/parrot 금지 system prompt rule

기타: /stocks 슬래시 자동완성 dropdown UI, Naver JSON API 전환 (cheerio 제거)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
g1nation
2026-05-25 09:59:32 +09:00
parent 4153f640c2
commit 0a97324f1b
149 changed files with 14628 additions and 6927 deletions
+40 -6
View File
@@ -35,12 +35,38 @@ export async function handleChatMessage(provider: SidebarChatProvider, data: any
return true;
}
logInfo(`[SLASH] handleSlashCommand entering`);
await handleSlashCommand(data.value, provider._view.webview, provider._context);
logInfo(`[SLASH] handleSlashCommand returned`);
// Slash 명령 결과를 *chatHistory 에도* mirror — 다음 turn 의 LLM 이
// 직전 명령 출력 (예: /stocks discover 발굴 결과) 을 컨텍스트로 보게 한다.
// 안 하면 LLM 은 webview UI 만 보고 history 는 비어 있어서 "주식 데이터
// 없음" 같은 환각 응답이 나옴.
const realWebview = provider._view.webview;
const captured: string[] = [];
const captureWebview = {
postMessage: (msg: any) => {
if (msg && msg.type === 'streamChunk' && typeof msg.value === 'string') {
captured.push(msg.value);
}
return realWebview.postMessage(msg);
},
};
await handleSlashCommand(data.value, captureWebview as any, provider._context);
const collected = captured.join('').trim();
if (collected) {
// CRITICAL: getHistory() 는 *filtered copy* 를 반환하므로 직접 push 하면
// 원본 chatHistory 에 안 들어감 (silent fail). 새 배열로 setHistory.
const current = provider._agent.getHistory();
const updated = [
...current,
{ role: 'user' as const, content: data.value },
{ role: 'assistant' as const, content: collected, internal: false },
];
provider._agent.setHistory(updated);
}
logInfo(`[SLASH] handleSlashCommand returned, captured ${collected.length} chars → history len ${provider._agent.getHistory().length}`);
return true;
}
}
await provider._context.globalState.update(SidebarChatProvider.blankChatStateKey, false);
await provider._sessionState.setBlankChatActive(false);
// ── 1인 기업 모드 우선 분기 ──
// 회사 모드일 땐 들어온 메시지를 intent classifier에 한 번 통과시켜
// (a) 잡담/질문/짧은 응답 → 일반 채팅 경로, (b) 후속 대화 → 일반 채팅
@@ -214,6 +240,14 @@ export async function handleChatMessage(provider: SidebarChatProvider, data: any
await provider._sendChronicleProjects();
await provider._restoreActiveSessionIntoView();
await provider._sendReadyStatus();
// Slash 명령 목록 — webview 의 `/` 자동완성 dropdown 이 사용.
try {
const { listSlashCommands } = await import('../features/datacollect/slashRouter');
const cmds = listSlashCommands().map(c => ({ name: c.name, description: c.description || '' }));
provider._view?.webview.postMessage({ type: 'slashCommandList', commands: cmds });
} catch (e: any) {
// Slash 라우터 로드 실패해도 채팅 자체는 동작해야 — silent skip.
}
// Restore the Project Architecture chip + watcher if the active project
// was already running in architecture mode in a previous VS Code session.
await provider._sendArchitectureStatus();
@@ -243,9 +277,9 @@ export async function handleChatMessage(provider: SidebarChatProvider, data: any
provider._currentSessionId = null;
provider._currentSessionBrainId = getActiveBrainProfile().id;
provider._agent.resetConversation();
await provider._context.globalState.update(SidebarChatProvider.activeSessionStateKey, null);
await provider._context.globalState.update(SidebarChatProvider.lastVisibleChatStateKey, null);
await provider._context.globalState.update(SidebarChatProvider.blankChatStateKey, true);
await provider._sessionState.setActiveSessionId(null);
await provider._sessionState.setLastVisibleChat(null);
await provider._sessionState.setBlankChatActive(true);
// 직전 회사 turn 컨텍스트 캐시 비우기 — 새 세션은 followup 기준점이 없다.
provider.clearLastCompanyTurnSummary();
// 진행 중이던 alignment도 새 세션과 함께 폐기.