fix: v2.2.202 — 기업모드 Intent Alignment 가 일반 채팅 컨텍스트 무시하던 버그

증상: 일반 채팅에서 프로젝트·요구사항을 충분히 논의한 뒤 기업모드 전환 후
후속 작업을 요청하면 "추가 정보 필요 — 맥락/목표/기준/형식" 화면이 떠
사용자에게 *방금 말한 내용을 다시 묻는* 느낌을 줌.

원인:
- Intent Classifier 는 prior chat 컨텍스트(previousBrief/Tail) 받음 → follow-up
  분기 정확
- Intent Alignment (clarification 화면 만드는 분석기) 는 IntentAnalysisInput
  인터페이스에 chat history 필드가 없음 → 오직 현재 사용자 메시지만 봄
- 결과: 모드 전환 직후 첫 라운드 분석기는 사용자가 이전에 일반 채팅에서 한
  모든 설명을 못 봄 → context 빈칸 → openQuestions 에 "맥락은?" 추가

Fix:
- IntentAnalysisInput 에 priorChatSummary?: string 필드 추가
- 시스템 프롬프트에 *모드 전환 시 context 우선 추출* 규칙 추가 — 일반 채팅에서
  명시된 항목은 추측이 아니라 명시된 사실로 취급
- _buildUserMessage() 가 [모드 전환 직전 일반 채팅 요약] 블록을 user message
  상단에 주입
- sidebarProvider.ts 호출 지점에서 this._agent.getHistory() → 최근 10 turn
  (!internal) 추출 → "role: content" 한 줄씩, content 200자 cap
- 후속 라운드 (previousContract 있음) 면 history 중복 첨부 안 함 — 이미 contract
  에 흡수됨

효과: 일반 채팅 → 기업모드 전환 시 분석기가 prior chat 의 context/goal/criteria
를 직접 추출. redundant "맥락/목표/기준/형식 다시 말해 주세요" 질문 사라짐.
첫 라운드부터 confidence=high 가능 → 바로 본 작업 진행.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 11:24:34 +09:00
parent 7bec20620a
commit c27cd823a9
13 changed files with 98 additions and 25 deletions
@@ -1,5 +1,5 @@
{
"result": "직답 결과 — single-pass mock 응답입니다.",
"createdAt": 1780282136586,
"createdAt": 1780366882252,
"modelVersion": "unknown"
}
@@ -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"
}
@@ -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": {
@@ -1,5 +1,5 @@
{
"result": "Final report with inconsistencies. This should be long enough to pass validation.",
"createdAt": 1780282143243,
"createdAt": 1780366888974,
"modelVersion": "unknown"
}
@@ -1,5 +1,5 @@
{
"result": "Final report with inconsistencies. This should be long enough to pass validation.",
"createdAt": 1780282143242,
"createdAt": 1780366888973,
"modelVersion": "unknown"
}
@@ -1,5 +1,5 @@
{
"result": "[{\"heading\":\"본문\",\"scope\":\"전체 답변\"}]",
"createdAt": 1780282143239,
"createdAt": 1780366888969,
"modelVersion": "unknown"
}
@@ -1,5 +1,5 @@
{
"result": "[CONFLICT WARNING] 성능이 200% 증가했습니다. vs 그러나 동시에 50% 감소했습니다. 최적화와 성능 저하가 동시에 발견됨.",
"createdAt": 1780282143241,
"createdAt": 1780366888971,
"modelVersion": "unknown"
}
@@ -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": {
+29
View File
@@ -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) 도 별도 모듈로.
+1 -1
View File
@@ -6,7 +6,7 @@
"packages": {
"": {
"name": "astra",
"version": "2.2.201",
"version": "2.2.202",
"license": "MIT",
"dependencies": {
"@lmstudio/sdk": "^1.5.0",
+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.2.201",
"version": "2.2.202",
"publisher": "g1nation",
"license": "MIT",
"icon": "assets/icon.png",
+24
View File
@@ -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}"`);
+20
View File
@@ -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 },