10. 서브에이전트 위임 규격 (Subagent Delegation)
에이전트가 하위 에이전트(서브에이전트)를 생성하여 작업을 위임하는 구조를 정의한다. 서브에이전트는 부모 에이전트와 동일한 Agent Session 내에서 실행되며, 서브에이전트 내부에서 발생하는 모든 DPS 프레임은 부모와 동일한 session_id를 공유한다.
10.1. 서브에이전트 호출
tool.invoke.request에서 서브에이전트를 생성하는 도구를 호출한다. payload에 subagent 필드가 존재하면 이 도구 호출이 서브에이전트를 생성함을 의미한다.
{
"type": "tool.invoke.request",
"payload": {
"invocation_id": "String (필수, UUID v4. 이 값이 서브에이전트의 parent_invocation_id가 된다)",
"tool_name": "String (필수, 예: 'Task', 'Agent')",
"input": {
"description": "String (필수, 서브에이전트 임무 설명)",
"prompt": "String (필수, 서브에이전트에게 전달할 프롬프트)",
"allowed_tools": ["String (선택, 서브에이전트 허용 도구 목록)"],
"model": "String (선택, 사용할 모델)"
},
"subagent": {
"agent_type": "String (선택, 서브에이전트 유형. 예: 'Explore', 'Plan', 'general-purpose')",
"description": "String (선택, 서브에이전트 임무 요약)"
}
}
}
subagent 필드가 없으면 일반 도구 호출이다.
10.2. 서브에이전트 컨텍스트 (metadata.subagent_context)
서브에이전트 내부에서 발생하는 모든 DPS 프레임은 metadata.subagent_context 필드를 포함해야 한다 (MUST). 이를 통해 수신 측은 각 메시지의 출처 에이전트를 식별할 수 있다.
{
"metadata": {
"subagent_context": {
"parent_invocation_id": "String (필수, 이 서브에이전트를 호출한 tool.invoke.request의 invocation_id)",
"agent_type": "String (선택, 서브에이전트 유형)",
"depth": "Number (필수, 중첩 깊이. 0 = 메인 에이전트, 1 = 서브에이전트, 2 = 서브의 서브에이전트)"
}
}
}
규칙:
subagent_context가 없거나null인 프레임은 메인 에이전트(depth: 0)의 메시지로 취급해야 한다 (MUST).- 서브에이전트 내부의
agent.*,tool.*,session.*모든 프레임에 포함해야 한다 (MUST). depth는 발신 측(클라이언트)이 서브에이전트 생성 시점에 이미 알고 있는 값이다. 수신 측이 전체 프레임 히스토리 없이 단일 프레임만으로 중첩 깊이를 결정할 수 있도록 명시적으로 포함한다.- 중첩 서브에이전트의 경우
parent_invocation_id는 직계 부모의invocation_id만 가리킨다. 전체 위임 체인이 필요한 경우parent_invocation_id를 재귀 추적하여 복원한다.
10.3. 서브에이전트 생명주기 이벤트
10.3.1. agent.subagent.started (Client → Master)
서브에이전트가 시작되었음을 통보한다. tool.invoke.request(subagent 포함) 발송 직후에 발송해야 한다 (MUST).
{
"type": "agent.subagent.started",
"payload": {
"parent_invocation_id": "String (필수, 대응하는 tool.invoke.request의 invocation_id)",
"agent_type": "String (선택, 서브에이전트 유형)",
"description": "String (선택, 서브에이전트 임무 설명)",
"depth": "Number (필수, 중첩 깊이. 1 = 서브에이전트, 2 = 서브의 서브에이전트)"
}
}
10.3.2. agent.subagent.ended (Client → Master)
서브에이전트가 종료되었음을 통보한다. tool.invoke.result(output_type: agent_result) 발송 직전에 발송해야 한다 (MUST).
{
"type": "agent.subagent.ended",
"payload": {
"parent_invocation_id": "String (필수)",
"status": "String (필수, 'completed' | 'failed' | 'cancelled')",
"duration_ms": "Number (선택, 서브에이전트 실행 시간 밀리초)"
}
}
이벤트 순서:
tool.invoke.request (subagent 포함)
→ agent.subagent.started
→ 서브에이전트 내부 메시지들 (subagent_context 포함)
→ agent.subagent.ended
→ tool.invoke.result (output_type: "agent_result")
10.4. 서브에이전트 출력
서브에이전트의 중간 출력은 tool.invoke.stream으로 중계되거나, subagent_context가 포함된 개별 DPS 프레임(agent.text.delta, tool.invoke.request 등)으로 마스터에 직접 노출될 수 있다.
완료 시 tool.invoke.result(output_type: agent_result)로 최종 결과가 보고된다.
10.5. 사용량 보고 규칙
서브에이전트 내에서 발생하는 session.usage는 subagent_context를 포함하여 독립적으로 보고해야 한다 (MUST). 서브에이전트의 사용량을 메인 에이전트의 누적 사용량에 합산할지 여부는 마스터 또는 엣지 노드가 결정한다. 본 규격은 합산 정책을 규정하지 않는다.
10.6. 능력 협상
session.capabilities(§12.2.1)의 features 객체에 서브에이전트 관련 능력을 고지한다:
| 필드 | 설명 |
|---|---|
subagent |
서브에이전트 도구 호출 지원 여부 (기존) |
subagent_context |
metadata.subagent_context 필드 제공 여부. true이면 서브에이전트 메시지에 컨텍스트를 포함한다. false이거나 미고지이면 모든 메시지를 플랫하게 처리한다. |
subagent_context: false인 클라이언트의 메시지에 대해 마스터 및 CRS는 그룹핑을 시도해서는 안 된다 (MUST NOT).
10.7. 서브에이전트 미지원 폴백
서브에이전트를 지원하지 않는 에이전트(프로세스 기반 어댑터 등)의 경우:
subagent_context를 생략하거나null로 설정해야 한다 (MUST).- 모든 메시지는 메인 에이전트의 메시지로 취급된다.
output_type: "agent_result"인tool.invoke.result는subagent_context없이도 서브에이전트 결과임을 암시하지만, 내부 메시지 그룹핑은 불가능하다.