feat(core): 자기지식 접지·웹 접근·환경 자가점검 — 할루시네이션 방어 3중화 (v2.2.247)

- Alignment Self-Learning: 자가 조사(질문 전 두뇌 검색)·사용자 답변 두뇌 저장·핵심메시지/프로젝트 컨텍스트 주입 (alignmentResearch.ts 신규)
- 웹 접근: Bridge 폴백 직접 fetch(webFetch.ts 신규)·<fetch_url> 액션 태그·기업 모드 URL/아키텍처 컨텍스트 주입·bare 도메인 인식
- 트리거 버그 수정: startsWith('/') 가 절대경로를 슬래시 명령으로 오인 — 분석 지시·URL 주입 전멸 원인 (회귀 테스트 고정)
- 자기지식 접지: 기능 인벤토리 lazy 재생성·학습 메커니즘 정본 섹션·[인벤토리 대조] 태그 의무화·결정론적 재구현 제안 정정 훅(featureConceptMap.ts 신규)
- 환경 자가점검: HealthCheckMonitor 에 Bridge/두뇌 볼륨/git 자격증명/확장 버전 검사 4종 + readyBar ⚠ 표시
- 두뇌 동기화: 원격 미설정 시 로컬 새로고침 모드·staged 기준 commit 판정·인증 부재 안내
- 기타: outputFormat 기본 markdown(제목 렌더 복구)·레슨/행동제약 truncation 보호 구역 이동·[CONTEXT] 절단 우선순위 재정렬

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
g1nation
2026-06-12 23:46:07 +09:00
parent 553aa0b134
commit a114d968b0
42 changed files with 4178 additions and 2088 deletions
+34 -7
View File
@@ -20,8 +20,10 @@ import { SessionManager } from './core/session';
import { AgentWorkflowManager } from './agents/AgentWorkflowManager';
import { buildAstraModeArchitectureContext } from './lib/contextBuilders/astraModeArchitecture';
import { isScheduleRequest, buildScheduleContext } from './lib/contextBuilders/scheduleContext';
import { isSelfAssessRequest, buildSelfAssessContext } from './lib/contextBuilders/selfAssessContext';
import { extractUrlFromPrompt, buildUrlContext } from './lib/contextBuilders/urlContext';
import { isSelfAssessRequest, isAboutSelf, buildSelfAssessContext } from './lib/contextBuilders/selfAssessContext';
import { ensureFeatureInventory } from './extension/featureInventory';
import { buildUrlContext } from './lib/contextBuilders/urlContext';
import { extractUrls } from './features/web/webFetch';
import { looksLikeCorrection, captureCorrection } from './intelligence/correctionLoop';
import { shouldUseMultiAgentWorkflow } from './lib/contextBuilders/multiAgentRouting';
import { buildThinkingPartnerResponseContract } from './lib/contextBuilders/thinkingPartnerContract';
@@ -35,6 +37,7 @@ import {
isExplicitSecondBrainRequest,
isSecondBrainInventoryRequest,
isNoBrainDataRefusal,
isAnalysisRequest,
} from './lib/contextBuilders/promptDetection';
import { stripAstraFormattingForAgentMode, computeModeSignature } from './lib/contextBuilders/systemPromptShaping';
import { sanitizeAssistantContent, isRestartedAnswer, parseRationale } from './lib/contextBuilders/outputSanitization';
@@ -154,6 +157,7 @@ import { applyFileCreateEditActions } from './agent/actions/fileCreateEdit';
import { applyFileDeleteReadActions } from './agent/actions/fileDeleteRead';
import { applyRunCommandActions } from './agent/actions/runCommand';
import { applyListFilesActions } from './agent/actions/listFiles';
import { applyWebFetchActions } from './agent/actions/webFetch';
import { applyBrainOpsActions } from './agent/actions/brainOps';
import { applyCalendarActions } from './agent/actions/calendar';
import { applySheetsActions } from './agent/actions/sheets';
@@ -542,8 +546,14 @@ export class AgentExecutor {
// [자기 평가 정본 주입] 기능 개선/자기 평가 질의는 RAG 경쟁에 맡기지 않고
// 현행 기능 인벤토리를 결정론적으로 주입 — 모델이 검색 없이 기억으로 답해
// 이미 있는 기능을 신규 제안하던 구식화 버그(3회 재발)의 마지막 구멍 봉쇄.
if (prompt && loopDepth === 0 && !isCasualConversation && activeBrain?.localBrainPath && isSelfAssessRequest(prompt)) {
if (prompt && loopDepth === 0 && !isCasualConversation && activeBrain?.localBrainPath
&& (isSelfAssessRequest(prompt) || (isAnalysisRequest(prompt) && isAboutSelf(prompt)))) {
try {
// 인벤토리 lazy 재생성 — 활성화 시 1회 생성은 brain 볼륨이 늦게
// 마운트되면 조용히 건너뛰어 파일이 영영 없는 상태가 됐다 (그 결과
// "파일 없음" 안내만 주입돼 모델이 구현 여부를 알 수 없었음).
// 질의 시점에 한 번 더 보장. idempotent — 있으면 즉시 return.
await ensureFeatureInventory(this.context);
const selfAssessBlock = buildSelfAssessContext(activeBrain.localBrainPath);
contextBlock += `\n\n${selfAssessBlock}`;
// 성공 로그 필수 — "주입이 됐는데 모델이 무시" vs "주입 자체가 안 됨"을
@@ -554,11 +564,26 @@ export class AgentExecutor {
}
}
// [URL 실데이터] 채팅 프롬프트에 URL 이 있으면 브리지로 본문을 추출해 주입.
// [근거 기반 분석 강제] 분석/검토/의견형 요청인데 모델이 코드를 읽지 않고
// "~로 보입니다" 추측으로 답하는 실패 모드 차단. 워크스페이스가 열려 있으면
// "주장 전에 read_file 로 실제 확인하라"는 지시를 주입 — 강제 주입 패턴의
// 5번째 적용 (일정→캘린더, 자기평가→인벤토리, 정정→캡처, URL→실데이터와 동일).
if (prompt && loopDepth === 0 && !isCasualConversation && isAnalysisRequest(prompt)
&& vscode.workspace.workspaceFolders?.length) {
contextBlock += `\n\n[근거 기반 분석 규칙 — 이 요청은 분석/검토형]
- 이 워크스페이스의 코드·문서·기능에 대한 주장은 *이 대화에서 실제로 읽은 파일*에만 근거하라.
- 확인하지 않은 구현을 "~로 보입니다", "~일 것입니다"라고 추측 서술하는 것은 금지. 먼저 <list_files path="..."/> 와 <read_file path="..."/> 태그로 관련 파일을 직접 열어 확인한 뒤 답하라. 태그를 emit 하면 시스템이 파일 내용을 주입하고 자동으로 이어서 답변하게 된다.
- ⚠️ "소스 코드 확인이 필요합니다"라고 말만 하고 끝내는 것은 금지다. 확인이 필요하다고 판단했다면 *바로 이 답변 안에서* <list_files>/<read_file> 태그를 emit 하라 — 그것이 확인하는 방법이다. 태그로 접근 불가능한 대상(외부 시스템·미설치 도구 등)에 한해서만 "확인하지 못함"으로 명시하라.
- "X 기능을 추가하라"고 제안하기 전에 그 기능이 이미 구현돼 있는지 해당 모듈을 찾아 읽어라. 이미 있는 기능을 새로 만들라고 제안하는 것은 잘못된 분석이다.
- 일반론·추측으로 빈칸을 채우지 마라.`;
}
// [URL 실데이터] 채팅 프롬프트에 URL 이 있으면 본문을 추출해 주입.
// /wikify 만 URL 접근이 가능하고 일반 채팅은 "접근 불가"라고 답하던 공백 수정.
if (prompt && loopDepth === 0 && !isCasualConversation) {
const url = extractUrlFromPrompt(prompt);
if (url) {
// v2: Bridge 추출 → 직접 fetch 폴백 (urlContext 내부) + 최대 2개 URL + config 게이트.
if (prompt && loopDepth === 0 && !isCasualConversation && getConfig().webAutoFetchEnabled !== false) {
const urls = extractUrls(prompt, 2);
for (const url of urls) {
try {
contextBlock += `\n\n${await buildUrlContext(url)}`;
logInfo('URL 컨텍스트 주입 시도.', { url });
@@ -720,6 +745,7 @@ export class AgentExecutor {
negativeCtx,
actualModel,
contextLength: config.contextLength,
dynamicBlocks: this._turnCtx.dynamicBlocks,
})
: buildAstraModeSystemPrompt({
prompt,
@@ -1586,6 +1612,7 @@ export class AgentExecutor {
await applyFileDeleteReadActions(ctx);
await applyRunCommandActions(ctx);
await applyListFilesActions(ctx);
await applyWebFetchActions(ctx);
await applyBrainOpsActions(ctx);
await applyCalendarActions(ctx);
await applySheetsActions(ctx);