# 봇 Telegram 출력 필터링 — tool 실행 결과 노출 방지

## 배경
cokacdir가 Claude Code를 `--output-format text`로 실행할 때, Claude의 텍스트 응답에 tool 실행 과정(파일 읽기, 셸 명령 등)이 포함되어 Telegram 채팅에 그대로 노출됨.
- 예: CLAUDE.md 내용이 Telegram에 그대로 출력 (내부 시스템 프롬프트 노출)
- 모든 봇(dev1/dev2/dev3/dev4)이 동일 구조로 영향받음

## 수정 대상 파일
1. `/home/jay/workspace/services/multimodel-bot/engine_v2/cli_runner.py` (L42-64)
2. `/home/jay/workspace/services/multimodel-bot/engine_v2/bot_api.py` (L24-38)
3. `/home/jay/workspace/services/multimodel-bot/engine_v2/content_sanitizer.py` (기존 미사용)

## 작업 내용

### A안: cli_runner.py 출력 형식 변경 (근본 해결)

#### A-1. `run_claude()` 메서드 수정 (cli_runner.py L42-64)
현재:
```python
cmd = [
    "/home/jay/.local/bin/claude",
    "-p",
    "--output-format", "text",
    "--model", model,
]
```

변경:
```python
cmd = [
    "/home/jay/.local/bin/claude",
    "-p",
    "--output-format", "json",
    "--model", model,
]
```

#### A-2. `run_claude()` 반환값에서 JSON 파싱 추가
`--output-format json` 사용 시 stdout은 JSON 배열로 반환됨.
응답 구조 (예시):
```json
[
  {"type": "text", "text": "실제 응답 내용..."},
  {"type": "tool_use", "name": "Read", ...},
  {"type": "tool_result", ...}
]
```

또는 단일 객체:
```json
{"type": "result", "result": "응답 텍스트", "cost_usd": 0.05, ...}
```

**주의**: `claude -p --output-format json`의 정확한 출력 형식을 먼저 확인해야 함.
테스트 방법:
```bash
echo "안녕" | CLAUDECODE= /home/jay/.local/bin/claude -p --output-format json --model haiku 2>/dev/null
```

파싱 로직:
1. stdout을 JSON으로 파싱
2. `type: "result"` 또는 최종 텍스트 블록만 추출
3. tool_use / tool_result 블록은 무시
4. 추출된 텍스트만 CLIResult.stdout에 저장

⚠️ JSON 파싱 실패 시 기존 text 출력으로 fallback (안전장치 필수)

### B안: bot_api.py에 content_sanitizer 적용 (이중 안전장치)

#### B-1. bot_api.py `call_claude()` 수정 (L24-38)
content_sanitizer를 import하고, 반환 전 필터링 적용:

```python
from engine_v2.content_sanitizer import sanitize_output

async def call_claude(prompt: str, timeout: int = 600, code_analysis: bool = False) -> str:
    result = await CLIRunner.run_claude(prompt, timeout=timeout, code_analysis=code_analysis)
    # ... 기존 에러 처리 ...
    output = result.stdout if result.stdout else "⚠️ Claude CLI에서 빈 응답이 반환되었습니다."
    return sanitize_output(output)  # 필터링 적용
```

#### B-2. content_sanitizer.py에 봇 출력용 sanitize_output 함수 추가/확인
다음 패턴을 필터링:
- ```` ```shell ... ``` ```` 코드 블록 중 tool 실행 내용 (cat, Read, Grep 등)
- `# 팀장이름 - 개발N팀장` 같은 CLAUDE.md 프롬프트 시작 패턴
- `## 정체성`, `## 역할`, `## 작업 규칙` 등 시스템 프롬프트 섹션 헤더
- 연속된 파일 내용 덤프 (20줄 이상 코드 블록)

**필터링 우선순위**:
1. A안(JSON 파싱)이 정상 작동하면 B안은 fallback용으로만 동작
2. A안 실패 시 B안이 최소한의 필터링 수행

### 공통: call_codex(), call_gemini()에도 동일 적용
- `call_codex()` (L41-60): Codex CLI도 동일 패턴 적용
- `call_gemini()` (L63-75): Gemini CLI도 동일 패턴 적용
- 각 엔진의 `--output-format` 옵션 확인 후 적용

## 검증

### 필수 테스트
1. 기존 테스트 통과: `cd /home/jay/workspace/services/multimodel-bot && python3 -m pytest tests/ -x` (테스트 있는 경우)
2. JSON 출력 형식 확인:
   ```bash
   echo "안녕하세요" | CLAUDECODE= /home/jay/.local/bin/claude -p --output-format json --model haiku 2>/dev/null | python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin), indent=2, ensure_ascii=False)[:500])"
   ```
3. 수동 검증: 수정 후 간단한 프롬프트로 봇 호출 → Telegram에 tool 출력이 안 보이는지 확인
4. edge case: Claude가 도구를 사용하지 않는 단순 응답도 정상 반환되는지 확인

### 안전장치 (필수)
- JSON 파싱 실패 시 기존 text fallback 반드시 구현
- 빈 응답 방지: 필터링 후 빈 문자열이면 원본 반환
- 로깅: 필터링 전/후 길이 차이를 DEBUG 레벨로 로깅

## 주의사항
- multimodel-bot 서비스가 현재 실행 중일 수 있음. 파일 수정 후 서비스 재시작 필요 여부 확인
- `code_analysis=True` 모드에서는 tool 결과가 의도적으로 포함될 수 있음 → 이 모드에서는 필터링 완화 검토
- cokacdir 바이너리 자체는 수정 불가. multimodel-bot 코드만 수정 대상
- content_sanitizer.py 기존 코드 구조를 존중하고 확장할 것