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:
@@ -215,6 +215,30 @@ export interface DispatcherDeps {
|
||||
* 'off'였던 경우.
|
||||
*/
|
||||
requirementContract?: RequirementContract;
|
||||
/**
|
||||
* 현재 워크스페이스의 아키텍처 컨텍스트 (architecture.md 요약, 호출자가
|
||||
* 절단해 전달). 일반 챗은 이 컨텍스트를 자동 주입받지만 기업 모드는 빠져
|
||||
* 있던 공백 수정 — specialist 가 "이 프로젝트가 뭐냐"를 추측하지 않게.
|
||||
* contract 와 같은 4개 지점(planner/specialist/verifier/inspector)에 prepend.
|
||||
*/
|
||||
architectureContextBlock?: string;
|
||||
/**
|
||||
* 사용자 프롬프트에 포함된 URL 의 pre-fetch 결과 ([URL CONTENT] 블록).
|
||||
* 기업 모드에는 continuation loop 가 없어 LLM 주도 fetch 결과를 재분석할
|
||||
* 기회가 없으므로, dispatch 전에 호출자가 가져와 모든 에이전트에게 배포.
|
||||
*/
|
||||
webContextBlock?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* deps 의 자동 수집 컨텍스트(architecture + web)를 한 prefix 문자열로 합성.
|
||||
* 둘 다 없으면 빈 문자열 — 기존 동작과 100% 동일.
|
||||
*/
|
||||
function buildExtraContextPrefix(deps: DispatcherDeps): string {
|
||||
const blocks = [deps.architectureContextBlock, deps.webContextBlock]
|
||||
.map((b) => (b || '').trim())
|
||||
.filter(Boolean);
|
||||
return blocks.length > 0 ? blocks.join('\n\n') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,11 +377,13 @@ export async function runCompanyTurn(
|
||||
};
|
||||
} else {
|
||||
const ceoModel = modelForAgent(state, 'ceo', deps.defaultModel);
|
||||
const plannerExtraPrefix = buildExtraContextPrefix(deps);
|
||||
const plannerContract = deps.requirementContract
|
||||
? formatContractForPrompt(deps.requirementContract)
|
||||
: undefined;
|
||||
const plannerResult = await runCeoPlanner(deps.ai, userPrompt, state, {
|
||||
model: ceoModel,
|
||||
contractBlock: deps.requirementContract
|
||||
? formatContractForPrompt(deps.requirementContract)
|
||||
: undefined,
|
||||
contractBlock: [plannerExtraPrefix, plannerContract].filter(Boolean).join('\n\n') || undefined,
|
||||
signal: deps.signal,
|
||||
});
|
||||
plan = plannerResult.plan;
|
||||
@@ -666,11 +692,13 @@ async function _dispatchOne(
|
||||
peerOutputs,
|
||||
brainContext, // injected as `[SECOND BRAIN CONTEXT]` block
|
||||
knowledgeMixPolicy: policyBlock, // injected as `[KNOWLEDGE MIX POLICY]` block
|
||||
// alignment 단계에서 도출된 contract가 deps에 있으면 모든 specialist의
|
||||
// system 프롬프트에 같은 ground truth로 prepend된다. 추측 방지.
|
||||
contractBlock: deps.requirementContract
|
||||
? formatContractForPrompt(deps.requirementContract)
|
||||
: undefined,
|
||||
// alignment 단계에서 도출된 contract + 자동 수집 컨텍스트(architecture/web)가
|
||||
// deps에 있으면 모든 specialist의 system 프롬프트에 같은 ground truth로
|
||||
// prepend된다. 추측 방지.
|
||||
contractBlock: [
|
||||
buildExtraContextPrefix(deps),
|
||||
deps.requirementContract ? formatContractForPrompt(deps.requirementContract) : '',
|
||||
].filter(Boolean).join('\n\n') || undefined,
|
||||
});
|
||||
// 우선순위: stage > agent > global default.
|
||||
const model = (stageModelOverride && stageModelOverride.trim())
|
||||
@@ -696,9 +724,10 @@ async function _dispatchOne(
|
||||
// 옛 dynamic import 8회 → 정적 import 로 promote (파일 상단). 모듈 자체 cyclic 없음.
|
||||
const cfgRuntime = getDispatcherConfig();
|
||||
if (cfgRuntime.selfReflectorExternalEnabled && rawResponse) {
|
||||
const contractBlock = deps.requirementContract
|
||||
? formatContractForPrompt(deps.requirementContract)
|
||||
: undefined;
|
||||
const contractBlock = [
|
||||
buildExtraContextPrefix(deps),
|
||||
deps.requirementContract ? formatContractForPrompt(deps.requirementContract) : '',
|
||||
].filter(Boolean).join('\n\n') || undefined;
|
||||
const verdict = await verifyResponse(deps.ai, {
|
||||
task,
|
||||
response: rawResponse,
|
||||
@@ -1048,11 +1077,13 @@ async function _runReviewCycle(args: {
|
||||
return { verdict: 'aborted', rounds: round - 1 };
|
||||
}
|
||||
const startedAt = Date.now();
|
||||
// contract가 있으면 검수자/CEO 모두에게 같은 ground truth를 prepend —
|
||||
// 검수 기준이 contract와 일치하는지를 정확히 평가할 수 있다.
|
||||
const contractPrefix = deps.requirementContract
|
||||
? formatContractForPrompt(deps.requirementContract) + '\n\n'
|
||||
: '';
|
||||
// contract + 자동 수집 컨텍스트가 있으면 검수자/CEO 모두에게 같은 ground
|
||||
// truth를 prepend — 검수 기준이 contract와 일치하는지를 정확히 평가할 수 있다.
|
||||
const contractPrefixParts = [
|
||||
buildExtraContextPrefix(deps),
|
||||
deps.requirementContract ? formatContractForPrompt(deps.requirementContract) : '',
|
||||
].filter(Boolean).join('\n\n');
|
||||
const contractPrefix = contractPrefixParts ? contractPrefixParts + '\n\n' : '';
|
||||
|
||||
// ── 1) 검수자 LLM 콜 ──
|
||||
const inspectorSystem = contractPrefix + '당신은 산출물 *감리*입니다. 작업자의 결과물을 객관적으로 검토하고 한국어 마크다운으로 응답하세요.\n\n반드시 첫 줄을 다음 둘 중 하나로 시작:\n - ✅ 통과 — 산출물이 task 요구 + 위 contract의 criteria를 모두 충족하면.\n - ❌ 보완 필요: <구체 항목 한 줄> — contract 기준 누락·오류·약점이 있으면.\n\n그 다음 줄들에 *구체적인* 피드백 또는 칭찬 1~3줄. 모호한 일반론 금지.';
|
||||
|
||||
Reference in New Issue
Block a user