Messages and delivery

명령 큐

인바운드 자동 응답 실행(모든 채널)을 작은 프로세스 내 큐를 통해 직렬화하여 여러 에이전트 실행이 충돌하지 않도록 하면서도, 세션 간에는 안전한 병렬 처리를 허용합니다.

이유

  • 자동 응답 실행은 비용이 많이 들 수 있으며(LLM 호출), 여러 인바운드 메시지가 거의 동시에 도착하면 충돌할 수 있습니다.
  • 직렬화하면 공유 리소스(세션 파일, 로그, CLI stdin)를 두고 경쟁하는 일을 피하고, 업스트림 속도 제한 가능성을 줄일 수 있습니다.

작동 방식

  • 레인 인식 FIFO 큐가 구성 가능한 동시성 한도에 따라 각 레인을 비웁니다(구성되지 않은 레인은 기본 1, main은 기본 4, subagent는 8).
  • runEmbeddedPiAgent세션 키(레인 session:<key>)별로 큐에 넣어 세션당 활성 실행이 하나만 있도록 보장합니다.
  • 그런 다음 각 세션 실행은 전역 레인(기본값 main)에 큐에 들어가므로 전체 병렬 처리는 agents.defaults.maxConcurrent에 의해 제한됩니다.
  • 상세 로깅이 활성화된 경우, 큐에 들어간 실행이 시작 전 약 2초보다 오래 기다리면 짧은 알림을 내보냅니다.
  • 타이핑 표시기는(채널에서 지원하는 경우) 큐에 넣는 즉시 계속 실행되므로, 차례를 기다리는 동안 사용자 경험은 변경되지 않습니다.

기본값

설정하지 않으면 모든 인바운드 채널 표면은 다음을 사용합니다.

  • mode: "steer"
  • debounceMs: 500
  • cap: 20
  • drop: "summarize"

steer는 활성 모델 턴의 응답성을 유지하면서 두 번째 세션 실행을 시작하지 않기 때문에 기본값입니다. 다음 모델 경계 전에 도착한 모든 스티어링 메시지를 비웁니다. 현재 실행이 스티어링을 받을 수 없으면, OpenClaw는 후속 큐 항목으로 폴백합니다.

큐 모드

인바운드 메시지는 현재 실행을 스티어링하거나, 후속 턴을 기다리거나, 둘 다 할 수 있습니다.

  • steer: 스티어링 메시지를 활성 런타임에 큐에 넣습니다. Pi는 현재 어시스턴트 턴이 도구 호출 실행을 마친 뒤, 다음 LLM 호출 전에 대기 중인 모든 스티어링 메시지를 전달합니다. Codex app-server는 하나로 묶인 turn/steer를 받습니다. 실행이 활성 스트리밍 중이 아니거나 스티어링을 사용할 수 없으면, OpenClaw는 후속 큐 항목으로 폴백합니다.
  • queue(레거시): 이전의 한 번에 하나씩 처리하는 스티어링입니다. Pi는 각 모델 경계에서 큐에 있는 스티어링 메시지 하나를 전달합니다. Codex app-server는 별도의 turn/steer 요청을 받습니다. 이전의 직렬화된 동작이 필요한 경우가 아니라면 steer를 선호하세요.
  • followup: 현재 실행이 끝난 뒤 나중의 에이전트 턴을 위해 각 메시지를 큐에 넣습니다.
  • collect: 조용한 창 이후 큐에 있는 메시지를 단일 후속 턴으로 합칩니다. 메시지가 서로 다른 채널/스레드를 대상으로 하면 라우팅을 보존하기 위해 개별적으로 비웁니다.
  • steer-backlog(일명 steer+backlog): 지금 스티어링하고 동시에 같은 메시지를 후속 턴용으로 보존합니다.
  • interrupt(레거시): 해당 세션의 활성 실행을 중단한 다음, 가장 최신 메시지를 실행합니다.

steer-backlog는 스티어링된 실행 이후 후속 응답을 받을 수 있음을 의미하므로 스트리밍 표면에서는 중복처럼 보일 수 있습니다. 인바운드 메시지마다 응답을 하나만 원한다면 collect/steer를 선호하세요.

런타임별 타이밍과 의존성 동작은 스티어링 큐를 참조하세요. 명시적인 /steer <message> 명령은 스티어링을 참조하세요.

전역 또는 채널별로 messages.queue를 통해 구성하세요.

{
  messages: {
    queue: {
      mode: "steer",
      debounceMs: 500,
      cap: 20,
      drop: "summarize",
      byChannel: { discord: "collect" },
    },
  },
}

큐 옵션

옵션은 followup, collect, steer-backlog에 적용됩니다(그리고 스티어링이 후속으로 폴백할 때 steer 또는 레거시 queue에도 적용됩니다).

  • debounceMs: 큐에 있는 후속 항목을 비우기 전의 조용한 창입니다. 단독 숫자는 밀리초이며, /queue 옵션은 ms, s, m, h, d 단위를 허용합니다.
  • cap: 세션당 큐에 넣을 수 있는 최대 메시지 수입니다. 1보다 작은 값은 무시됩니다.
  • drop: "summarize": 기본값입니다. 필요에 따라 가장 오래된 큐 항목을 삭제하고, 간결한 요약을 유지하며, 이를 합성 후속 프롬프트로 주입합니다.
  • drop: "old": 필요에 따라 가장 오래된 큐 항목을 삭제하되, 요약은 보존하지 않습니다.
  • drop: "new": 큐가 이미 가득 찬 경우 가장 최신 메시지를 거부합니다.

기본값: debounceMs: 500, cap: 20, drop: summarize.

우선순위

모드 선택 시 OpenClaw는 다음 순서로 확인합니다.

  1. 인라인 또는 저장된 세션별 /queue 재정의.
  2. messages.queue.byChannel.<channel>.
  3. messages.queue.mode.
  4. 기본 steer.

옵션의 경우, 인라인 또는 저장된 /queue 옵션이 구성보다 우선합니다. 그런 다음 채널별 디바운스(messages.queue.debounceMsByChannel), Plugin 디바운스 기본값, 전역 messages.queue 옵션, 내장 기본값이 적용됩니다. capdrop은 전역/세션 옵션이며, 채널별 구성 키가 아닙니다.

세션별 재정의

  • 현재 세션의 모드를 저장하려면 /queue <mode>를 독립 명령으로 보내세요.
  • 옵션은 조합할 수 있습니다. /queue collect debounce:0.5s cap:25 drop:summarize
  • /queue default 또는 /queue reset은 세션 재정의를 지웁니다.

범위와 보장

  • Gateway 응답 파이프라인을 사용하는 모든 인바운드 채널(WhatsApp 웹, Telegram, Slack, Discord, Signal, iMessage, 웹챗 등)의 자동 응답 에이전트 실행에 적용됩니다.
  • 기본 레인(main)은 인바운드 + main Heartbeat에 대해 프로세스 전체에 적용됩니다. 여러 세션을 병렬로 허용하려면 agents.defaults.maxConcurrent를 설정하세요.
  • 백그라운드 작업이 인바운드 응답을 막지 않고 병렬로 실행될 수 있도록 추가 레인(예: cron, cron-nested, nested, subagent)이 존재할 수 있습니다. 격리된 cron 에이전트 턴은 내부 에이전트 실행이 cron-nested를 사용하는 동안 cron 슬롯을 점유합니다. 둘 다 cron.maxConcurrentRuns를 사용합니다. 공유 비-cron nested 흐름은 자체 레인 동작을 유지합니다. 이러한 분리된 실행은 백그라운드 작업으로 추적됩니다.
  • 세션별 레인은 특정 세션을 한 번에 하나의 에이전트 실행만 건드리도록 보장합니다.
  • 외부 의존성이나 백그라운드 워커 스레드는 없습니다. 순수 TypeScript + 프로미스만 사용합니다.

문제 해결

  • 명령이 멈춘 것처럼 보이면 상세 로그를 활성화하고 큐가 비워지고 있는지 확인하기 위해 "queued for ...ms" 줄을 찾아보세요.
  • 큐 깊이가 필요하면 상세 로그를 활성화하고 큐 타이밍 줄을 확인하세요.
  • 턴을 수락한 뒤 진행 상황 내보내기를 중지한 Codex app-server 실행은 Codex 어댑터에 의해 중단되므로, 외부 실행 제한 시간을 기다리는 대신 활성 세션 레인이 해제될 수 있습니다.
  • 진단이 활성화된 경우, 관찰된 응답, 도구, 상태, 블록 또는 ACP 진행 없이 diagnostics.stuckSessionWarnMs를 지나 processing 상태로 남아 있는 세션은 현재 활동 기준으로 분류됩니다. 활성 작업은 session.long_running으로 로그를 남깁니다. 최근 진행이 없는 활성 작업은 session.stalled로 로그를 남깁니다. session.stuck은 활성 작업이 없는 오래된 세션 장부 기록용으로 예약되어 있으며, 해당 경로만 영향을 받은 세션 레인을 해제해 큐에 있는 작업이 비워지게 할 수 있습니다. 반복되는 session.stuck 진단은 세션이 변경되지 않은 동안 백오프됩니다.

관련 항목