fix: proactive context compression for LM Studio small models - compress BEFORE fetch not after error

This commit is contained in:
2026-05-07 15:57:48 +09:00
parent faf3060ae7
commit d9a2ebfedd
7 changed files with 86 additions and 19 deletions
@@ -1,5 +1,5 @@
{
"result": "Final report with inconsistencies. This should be long enough to pass validation.",
"createdAt": 1778136474568,
"createdAt": 1778137049532,
"modelVersion": "unknown"
}
@@ -1,5 +1,5 @@
{
"result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
"createdAt": 1778136474566,
"createdAt": 1778137049529,
"modelVersion": "unknown"
}
@@ -1,5 +1,5 @@
{
"result": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
"createdAt": 1778136474564,
"createdAt": 1778137049527,
"modelVersion": "unknown"
}
@@ -1,5 +1,5 @@
{
"result": "---\nid: stress_conflict_1778136474544\ndate: 2026-05-07T06:47:54.569Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\nFinal report with inconsistencies. This should be long enough to pass validation.\n\nFinal report with inconsistencies. This should be long enough to pass validation.\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\nFinal report with inconsistencies. This should be long enough to pass validation.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `60/100` | ⚠️ Medium |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[PLANNER]** 전략 수립 중... (18ms)\n- **[RESEARCHER]** 핵심 정보 수집 및 분석 중... (3ms)\n- **[WRITER]** 최종 리포트 작성 및 편집 중... (2ms)\n",
"createdAt": 1778136474569,
"result": "---\nid: stress_conflict_1778137049510\ndate: 2026-05-07T06:57:29.533Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\nFinal report with inconsistencies. This should be long enough to pass validation.\n\nFinal report with inconsistencies. This should be long enough to pass validation.\n\n---\n## 💡 Astra의 선제적 제안 (Proactive Next Actions)\nFinal report with inconsistencies. This should be long enough to pass validation.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `60/100` | ⚠️ Medium |\n| **Fallbacks Used** | `0` | ✅ None |\n| **Auto Retries** | `0` | ✅ Stable |\n| **Deduplication** | `0` | Standard |\n| **Processing Time** | `0.0s` | ✅ Fast |\n\n### 🔍 Decision Audit Trail\n- **[PLANNER]** 전략 수립 중... (16ms)\n- **[RESEARCHER]** 핵심 정보 수집 및 분석 중... (2ms)\n- **[WRITER]** 최종 리포트 작성 및 편집 중... (3ms)\n",
"createdAt": 1778137049533,
"modelVersion": "unknown"
}
@@ -1,8 +1,8 @@
{
"missionId": "stress_conflict_1778136474544",
"missionId": "stress_conflict_1778137049510",
"status": "completed",
"startTime": "2026-05-07T06:47:54.544Z",
"totalElapsedMs": 26,
"startTime": "2026-05-07T06:57:29.510Z",
"totalElapsedMs": 24,
"results": {
"planner": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
"researcher": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
@@ -16,30 +16,30 @@
{
"from": "idle",
"to": "planner",
"durationMs": 18,
"durationMs": 16,
"message": "전략 수립 중...",
"ts": "2026-05-07T06:47:54.562Z"
"ts": "2026-05-07T06:57:29.526Z"
},
{
"from": "planner",
"to": "researcher",
"durationMs": 3,
"durationMs": 2,
"message": "핵심 정보 수집 및 분석 중...",
"ts": "2026-05-07T06:47:54.565Z"
"ts": "2026-05-07T06:57:29.528Z"
},
{
"from": "researcher",
"to": "writer",
"durationMs": 2,
"durationMs": 3,
"message": "최종 리포트 작성 및 편집 중...",
"ts": "2026-05-07T06:47:54.567Z"
"ts": "2026-05-07T06:57:29.531Z"
},
{
"from": "writer",
"to": "completed",
"durationMs": 3,
"message": "미션 완료",
"ts": "2026-05-07T06:47:54.570Z"
"ts": "2026-05-07T06:57:29.534Z"
}
],
"resilienceMetrics": {
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "astra",
"displayName": "Astra",
"description": "The personal intelligence layer for Antigravity and VS Code. A private cognitive partner for deep project context, memory, and proactive strategic decision-making.",
"version": "2.80.14",
"version": "2.80.15",
"publisher": "g1nation",
"license": "MIT",
"icon": "assets/icon.png",
+70 -3
View File
@@ -2022,16 +2022,83 @@ export class AgentExecutor {
for (const candidateModel of modelCandidates) {
for (const variant of messageVariants) {
// 실제 전송할 메시지 (n_ctx 재시도 시 수정됨)
// 실제 전송할 메시지
let finalMessages = variant.messages;
// ── LM Studio 선제적 컨텍스트 압축 ──
// 소형 모델(4B 등)은 GPU 메모리 부족으로 n_ctx가 설정값보다 크게 줄어들 수 있고,
// 이때 LM Studio는 에러 대신 200 OK + 빈 스트림을 반환하여 재시도 불가.
// 따라서 전송 전에 선제적으로 메시지를 n_ctx에 맞게 압축합니다.
if (engine === 'lmstudio') {
const totalCharsRaw = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0);
const estimatedTokensRaw = Math.ceil(totalCharsRaw / 4);
const LM_CTX_SAFE_LIMIT = 3500; // 4096 n_ctx 기준 안전 마진
if (estimatedTokensRaw > LM_CTX_SAFE_LIMIT) {
logInfo('LM Studio proactive compression triggered.', {
estimatedTokens: estimatedTokensRaw,
limit: LM_CTX_SAFE_LIMIT,
originalMessageCount: finalMessages.length
});
// 1. system 메시지에서 [CONTEXT] 이후 부분을 우선 제거
const sysIdx = finalMessages.findIndex(m => m.role === 'system');
if (sysIdx >= 0) {
const sysContent = String(finalMessages[sysIdx].content || '');
const contextSplit = sysContent.indexOf('[CONTEXT]');
if (contextSplit > 0) {
// [CONTEXT] 이전까지만 유지 (기본 시스템 프롬프트 + 핵심 지시)
const trimmedSys = sysContent.slice(0, contextSplit).trimEnd();
finalMessages = finalMessages.map((m, i) =>
i === sysIdx ? { ...m, content: trimmedSys + '\n[Context omitted: model context limit]' } : m
);
}
}
// 2. 그래도 크면 시스템 프롬프트를 max 글자로 강제 잘라냄
const afterTrimChars = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0);
const afterTrimTokens = Math.ceil(afterTrimChars / 4);
if (afterTrimTokens > LM_CTX_SAFE_LIMIT && sysIdx >= 0) {
// 유저 메시지 토큰 계산
const nonSysTokens = finalMessages
.filter((_, i) => i !== sysIdx)
.reduce((acc, m) => acc + String(m.content || '').length, 0) / 4;
const maxSysChars = Math.max(2000, (LM_CTX_SAFE_LIMIT - Math.ceil(nonSysTokens) - 512)) * 4;
const sysContent = String(finalMessages[sysIdx].content || '');
if (sysContent.length > maxSysChars) {
finalMessages = finalMessages.map((m, i) =>
i === sysIdx ? { ...m, content: sysContent.slice(0, maxSysChars) + '\n[Truncated for model context limit]' } : m
);
}
}
// 3. 히스토리 메시지 정리: system + 마지막 user만 유지
const finalCheck = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0) / 4;
if (finalCheck > LM_CTX_SAFE_LIMIT) {
const sysMsg = finalMessages.find(m => m.role === 'system');
const lastUserMsg = [...finalMessages].reverse().find(m => m.role === 'user');
finalMessages = [
...(sysMsg ? [sysMsg] : []),
...(lastUserMsg ? [lastUserMsg] : [])
];
}
logInfo('LM Studio compression result.', {
originalTokens: estimatedTokensRaw,
compressedTokens: Math.ceil(finalMessages.reduce((a, m) => a + String(m.content || '').length, 0) / 4),
messageCount: finalMessages.length
});
}
}
const totalChars = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0);
const estimatedTokens = Math.ceil(totalChars / 4);
const streamBody = {
model: candidateModel,
messages: finalMessages,
messages: finalMessages.map(m => ({ role: m.role, content: m.content })),
stream: true,
...(engine === 'lmstudio'
? { max_tokens: 4096, temperature }
? { max_tokens: Math.min(4096, Math.max(256, 3500 - estimatedTokens)), temperature }
: { options: { num_ctx: 32768, num_predict: 4096, temperature } }),
};
logInfo('AI streaming request started.', {