결재 & 시크릿 (Human-in-the-loop)
일부 작업은 실행 전에 사람의 승인이 필요하거나, 실행 중에 시크릿(민감 정보) 을 요구합니다. 이때 스트림은 input_required 이벤트로 잠시 멈추고 회신을 기다립니다.
결재 (approval)
도구 실행에 승인이 필요하면 다음 이벤트가 옵니다:
event: input_required
data: {
"v": 1, "kind": "approval",
"plan": "…무엇을 하려는지…",
"operations": [ … ],
"approval_id": "…",
"decide_url": "https://…/approvals/…/decide"
}
decide_url로 결정을 회신하면 같은 세션이 이어집니다:
curl -X POST "$DECIDE_URL" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"decision": "allow"}' # 또는 "deny", 선택적으로 "allowlist_pattern"
회신 후 GET /sessions/:id/events(마지막 id로)로 이후 이벤트를 이어받습니다. 10분 내 미회신이면 자동 거부됩니다.
시크릿 제출 (secret)
에이전트가 환경변수/시크릿을 요구하면:
event: input_required
data: { "v": 1, "kind": "secret", "key_name": "OPENAI_API_KEY", "reason": "…", "approval_id": "…", "secret_url": "https://…" }
secret_url로 값을 제출합니다(secret 스코프 필요):
curl -X POST "$SECRET_URL" \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"action": "provide", "value": "sk-…"}' # 또는 {"action": "skip"}
평문 value는 이 요청 바디에서만 흐르고 vault에 암호화 저장됩니다(응답·로그·DB에 평문 미저장). 회신 후 재접속으로 이어받으며, 10분 미회신 시 자동 거부됩니다.
프로토콜별 회신 방식
| 방식 | 결재/시크릿 표면 |
|---|---|
| REST (SSE) | input_required 이벤트 + decide_url/secret_url로 회신 (위) |
| REST (블로킹/콜백) | callback_url을 주면 결재 요청을 그 URL로 push. 콜백이 없으면 위험 도구는 즉시 거부(headless) |
| A2A | input-required Task 상태로 매핑 |
무인(headless) 실행 주의
콜백이나 SSE 같은 회신 경로가 없는 요청(예: stream:false에 callback_url 미지정)은 결재를 받을 수 없으므로, 승인이 필요한 위험 도구는 즉시 거부됩니다. 승인이 필요한 작업을 자동화하려면 callback_url을 제공하세요.