a114d968b0
- Alignment Self-Learning: 자가 조사(질문 전 두뇌 검색)·사용자 답변 두뇌 저장·핵심메시지/프로젝트 컨텍스트 주입 (alignmentResearch.ts 신규)
- 웹 접근: Bridge 폴백 직접 fetch(webFetch.ts 신규)·<fetch_url> 액션 태그·기업 모드 URL/아키텍처 컨텍스트 주입·bare 도메인 인식
- 트리거 버그 수정: startsWith('/') 가 절대경로를 슬래시 명령으로 오인 — 분석 지시·URL 주입 전멸 원인 (회귀 테스트 고정)
- 자기지식 접지: 기능 인벤토리 lazy 재생성·학습 메커니즘 정본 섹션·[인벤토리 대조] 태그 의무화·결정론적 재구현 제안 정정 훅(featureConceptMap.ts 신규)
- 환경 자가점검: HealthCheckMonitor 에 Bridge/두뇌 볼륨/git 자격증명/확장 버전 검사 4종 + readyBar ⚠ 표시
- 두뇌 동기화: 원격 미설정 시 로컬 새로고침 모드·staged 기준 commit 판정·인증 부재 안내
- 기타: outputFormat 기본 markdown(제목 렌더 복구)·레슨/행동제약 truncation 보호 구역 이동·[CONTEXT] 절단 우선순위 재정렬
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
103 lines
6.3 KiB
Markdown
103 lines
6.3 KiB
Markdown
# 웹 접근 + 모드 동등성 수정 계획 (v2 — 적대적 리뷰 + 재검증 반영)
|
|
|
|
## v1 → v2 핵심 변화: 근본 원인 재진단
|
|
|
|
리뷰 과정에서 **일반 챗에는 URL 주입 기능이 이미 존재**함이 확인됨
|
|
(`src/lib/contextBuilders/urlContext.ts`, agent.ts:557-569에서 호출).
|
|
|
|
### 그런데 왜 실패했나 (정확한 원인)
|
|
1. **일반 챗**: `buildUrlContext`가 **Datacollect Bridge(127.0.0.1:3002)에 100% 의존**.
|
|
확장은 Bridge를 자동 시작하지 않음 → Bridge 꺼져 있으면 '접근 실패' 정직 블록
|
|
→ 모델이 "사이트 방문 불가"라고 답함. (Bridge 추출 실패/JS 렌더링 페이지도 동일)
|
|
2. **기업 모드**: dispatcher 경로에 URL 주입이 **아예 없음** → 항상 불가.
|
|
3. 검증 완료된 사실:
|
|
- `isCasualConversation` 게이트는 40자 초과 프롬프트에 영향 없음 (문제 아님)
|
|
- `buildRequestHistory`는 internal 메시지를 필터링하지 않음 → internal push가 LLM에 도달
|
|
- continuation loop 트리거 = "action이 chatHistory를 늘렸는가" (agent.ts:1238) → read_file과 동일 패턴이면 fetch_url도 자동 재분석
|
|
- `_handleCompanyCasual`은 일반 챗 경로(_handlePrompt)를 타므로 별도 처리 불필요
|
|
- BASE_SYSTEM_PROMPT/DispatcherDeps를 단언하는 기존 테스트 없음 (안전)
|
|
|
|
---
|
|
|
|
## 수정 설계 (v2)
|
|
|
|
### A. 신규 `src/features/web/webFetch.ts` — Bridge 무관 직접 fetch (vscode 의존 없음)
|
|
```ts
|
|
export function extractUrls(text: string, max = 2): string[]
|
|
// http(s)만, dedupe, trailing 구두점 제거, 슬래시 명령(/...)으로 시작하면 빈 배열
|
|
|
|
export interface WebFetchResult { ok: boolean; url: string; title: string; text: string; error?: string }
|
|
export async function fetchUrlDirect(url: string, opts?: { timeoutMs?: number /*15s*/; maxChars?: number /*20000*/ }): Promise<WebFetchResult>
|
|
// global fetch (bridgeClient가 이미 사용 — 호스트 지원 확인됨) + typeof 가드
|
|
// AbortController timeout / html이면 script·style·noscript 제거 → 태그 strip →
|
|
// 엔티티 최소 디코드 → 공백 정리 + <title> 추출 / html 아니면 raw cap / throw 금지
|
|
```
|
|
|
|
### B. `urlContext.ts` 개선 — Bridge → 직접 fetch 폴백 (기존 인터페이스 유지)
|
|
- `buildUrlContext(url)`: ① Bridge `/api/web-extract` 시도 (타임아웃 45s→**15s** 단축)
|
|
→ ② 실패/빈 본문이면 `fetchUrlDirect` 폴백 → ③ 둘 다 실패 시 기존 정직 블록
|
|
- **모듈 레벨 TTL 캐시** (URL→블록, 5분, 최대 10개) — chat/alignment/dispatcher가
|
|
같은 URL을 연달아 요청해도 네트워크 1회
|
|
- `extractUrlFromPrompt`는 유지하되 호출부는 `extractUrls`(최대 2개)로 확장
|
|
- 실패 안내 문구에서 "브리지 실행 확인" → "직접 접속도 실패" 반영
|
|
|
|
### C. `<fetch_url>` 액션 태그 (LLM 주도 — 양 모드 광고)
|
|
- 신규 `src/agent/actions/webFetch.ts`: `<fetch_url url="..."/>` (회당 최대 2개)
|
|
- fileDeleteRead.ts의 read_file 패턴 복제: regex → `buildUrlContext(url)` →
|
|
`ctx.report.push('🌐 Fetched: <url>')` + `ctx.chatHistory.push({role:'system', internal:true})`
|
|
- chatHistory push → 일반 챗 continuation loop 자동 트리거 (검증됨)
|
|
- transactionManager 불필요 (read-only)
|
|
- agent.ts `executeActions`에 `applyWebFetchActions(ctx)` 등록 (listFiles 다음)
|
|
- `utils.ts` BASE_SYSTEM_PROMPT: [ACTION 15: FETCH URL] — 라인 401 부근, 기존 포맷 준수
|
|
("링크의 실제 내용이 필요할 때만, 일반 지식 질문에는 사용 금지" 지침 포함)
|
|
- `promptBuilder.ts` specialist 액션 목록(129-142)에 fetch_url 추가
|
|
|
|
### D. 기업 모드 — DispatcherDeps에 **2개 별도 필드** (리뷰 권고 반영)
|
|
```ts
|
|
// dispatcher.ts DispatcherDeps에 추가:
|
|
architectureContextBlock?: string; // 현재 워크스페이스 아키텍처 (문제 2 해소)
|
|
webContextBlock?: string; // 사용자 프롬프트 URL pre-fetch 결과
|
|
```
|
|
- 4개 합성 지점(planner ~358, specialist ~671, verifier ~699, inspector/CEO ~1053)에서:
|
|
```ts
|
|
const prefix = [deps.architectureContextBlock, deps.webContextBlock, contract...]
|
|
.filter(Boolean).join('\n\n');
|
|
```
|
|
contract **앞에** 배치 (둘 다 optional — 미전달 시 기존 동작 100% 동일)
|
|
- `_runCompanyTurn`(sidebarProvider:2189) deps 빌드 시:
|
|
- `architectureContextBlock` = `this._buildProjectArchitectureContext()` 6,000자 절단
|
|
- `webContextBlock` = `extractUrls(userPrompt)` → `buildUrlContext` (캐시 적중) → 8,000자 cap
|
|
- 빌드는 try/catch — 실패해도 turn 진행
|
|
|
|
### E. Alignment 웹 컨텍스트
|
|
- `_runIntentAlignment` 첫 라운드: URL 있으면 `buildUrlContext`(캐시) 결과를
|
|
기존 `projectContext` 입력에 append (합계 3,000자 cap 유지 — web 부분은 별도 2,000자 cap 후 합산이 아니라, arch 먼저 + web 이어붙이고 총 5,000자로 상향)
|
|
- 효과: "그 사이트가 뭐냐"는 alignment 질문 차단
|
|
|
|
### F. config + package.json
|
|
- `webAutoFetchEnabled: boolean` 기본 true — `g1nation.web.autoFetchUrls`
|
|
(pre-fetch 게이트: 일반 챗 주입부 + _runCompanyTurn + alignment 모두 이 키 확인.
|
|
기존 일반 챗 주입부에도 게이트 추가 — 현재는 무조건 실행)
|
|
|
|
---
|
|
|
|
## 구현 순서
|
|
1. `src/features/web/webFetch.ts` 신규 + `tests/webFetch.test.ts`
|
|
2. `urlContext.ts` 폴백 + 캐시 + 타임아웃 단축
|
|
3. config.ts + package.json 키
|
|
4. `src/agent/actions/webFetch.ts` + agent.ts 등록 + BASE_SYSTEM_PROMPT + promptBuilder
|
|
5. dispatcher.ts deps 2필드 + 4지점 합성
|
|
6. sidebarProvider.ts: `_runCompanyTurn` + `_runIntentAlignment`
|
|
7. agent.ts 일반 챗 주입부: extractUrls(2개) + config 게이트
|
|
8. `npx tsc --noEmit` + `npm test`
|
|
|
|
## 리스크 (v2)
|
|
| 리스크 | 완화 |
|
|
|---|---|
|
|
| Bridge 타임아웃 45→15s 단축으로 느린 추출 실패 ↑ | 직접 fetch 폴백이 받아줌 (총 최대 ~30s) |
|
|
| EUC-KR 등 비UTF-8 직접 fetch 깨짐 | Bridge 우선 경로가 1차 방어, 한계 문서화 |
|
|
| 거대 페이지 토큰 폭주 | 직접 20,000자 / 기업 블록 8,000자 / alignment 총 5,000자 cap |
|
|
| dispatcher 테스트 파손 | 신규 필드 optional — 미전달 시 기존과 동일 |
|
|
| 캐시 오염 (실패 결과 캐시) | 실패 블록은 캐시하지 않음 — 성공 결과만 TTL 캐시 |
|
|
| LLM의 fetch_url 남발 | 회당 최대 2개 처리 + "필요할 때만" 프롬프트 지침 |
|