diff --git a/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json b/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json index 461e9d0..6affb61 100644 --- a/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json +++ b/.astra/tests/engine/.astra/cache/7fa9e2c0ed212d5dbde1172e996cde86955f34dda22a6e02b95c9adc0a456927.json @@ -1,5 +1,5 @@ { "result": "직답 결과 — single-pass mock 응답입니다.", - "createdAt": 1780282136586, + "createdAt": 1780366882252, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json b/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json index 6dc29ca..97813a7 100644 --- a/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json +++ b/.astra/tests/engine/.astra/cache/8c208151bed9108b665cd93e98fc10d377a9fef641dd359504b8d53aecd0a4c3.json @@ -1,5 +1,5 @@ { - "result": "---\nid: wiki_on\ndate: 2026-06-01T02:48:56.587Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\n직답 결과 — single-pass mock 응답입니다.\n\n직답 결과 — single-pass mock 응답입니다.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `0/100` | ✅ Low |\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- **[DIRECT]** 답변 작성 중... (단일 호출 fast-path) (26ms)\n", - "createdAt": 1780282136588, + "result": "---\nid: wiki_on\ndate: 2026-06-02T02:21:22.254Z\ntype: knowledge_artifact\nstandard: P-Reinforce v3.0\ntags: [automated, connect_ai, brain_sync]\n---\n\n## 📌 Brief Summary\n직답 결과 — single-pass mock 응답입니다.\n\n직답 결과 — single-pass mock 응답입니다.\n---\n## 🛡️ Reliability & Audit Summary\n> [!NOTE]\n> 이 문서는 ConnectAI의 **Intelligent Resilience** 엔진에 의해 검증 및 정제되었습니다.\n\n| Metric | Value | Status |\n| :--- | :--- | :--- |\n| **Conflict Risk** | `0/100` | ✅ Low |\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- **[DIRECT]** 답변 작성 중... (단일 호출 fast-path) (21ms)\n", + "createdAt": 1780366882254, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/engine/.astra/missions/wiki_on.json b/.astra/tests/engine/.astra/missions/wiki_on.json index e64244f..ead4104 100644 --- a/.astra/tests/engine/.astra/missions/wiki_on.json +++ b/.astra/tests/engine/.astra/missions/wiki_on.json @@ -1,8 +1,8 @@ { "missionId": "wiki_on", "status": "completed", - "startTime": "2026-06-01T02:48:56.559Z", - "totalElapsedMs": 29, + "startTime": "2026-06-02T02:21:22.229Z", + "totalElapsedMs": 26, "results": { "direct": "직답 결과 — single-pass mock 응답입니다." }, @@ -12,16 +12,16 @@ { "from": "idle", "to": "direct", - "durationMs": 26, + "durationMs": 21, "message": "답변 작성 중... (단일 호출 fast-path)", - "ts": "2026-06-01T02:48:56.585Z" + "ts": "2026-06-02T02:21:22.250Z" }, { "from": "direct", "to": "completed", - "durationMs": 3, + "durationMs": 5, "message": "미션 완료", - "ts": "2026-06-01T02:48:56.588Z" + "ts": "2026-06-02T02:21:22.255Z" } ], "resilienceMetrics": { diff --git a/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json b/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json index 997b7be..2ad1099 100644 --- a/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json +++ b/.astra/tests/stress/.astra/cache/21818066876cbf8515758bc351bb3d9d44f32b0e4cd024b2e055db3a0d34417e.json @@ -1,5 +1,5 @@ { "result": "Final report with inconsistencies. This should be long enough to pass validation.", - "createdAt": 1780282143243, + "createdAt": 1780366888974, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json b/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json index eb4c5b0..a6af7e3 100644 --- a/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json +++ b/.astra/tests/stress/.astra/cache/4fc755e372f1dd80d6bffc7b2ef973124fb64ba505f767c53a783833bbc3fa6a.json @@ -1,5 +1,5 @@ { "result": "Final report with inconsistencies. This should be long enough to pass validation.", - "createdAt": 1780282143242, + "createdAt": 1780366888973, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json b/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json index 2c39627..c1303b4 100644 --- a/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json +++ b/.astra/tests/stress/.astra/cache/6e559207c4542d959700ff14f360e6575e54853929e991e579e318f2f5a19030.json @@ -1,5 +1,5 @@ { "result": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]", - "createdAt": 1780282143239, + "createdAt": 1780366888969, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json b/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json index ee8df55..a98cc17 100644 --- a/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json +++ b/.astra/tests/stress/.astra/cache/f65136cebc95448a7e93a45745cb73b3a5a01af5d82391ec29a25bd72b8239a5.json @@ -1,5 +1,5 @@ { "result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.", - "createdAt": 1780282143241, + "createdAt": 1780366888971, "modelVersion": "unknown" } \ No newline at end of file diff --git a/.astra/tests/stress/.astra/missions/stress_conflict_1780282143218.json b/.astra/tests/stress/.astra/missions/stress_conflict_1780366888954.json similarity index 75% rename from .astra/tests/stress/.astra/missions/stress_conflict_1780282143218.json rename to .astra/tests/stress/.astra/missions/stress_conflict_1780366888954.json index 94ca63b..0788462 100644 --- a/.astra/tests/stress/.astra/missions/stress_conflict_1780282143218.json +++ b/.astra/tests/stress/.astra/missions/stress_conflict_1780366888954.json @@ -1,8 +1,8 @@ { - "missionId": "stress_conflict_1780282143218", + "missionId": "stress_conflict_1780366888954", "status": "completed", - "startTime": "2026-06-01T02:49:03.218Z", - "totalElapsedMs": 26, + "startTime": "2026-06-02T02:21:28.954Z", + "totalElapsedMs": 21, "results": { "outline": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]", "section_0": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.", @@ -14,30 +14,30 @@ { "from": "idle", "to": "outline", - "durationMs": 20, + "durationMs": 14, "message": "답변 구조 잡는 중...", - "ts": "2026-06-01T02:49:03.238Z" + "ts": "2026-06-02T02:21:28.968Z" }, { "from": "outline", "to": "section", "durationMs": 2, "message": "본문 작성 중...", - "ts": "2026-06-01T02:49:03.240Z" + "ts": "2026-06-02T02:21:28.970Z" }, { "from": "section", "to": "polish", - "durationMs": 1, + "durationMs": 2, "message": "최종 다듬기 중...", - "ts": "2026-06-01T02:49:03.241Z" + "ts": "2026-06-02T02:21:28.972Z" }, { "from": "polish", "to": "completed", - "durationMs": 3, + "durationMs": 2, "message": "미션 완료", - "ts": "2026-06-01T02:49:03.244Z" + "ts": "2026-06-02T02:21:28.974Z" } ], "resilienceMetrics": { diff --git a/PATCHNOTES.md b/PATCHNOTES.md index 720925c..9bb6215 100644 --- a/PATCHNOTES.md +++ b/PATCHNOTES.md @@ -1,5 +1,34 @@ # Astra Patch Notes +## v2.2.202 (2026-06-01) +### 🐛 기업모드 — Intent Alignment 가 일반 채팅 컨텍스트 무시하던 버그 +**증상**: 사용자가 일반 채팅에서 프로젝트·요구사항을 충분히 논의한 뒤 기업모드로 전환해 *후속 작업* 을 요청하면, 분석기가 "추가 정보 필요 — 맥락/목표/기준/형식" 화면을 띄움. 사용자 입장에선 *방금 다 말한 내용을 다시 묻는* 느낌. + +**원인** (감사로 확인): +- `Intent Classifier` 는 prior chat 컨텍스트(previousBrief/Tail) 를 *받음* — 그래서 "follow-up vs new task" 분기는 정확 +- `Intent Alignment` (clarification 화면 만드는 분석기) 는 `IntentAnalysisInput` 인터페이스에 *chat history 필드가 없음* — 오직 현재 사용자 메시지만 봄 +- 결과: 모드 전환 직후 첫 라운드의 분석기는 사용자가 이전에 일반 채팅에서 한 모든 설명을 *못 봄* → context 빈칸 → openQuestions 에 "맥락은?" 추가 + +**Fix:** +- [`intentAlignment.ts`](src/features/company/intentAlignment.ts) `IntentAnalysisInput` 에 `priorChatSummary?: string` 필드 추가 +- 시스템 프롬프트에 *모드 전환 시 context 우선 추출* 규칙 추가 — 일반 채팅에서 명시된 항목은 *추측이 아니라 명시된 사실* 로 취급 +- `_buildUserMessage()` 가 `[모드 전환 직전 일반 채팅 요약]` 블록을 user message 상단에 주입 +- [`sidebarProvider.ts`](src/sidebarProvider.ts) 호출 지점에서 `this._agent.getHistory()` → 최근 10 turn (`!internal`) 추출 → `role: content` 한 줄씩, content 200자 cap +- *후속 라운드* (previousContract 있음) 면 history 중복 첨부 안 함 — 이미 contract 에 흡수됨 + +**효과**: +- 일반 채팅 → 기업모드 전환 시 분석기가 prior chat 의 context/goal/criteria 를 *직접 추출* +- "맥락/목표/기준/형식 다 다시 말해 주세요" 같은 redundant 질문 사라짐 +- 첫 라운드부터 confidence='high' 가능 → 바로 본 작업 진행 + +**기능 변경 없음 외부 API**. 컨텍스트 전달 누락만 fix. + +**신규 패키징:** `astra-2.2.202.vsix`. + +--- + + + ## v2.2.201 (2026-05-29) 🎯 ### 🏗️ 리팩터링 라운드 7 — datacollect cluster split (god-file 완전 해체) slashRouter god-file 의 마지막 클러스터 — 6 datacollect 핸들러 (research/benchmark/youtube/blog/wikify/meet) 도메인 파일로. 더불어 LLM 호출 인프라(callLmSynthesis/repairKoreanGlitches/bridgeErrorRemedy) 도 별도 모듈로. diff --git a/package-lock.json b/package-lock.json index 4433408..22017d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "astra", - "version": "2.2.201", + "version": "2.2.202", "license": "MIT", "dependencies": { "@lmstudio/sdk": "^1.5.0", diff --git a/package.json b/package.json index 9f99688..f4a922a 100644 --- a/package.json +++ b/package.json @@ -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.2.201", + "version": "2.2.202", "publisher": "g1nation", "license": "MIT", "icon": "assets/icon.png", diff --git a/src/features/company/intentAlignment.ts b/src/features/company/intentAlignment.ts index ae25669..dfe1473 100644 --- a/src/features/company/intentAlignment.ts +++ b/src/features/company/intentAlignment.ts @@ -61,6 +61,16 @@ export interface IntentAnalysisInput { * goal/format을 그쪽 능력에 맞춰 추출할 수 있다. */ availableRoleCategories?: string[]; + /** + * 모드 전환 *직전* 의 일반 채팅 히스토리 요약. 사용자가 일반 채팅에서 + * 프로젝트·맥락·요구를 충분히 논의한 뒤 기업모드로 전환해 *후속 작업* 을 + * 요청한 경우, 분석기가 이를 보면 context/goal/criteria 를 이미 도출 + * 가능 — 중복 질문(맥락/목표/기준/형식) 을 안 던진다. + * + * 형식: 최근 N(기본 10) 턴의 `role: content` 한 줄씩, 각 content 200자 cap. + * 없으면 undefined (첫 진입 / 모드 토글 없는 케이스). + */ + priorChatSummary?: string; } const SYSTEM_PROMPT = `당신은 "1인 기업 모드"의 *요청 분석가*입니다. 사용자의 자연어 요청을 받아 그것을 실행 가능한 작업 조건 5가지(C-G-C-F-Q)로 정리합니다. @@ -73,6 +83,8 @@ const SYSTEM_PROMPT = `당신은 "1인 기업 모드"의 *요청 분석가*입 ⚠️ 추측 금지. 사용자의 한 줄 + 컨텍스트에서 *직접 추론*되지 않는 정보는 채우지 마세요. 빈 칸은 그대로 두고 그 자리에 대응하는 질문을 openQuestions에 넣으세요. +⚠️ **[모드 전환 시 context 우선 추출]**: 입력에 \`[모드 전환 직전 일반 채팅 요약]\` 블록이 있으면, 그것을 **사용자의 한 줄과 같은 권위로** 취급하세요. 거기서 context/goal/criteria/format 을 *직접 추출* 한 뒤, 그래도 빠진 항목만 openQuestions 에 넣으세요. 사용자가 이미 일반 채팅에서 충분히 설명한 내용을 다시 물어보면 안 됩니다 — 일반 채팅에서 *명시적으로 언급* 된 항목은 추측이 아니라 **명시된 사실** 입니다. + confidence는 다음 기준으로 자체 판정: - "high" : C·G·C·F 4개 모두 prompt에서 직접 추론 가능. openQuestions = [] 가능. - "medium" : 대체로 명확하지만 1~2개 항목에서 합리적 가정 필요. 추가 질문 1~2개. @@ -95,6 +107,18 @@ function _buildUserMessage(input: IntentAnalysisInput): string { const lines: string[] = []; lines.push('[사용자 원본 요청]'); lines.push(input.userOriginalPrompt); + // 모드 전환 직전 일반 채팅 요약 — 분석기가 context/goal/criteria 를 *여기서 먼저 추출*. + // 사용자가 일반 채팅에서 이미 설명한 항목을 openQuestions 에 다시 넣지 못하게 막음. + if (input.priorChatSummary && input.priorChatSummary.trim()) { + lines.push(''); + lines.push('[모드 전환 직전 일반 채팅 요약]'); + lines.push('아래는 사용자가 *기업모드 전환 전* 일반 채팅에서 같은 주제로 나눈 대화입니다.'); + lines.push('여기에 명시된 context/goal/criteria/format 은 *사용자가 이미 말한 사실* 로 취급하여'); + lines.push('contract 의 해당 슬롯을 채우고, 다시 묻지 마세요.'); + lines.push('---'); + lines.push(input.priorChatSummary); + lines.push('---'); + } if (input.activePipelineName) { lines.push(''); lines.push(`(활성 파이프라인) "${input.activePipelineName}"`); diff --git a/src/sidebarProvider.ts b/src/sidebarProvider.ts index 0ca3c1f..d252afe 100644 --- a/src/sidebarProvider.ts +++ b/src/sidebarProvider.ts @@ -1890,6 +1890,25 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn // Pixel Office: 분석 시작 표시 (LLM 콜 직전). try { this.pixelOfficeOnAlignmentStart(opts.userPrompt); } catch { /* noop */ } + + // 모드 전환 직전 일반 채팅 요약 — Intent Alignment 가 *이미 논의된 맥락* 을 + // 재질문하지 않도록. 후속 라운드(previousContract 있음) 면 chatHistory 가 + // 이미 contract 에 흡수됐으므로 중복 첨부 안 함. + let priorChatSummary: string | undefined; + if (!opts.previousContract) { + try { + const history = this._agent.getHistory(); + const visible = history.filter((m) => !m.internal && (m.role === 'user' || m.role === 'assistant')); + // 마지막 N=10 턴, content 200자 cap — 토큰 폭주 방지. + const recent = visible.slice(-10); + if (recent.length > 0) { + priorChatSummary = recent + .map((m) => `${m.role}: ${String(m.content || '').replace(/\s+/g, ' ').trim().slice(0, 200)}`) + .join('\n'); + } + } catch { /* history 못 가져와도 alignment 자체는 동작 */ } + } + const analysis = await analyzeIntent( new AIService(), { @@ -1898,6 +1917,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn previousContract: opts.previousContract, activePipelineName: activePipeline?.name, availableRoleCategories: extractActiveRoleCategories(state), + priorChatSummary, }, // 분류기와 같은 작은 모델을 재사용 — 이 단계도 빠르고 가벼워야 함. { model: cfg.companyIntentClassifierModel || cfg.defaultModel },