에이전트 루프 (OpenClaw)

에이전트 루프란 에이전트가 실제로 실행되는 전체 과정을 말합니다. 입력 수신 -> 컨텍스트 조립 -> 모델 추론 -> 도구 실행 -> 스트리밍 응답 -> 영속화까지, 메시지를 행동과 최종 응답으로 변환하면서 세션 상태를 일관되게 유지하는 핵심 경로입니다.

OpenClaw에서 루프는 세션당 하나의 직렬 실행 단위로, 모델이 사고하고 도구를 호출하고 출력을 스트리밍하는 동안 생명주기 이벤트와 스트림 이벤트를 발생시킵니다. 이 문서에서는 이 루프가 처음부터 끝까지 어떻게 연결되는지 설명합니다.

진입점

  • Gateway RPC: agentagent.wait.
  • CLI: agent 명령어.

동작 원리 (개괄)

  1. agent RPC가 파라미터를 검증하고, 세션을 확인(sessionKey/sessionId)한 뒤, 세션 메타데이터를 저장하고 즉시 { runId, acceptedAt }을 반환합니다.
  2. agentCommand가 에이전트를 실행합니다:
    • 모델 및 thinking/verbose 기본값 확인
    • 스킬 스냅샷 로드
    • runEmbeddedPiAgent (pi-agent-core 런타임) 호출
    • 임베디드 루프가 생명주기 이벤트를 발생시키지 않을 경우 lifecycle end/error를 직접 발생
  3. runEmbeddedPiAgent:
    • 세션별 + 글로벌 큐를 통해 실행을 직렬화
    • 모델 + 인증 프로필을 확인하고 pi 세션 구성
    • pi 이벤트를 구독하여 assistant/tool 델타를 스트리밍
    • 타임아웃 초과 시 실행 중단
    • 페이로드 + 사용량 메타데이터 반환
  4. subscribeEmbeddedPiSession이 pi-agent-core 이벤트를 OpenClaw agent 스트림에 연결합니다:
    • tool 이벤트 => stream: "tool"
    • assistant 델타 => stream: "assistant"
    • 생명주기 이벤트 => stream: "lifecycle" (phase: "start" | "end" | "error")
  5. agent.waitwaitForAgentJob을 사용합니다:
    • 해당 runIdlifecycle end/error를 대기
    • { status: ok|error|timeout, startedAt, endedAt, error? } 반환

큐잉 + 동시성

  • 세션 키(세션 레인) 단위로 실행이 직렬화되며, 선택적으로 글로벌 레인도 거칩니다.
  • 이를 통해 도구/세션 경합을 방지하고 세션 히스토리 일관성을 유지합니다.
  • 메시징 채널은 이 레인 시스템에 연결되는 큐 모드(collect/steer/followup)를 선택할 수 있습니다. 명령어 큐를 참고하세요.

세션 + 워크스페이스 준비

  • 워크스페이스가 확인되고 생성됩니다. 샌드박스 실행은 샌드박스 워크스페이스 루트로 리다이렉트될 수 있습니다.
  • 스킬이 로드(또는 스냅샷에서 재사용)되어 환경 변수와 프롬프트에 주입됩니다.
  • 부트스트랩/컨텍스트 파일이 확인되어 시스템 프롬프트 리포트에 주입됩니다.
  • 세션 쓰기 잠금이 획득됩니다. 스트리밍 전에 SessionManager가 열리고 준비됩니다.

프롬프트 조립 + 시스템 프롬프트

  • 시스템 프롬프트는 OpenClaw의 기본 프롬프트, 스킬 프롬프트, 부트스트랩 컨텍스트, 실행별 오버라이드로 구성됩니다.
  • 모델별 제한 및 압축 예비 토큰이 적용됩니다.
  • 모델에 전달되는 내용은 시스템 프롬프트를 참고하세요.

훅 포인트 (가로챌 수 있는 지점)

OpenClaw에는 두 가지 훅 시스템이 있습니다:

  • 내부 훅 (Gateway 훅): 명령어와 생명주기 이벤트를 위한 이벤트 기반 스크립트.
  • 플러그인 훅: 에이전트/도구 생명주기와 게이트웨이 파이프라인 내 확장 포인트.

내부 훅 (Gateway 훅)

  • agent:bootstrap: 시스템 프롬프트 확정 전 부트스트랩 파일을 구성하는 동안 실행됩니다. 부트스트랩 컨텍스트 파일을 추가/제거하는 데 사용합니다.
  • 명령어 훅: /new, /reset, /stop 등의 명령어 이벤트 (훅 문서 참고).

자세한 설정과 예시는 을 참고하세요.

플러그인 훅 (에이전트 + 게이트웨이 생명주기)

에이전트 루프 또는 게이트웨이 파이프라인 내에서 실행됩니다:

  • before_model_resolve: 세션 이전(messages 없이) 실행되어 모델 확인 전에 프로바이더/모델을 결정적으로 오버라이드합니다.
  • before_prompt_build: 세션 로드 후(messages와 함께) 실행되어 프롬프트 제출 전에 prependContext, systemPrompt, prependSystemContext, appendSystemContext를 주입합니다. 턴별 동적 텍스트에는 prependContext를, 시스템 프롬프트 영역에 위치해야 할 안정적 가이드에는 system-context 필드를 사용하세요.
  • before_agent_start: 두 단계 중 하나에서 실행될 수 있는 레거시 호환 훅. 위의 명시적 훅을 사용하는 것을 권장합니다.
  • agent_end: 완료 후 최종 메시지 목록과 실행 메타데이터를 검사합니다.
  • before_compaction / after_compaction: 압축 사이클을 관찰하거나 주석을 달 수 있습니다.
  • before_tool_call / after_tool_call: 도구 파라미터/결과를 가로챕니다.
  • tool_result_persist: 도구 결과가 세션 트랜스크립트에 기록되기 전에 동기적으로 변환합니다.
  • message_received / message_sending / message_sent: 인바운드 + 아웃바운드 메시지 훅.
  • session_start / session_end: 세션 생명주기 경계.
  • gateway_start / gateway_stop: 게이트웨이 생명주기 이벤트.

훅 API와 등록 방법은 플러그인을 참고하세요.

스트리밍 + 부분 응답

  • pi-agent-core에서 assistant 델타가 스트리밍되어 assistant 이벤트로 발생합니다.
  • 블록 스트리밍은 text_end 또는 message_end 시점에 부분 응답을 내보낼 수 있습니다.
  • 추론 스트리밍은 별도 스트림 또는 블록 응답으로 내보낼 수 있습니다.
  • 청킹과 블록 응답 동작은 스트리밍을 참고하세요.

도구 실행 + 메시징 도구

  • tool start/update/end 이벤트가 tool 스트림으로 발생합니다.
  • 도구 결과는 로깅/발생 전에 크기와 이미지 페이로드가 정리됩니다.
  • 메시징 도구 전송은 중복 assistant 확인 메시지를 방지하기 위해 추적됩니다.

응답 형성 + 억제

  • 최종 페이로드는 다음으로 구성됩니다:
    • assistant 텍스트 (및 선택적 추론)
    • 인라인 도구 요약 (verbose + 허용 시)
    • 모델 오류 시 assistant 오류 텍스트
  • NO_REPLY는 무음 토큰으로 처리되어 발신 페이로드에서 필터링됩니다.
  • 메시징 도구 중복이 최종 페이로드 목록에서 제거됩니다.
  • 렌더링 가능한 페이로드가 없고 도구에서 오류가 발생한 경우, 대체 도구 오류 응답이 발생합니다 (메시징 도구가 이미 사용자에게 보이는 응답을 보낸 경우는 제외).

압축 + 재시도

  • 자동 압축은 compaction 스트림 이벤트를 발생시키며 재시도를 유발할 수 있습니다.
  • 재시도 시 중복 출력을 방지하기 위해 인메모리 버퍼와 도구 요약이 초기화됩니다.
  • 압축 파이프라인은 압축을 참고하세요.

이벤트 스트림 (현재)

  • lifecycle: subscribeEmbeddedPiSession에 의해 발생 (agentCommand에서 대체 수단으로도 발생)
  • assistant: pi-agent-core에서 스트리밍되는 델타
  • tool: pi-agent-core에서 스트리밍되는 도구 이벤트

채팅 채널 처리

  • assistant 델타가 채팅 delta 메시지로 버퍼링됩니다.
  • lifecycle end/error 시 채팅 final이 발생합니다.

타임아웃

  • agent.wait 기본값: 30초 (대기만 해당). timeoutMs 파라미터로 오버라이드 가능.
  • 에이전트 런타임: agents.defaults.timeoutSeconds 기본값 600초. runEmbeddedPiAgent 중단 타이머에서 적용.

조기 종료될 수 있는 경우

  • 에이전트 타임아웃 (중단)
  • AbortSignal (취소)
  • 게이트웨이 연결 해제 또는 RPC 타임아웃
  • agent.wait 타임아웃 (대기 전용, 에이전트를 중단하지 않음)