14 KiB
Antigravity Chat Relay — 접근 히스토리
최종 업데이트: 2026-03-07 20:38 KST
목표: Discord ↔ Antigravity IDE 양방향 대화 릴레이
📊 현재 상태 요약
| 방향 | 상태 | 방법 |
|---|---|---|
| Discord → Antigravity | ✅ 동작 | sendPromptToAgentPanel 명령어 |
| Antigravity → Discord | ⚠️ 부분 | getDiagnostics.summary (영어 제목만) |
| 실제 AI 텍스트 릴레이 | ❌ 미해결 | 모든 RPC 차단됨 |
Phase 1: Discord → Antigravity (채팅 전송) — ✅ 해결
시도 1: 채팅 입력 시뮬레이션 ❌
vscode.commands.executeCommand('workbench.action.chat.open')+ 클립보드 붙여넣기- 결과: 채팅 패널은 열리지만 텍스트 입력 안 됨
- 커밋:
b42475c,35f39ab,5780896,7f81528
시도 2: sendTextToChat API ❌
antigravity.sendTextToChat명령어 사용- 결과: 명령어 존재하지만 동작 안 함 (파라미터 불일치)
- 커밋:
e4eb756,c688812,180dba1,ae0fd78
시도 3: 전체 명령어 열거 → sendPromptToAgentPanel 발견 ✅
vscode.commands.getCommands(true)→ 171개 명령어 덤프antigravity.sendPromptToAgentPanel발견 → 직접 AI 에이전트에 텍스트 전송- 결과: ✅ 성공! Discord 메시지 → AI 에이전트 직접 전달
- 커밋:
8d5e59c
핵심 교훈: 문서화되지 않은 내부 API는 전체 열거 후 시도해야 함
Phase 2: Antigravity → Discord (AI 응답 릴레이) — ❌ 미해결
❌ 시도 1: 파일 변경 감시 (task.md 등)
- Brain 디렉토리의
task.md,walkthrough.md변경 감시 - 결과: 이 파일들은 AI 대화 텍스트가 아님! artifact(계획서, 보고서)만 저장됨
- 사용자 피드백: "md파일은 참고일뿐. 실제 AI가 대답한 것이 전달되어야"
- 커밋:
befa5d7
❌ 시도 2: getManagerTrace / getWorkbenchTrace 명령어
antigravity.getManagerTrace,antigravity.getWorkbenchTrace실행- 결과: 양쪽 모두
undefined반환 - 커밋:
150967d
❌ 시도 3: getDiagnostics → recentTrajectories 발견 → LS ConnectRPC 시도
getDiagnostics→ 대형 JSON (LS PID, CSRF 토큰,recentTrajectories포함)- 발견: LS 프로세스(language_server_windows_x64.exe) PID=7856, CSRF 토큰, 포트 3274
- 커밋:
952883d
❌ 시도 4: ConnectRPC GetTrajectoryDescriptions (잘못된 메서드명)
exa.language_server_pb.LanguageServerService/GetTrajectoryDescriptions- 결과: HTTP 404 — 메서드명이 잘못됨
- 커밋:
91b3a7e
❌ 시도 5: HTTPS 프로토콜 문제 → HTTP임을 발견
- LS가 HTTPS를 요구한다고 오인 → "Client sent HTTP to HTTPS server" 에러
- 실제로는 HTTP 포트 3274
- 결과: 프로토콜 수정 후 연결 성공 (Heartbeat OK)
- 커밋:
f2ed431
✅ 시도 6: Go 바이너리 분석 → 정확한 RPC 메서드명 추출
- Python으로
language_server_windows_x64.exe에서 100+ RPC 메서드 추출 - 발견:
Heartbeat← 연결 확인 ✅ (200 OK)GetUserTrajectoryDescriptions← trajectory 목록 ✅ (데이터 반환)GetCascadeTrajectorySteps← 대화 단계 ❌ (아래 참조)
- 커밋:
be6fae7,e4b98af
❌ 시도 7: GetCascadeTrajectorySteps + trajectoryId (from GetUserTrajectoryDescriptions)
GetUserTrajectoryDescriptions→{trajectoryId: "9807a8ec...", current: true}반환GetCascadeTrajectorySteps({trajectoryId: "9807a8ec..."})호출- 결과:
"trajectory not found"— workspace-level ID이지 conversation ID가 아님! - 커밋:
b6adeff
❌ 시도 8: 5가지 RPC 메서드+필드 조합 시도
GetCascadeTrajectorySteps({trajectoryId})→ ❌ trajectory not foundGetCascadeTrajectory({trajectoryId})→ ❌ trajectory not foundGetCascadeTrajectorySteps({cascadeId})→ ❌ trajectory not foundGetCascadeTrajectory({cascadeId})→ ❌ trajectory not foundGetUserTrajectory({trajectoryId})→ ❌ not_found
- 결론:
GetUserTrajectoryDescriptions의trajectoryId로는 단계 데이터를 가져올 수 없음 - 커밋:
dfc76a9
⚠️ 시도 9: getDiagnostics.recentTrajectories → googleAgentId + lastStepIndex
getDiagnostics→recentTrajectories에 cascade-levelgoogleAgentId,lastStepIndex,summary존재- 결과:
- ✅
lastStepIndex변화 감지 가능 (step 42 → 48 등) - ✅
summary추출 가능 (하지만 영어 대화 제목뿐 "Greeting User") - ❌ 실제 AI 응답 텍스트는 없음
- ✅
- 커밋:
0c96645
❌ 시도 10: latest trajectory만 추적 → 새 대화 놓침
trajectories[length-1]하나만 추적- 결과: 새 대화의 step 변화를 놓침
- 수정: 모든 trajectory 추적으로 변경
- 커밋:
41f90b3
⚠️ 시도 11: 새 대화 감지 → summary 릴레이 성공
- 새 trajectory 출현 (step > 0) 감지 → summary를 Discord에 전달
- 결과: ✅ Discord에서 메시지 수신! 하지만 "Greeting User" (영어 제목)
- 사용자 피드백: "대화창은 한글인데 돌아온건 영어야"
- 커밋:
7415ab7
❌ 시도 12: LoadTrajectory + 기존 RPC (googleAgentId 키로 재시도)
LoadTrajectory({trajectoryId})→ ❌ internal: failed to load trajectoryLoadTrajectory({googleAgentId})→ ❌ internal: failed to load trajectoryGetCascadeTrajectory({googleAgentId})→ ❌ trajectory not foundGetCascadeTrajectorySteps({googleAgentId})→ ❌ trajectory not found
- 결론: 모든 trajectory/cascade RPC가 외부 호출자에게 차단됨
- 커밋:
b0c2f86
❌ 시도 13: Brain 디렉토리에서 대화 텍스트 검색
- 짧은 대화 (
e8238b5e)의 brain 폴더 → 빈 폴더 (파일 없음) .system_generated/logs/→ 존재하지 않음 (모든 대화).system_generated/click_feedback/→ 브라우저 스크린샷만- 결론: Brain 디렉토리에는 AI 대화 텍스트가 저장되지 않음
❌ 시도 14: getDiagnostics.extensionLogs에서 AI 텍스트 추출
- extensionLogs에서 notify_user 패턴, content 블록, 한국어 텍스트 검색
- 결과: ❌ 실패 — summary fallback 트리거됨, extensionLogs에 AI 응답 텍스트 없음
- 커밋:
0d90b25
🔑 확인된 사실
동작하는 것
| 항목 | 상태 | 비고 |
|---|---|---|
sendPromptToAgentPanel |
✅ | Discord → AI 전달 완벽 동작 |
| LS Heartbeat (port 3274) | ✅ | ConnectRPC 연결 확인 |
GetUserTrajectoryDescriptions |
✅ | workspace-level trajectory 목록 반환 |
getDiagnostics.recentTrajectories |
✅ | cascade-level 메타데이터 (googleAgentId, summary, lastStepIndex) |
| Step count 변화 감지 | ✅ | lastStepIndex diff로 새 응답 감지 |
| Summary를 Discord에 전달 | ✅ | 영어 대화 제목만 (실제 AI 텍스트 아님) |
동작하지 않는 것 (차단됨)
| 항목 | 에러 | 시도 횟수 |
|---|---|---|
GetCascadeTrajectorySteps |
trajectory not found | 6+ |
GetCascadeTrajectory |
trajectory not found | 4+ |
LoadTrajectory |
internal: failed to load | 2 |
GetUserTrajectory |
not_found | 1 |
| Brain 디렉토리 대화 텍스트 | 파일 없음 | 1 |
getManagerTrace |
undefined | 1 |
getWorkbenchTrace |
undefined | 1 |
🔬 SDK / Extension.js 심층 분석 결과
extension.js (2.9MB minified) 정적 분석 (2026-03-07 20:50 KST)
핵심 아키텍처 발견
| 항목 | 발견 |
|---|---|
| LS 통신 | LanguageServerClient.getInstance().client.XXX() — raw HTTP가 아닌 내부 client 객체 |
| 채팅 패널 | ChatPanelProvider 클래스 → WebView 관리 |
| WebView 통신 | sendActionToChatPanel() → LS → WebView |
| WebView → Host | onDidReceiveMessage({type:'update', content:...}) |
| 내보내기 API | 없음 — exports는 npm 라이브러리뿐 |
| 명령어 | 21개 등록, 대화 접근 명령어 없음 |
ChatActionType 열거형 (확인된 값)
| 액션 | 용도 |
|---|---|
toggleFocus |
채팅 포커스 토글 |
openChatPanel |
채팅 패널 열기 |
CodeBlockMention |
코드 블록 멘션 |
FileMention |
파일 멘션 |
setCascadeId |
cascade ID 설정 |
setApiKey |
API 키 설정 |
pollMcpServerStates |
MCP 서버 폴링 |
updateUserStatus |
사용자 상태 업데이트 |
updateStateForCascadeFilesWithInIdeDiffs |
IDE diff 상태 업데이트 |
핵심 통신 경로 (확인됨)
Extension Host → LanguageServerClient.client → LS Process (ConnectRPC)
↕
ChatPanelProvider → WebView (chat.js)
↕
onDidReceiveMessage / postMessage
⚠️ 우리의 raw HTTP 접근이 실패한 이유: LS Client와 raw HTTP는 다른 인증/세션 컨텍스트를 사용. LS Client는 Extension Host 프로세스 내에서 초기화되며, 자체 gRPC 채널을 가짐. Raw HTTP는 CSRF 토큰으로 인증하지만, trajectory 데이터 접근에는 추가 세션 컨텍스트 필요.
🚧 아직 시도하지 않은 접근법
1. StreamCascadeReactiveUpdates (서버 스트리밍 RPC)
- ConnectRPC 서버-사이드 스트리밍 — 실시간 업데이트 구독
- 단순 요청/응답이 아닌 SSE/chunked 방식 필요
- 난이도: 높음 (스트리밍 프로토콜 구현 필요)
2. Antigravity WebView 메시지 인터셉트
- 채팅 패널 WebView ↔ Extension Host 사이의 postMessage 후킹
- VS Code API의
window.registerWebviewViewProvider또는 WebView panel 접근 - 난이도: 높음 (내부 WebView 참조 필요)
3. Extension Host 콘솔 출력 캡처
console.log출력에서 AI 응답 텍스트 패턴 검색- OutputChannel이나 DevTools 콘솔에서 직접 캡처
- 난이도: 중간
4. LS 네트워크 트래픽 스니핑
- LS ↔ Extension Host 사이의 네트워크 트래픽 캡처
- Wireshark/mitmproxy 등으로 실제 데이터 흐름 확인
- 난이도: 중간 (디버깅 단계, 프로덕션 불가)
5. Antigravity 확장의 내부 API 직접 접근
vscode.extensions.getExtension('google.antigravity')→ exports 탐색- 내부
lspClient또는 대화 저장소에 직접 접근 - 난이도: 중간 (exports가 노출되어 있다면)
6. IndexedDB / LevelDB 대화 저장소
- VS Code는 IndexedDB(웹) 또는 LevelDB(네이티브)에 데이터 저장
%APPDATA%/Antigravity/하위의 DB 파일 직접 읽기- 난이도: 높음 (DB 스키마 역설계 필요)
7. workbench.action.chat.openEditSession 등 채팅 내보내기 명령
- VS Code 내장 채팅 관련 명령어로 대화 내용 추출
- 난이도: 낮음 (시도 안 해봄)
📝 핵심 교훈
trajectoryId≠ 대화 ID:GetUserTrajectoryDescriptions의trajectoryId는 workspace-level,getDiagnostics의googleAgentId는 cascade-level — 둘 다 RPC 단계 데이터 접근에 실패- LS는 외부 HTTP 호출 차단: Heartbeat, GetUserTrajectoryDescriptions는 동작하지만, 실제 대화 데이터를 반환하는 모든 RPC는 차단됨
- Brain 디렉토리 = artifacts만: 실제 AI 대화 텍스트는 brain에 저장되지 않음
- summary = 영어 대화 제목:
getDiagnostics.recentTrajectories.summary는 AI가 자동 생성한 제목이지 실제 응답이 아님 - 반복 실수: 같은 RPC를 다른 필드명으로 반복 시도 (trajectoryId, cascadeId, googleAgentId, conversationId → 모두 실패)
🎯 체계적 시도 계획 (우선순위순)
아래 각 접근법을 순서대로 시도. 각 시도는 별도 프로브 코드로, 결과 로그 확인 후 다음 단계 진행.
Trial A: Extension API exports 탐색 (난이도: 낮음)
방법: vscode.extensions.getExtension('google.antigravity') → .exports 탐색
SDK 분석 결과: exports는 npm 라이브러리만 (63개). 유용한 API 없을 것으로 예상
그래도 시도하는 이유: 런타임에서만 노출되는 API가 있을 수 있음 (minified 코드에서 못 찾은 것)
상태: 🔄 프로브 코드 빌드 완료, 설치 대기 중
Trial B: sendChatActionMessage 명령어 활용 (난이도: 중, 새로 발견)
방법: antigravity.sendChatActionMessage 명령어로 SendActionToChatPanelRequest JSON 전달
SDK 분석 근거: extension.js에서 registerCommand(i.SEND_CHAT_ACTION_MESSAGE, async e => { ... sendActionToChatPanel(e) }) 확인
프로브 코드:
// SendActionToChatPanelRequest JSON 구조로 호출
await vscode.commands.executeCommand('antigravity.sendChatActionMessage',
JSON.stringify({ actionType: 'toggleFocus', payload: [] })
);
성공 기준: 채팅 패널 상태 변경이나 데이터 반환
기대: 직접적인 대화 텍스트 접근보다는 채팅 패널 제어에 가까움
Trial C: VS Code Chat History API (난이도: 낮음)
방법: chat 관련 내보내기/히스토리 명령어 탐색
프로브 코드: chat export/history/conversation 명령어 필터링 (Trial A 프로브에 포함)
상태: 🔄 Trial A와 함께 프로브 중
Trial D: StreamCascadeReactiveUpdates (난이도: 높음, 기대확률: 높)
방법: ConnectRPC 서버-사이드 스트리밍으로 실시간 업데이트 구독
프로브 코드:
// ConnectRPC streaming: POST + Transfer-Encoding: chunked
// 또는 SSE endpoint
const streamRes = await fetch(`http://127.0.0.1:3274/exa.language_server_pb.LanguageServerService/StreamCascadeReactiveUpdates`, {
method: 'POST',
headers: { 'Content-Type': 'application/connect+proto', 'x-codeium-csrf-token': csrfToken },
body: Buffer.from([0, 0, 0, 0, 0]) // empty protobuf message
});
// Read streaming response chunks
성공 기준: 스트림에서 AI 응답 텍스트가 실시간으로 수신됨
실패 시: Trial E 진행
Trial E: Electron IPC / DevTools Protocol 인터셉트 (난이도: 높음, 기대확률: 높)
방법: Electron의 IPC 또는 Chrome DevTools Protocol로 WebView 메시지 캡처
프로브 코드:
// DevTools Protocol로 WebView의 console.log/network 캡처
// 또는 Electron의 webContents.getAllWebContents()로 채팅 패널 접근
성공 기준: WebView ↔ Extension Host 사이 메시지에서 AI 텍스트 추출
실패 시: 완전히 다른 아키텍처 접근 필요 (예: 화면 OCR, Accessibility API 등)