v2.2.299~307: 아키텍처 수렴 + 채팅 정리 + 벤치마킹 강화 + Claude 구독 엔진
- v2.2.299 아키텍처 수렴: coreChat 통일(엔진 휴리스틱 3벌 제거), 기업 모드 검색 오케스트레이터 승격, lib/execUtil(실행 래퍼 6곳·Python 탐지 3벌 단일화), lib/kstSchedule(워처 4개 nowInKst 통합), estimateTokens 통합, 설정 접근 규칙 명문화 - v2.2.300 채팅 화면 정리: LiveReasoningFilter(스트리밍 중 <think>/Harmony 추론 토큰 단위 차단), 확신도·검토요청 footer 기본 숨김(계산·Reflection 은 유지) - v2.2.301 문맥·의도 이해: [답변 전 이해 원칙] 상시 주입, 워크플로우 의도 브리핑, Report QA 루프(규칙 레지스트리+실측치+회귀 게이트, 블로그_v3 개념 이식) - v2.2.302 /benchmark 비즈니스 렌즈(가격·수익·운영)+빌드 프롬프트 모드+QA 연계 - v2.2.303 handoff 모드(측정치 무손실 인수인계 문서)+/claude(Claude Code 터미널 위임) - v2.2.304 이식성: 지식 경로 두뇌-상대 규약(pickWikiDir 상대 해석), 이사 체크리스트 - v2.2.305 Claude 구독 엔진: claude: 프로바이더(CLI 위임, 모델 드롭다운 자동 노출, coreChat 지원 — 워크플로우·QA도 구독 모델 가능) - v2.2.306 Tone Guard: AI 상투어 금지 레지스트리(상담사 화법 실사례 8종+대조 예시) - v2.2.307 /benchmark 레이아웃 골격(sectionRoles 결정론 분석, 롤링 배너 즉답), 파트별 실패 격리, 합성 타임아웃 120→300초 검증: tsc 무오류 + jest 888 통과 + esbuild 정상 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+52
-6
@@ -41,6 +41,7 @@ import {
|
||||
} from './lib/contextBuilders/promptDetection';
|
||||
import { stripAstraFormattingForAgentMode, computeModeSignature } from './lib/contextBuilders/systemPromptShaping';
|
||||
import { sanitizeAssistantContent, isRestartedAnswer, parseRationale } from './lib/contextBuilders/outputSanitization';
|
||||
import { LiveReasoningFilter } from './lib/contextBuilders/liveReasoningFilter';
|
||||
import { buildEngineMessageVariants } from './lib/contextBuilders/engineMessages';
|
||||
import { buildMemoryContext as buildMemoryContextFn } from './lib/contextBuilders/memoryContext';
|
||||
import { extractEvidenceFilesFromProjectKnowledge, extractPriorityPreviewFiles } from './lib/contextBuilders/projectEvidence';
|
||||
@@ -102,6 +103,7 @@ import {
|
||||
} from './features/secondBrainTrace';
|
||||
import { MemoryManager } from './memory';
|
||||
import { RetrievalOrchestrator } from './retrieval';
|
||||
import { embedQuery } from './retrieval/embeddings';
|
||||
import { isQaRegressionFeedback, findUnaddressedChecklistItems } from './retrieval/lessonHelpers';
|
||||
import { buildKnowledgeMixPolicy, ResolvedKnowledgeMix } from './retrieval/knowledgeMix';
|
||||
import {
|
||||
@@ -358,6 +360,44 @@ export class AgentExecutor {
|
||||
this.restoreLastSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* [코어 수렴] 기업 모드(dispatcher)용 두뇌 컨텍스트 블록 — 경량 scopedBrainRetriever
|
||||
* 대신 메인 오케스트레이터의 전체 검색 경로(임베딩 하이브리드·청크)를 태운다.
|
||||
* 텔레그램 경량 경로는 의존성 최소화를 위해 의도적으로 그대로 둔다.
|
||||
* 반환 포맷은 기존 buildContextBlock 과 동일 — specialist 프롬프트 형식 불변.
|
||||
*/
|
||||
public async retrieveBrainBlockForCompany(query: string, scopeFolders: string[], limit: number): Promise<string> {
|
||||
const config = getConfig();
|
||||
const brain = getActiveBrainProfile();
|
||||
if (!brain?.localBrainPath) return '';
|
||||
let queryEmbedding: number[] | undefined;
|
||||
if (config.embeddingModel) {
|
||||
try {
|
||||
queryEmbedding = await Promise.race([
|
||||
embedQuery(query, { baseUrl: config.ollamaUrl, model: config.embeddingModel }),
|
||||
new Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), 4000)),
|
||||
]);
|
||||
} catch { queryEmbedding = undefined; }
|
||||
}
|
||||
const chunks = this.retrievalOrchestrator.retrieveBrainChunksScoped(query, brain, {
|
||||
limit,
|
||||
scopeFolders,
|
||||
queryEmbedding,
|
||||
embeddingModel: config.embeddingModel || undefined,
|
||||
embeddingBlendAlpha: config.embeddingBlendAlpha,
|
||||
chunkLevelRetrieval: config.chunkLevelRetrieval === true,
|
||||
chunkTargetChars: config.chunkTargetChars,
|
||||
});
|
||||
if (chunks.length === 0) return '';
|
||||
const header = scopeFolders.length > 0
|
||||
? '[제2뇌 컨텍스트 — 매핑된 지식 폴더에서 검색]'
|
||||
: '[제2뇌 컨텍스트 — 전체 브레인 검색]';
|
||||
const body = chunks
|
||||
.map((c, i) => `(#${i + 1}) ${c.title}\n${c.content}`)
|
||||
.join('\n\n---\n\n');
|
||||
return `${header}\n\n${body}`;
|
||||
}
|
||||
|
||||
private async restoreLastSession() {
|
||||
return restoreLastSessionFn({
|
||||
sessionManager: this.sessionManager,
|
||||
@@ -946,10 +986,16 @@ export class AgentExecutor {
|
||||
// policy enforcement) emits a final `streamReplace` so the bubble
|
||||
// ends up matching the cleaned answer regardless of what slipped
|
||||
// through live.
|
||||
// [Clean Stream] g1nation.liveStreamTokens=false (기본) 이면 토큰을 내부에만
|
||||
// 누적하고 sanitize 끝난 최종 답변만 한 번에 표시 → Harmony/think 마커가 잠깐
|
||||
// 화면에 노출되는 누설을 원천 차단한다. true 로 두면 legacy 라이브 스트리밍.
|
||||
// [Clean Stream] liveStreamTokens=true(기본) 면 토큰을 실시간 표시하되,
|
||||
// LiveReasoningFilter 가 <think>/<|channel|>thought 류 추론 구간을 토큰 단위로
|
||||
// 걸러 사용자가 볼 필요 없는 생각 텍스트는 화면에 흐르지 않는다. false 면
|
||||
// 내부 누적 후 sanitize 된 최종 답변만 한 번에 표시.
|
||||
const postLiveDeltas = loopDepth === 0 && getConfig().liveStreamTokens === true;
|
||||
const liveFilter = postLiveDeltas ? new LiveReasoningFilter() : null;
|
||||
const postLiveToken = (token: string) => {
|
||||
const visible = liveFilter ? liveFilter.push(token) : token;
|
||||
if (visible) this.webview?.postMessage({ type: 'streamChunk', value: visible });
|
||||
};
|
||||
|
||||
let lmStudioStats: ChatStreamStats | undefined;
|
||||
if (useLmStudioSdk) {
|
||||
@@ -970,7 +1016,7 @@ export class AgentExecutor {
|
||||
if (this.isStaleRun(runId)) return;
|
||||
if (token) {
|
||||
aiResponseText += token;
|
||||
if (postLiveDeltas) this.webview.postMessage({ type: 'streamChunk', value: token });
|
||||
if (postLiveDeltas) postLiveToken(token);
|
||||
}
|
||||
if (stopReason) finishStopReason = stopReason;
|
||||
if (stats) lmStudioStats = stats;
|
||||
@@ -1045,7 +1091,7 @@ export class AgentExecutor {
|
||||
const token = engine === 'lmstudio' ? json.choices?.[0]?.delta?.content || '' : json.message?.content || json.response || '';
|
||||
if (token) {
|
||||
aiResponseText += token;
|
||||
if (postLiveDeltas) this.webview.postMessage({ type: 'streamChunk', value: token });
|
||||
if (postLiveDeltas) postLiveToken(token);
|
||||
}
|
||||
const fr = engine === 'lmstudio'
|
||||
? json.choices?.[0]?.finish_reason
|
||||
@@ -1077,7 +1123,7 @@ export class AgentExecutor {
|
||||
const token = engine === 'lmstudio' ? json.choices?.[0]?.delta?.content || '' : json.message?.content || json.response || '';
|
||||
if (token) {
|
||||
aiResponseText += token;
|
||||
if (postLiveDeltas) this.webview.postMessage({ type: 'streamChunk', value: token });
|
||||
if (postLiveDeltas) postLiveToken(token);
|
||||
}
|
||||
const fr = engine === 'lmstudio'
|
||||
? json.choices?.[0]?.finish_reason
|
||||
|
||||
Reference in New Issue
Block a user