결재 & 시크릿 (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 상태로 매핑 |
결재 카드에 실리는 것
카드에는 무엇을 하려는지(plan)와 함께 그 도구에 넘길 인자가 그대로 실립니다. 외부 MCP 도구를 호출하는 경우도 마찬가지입니다 — 어떤 값으로 실행되는지 보고 결정할 수 있습니다.
회신 경로가 없을 때 — 세 가지 선택
콜백이나 SSE 같은 회신 경로가 없는 요청(예: stream:false에 callback_url 미지정)은 결재를 받을 수 없습니다. 그때 어떻게 할지는 워크스페이스(직원) 설정이 정하며, API 요청은 그 정책을 그대로 상속합니다.
설정 → 운영 정책 → 도구 호출 정책 → 「결재가 필요해질 때」
| 선택 | 저장값 | 동작 |
|---|---|---|
| 기다리고, 답이 없으면 중단 | deny | 기본. 승인이 필요한 위험 도구는 즉시 거부 |
| 기다리되, 물어볼 사람이 없으면 진행 | full | 루틴·외부 트리거에서 그대로 실행 |
| 기다리지 않고 보고 | report | 묻지 않고 그 동작만 접은 뒤 나머지를 완주하고, 접힌 동작을 최종 답변 끝에 정리해 붙임 |
report(보고형)는 "회신 경로가 있어도 기다리지 않겠다" 는 선택입니다. 접힌 동작은 모델이 스스로 서술했더라도 기계적으로 한 번 더 붙습니다 — 모델 서술은 누락될 수 있고, 이 줄은 "무엇이 접혔는지의 사실"이라 종류가 다르기 때문입니다.
보고형은
APPROVAL_TIMEOUT_MS(10분)를 우회할 뿐 없애지 않습니다. 기다리는 갈래에서는 그대로 10분입니다.
승인이 필요한 작업을 기다렸다가 실행하려면 callback_url을 제공하세요.
사용자용
화면에서 결재 카드를 받아 처리하는 흐름(규칙 학습 승인 포함)은 → 결재 승인하기