요약: Claude Managed Agents에 event delta, backward pagination, session override, lifecycle webhook이 추가되면서 장시간 에이전트 세션을 제품 UI에 붙이기 쉬워졌습니다. 핵심은 모든 상태를 한 번에 받으려 하지 말고, SSE 스트림·웹훅·세션 조회를 역할별로 나누는 것입니다.
장시간 에이전트를 서비스에 붙이면 사용자는 “지금 뭐 하는 중인지”를 계속 묻습니다. 단순한 채팅 응답이면 loading spinner로 충분하지만, 코드 분석, 리서치, 데이터 처리, 다단계 업무 자동화는 다릅니다. 사용자는 에이전트가 멈춘 건지, 도구 승인을 기다리는 건지, 하위 에이전트가 작업 중인지, 실패 후 재시도 중인지 알아야 합니다.
Claude Managed Agents의 Session event stream은 이 문제를 이벤트 모델로 풉니다. user.message를 보내고 agent.message, session.status_idle, session.error 같은 이벤트를 받습니다. 최근 업데이트에서는 event_start와 event_delta를 통해 agent.message가 완성되기 전 생성 중인 텍스트를 미리 볼 수 있게 됐습니다. GET /v1/sessions/{session_id}/events/stream 호출에 event_deltas[] query parameter로 opt-in하는 방식입니다.
제품 입장에서는 “작업 완료 후 한 번에 결과 표시”에서 “작업 중간 과정을 사용자에게 노출”하는 구조로 바꿀 수 있습니다.
실무 구현에서 가장 흔한 실수는 모든 상태를 하나의 방식으로 처리하려는 것입니다. 이벤트 스트림만으로 영구 상태를 만들거나, webhook만으로 실시간 UX를 만들거나, 주기적 GET polling만으로 진행률을 만들면 각각 한계가 있습니다.
권장 구조는 세 가지를 분리하는 것입니다.
첫째, SSE stream은 사용자에게 보이는 실시간 진행률용입니다. 세션이 열려 있는 동안 agent.message, event_delta, session.status_idle, session.error를 받아 화면에 반영합니다. 사용자가 현재 페이지를 보고 있을 때 가장 중요합니다.
둘째, webhook은 백그라운드 상태 전환용입니다. session.status_run_started, session.status_idled, session.status_rescheduled, session.status_terminated, deployment_run.succeeded 같은 큰 이벤트를 받아 DB 상태를 갱신합니다. 사용자가 페이지를 닫아도 서버는 상태를 알아야 합니다.
셋째, GET 조회는 정합성 보정용입니다. webhook payload는 event type과 id 중심이며 전체 객체를 주지 않습니다. 따라서 webhook을 받으면 해당 session, deployment run, agent object를 다시 조회해 최신 상태를 저장하는 방식이 안전합니다. Anthropic 문서도 stale data를 피하기 위해 webhook delivery를 작게 유지하고 직접 GET으로 객체를 가져오라고 설명합니다.
event delta는 채팅 UI에 바로 유용합니다. 기존 agent.message 이벤트는 완성된 메시지를 주지만, 긴 작업에서는 사용자가 수십 초 이상 빈 화면을 봅니다. event_start와 event_delta를 받으면 ‘생성 중인 메시지’를 progressive하게 표시할 수 있습니다.
구현 방식은 단순합니다. stream 연결을 먼저 열고, 그 다음 user.message를 보냅니다. 문서 예시처럼 스트림을 먼저 열지 않으면 첫 이벤트를 놓치는 race condition이 생길 수 있습니다. 이후 이벤트 타입별로 처리합니다. event_start가 오면 임시 메시지 버퍼를 만들고, event_delta가 오면 해당 버퍼에 text chunk를 붙입니다. 완성된 agent.message가 오면 임시 메시지를 확정 메시지로 바꿉니다. session.status_idle이 오면 입력 대기 상태로 전환하고, session.error가 오면 오류 UI를 보여줍니다.
주의할 점은 delta를 영구 저장 원본으로 삼지 않는 것입니다. 네트워크 재연결, 중복 이벤트, 부분 이벤트 누락 가능성이 있습니다. 화면 표시에는 delta를 쓰되, 최종 저장은 완성된 agent.message나 세션 이벤트 조회 결과를 기준으로 하는 편이 안전합니다.
최근 Managed Agents에는 session 생성 시 agent configuration override 기능도 추가됐습니다. agent에 type: "agent_with_overrides"를 넣고 model, system, tools, MCP servers, skills를 세션 단위로 바꿀 수 있습니다. 에이전트 리소스 자체는 바뀌지 않고 해당 세션에만 적용됩니다.
이 기능은 A/B 테스트와 긴급 운영에 유용합니다. 예를 들어 기본 에이전트는 안정 모델을 쓰고, 특정 사용자 세션에서만 claude-sonnet-5로 바꿔 성능을 비교할 수 있습니다. 또는 장애 대응 중 특정 MCP 서버를 한 세션에서만 빼고 실행할 수 있습니다. 시스템 프롬프트를 null로 지워 baseline을 확인하는 실험도 가능합니다.
다만 override는 merge가 아니라 replace라는 점을 조심해야 합니다. tools를 override하면 필요한 모든 tool을 다시 나열해야 합니다. skills가 남아 있는데 tools를 비우면 read tool 요구사항 때문에 400이 날 수 있습니다. 운영 UI에서는 “기존 설정에서 이 필드만 추가”처럼 보이게 만들되, 실제 API 요청은 완성된 전체 목록을 명시하는 방식이 안전합니다.
Managed Agents webhook은 session뿐 아니라 vault, agent, deployment, deployment run 이벤트도 다룹니다. 여기서 중요한 것은 이벤트가 ‘상태 변화 알림’이지 ‘상태 원본’이 아니라는 점입니다.
예를 들어 deployment_run.succeeded는 scheduled run이 session을 만들었다는 뜻입니다. 하지만 실제 작업 진행을 보려면 session_id를 따라가서 session events를 구독하거나 조회해야 합니다. session.status_idled는 도구 승인이나 새 사용자 입력을 기다리는 상태일 수 있습니다. 제품 UI에서는 이 이벤트를 받았을 때 “사용자 입력 필요”, “권한 승인 필요”, “작업 완료 후 대기”를 더 세분화해야 합니다.
서명 검증도 필수입니다. 문서에서는 X-Webhook-Signature 헤더와 SDK의 unwrap helper를 사용하라고 안내합니다. Express를 쓴다면 express.json()이 아니라 raw body를 써야 서명 검증이 맞습니다. 이 부분은 실제 배포에서 자주 놓치는 지점입니다.
실시간 에이전트 UI는 정상 경로보다 장애 경로를 먼저 설계해야 합니다. 네트워크가 끊겨 SSE가 닫히면 클라이언트는 마지막으로 본 event id나 세션 상태를 기준으로 재연결해야 합니다. 재연결 직후에는 GET으로 최근 이벤트를 조회해 누락된 최종 메시지가 있는지 확인합니다.
서버는 webhook을 받아 DB 상태를 업데이트합니다. 만약 클라이언트가 꺼져 있어도 session.status_terminated나 deployment_run.failed 같은 이벤트는 남아야 합니다. 이후 사용자가 페이지를 다시 열면 DB 상태와 세션 조회 결과로 화면을 복원합니다.
즉 화면은 SSE로 빠르게, 서버 상태는 webhook으로 지속적으로, 정합성은 GET으로 보정하는 3단 구조가 운영에 맞습니다.