v5.4.4: 에이전트 스모크 테스트 신뢰성——출력 계약 클라이언트와 타임아웃 자동 에스컬레이션¶
빠른 답변: v5.4.4는 "command 무효 / workflow 스턱" 장애 모드를 수정합니다. 에이전트는 자신과 무관한 이유로 영구적으로 비활성화되고 있었습니다. Codex 같은 클라이언트는 모든 응답을 JSON 출력 계약으로 감싸며(프로브가 자신의 ACK를 인식하지 못함), 하드코딩된 30초 타임아웃이 한 번의 느린 콜드 스타트를 영구적 차단으로 바꿨습니다. 이제 프로브는 출력 계약을 명시적으로 재정의하고, JSON으로 감싸진 응답을 허용하며, 설정 가능한 타임아웃(기본 60초,
AIOS_AGENT_SMOKE_TIMEOUT_MS또는--timeout-ms)을 사용하고, 에이전트를 차단하기 전에 2x/4x로 자동 에스컬레이션하며 재시도합니다.
장애 모드: 조용히 죽는 워크플로¶
워크플로가 갑자기 overallstatus: "blocked"를 보고하고 모든 명령이 "무효"로 판정됩니다. 근본 원인 체인은 보기보다 깁니다:
- live smoke 프로브는 게이트키퍼입니다——에이전트는 smoke 증거가 기록될 때까지 라이브 오케스트레이션에 참여할 수 없습니다.
- 프로브가 실패하면 증거가 기록되지 않고, 에이전트는 워크플로 비활성 상태로 남습니다.
- 비활성 에이전트 →
strict.blocked→ 모든 Command가 무효로 거부됩니다.
두 개의 독립적인 버그가 정상 에이전트의 프로브도 실패하게 만들었습니다:
버그 1——출력 계약의 함정. 일부 클라이언트(가장 흔한 것은 Codex)는 "ACK만 돌려달라"는 프로브 지시에도 모든 응답을 JSON handoff 계약으로 감쌉니다. 프로브는 평문 ACK 마커를 찾지만 JSON 래퍼 안에서는 찾지 못해 실패로 보고합니다. 더 나쁜 것은, 클라이언트가 자신의 계약을 엄격히 따를수록 프로브는 더 확실하게 실패한다는 점입니다——프로토콜 교착 상태입니다.
버그 2——한 번의 느린 응답 = 영구 차단. 프로브는 하드코딩된 30초 타임아웃에 재시도가 없었습니다. 느린 콜드 스타트나 모델 대기 지연이 프로브를 30초 이상 끌고 가면 에이전트가 차단되었고, 아무것도 재시도하지 않았습니다——복구하려면 --timeout-ms를 아는 사람이 수동으로 smoke를 다시 실행해야 했습니다.
v5.4.4의 변경 사항¶
출력 계약 클라이언트에서 동작하는 smoke¶
- 프로브 프롬프트는 이제 "Do NOT return a JSON handoff object — reply with the ACK marker only"를 명시적으로 선언하여, 프로브에 한해 클라이언트의 출력 계약을 재정의합니다.
- ACK 감지는 JSON으로 감싸진 응답을 허용합니다. 평문 마커가 없으면 응답을 JSON으로 파싱해 래퍼 내부를 검색합니다.
- post-receive 압축 증명은
minRawBytes(2048바이트) 이상의 출력에만 요구됩니다. 짧은 출력은 설계상 인라인됩니다——이는 정당한 경계 동작이지 smoke 실패가 아닙니다. - 빈 압축 refs로 인해 증거 기록이 충돌하지 않습니다(
refs[0]의 옵셔널 체이닝).
일발 사형이 아닌 에스컬레이션 타임아웃¶
- 하드코딩된 30초는
AIOS_AGENT_SMOKE_TIMEOUT_MS(환경 변수)와agents smoke --timeout-ms <ms>(CLI)로 대체되었고, 기본값은 60초로 상향되었습니다. - 일시적인 느린 응답에서는 프로브가 60s → 120s → 240s로 타임아웃을 자동 에스컬레이션하며 재시도합니다. 세 번 모두 타임아웃된 경우에만 에이전트가 차단됩니다.
- 최종 blocker 메시지에는 정확한 복구 명령이 포함되어, 차단 해제 방법을 추측할 필요가 없습니다.
왜 에이전트 스스로 타임아웃을 정하게 하지 않는가?¶
자연스러운 질문입니다. 에이전트가 "더 생각해서" 스스로 시간을 늘리게 하면 어떨까요? 그것은 불가능하고, 그래서도 안 됩니다. 타임아웃은 호스트 측 프로세스 매개변수이며 에이전트 프로세스는 이를 볼 수 없습니다. 그리고 피평가자가 자신의 시험을 채점하게 하는 것은 자기 인증식 통과를 만들 뿐입니다. 예산은 클라이언트의 콜드 스타트 특성을 아는 운영자에게 속하며, 호스트 측이 자동 에스컬레이션하는 것이 올바른 형태입니다.
실제 작업 실행은 완전히 별개의 예산입니다: 서브에이전트 작업은 SUBAGENT_TIMEOUT_MS(기본 10분)를 사용합니다. 30초/60초 프로브 타임아웃은 실제 작업을 제약한 적이 없습니다——연결성 핸드셰이크만 지킵니다.
해야 할 일¶
- 기존 설치:
aios update. - 이전에 "command 무효 / workflow 스턱"을 겪었다면:
aios agents smoke --live --client <이름> --timeout-ms <ms>를 다시 실행해 v2 smoke 증거를 재생성하고,aios doctor --agents로 카탈로그가 정상인지 확인하세요. - 클라이언트 콜드 스타트가 특히 느리다면: 매번 플래그를 넘기는 대신 환경에
AIOS_AGENT_SMOKE_TIMEOUT_MS를 설정하세요.
FAQ¶
이 변경으로 진짜 고장난 에이전트가 숨겨지지는 않나요?¶
아닙니다. 긴 출력에 압축 ref가 없으면 여전히 fail-closed입니다. 타임아웃 외의 오류(명령 누락, 0이 아닌 종료 코드, managed-invocation 증명 누락)는 절대 재시도되지 않고 즉시 차단됩니다. 2x/4x 에스컬레이션을 받는 것은 타임아웃 클래스 실패뿐이며, 그것도 총 3회까지만입니다.
60초 × 3회는 프로브로서 너무 긴가요?¶
에스컬레이션은 실제 타임아웃 후에만 발생합니다. 정상 클라이언트는 몇 초 안에 응답합니다——첫 시도에서 성공하고 재시도는 없습니다. 240초의 최악 케이스는 60~120초 안에 정말로 응답할 수 없는 클라이언트만 부담합니다.
마이그레이션이 필요한가요?¶
아닙니다. 동작 수정이며 증거 파일 스키마는 변하지 않습니다. 에이전트가 현재 차단되어 있다면 live smoke를 다시 실행해 v2 증거를 재생성하면 됩니다.
여기서 기억할 교훈이 있습니다: 한 번의 느린 응답을 실패로 처벌하는 게이트키퍼는 헬스 체크가 아니라 시계입니다. 에스컬레이션하고, 재시도하고, 그다음에야 판단하세요.