왜 만들게 되었나?
Pi 에이전트에게 작업을 시키면, 보통 다른 일을 하면서 기다립니다. 작업이 끝났는지 확인하려면 항상 터미널을 들여다봐야 했는데, 그게 좀 귀찮았죠.
작업 완료 시 TTS 로 음성 노티를 주면, 다른 일 하면서도 결과를 알 수 있을 것 같아서 확장 기능을 만들어보기로 했습니다.
원하는 기능:
- ✅ 작업 성공 시:
"Task completed successfully." - ❌ 작업 실패 시:
"Task completed with errors. Please review the output." - ⚠️ 무한루프 감지 시: 경고 음성
Pi 에이전트에게 요청하고 기다리기
Pi 에이전트에게 “TTS 피드백 기능 확장 만들어줘”라고 요청하고, 잠시 다른 일을 했습니다.
AI 가 코드를 생성해서 돌려주는데… 테스트해보니 버그가 많았습니다. 😅
거쳐온 과정
1. 볼륨 문제
처음에 execFile 로 비동기 실행하면서 볼륨을 조절하는 코드를 줬는데, 테스트해보니 시스템 볼륨이 100% 로 고정되었습니다. execSync 로 변경하고 osascript 로직을 완전히 제거해서 해결했습니다.
2. TTS 가 안 들림
execSync 에서 stderr 를 pipe 로 설정하면 say 명령어가 stderr 에 에러 메시지를 출력할 때 pipe 버퍼가 가득 차서 블로킹됩니다. 모든 stdio 를 ignore 로 설정해서 해결했습니다.
3. 무한루프 감지 시 TTS 가 안 들림
execSync 는 동기 실행이라 TTS 가 완료될 때까지 Node.js 이벤트 루프 전체가 블로킹됩니다.
execSync 대신 spawn 을 사용하고, 이전 TTS 가 실행 중이면 자동으로 취소하도록 개선했습니다.
4. 에러 감지가 안 됨
stopReason === "error" 를 확인했는데, 이 필드가 항상 신뢰할 수 있는 값을 반환하지 않았습니다. 메시지 content 배열에서 isError 플래그를 직접 확인하도록 변경했습니다.
5. 세션 엔트리가 계속 쌓임
매번 sessionManager.getEntries() 를 호출하여 "tts-feedback-first-error" 엔트리를 검색했는데, 이게 느리고 세션이 계속 쌓였습니다. 인메모리 변수로 관리하도록 변경했습니다.
6. 음성 속도가 너무 느림
rate * 100 으로 계산했는데, macOS say -r 은 words-per-minute(wpm) 단위였습니다. 100 wpm 은 초당 약 2 단어라서 매우 느렸습니다. rate * 200 으로 수정했습니다.
7. /tts off 시 음성이 안 들림
speak() 가 config.enabled === false 라 바로 return 했습니다. 먼저 config 를 비활성화하고 speak() 를 호출하면 무시되는 것이었습니다. 순서를 바꾸고, speak() 대신 UI notify 만으로 충분하게 변경했습니다.
최종 결과
7 번의 피드백을 거쳐, TTS 피드백 확장이 완전히 작동합니다:
| 기능 | 상태 |
|---|---|
| 작업 완료 피드백 (성공/실패) | ✅ 정상 작동 |
| 무한루프 감지 및 경고 | ✅ 정상 작동 |
| 도구 에러 첫 알림 (스팜 방지) | ✅ 정상 작동 |
| TTS 온/오프 토글 | ✅ 정상 작동 |
| 음성 속도 조절 | ✅ 정상 작동 |
마무리
다른 일 하면서 Pi 결과를 TTS 로 노티 받을 수 있게 됐습니다. 이제 터미널을 계속 들여다볼 필요가 없어졌네요. 🎧