fix: proactive context compression for LM Studio small models - compress BEFORE fetch not after error
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"result": "Final report with inconsistencies. This should be long enough to pass validation.",
|
||||
"createdAt": 1778136474568,
|
||||
"createdAt": 1778137049532,
|
||||
"modelVersion": "unknown"
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
|
||||
"createdAt": 1778136474566,
|
||||
"createdAt": 1778137049529,
|
||||
"modelVersion": "unknown"
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"result": "Detailed Execution Plan: 1. Research 2. Analyze 3. Write report with high quality.",
|
||||
"createdAt": 1778136474564,
|
||||
"createdAt": 1778137049527,
|
||||
"modelVersion": "unknown"
|
||||
}
|
||||
+2
-2
@@ -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"
|
||||
}
|
||||
+10
-10
@@ -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
@@ -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
@@ -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.', {
|
||||
|
||||
Reference in New Issue
Block a user