chore: v2.2.73 — ASTRA-DEBUG 로그 레벨 + webview CSP font-src 보강
- ASTRA-DEBUG 정상 흐름 로그를 console.error → logInfo/console.log 로 강등 (chatHandlers, extension, slashRouter): DevTools에 ERR로 찍히던 오탐 제거 - sidebar webview에 명시적 CSP meta 추가 + font-src에 data: 허용 (sidebar.html, sidebarProvider._getHtml): VS Code outer iframe이 codicon.ttf를 data:font/ttf 로 inject하면서 기본 CSP에 막혀 매 prompt 마다 violation 경고가 찍히던 문제 해소 - 누적된 LM Studio / agent / 컨텍스트 매니저 / 테스트 갱신 동반 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -118,19 +118,21 @@ export interface TrimResult<M extends BudgetMessage> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 대화 기록을 토큰 예산 안에 맞춥니다.
|
||||
* 대화 기록을 토큰 예산 안에 맞춥니다 (sliding window).
|
||||
*
|
||||
* 전략:
|
||||
* 1. 항상 마지막 메시지(보통 현재 사용자 질문)는 유지.
|
||||
* 2. 최근 메시지부터 역순으로 예산이 허용하는 만큼 채움.
|
||||
* 3. 하나라도 잘렸으면 맨 앞에 `[이전 대화 N개 생략]` 마커를 끼워 모델이 맥락 누락을 인지하게 함.
|
||||
* 3. 하나라도 잘렸으면 맨 앞에 marker 를 끼워 모델이 맥락 누락을 인지하게 함.
|
||||
* v2.2.69+ — marker 콜백은 droppedCount 뿐 아니라 *잘려나간 메시지 배열* 도 받아
|
||||
* 단순 count 가 아닌 진짜 요약/맥락을 작성할 수 있다.
|
||||
*
|
||||
* 주의: 여기서 잘라내는 것은 *요청에 보낼* 메시지 배열일 뿐, UI에 표시되는 전체 기록은 그대로 둡니다.
|
||||
*/
|
||||
export function trimHistoryToBudget<M extends BudgetMessage>(
|
||||
messages: M[],
|
||||
budgetTokens: number,
|
||||
makeMarker: (droppedCount: number) => M
|
||||
makeMarker: (droppedCount: number, droppedMessages: M[]) => M
|
||||
): TrimResult<M> {
|
||||
if (messages.length === 0) {
|
||||
return { messages, droppedCount: 0, tokensAfter: 0 };
|
||||
@@ -154,7 +156,8 @@ export function trimHistoryToBudget<M extends BudgetMessage>(
|
||||
|
||||
const droppedCount = messages.length - kept.length;
|
||||
if (droppedCount > 0) {
|
||||
const marker = makeMarker(droppedCount);
|
||||
const droppedMessages = messages.slice(0, droppedCount);
|
||||
const marker = makeMarker(droppedCount, droppedMessages);
|
||||
kept.unshift(marker);
|
||||
used += estimateMessageTokens(marker);
|
||||
}
|
||||
|
||||
+40
-6
@@ -51,7 +51,7 @@ export interface IAgent {
|
||||
/**
|
||||
* 파이프라인 단계 상태 정의
|
||||
*/
|
||||
export type PipelineStage = 'idle' | 'planner' | 'researcher' | 'reflector' | 'writer' | 'completed' | 'error';
|
||||
export type PipelineStage = 'idle' | 'planner' | 'researcher' | 'reflector' | 'writer' | 'synthesizer' | 'completed' | 'error';
|
||||
|
||||
/**
|
||||
* 감사(Audit) 이력에 기록되는 단일 상태 전환 엔트리.
|
||||
@@ -453,7 +453,10 @@ export class AgentEngine {
|
||||
private readonly researcher: IAgent,
|
||||
private readonly writer: IAgent,
|
||||
// [Self-Reflection] Researcher와 Writer 사이에 주입되는 메타인지 노드. 미주입 시 기존 3단계 파이프라인을 그대로 유지.
|
||||
private readonly reflector?: IAgent
|
||||
private readonly reflector?: IAgent,
|
||||
// [5-stage pipeline] Writer(=Drafter)가 만든 초안을 사용자용 최종 답변으로 다듬는 노드.
|
||||
// 미주입 시 Writer 출력이 그대로 최종 답변이 된다(기존 동작 유지).
|
||||
private readonly synthesizer?: IAgent
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -600,14 +603,45 @@ export class AgentEngine {
|
||||
);
|
||||
|
||||
state.setResult('finalReport', finalReport);
|
||||
|
||||
|
||||
// --- Phase 4.5: Synthesizer (final polish) ---
|
||||
// Drafter(=Writer) 출력은 "초안"이다. Synthesizer가 주어졌으면 한 번 더 압축/매끄럽게 정리한다.
|
||||
// 입력이 작은 draft 뿐이라 컨텍스트가 가벼워, 작은 로컬 모델도 한 번에 처리할 수 있다.
|
||||
// 실패해도 미션을 막지 않고 Drafter 출력을 그대로 사용한다(soft-fail).
|
||||
let polishedReport = finalReport;
|
||||
if (this.synthesizer) {
|
||||
try {
|
||||
polishedReport = await this.executeStep(
|
||||
state, 'synthesizer', '최종 답변 다듬기 중...',
|
||||
() => this.resilientExecute(state, this.synthesizer!, 'Synthesizer', finalReport, prompt, signal, onProgress, {
|
||||
...options,
|
||||
context: brainContext,
|
||||
signal,
|
||||
config: { ...options?.config, role: 'synthesizer', isSamePrompt: true },
|
||||
priorResults: { plan, reflection, originalPrompt: prompt, ...options?.priorResults },
|
||||
abstractionLevel: 'balanced'
|
||||
}),
|
||||
`synthesizer::${finalReport}`, prompt, signal, onProgress
|
||||
);
|
||||
if (!polishedReport || polishedReport.trim().length < 24) {
|
||||
// 합성기가 빈/잘린 결과를 내면 안전하게 초안 사용.
|
||||
logError('[AgentEngine] Synthesizer returned empty/tiny output — using Drafter output.');
|
||||
polishedReport = finalReport;
|
||||
}
|
||||
} catch (synthErr: any) {
|
||||
if (synthErr?.name === 'AbortError') throw synthErr;
|
||||
logError(`[AgentEngine] Synthesizer soft-fail — using Drafter output: ${synthErr?.message || synthErr}`);
|
||||
polishedReport = finalReport;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Phase 5: Advice & Standardization ---
|
||||
const proactiveAdvice = await this.generateProactiveAdvice(finalReport, prompt, brainContext, signal);
|
||||
const proactiveAdvice = await this.generateProactiveAdvice(polishedReport, prompt, brainContext, signal);
|
||||
|
||||
// [Structural Fix] 생성된 제안의 무결성 검증 (최소 길이 50자 이상일 때만 append)
|
||||
const enrichedReport = proactiveAdvice && proactiveAdvice.length > 50
|
||||
? `${finalReport}\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\n${proactiveAdvice}`
|
||||
: finalReport;
|
||||
? `${polishedReport}\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\n${proactiveAdvice}`
|
||||
: polishedReport;
|
||||
|
||||
const standardizedReport = WikiFormatter.format(enrichedReport, state);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user