diff --git a/docs/ko/automation/cron-jobs.md b/docs/ko/automation/cron-jobs.md index f43249cd0..46eb3cef6 100644 --- a/docs/ko/automation/cron-jobs.md +++ b/docs/ko/automation/cron-jobs.md @@ -1,22 +1,22 @@ --- read_when: - - 백그라운드 작업 또는 깨우기 예약 - - 외부 트리거(웹훅, Gmail)를 OpenClaw에 연결 - - 예약 작업에 heartbeat와 cron 중 무엇을 사용할지 결정 -summary: Gateway 스케줄러를 위한 예약 작업, 웹훅, Gmail PubSub 트리거 -title: 예약 작업 + - 백그라운드 작업 또는 웨이크업 예약하기 + - 외부 트리거(웹훅, Gmail)를 OpenClaw에 연결하기 + - 예약된 작업에 heartbeat와 cron 중 무엇을 사용할지 결정하기 +summary: Gateway 스케줄러용 예약된 작업, 웹훅, Gmail PubSub 트리거 +title: 예약된 작업 x-i18n: - generated_at: "2026-04-05T12:34:54Z" + generated_at: "2026-04-11T02:44:26Z" model: gpt-5.4 provider: openai - source_hash: 43b906914461aba9af327e7e8c22aa856f65802ec2da37ed0c4f872d229cfde6 + source_hash: 04d94baa152de17d78515f7d545f099fe4810363ab67e06b465e489737f54665 source_path: automation/cron-jobs.md workflow: 15 --- -# 예약 작업 (Cron) +# 예약된 작업 (Cron) -Cron은 Gateway에 내장된 스케줄러입니다. 작업을 영속적으로 저장하고, 적절한 시간에 에이전트를 깨우며, 출력 결과를 채팅 채널이나 웹훅 엔드포인트로 다시 전달할 수 있습니다. +Cron은 Gateway에 내장된 스케줄러입니다. 작업을 영구 저장하고, 적절한 시점에 에이전트를 깨우며, 출력을 채팅 채널이나 웹훅 엔드포인트로 다시 전달할 수 있습니다. ## 빠른 시작 @@ -33,21 +33,23 @@ openclaw cron add \ # 작업 확인 openclaw cron list -# 실행 기록 보기 +# 실행 기록 확인 openclaw cron runs --id ``` ## cron 작동 방식 - Cron은 **Gateway 프로세스 내부에서** 실행됩니다(모델 내부가 아님). -- 작업은 `~/.openclaw/cron/jobs.json`에 영속 저장되므로 재시작해도 일정이 사라지지 않습니다. -- 모든 cron 실행은 [background task](/automation/tasks) 레코드를 생성합니다. +- 작업은 `~/.openclaw/cron/jobs.json`에 저장되므로 재시작해도 일정이 사라지지 않습니다. +- 모든 cron 실행은 [백그라운드 작업](/ko/automation/tasks) 레코드를 생성합니다. - 일회성 작업(`--at`)은 기본적으로 성공 후 자동 삭제됩니다. -- 격리된 cron 실행은 완료 시 해당 `cron:` 세션에 대해 추적된 브라우저 탭/프로세스를 최선의 노력으로 종료하므로, 분리된 브라우저 자동화가 고아 프로세스를 남기지 않습니다. -- 격리된 cron 실행은 오래된 확인 응답도 방지합니다. 첫 번째 결과가 단지 중간 상태 업데이트(`on it`, `pulling everything together` 및 유사한 힌트)이고, 최종 답변에 여전히 책임이 있는 하위 subagent 실행이 없다면, OpenClaw는 전달 전에 실제 결과를 얻기 위해 한 번 더 다시 프롬프트합니다. +- 격리된 cron 실행은 실행이 완료되면 해당 `cron:` 세션에 대해 추적 중인 브라우저 탭/프로세스를 가능한 범위에서 종료하므로, 분리된 브라우저 자동화가 고아 프로세스를 남기지 않습니다. +- 격리된 cron 실행은 오래된 확인 응답도 방지합니다. 첫 번째 결과가 단지 중간 상태 업데이트(`on it`, `pulling everything together` 및 유사한 힌트)이고, 최종 응답을 여전히 담당하는 하위 에이전트 실행이 없다면, OpenClaw는 전달 전에 실제 결과를 한 번 더 요청합니다. -cron의 작업 조정은 런타임이 소유합니다. 오래된 하위 세션 행이 여전히 존재하더라도, 활성 cron 작업은 cron 런타임이 해당 작업을 실행 중으로 추적하는 동안 계속 활성 상태로 유지됩니다. -런타임이 더 이상 작업을 소유하지 않고 5분 유예 시간이 지나면, 유지보수에서 해당 작업을 `lost`로 표시할 수 있습니다. + + +cron의 작업 정합성 조정은 런타임에서 관리됩니다. 활성 cron 작업은, 오래된 하위 세션 행이 여전히 존재하더라도, cron 런타임이 해당 작업을 실행 중으로 추적하는 동안 계속 활성 상태를 유지합니다. +런타임이 더 이상 해당 작업을 소유하지 않고 5분 유예 창이 지나면, 유지 관리가 작업을 `lost`로 표시할 수 있습니다. ## 일정 유형 @@ -55,66 +57,66 @@ cron의 작업 조정은 런타임이 소유합니다. 오래된 하위 세션 | ------- | ---------- | --------------------------------------------------------- | | `at` | `--at` | 일회성 타임스탬프(ISO 8601 또는 `20m` 같은 상대 시간) | | `every` | `--every` | 고정 간격 | -| `cron` | `--cron` | 선택적 `--tz`와 함께 사용하는 5필드 또는 6필드 cron 표현식 | +| `cron` | `--cron` | 선택적 `--tz`를 포함한 5필드 또는 6필드 cron 표현식 | -타임존이 없는 타임스탬프는 UTC로 처리됩니다. 로컬 벽시계 기준 예약에는 `--tz America/New_York`를 추가하세요. +시간대가 없는 타임스탬프는 UTC로 처리됩니다. 로컬 벽시계 기준 스케줄링에는 `--tz America/New_York`를 추가하세요. -정시 반복 표현식은 부하 급증을 줄이기 위해 최대 5분까지 자동으로 분산됩니다. 정확한 타이밍을 강제하려면 `--exact`를 사용하고, 명시적인 범위를 원하면 `--stagger 30s`를 사용하세요. +매시 정각에 반복되는 표현식은 부하 급증을 줄이기 위해 자동으로 최대 5분까지 분산됩니다. 정확한 타이밍을 강제하려면 `--exact`를 사용하고, 명시적인 창을 지정하려면 `--stagger 30s`를 사용하세요. ## 실행 스타일 -| 스타일 | `--session` 값 | 실행 위치 | 적합한 용도 | -| -------------- | ------------------- | ------------------------- | ------------------------------- | -| 메인 세션 | `main` | 다음 heartbeat 턴 | 리마인더, 시스템 이벤트 | -| 격리됨 | `isolated` | 전용 `cron:` | 리포트, 백그라운드 작업 | -| 현재 세션 | `current` | 생성 시점에 바인딩됨 | 컨텍스트 인지형 반복 작업 | -| 커스텀 세션 | `session:custom-id` | 영속적인 이름 있는 세션 | 기록을 기반으로 쌓이는 워크플로 | +| 스타일 | `--session` 값 | 실행 위치 | 적합한 용도 | +| -------------- | ------------------- | ------------------------ | ------------------------------ | +| 메인 세션 | `main` | 다음 heartbeat 턴 | 리마인더, 시스템 이벤트 | +| 격리됨 | `isolated` | 전용 `cron:` | 보고서, 백그라운드 작업 | +| 현재 세션 | `current` | 생성 시점에 바인딩됨 | 컨텍스트 인식 반복 작업 | +| 사용자 지정 세션 | `session:custom-id` | 영구적인 이름 있는 세션 | 기록을 기반으로 누적되는 워크플로 | -**메인 세션** 작업은 시스템 이벤트를 큐에 넣고 선택적으로 heartbeat를 깨웁니다(`--wake now` 또는 `--wake next-heartbeat`). **격리됨** 작업은 새 세션으로 전용 에이전트 턴을 실행합니다. **커스텀 세션**(`session:xxx`)은 실행 간 컨텍스트를 유지하므로, 이전 요약을 바탕으로 쌓이는 일일 스탠드업 같은 워크플로를 가능하게 합니다. +**메인 세션** 작업은 시스템 이벤트를 큐에 넣고 선택적으로 heartbeat를 깨웁니다(`--wake now` 또는 `--wake next-heartbeat`). **격리된** 작업은 새 세션으로 전용 에이전트 턴을 실행합니다. **사용자 지정 세션**(`session:xxx`)은 실행 간 컨텍스트를 유지하므로, 이전 요약을 바탕으로 하는 일일 스탠드업 같은 워크플로를 가능하게 합니다. -격리된 작업의 경우, 런타임 종료 단계에는 이제 해당 cron 세션에 대한 최선의 노력 기반 브라우저 정리가 포함됩니다. 정리 실패는 실제 cron 결과가 우선되도록 무시됩니다. +격리된 작업의 경우, 런타임 정리에는 이제 해당 cron 세션에 대한 브라우저 정리를 가능한 범위에서 수행하는 과정이 포함됩니다. 정리 실패는 무시되므로 실제 cron 결과가 계속 우선합니다. -격리된 cron 실행이 subagent를 조정할 때는, 전달 시에도 오래된 상위 중간 텍스트보다 최종 하위 결과를 우선합니다. 하위 실행이 아직 진행 중이면, OpenClaw는 그 부분적인 상위 업데이트를 알리는 대신 억제합니다. +격리된 cron 실행이 하위 에이전트를 조율할 때는, 전달도 오래된 상위 중간 텍스트보다 최종 하위 출력이 우선됩니다. 하위 항목이 아직 실행 중이면 OpenClaw는 그 부분적인 상위 업데이트를 알리지 않고 억제합니다. ### 격리된 작업의 페이로드 옵션 -- `--message`: 프롬프트 텍스트(격리됨에서 필수) -- `--model` / `--thinking`: 모델 및 thinking 수준 재정의 +- `--message`: 프롬프트 텍스트(격리된 작업에 필수) +- `--model` / `--thinking`: 모델 및 사고 수준 재정의 - `--light-context`: 워크스페이스 부트스트랩 파일 주입 건너뛰기 - `--tools exec,read`: 작업이 사용할 수 있는 도구 제한 -`--model`은 해당 작업에 대해 선택된 허용 모델을 사용합니다. 요청한 모델이 허용되지 않으면 cron은 경고를 기록하고, 대신 작업의 agent/default 모델 선택으로 대체합니다. 구성된 fallback 체인은 계속 적용되지만, 명시적 작업별 fallback 목록이 없는 단순 모델 재정의는 더 이상 숨겨진 추가 재시도 대상으로 agent primary를 덧붙이지 않습니다. +`--model`은 해당 작업에 대해 선택된 허용 모델을 사용합니다. 요청한 모델이 허용되지 않으면 cron은 경고를 기록하고 대신 작업의 에이전트/기본 모델 선택으로 대체합니다. 구성된 폴백 체인은 계속 적용되지만, 명시적인 작업별 폴백 목록이 없는 단순 모델 재정의는 더 이상 에이전트 기본 모델을 숨겨진 추가 재시도 대상으로 덧붙이지 않습니다. 격리된 작업의 모델 선택 우선순위는 다음과 같습니다. -1. Gmail 훅 모델 재정의(실행이 Gmail에서 왔고 해당 재정의가 허용된 경우) +1. Gmail 훅 모델 재정의(실행이 Gmail에서 왔고 해당 재정의가 허용되는 경우) 2. 작업별 페이로드 `model` 3. 저장된 cron 세션 모델 재정의 -4. Agent/default 모델 선택 +4. 에이전트/기본 모델 선택 -빠른 모드도 해결된 라이브 선택을 따릅니다. 선택된 모델 구성에 `params.fastMode`가 있으면, 격리된 cron은 기본적으로 이를 사용합니다. 저장된 세션 `fastMode` 재정의는 어느 방향에서든 여전히 구성보다 우선합니다. +Fast 모드도 해결된 라이브 선택을 따릅니다. 선택된 모델 구성에 `params.fastMode`가 있으면, 격리된 cron은 기본적으로 이를 사용합니다. 저장된 세션 `fastMode` 재정의는 어느 방향이든 구성보다 여전히 우선합니다. -격리된 실행이 라이브 모델 전환 handoff에 도달하면, cron은 전환된 provider/model로 재시도하고 재시도 전에 해당 라이브 선택을 영속 저장합니다. 전환에 새 auth profile도 포함되어 있으면, cron은 그 auth profile 재정의도 저장합니다. 재시도는 제한됩니다. 초기 시도에 더해 전환 재시도 2회를 넘기면, cron은 무한 반복하는 대신 중단합니다. +격리된 실행이 라이브 모델 전환 handoff에 도달하면, cron은 전환된 provider/model로 재시도하고 재시도 전에 해당 라이브 선택을 저장합니다. 전환에 새 인증 프로필도 포함되면, cron은 그 인증 프로필 재정의도 저장합니다. 재시도는 제한됩니다. 최초 시도와 2회의 전환 재시도 이후에는 무한 루프 대신 중단합니다. ## 전달 및 출력 -| 모드 | 동작 | -| ---------- | ------------------------------------------------------------ | -| `announce` | 요약을 대상 채널로 전달(격리됨의 기본값) | -| `webhook` | 완료된 이벤트 페이로드를 URL로 POST | -| `none` | 내부 전용, 전달 없음 | +| 모드 | 동작 | +| ---------- | ----------------------------------------------------------- | +| `announce` | 요약을 대상 채널로 전달(격리된 작업의 기본값) | +| `webhook` | 완료된 이벤트 페이로드를 URL로 POST | +| `none` | 내부 전용, 전달 없음 | -채널 전달에는 `--announce --channel telegram --to "-1001234567890"`를 사용하세요. Telegram 포럼 주제의 경우 `-1001234567890:topic:123`을 사용하세요. Slack/Discord/Mattermost 대상은 명시적 접두사(`channel:`, `user:`)를 사용해야 합니다. +채널 전달에는 `--announce --channel telegram --to "-1001234567890"`를 사용하세요. Telegram 포럼 토픽에는 `-1001234567890:topic:123`을 사용하세요. Slack/Discord/Mattermost 대상은 명시적 접두사(`channel:`, `user:`)를 사용해야 합니다. -cron이 소유한 격리된 작업의 경우, 실행기가 최종 전달 경로를 소유합니다. 에이전트는 일반 텍스트 요약을 반환하도록 프롬프트되며, 그 요약은 이후 `announce`, `webhook`으로 전송되거나 `none`일 경우 내부에만 유지됩니다. `--no-deliver`는 전달을 에이전트에 되돌리지 않으며, 실행을 내부 전용으로 유지합니다. +cron이 소유하는 격리된 작업의 경우, 실행기가 최종 전달 경로를 소유합니다. 에이전트는 일반 텍스트 요약을 반환하도록 프롬프트되며, 이 요약은 이후 `announce`, `webhook`을 통해 전송되거나 `none`일 경우 내부에만 유지됩니다. `--no-deliver`는 전달을 에이전트로 되돌리지 않으며, 실행을 내부용으로 유지합니다. -원래 작업이 어떤 외부 수신자에게 메시지를 보내라고 명시적으로 지시한 경우, 에이전트는 직접 전송을 시도하는 대신 그 메시지가 누구/어디로 가야 하는지를 출력에 적어야 합니다. +원래 작업이 어떤 외부 수신자에게 메시지를 보내라고 명시적으로 말하는 경우, 에이전트는 직접 보내려고 하지 말고 출력에 누구에게/어디로 그 메시지가 가야 하는지 적어야 합니다. 실패 알림은 별도의 대상 경로를 따릅니다. - `cron.failureDestination`은 실패 알림의 전역 기본값을 설정합니다. - `job.delivery.failureDestination`은 작업별로 이를 재정의합니다. -- 둘 다 설정되지 않았고 작업이 이미 `announce`를 통해 전달하는 경우, 실패 알림은 이제 기본 announce 대상으로 대체됩니다. +- 둘 다 설정되지 않았고 작업이 이미 `announce`를 통해 전달하는 경우, 실패 알림은 이제 해당 기본 announce 대상으로 폴백됩니다. - `delivery.failureDestination`은 기본 전달 모드가 `webhook`인 경우를 제외하면 `sessionTarget="isolated"` 작업에서만 지원됩니다. ## CLI 예시 @@ -144,7 +146,7 @@ openclaw cron add \ --to "channel:C1234567890" ``` -모델 및 thinking 재정의가 포함된 격리 작업: +모델 및 사고 재정의가 있는 격리 작업: ```bash openclaw cron add \ @@ -160,7 +162,7 @@ openclaw cron add \ ## 웹훅 -Gateway는 외부 트리거를 위해 HTTP 웹훅 엔드포인트를 노출할 수 있습니다. config에서 활성화하세요. +Gateway는 외부 트리거를 위한 HTTP 웹훅 엔드포인트를 노출할 수 있습니다. 구성에서 활성화하세요. ```json5 { @@ -174,7 +176,7 @@ Gateway는 외부 트리거를 위해 HTTP 웹훅 엔드포인트를 노출할 ### 인증 -모든 요청에는 헤더를 통해 훅 토큰이 포함되어야 합니다. +모든 요청은 헤더를 통해 훅 토큰을 포함해야 합니다. - `Authorization: Bearer `(권장) - `x-openclaw-token: ` @@ -210,39 +212,39 @@ curl -X POST http://127.0.0.1:18789/hooks/agent \ ### 매핑된 훅(POST /hooks/\) -커스텀 훅 이름은 config의 `hooks.mappings`를 통해 해석됩니다. 매핑은 템플릿이나 코드 변환을 사용해 임의의 페이로드를 `wake` 또는 `agent` 작업으로 변환할 수 있습니다. +사용자 지정 훅 이름은 구성의 `hooks.mappings`를 통해 해석됩니다. 매핑은 템플릿이나 코드 변환을 사용해 임의의 페이로드를 `wake` 또는 `agent` 작업으로 변환할 수 있습니다. ### 보안 - 훅 엔드포인트는 loopback, tailnet 또는 신뢰할 수 있는 리버스 프록시 뒤에 두세요. -- 전용 훅 토큰을 사용하세요. gateway auth 토큰을 재사용하지 마세요. -- `hooks.path`는 전용 하위 경로로 유지하세요. `/`는 거부됩니다. -- 명시적 `agentId` 라우팅을 제한하려면 `hooks.allowedAgentIds`를 설정하세요. -- 호출자가 세션을 선택해야 하는 경우가 아니라면 `hooks.allowRequestSessionKey=false`를 유지하세요. -- `hooks.allowRequestSessionKey`를 활성화하는 경우, 허용된 세션 키 형태를 제한하기 위해 `hooks.allowedSessionKeyPrefixes`도 함께 설정하세요. +- 전용 훅 토큰을 사용하세요. gateway 인증 토큰을 재사용하지 마세요. +- `hooks.path`는 전용 하위 경로에 두세요. `/`는 거부됩니다. +- `hooks.allowedAgentIds`를 설정해 명시적 `agentId` 라우팅을 제한하세요. +- 호출자 선택 세션이 꼭 필요하지 않다면 `hooks.allowRequestSessionKey=false`로 유지하세요. +- `hooks.allowRequestSessionKey`를 활성화한다면, 허용되는 세션 키 형태를 제한하기 위해 `hooks.allowedSessionKeyPrefixes`도 설정하세요. - 훅 페이로드는 기본적으로 안전 경계로 감싸집니다. ## Gmail PubSub 통합 -Google PubSub를 통해 Gmail 받은편지함 트리거를 OpenClaw에 연결하세요. +Google PubSub을 통해 Gmail 받은편지함 트리거를 OpenClaw에 연결합니다. -**사전 요구 사항**: `gcloud` CLI, `gog`(gogcli), OpenClaw hooks 활성화, 공개 HTTPS 엔드포인트용 Tailscale. +**사전 요구 사항**: `gcloud` CLI, `gog` (`gogcli`), 활성화된 OpenClaw hooks, 공개 HTTPS 엔드포인트를 위한 Tailscale. -### 마법사 설정(권장) +### 설정 마법사(권장) ```bash openclaw webhooks gmail setup --account openclaw@gmail.com ``` -이 명령은 `hooks.gmail` config를 기록하고, Gmail 프리셋을 활성화하며, 푸시 엔드포인트에 Tailscale Funnel을 사용합니다. +이 명령은 `hooks.gmail` 구성을 작성하고, Gmail 프리셋을 활성화하며, 푸시 엔드포인트에 Tailscale Funnel을 사용합니다. ### Gateway 자동 시작 -`hooks.enabled=true`이고 `hooks.gmail.account`가 설정되어 있으면, Gateway는 부팅 시 `gog gmail watch serve`를 시작하고 watch를 자동 갱신합니다. 제외하려면 `OPENCLAW_SKIP_GMAIL_WATCHER=1`을 설정하세요. +`hooks.enabled=true`이고 `hooks.gmail.account`가 설정되어 있으면, Gateway는 부팅 시 `gog gmail watch serve`를 시작하고 watch를 자동 갱신합니다. 비활성화하려면 `OPENCLAW_SKIP_GMAIL_WATCHER=1`을 설정하세요. ### 수동 1회 설정 -1. `gog`가 사용하는 OAuth 클라이언트를 소유한 GCP 프로젝트를 선택합니다. +1. `gog`에서 사용하는 OAuth 클라이언트를 소유한 GCP 프로젝트를 선택합니다. ```bash gcloud auth login @@ -284,16 +286,16 @@ gog gmail watch start \ ## 작업 관리 ```bash -# 모든 작업 나열 +# 모든 작업 목록 보기 openclaw cron list # 작업 편집 openclaw cron edit --message "Updated prompt" --model "opus" -# 지금 작업 강제 실행 +# 작업을 지금 강제 실행 openclaw cron run -# 기한이 지난 경우에만 실행 +# 기한이 된 경우에만 실행 openclaw cron run --due # 실행 기록 보기 @@ -302,7 +304,7 @@ openclaw cron runs --id --limit 50 # 작업 삭제 openclaw cron remove -# Agent 선택(멀티 agent 설정) +# 에이전트 선택(멀티 에이전트 설정) openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops openclaw cron edit --clear-agent ``` @@ -310,9 +312,9 @@ openclaw cron edit --clear-agent 모델 재정의 참고: - `openclaw cron add|edit --model ...`은 작업의 선택된 모델을 변경합니다. -- 모델이 허용되면, 정확히 그 provider/model이 격리된 agent 실행에 전달됩니다. -- 허용되지 않으면, cron은 경고를 표시하고 작업의 agent/default 모델 선택으로 대체합니다. -- 구성된 fallback 체인은 계속 적용되지만, 명시적 작업별 fallback 목록이 없는 일반 `--model` 재정의는 더 이상 조용한 추가 재시도 대상으로 agent primary로 넘어가지 않습니다. +- 모델이 허용되면, 정확히 그 provider/model이 격리된 에이전트 실행에 전달됩니다. +- 허용되지 않으면 cron이 경고를 표시하고 작업의 에이전트/기본 모델 선택으로 폴백합니다. +- 구성된 폴백 체인은 계속 적용되지만, 명시적인 작업별 폴백 목록이 없는 일반 `--model` 재정의는 더 이상 에이전트 기본 모델로 조용히 추가 재시도 대상이 되지 않습니다. ## 구성 @@ -336,11 +338,11 @@ openclaw cron edit --clear-agent cron 비활성화: `cron.enabled: false` 또는 `OPENCLAW_SKIP_CRON=1`. -**일회성 재시도**: 일시적 오류(rate limit, overload, network, server error)는 지수 백오프와 함께 최대 3회 재시도합니다. 영구 오류는 즉시 비활성화됩니다. +**일회성 재시도**: 일시적 오류(rate limit, overload, network, server error)는 지수형 백오프와 함께 최대 3회 재시도합니다. 영구 오류는 즉시 비활성화됩니다. -**반복 재시도**: 재시도 사이에 지수 백오프(30초~60분)를 사용합니다. 다음 성공 실행 후에는 백오프가 초기화됩니다. +**반복 재시도**: 재시도 사이에 지수형 백오프(30초~60분)를 사용합니다. 다음 실행이 성공하면 백오프는 초기화됩니다. -**유지보수**: `cron.sessionRetention`(기본값 `24h`)은 격리된 실행 세션 항목을 정리합니다. `cron.runLog.maxBytes` / `cron.runLog.keepLines`는 실행 로그 파일을 자동 정리합니다. +**유지 관리**: `cron.sessionRetention`(기본값 `24h`)은 격리된 실행 세션 항목을 정리합니다. `cron.runLog.maxBytes` / `cron.runLog.keepLines`는 실행 로그 파일을 자동으로 정리합니다. ## 문제 해결 @@ -357,30 +359,30 @@ openclaw logs --follow openclaw doctor ``` -### Cron이 실행되지 않음 +### cron이 실행되지 않음 - `cron.enabled`와 `OPENCLAW_SKIP_CRON` 환경 변수를 확인하세요. - Gateway가 계속 실행 중인지 확인하세요. -- `cron` 일정의 경우 타임존(`--tz`)과 호스트 타임존이 일치하는지 확인하세요. -- 실행 출력의 `reason: not-due`는 수동 실행이 `openclaw cron run --due`로 확인되었고 작업 기한이 아직 되지 않았음을 의미합니다. +- `cron` 일정의 경우 시간대(`--tz`)와 호스트 시간대가 맞는지 확인하세요. +- 실행 출력의 `reason: not-due`는 수동 실행이 `openclaw cron run --due`로 확인되었지만 작업이 아직 실행 시각이 되지 않았음을 의미합니다. -### Cron이 실행되었지만 전달이 없음 +### cron이 실행되었지만 전달되지 않음 -- 전달 모드가 `none`이면 외부 메시지는 예상되지 않습니다. -- 전달 대상이 없거나 잘못된 경우(`channel`/`to`) 아웃바운드가 건너뛰어집니다. -- 채널 인증 오류(`unauthorized`, `Forbidden`)는 자격 증명 때문에 전달이 차단되었음을 의미합니다. -- 격리된 실행이 무음 토큰(`NO_REPLY` / `no_reply`)만 반환하면, OpenClaw는 직접 아웃바운드 전달과 fallback 대기열 요약 경로도 모두 억제하므로 채팅으로 아무것도 게시되지 않습니다. -- cron이 소유한 격리된 작업의 경우, fallback으로 에이전트가 message 도구를 사용할 것이라 기대하지 마세요. 최종 전달은 실행기가 소유하며, `--no-deliver`는 직접 전송을 허용하는 대신 내부 전용으로 유지합니다. +- 전달 모드가 `none`이면 외부 메시지가 예상되지 않습니다. +- 전달 대상이 없거나 잘못된 경우(`channel`/`to`)에는 외부 전송이 건너뛰어집니다. +- 채널 인증 오류(`unauthorized`, `Forbidden`)는 자격 증명 문제로 전달이 차단되었음을 의미합니다. +- 격리된 실행이 무음 토큰(`NO_REPLY` / `no_reply`)만 반환하면, OpenClaw는 직접 외부 전달도 억제하고 폴백 대기열 요약 경로도 억제하므로 채팅에 아무것도 게시되지 않습니다. +- cron이 소유하는 격리된 작업의 경우, 에이전트가 폴백으로 message tool을 사용할 것이라고 기대하지 마세요. 최종 전달은 실행기가 소유하며, `--no-deliver`는 직접 전송을 허용하는 대신 내부용으로 유지합니다. -### 타임존 관련 주의사항 +### 시간대 관련 주의 사항 -- `--tz`가 없는 cron은 gateway 호스트 타임존을 사용합니다. -- 타임존이 없는 `at` 일정은 UTC로 처리됩니다. -- Heartbeat `activeHours`는 구성된 타임존 해석을 사용합니다. +- `--tz`가 없는 cron은 gateway 호스트 시간대를 사용합니다. +- 시간대가 없는 `at` 일정은 UTC로 처리됩니다. +- Heartbeat `activeHours`는 구성된 시간대 해석을 사용합니다. -## 관련 항목 +## 관련 문서 -- [Automation & Tasks](/automation) — 모든 자동화 메커니즘 한눈에 보기 -- [Background Tasks](/automation/tasks) — cron 실행을 위한 작업 원장 -- [Heartbeat](/gateway/heartbeat) — 주기적인 메인 세션 턴 -- [Timezone](/concepts/timezone) — 타임존 구성 +- [자동화 및 작업](/ko/automation) — 모든 자동화 메커니즘 한눈에 보기 +- [백그라운드 작업](/ko/automation/tasks) — cron 실행을 위한 작업 원장 +- [Heartbeat](/ko/gateway/heartbeat) — 주기적인 메인 세션 턴 +- [시간대](/ko/concepts/timezone) — 시간대 구성 diff --git a/docs/ko/automation/hooks.md b/docs/ko/automation/hooks.md index d0df88026..ba04fc229 100644 --- a/docs/ko/automation/hooks.md +++ b/docs/ko/automation/hooks.md @@ -1,14 +1,14 @@ --- read_when: - - /new, /reset, /stop 및 에이전트 수명 주기 이벤트에 대한 이벤트 기반 자동화를 원합니다 - - Hooks를 빌드, 설치 또는 디버그하려고 합니다 -summary: 'Hooks: 명령 및 수명 주기 이벤트를 위한 이벤트 기반 자동화' + - /new, /reset, /stop 및 에이전트 수명 주기 이벤트를 위한 이벤트 기반 자동화를 원합니다 + - hooks를 빌드, 설치 또는 디버그하려고 합니다 +summary: 'Hooks: 명령어 및 수명 주기 이벤트를 위한 이벤트 기반 자동화' title: Hooks x-i18n: - generated_at: "2026-04-05T12:34:20Z" + generated_at: "2026-04-11T02:44:21Z" model: gpt-5.4 provider: openai - source_hash: 66eb75bb2b3b2ad229bf3da24fdb0fe021ed08f812fd1d13c69b3bd9df0218e5 + source_hash: 14296398e4042d442ebdf071a07c6be99d4afda7cbf3c2b934e76dc5539742c7 source_path: automation/hooks.md workflow: 15 --- @@ -17,12 +17,12 @@ x-i18n: Hooks는 Gateway 내부에서 어떤 일이 발생할 때 실행되는 작은 스크립트입니다. 디렉터리에서 자동으로 검색되며 `openclaw hooks`로 확인할 수 있습니다. -OpenClaw에는 두 종류의 hooks가 있습니다. +OpenClaw에는 두 가지 종류의 hooks가 있습니다. - **내부 hooks**(이 페이지): `/new`, `/reset`, `/stop` 또는 수명 주기 이벤트처럼 에이전트 이벤트가 발생할 때 Gateway 내부에서 실행됩니다. -- **웹훅**: 다른 시스템이 OpenClaw에서 작업을 트리거할 수 있게 하는 외부 HTTP 엔드포인트입니다. [Webhooks](/automation/cron-jobs#webhooks)를 참조하세요. +- **Webhooks**: 다른 시스템이 OpenClaw에서 작업을 트리거할 수 있도록 해주는 외부 HTTP 엔드포인트입니다. [Webhooks](/ko/automation/cron-jobs#webhooks)를 참고하세요. -Hooks는 plugins 내부에 번들로 포함될 수도 있습니다. `openclaw hooks list`는 독립형 hooks와 plugin이 관리하는 hooks를 모두 표시합니다. +Hooks는 plugins 안에 번들로 포함될 수도 있습니다. `openclaw hooks list`는 독립형 hooks와 plugin이 관리하는 hooks를 모두 표시합니다. ## 빠른 시작 @@ -42,27 +42,27 @@ openclaw hooks info session-memory ## 이벤트 유형 -| 이벤트 | 발생 시점 | +| Event | 실행 시점 | | ------------------------ | ------------------------------------------------ | -| `command:new` | `/new` 명령이 실행될 때 | -| `command:reset` | `/reset` 명령이 실행될 때 | -| `command:stop` | `/stop` 명령이 실행될 때 | -| `command` | 모든 명령 이벤트(일반 리스너) | -| `session:compact:before` | 압축이 기록을 요약하기 전 | -| `session:compact:after` | 압축이 완료된 후 | -| `session:patch` | 세션 속성이 수정될 때 | -| `agent:bootstrap` | 워크스페이스 bootstrap 파일이 주입되기 전 | -| `gateway:startup` | 채널이 시작되고 hooks가 로드된 후 | -| `message:received` | 모든 채널의 수신 메시지 | -| `message:transcribed` | 오디오 전사가 완료된 후 | -| `message:preprocessed` | 모든 미디어 및 링크 이해가 완료된 후 | -| `message:sent` | 발신 메시지가 전달된 후 | +| `command:new` | `/new` 명령이 실행될 때 | +| `command:reset` | `/reset` 명령이 실행될 때 | +| `command:stop` | `/stop` 명령이 실행될 때 | +| `command` | 모든 명령 이벤트(일반 리스너) | +| `session:compact:before` | 압축이 기록을 요약하기 전 | +| `session:compact:after` | 압축이 완료된 후 | +| `session:patch` | 세션 속성이 수정될 때 | +| `agent:bootstrap` | 워크스페이스 bootstrap 파일이 주입되기 전 | +| `gateway:startup` | 채널이 시작되고 hooks가 로드된 후 | +| `message:received` | 아무 채널에서나 수신 메시지가 들어올 때 | +| `message:transcribed` | 오디오 전사가 완료된 후 | +| `message:preprocessed` | 모든 미디어 및 링크 이해가 완료된 후 | +| `message:sent` | 발신 메시지가 전달될 때 | -## Hooks 작성하기 +## hooks 작성하기 ### Hook 구조 -각 hook은 두 개의 파일이 포함된 디렉터리입니다. +각 hook은 두 개의 파일이 들어 있는 디렉터리입니다. ``` my-hook/ @@ -75,27 +75,27 @@ my-hook/ ```markdown --- name: my-hook -description: "이 hook이 수행하는 작업에 대한 짧은 설명" +description: "이 hook이 수행하는 작업의 짧은 설명" metadata: { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } } --- # My Hook -여기에 자세한 문서를 작성합니다. +자세한 문서는 여기에 작성합니다. ``` **메타데이터 필드** (`metadata.openclaw`): -| 필드 | 설명 | +| Field | 설명 | | ---------- | ---------------------------------------------------- | -| `emoji` | CLI용 표시 이모지 | -| `events` | 수신할 이벤트 배열 | -| `export` | 사용할 이름 있는 export(기본값: `"default"`) | -| `os` | 필요한 플랫폼(예: `["darwin", "linux"]`) | -| `requires` | 필요한 `bins`, `anyBins`, `env` 또는 `config` 경로 | -| `always` | 적격성 검사 우회(boolean) | -| `install` | 설치 방법 | +| `emoji` | CLI에 표시할 이모지 | +| `events` | 수신할 이벤트 배열 | +| `export` | 사용할 named export(기본값은 `"default"`) | +| `os` | 필요한 플랫폼(예: `["darwin", "linux"]`) | +| `requires` | 필요한 `bins`, `anyBins`, `env` 또는 `config` 경로 | +| `always` | 적격성 검사 우회(boolean) | +| `install` | 설치 방법 | ### 핸들러 구현 @@ -106,18 +106,18 @@ const handler = async (event) => { } console.log(`[my-hook] New command triggered`); - // 여기에 로직 작성 + // Your logic here - // 선택적으로 사용자에게 메시지 전송 + // Optionally send message to user event.messages.push("Hook executed!"); }; export default handler; ``` -각 이벤트에는 `type`, `action`, `sessionKey`, `timestamp`, `messages`(사용자에게 보내려면 push), `context`(이벤트별 데이터)가 포함됩니다. +각 이벤트에는 `type`, `action`, `sessionKey`, `timestamp`, `messages`(사용자에게 보내기 위해 push), 그리고 `context`(이벤트별 데이터)가 포함됩니다. -### 이벤트 컨텍스트 핵심 항목 +### 이벤트 context 주요 항목 **명령 이벤트** (`command:new`, `command:reset`): `context.sessionEntry`, `context.previousSessionEntry`, `context.commandSource`, `context.workspaceDir`, `context.cfg`. @@ -127,43 +127,43 @@ export default handler; **메시지 이벤트** (`message:transcribed`): `context.transcript`, `context.from`, `context.channelId`, `context.mediaPath`. -**메시지 이벤트** (`message:preprocessed`): `context.bodyForAgent`(최종 보강된 본문), `context.from`, `context.channelId`. +**메시지 이벤트** (`message:preprocessed`): `context.bodyForAgent`(최종 강화된 본문), `context.from`, `context.channelId`. **Bootstrap 이벤트** (`agent:bootstrap`): `context.bootstrapFiles`(변경 가능한 배열), `context.agentId`. -**세션 패치 이벤트** (`session:patch`): `context.sessionEntry`, `context.patch`(변경된 필드만), `context.cfg`. 패치 이벤트는 권한이 있는 클라이언트만 트리거할 수 있습니다. +**세션 patch 이벤트** (`session:patch`): `context.sessionEntry`, `context.patch`(변경된 필드만), `context.cfg`. patch 이벤트는 권한이 있는 클라이언트만 트리거할 수 있습니다. **압축 이벤트**: `session:compact:before`에는 `messageCount`, `tokenCount`가 포함됩니다. `session:compact:after`에는 `compactedCount`, `summaryLength`, `tokensBefore`, `tokensAfter`가 추가됩니다. ## Hook 검색 -Hooks는 다음 디렉터리에서 검색되며, 아래로 갈수록 재정의 우선순위가 높아집니다. +Hooks는 다음 디렉터리에서 검색되며, 아래 순서대로 재정의 우선순위가 높아집니다. 1. **번들 hooks**: OpenClaw와 함께 제공됨 -2. **Plugin hooks**: 설치된 plugins 내부에 번들된 hooks -3. **관리형 hooks**: `~/.openclaw/hooks/` (사용자가 설치하며 워크스페이스 간 공유). `hooks.internal.load.extraDirs`의 추가 디렉터리도 이 우선순위를 공유합니다. -4. **워크스페이스 hooks**: `/hooks/` (에이전트별, 명시적으로 활성화하기 전까지 기본적으로 비활성화됨) +2. **Plugin hooks**: 설치된 plugins 안에 번들된 hooks +3. **관리형 hooks**: `~/.openclaw/hooks/` (사용자가 설치하며 워크스페이스 간 공유). `hooks.internal.load.extraDirs`의 추가 디렉터리도 같은 우선순위를 가집니다. +4. **워크스페이스 hooks**: `/hooks/` (에이전트별, 명시적으로 활성화하기 전까지 기본적으로 비활성화) -워크스페이스 hooks는 새 hook 이름을 추가할 수 있지만, 같은 이름의 번들, 관리형 또는 plugin 제공 hooks를 재정의할 수는 없습니다. +워크스페이스 hooks는 새 hook 이름을 추가할 수는 있지만, 같은 이름의 번들, 관리형 또는 plugin 제공 hooks를 재정의할 수는 없습니다. -### Hook 팩 +### Hook packs -Hook 팩은 `package.json`의 `openclaw.hooks`를 통해 hooks를 export하는 npm 패키지입니다. 설치 방법: +Hook packs는 `package.json`의 `openclaw.hooks`를 통해 hooks를 내보내는 npm 패키지입니다. 다음으로 설치합니다. ```bash openclaw plugins install ``` -Npm spec은 레지스트리 전용입니다(패키지 이름 + 선택적 정확한 버전 또는 dist-tag). Git/URL/file spec 및 semver 범위는 거부됩니다. +Npm spec은 레지스트리 전용입니다(패키지 이름 + 선택적 정확한 버전 또는 dist-tag). Git/URL/file spec과 semver 범위는 거부됩니다. ## 번들 hooks -| Hook | 이벤트 | 수행 작업 | +| Hook | Events | 수행 작업 | | --------------------- | ------------------------------ | ----------------------------------------------------- | -| session-memory | `command:new`, `command:reset` | 세션 컨텍스트를 `/memory/`에 저장 | -| bootstrap-extra-files | `agent:bootstrap` | glob 패턴에서 추가 bootstrap 파일 주입 | -| command-logger | `command` | 모든 명령을 `~/.openclaw/logs/commands.log`에 기록 | -| boot-md | `gateway:startup` | gateway 시작 시 `BOOT.md` 실행 | +| session-memory | `command:new`, `command:reset` | 세션 context를 `/memory/`에 저장 | +| bootstrap-extra-files | `agent:bootstrap` | glob 패턴에서 추가 bootstrap 파일 주입 | +| command-logger | `command` | 모든 명령을 `~/.openclaw/logs/commands.log`에 기록 | +| boot-md | `gateway:startup` | gateway 시작 시 `BOOT.md` 실행 | 번들 hook 활성화: @@ -171,11 +171,15 @@ Npm spec은 레지스트리 전용입니다(패키지 이름 + 선택적 정확 openclaw hooks enable ``` + + ### session-memory 세부 정보 -최근 사용자/assistant 메시지 15개를 추출하고, LLM을 통해 설명적인 파일명 슬러그를 생성한 뒤 `/memory/YYYY-MM-DD-slug.md`에 저장합니다. `workspace.dir`이 구성되어 있어야 합니다. +마지막 사용자/assistant 메시지 15개를 추출하고, LLM을 통해 설명적인 파일명 slug를 생성한 뒤, `/memory/YYYY-MM-DD-slug.md`에 저장합니다. `workspace.dir`이 설정되어 있어야 합니다. -### bootstrap-extra-files 구성 + + +### bootstrap-extra-files 설정 ```json { @@ -192,15 +196,27 @@ openclaw hooks enable } ``` -경로는 워크스페이스를 기준으로 해석됩니다. 인식된 bootstrap basename만 로드됩니다(`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `MEMORY.md`). +경로는 워크스페이스 기준으로 해석됩니다. 인식되는 bootstrap basename만 로드됩니다(`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `MEMORY.md`). + + + +### command-logger 세부 정보 + +모든 슬래시 명령을 `~/.openclaw/logs/commands.log`에 기록합니다. + + + +### boot-md 세부 정보 + +gateway가 시작될 때 활성 워크스페이스의 `BOOT.md`를 실행합니다. ## Plugin hooks -Plugins는 더 깊은 통합을 위해 Plugin SDK를 통해 hooks를 등록할 수 있습니다. 예를 들어 도구 호출 가로채기, 프롬프트 수정, 메시지 흐름 제어 등이 가능합니다. Plugin SDK는 모델 확인, 에이전트 수명 주기, 메시지 흐름, 도구 실행, 서브에이전트 조정, gateway 수명 주기를 포괄하는 28개의 hooks를 제공합니다. +Plugins는 Plugin SDK를 통해 hooks를 등록하여 더 깊이 통합할 수 있습니다. 예를 들어 도구 호출 가로채기, 프롬프트 수정, 메시지 흐름 제어 등이 가능합니다. Plugin SDK는 모델 확인, 에이전트 수명 주기, 메시지 흐름, 도구 실행, 하위 에이전트 조정, gateway 수명 주기를 포함해 28개의 hooks를 제공합니다. -`before_tool_call`, `before_agent_reply`, `before_install` 및 기타 모든 plugin hooks를 포함한 전체 plugin hook 참조는 [Plugin Architecture](/plugins/architecture#provider-runtime-hooks)를 참조하세요. +`before_tool_call`, `before_agent_reply`, `before_install` 및 기타 모든 plugin hooks를 포함한 전체 plugin hook 참조는 [Plugin Architecture](/ko/plugins/architecture#provider-runtime-hooks)를 참고하세요. -## 구성 +## 설정 ```json { @@ -216,7 +232,7 @@ Plugins는 더 깊은 통합을 위해 Plugin SDK를 통해 hooks를 등록할 } ``` -Hook별 환경 변수: +hook별 환경 변수: ```json { @@ -248,7 +264,7 @@ Hook별 환경 변수: ``` -레거시 `hooks.internal.handlers` 배열 구성 형식도 이전 버전과의 호환성을 위해 계속 지원되지만, 새 hooks는 검색 기반 시스템을 사용해야 합니다. +레거시 `hooks.internal.handlers` 배열 설정 형식도 이전 버전과의 호환성을 위해 계속 지원되지만, 새 hooks는 검색 기반 시스템을 사용해야 합니다. ## CLI 참조 @@ -270,10 +286,10 @@ openclaw hooks disable ## 모범 사례 -- **핸들러를 빠르게 유지하세요.** Hooks는 명령 처리 중 실행됩니다. 무거운 작업은 `void processInBackground(event)`로 실행만 시작하고 기다리지 마세요. -- **오류를 우아하게 처리하세요.** 위험한 작업은 try/catch로 감싸고, 다른 핸들러도 실행될 수 있도록 throw하지 마세요. +- **핸들러를 빠르게 유지하세요.** Hooks는 명령 처리 중에 실행됩니다. 무거운 작업은 `void processInBackground(event)`로 fire-and-forget 방식으로 처리하세요. +- **오류를 우아하게 처리하세요.** 위험한 작업은 try/catch로 감싸고, 다른 핸들러가 실행될 수 있도록 예외를 던지지 마세요. - **이벤트를 초기에 필터링하세요.** 이벤트 type/action이 관련 없으면 즉시 반환하세요. -- **구체적인 이벤트 키를 사용하세요.** 오버헤드를 줄이기 위해 `"events": ["command"]`보다 `"events": ["command:new"]`를 권장합니다. +- **구체적인 이벤트 키를 사용하세요.** 오버헤드를 줄이기 위해 `"events": ["command"]`보다 `"events": ["command:new"]`를 선호하세요. ## 문제 해결 @@ -282,7 +298,7 @@ openclaw hooks disable ```bash # 디렉터리 구조 확인 ls -la ~/.openclaw/hooks/my-hook/ -# 표시되어야 함: HOOK.md, handler.ts +# 표시되어야 하는 항목: HOOK.md, handler.ts # 검색된 모든 hooks 나열 openclaw hooks list @@ -294,7 +310,7 @@ openclaw hooks list openclaw hooks info my-hook ``` -누락된 바이너리(PATH), 환경 변수, 구성 값 또는 OS 호환성을 확인하세요. +누락된 바이너리(PATH), 환경 변수, 설정 값 또는 OS 호환성을 확인하세요. ### Hook이 실행되지 않음 @@ -305,6 +321,6 @@ openclaw hooks info my-hook ## 관련 문서 - [CLI Reference: hooks](/cli/hooks) -- [Webhooks](/automation/cron-jobs#webhooks) -- [Plugin Architecture](/plugins/architecture#provider-runtime-hooks) — 전체 plugin hook 참조 -- [Configuration](/gateway/configuration-reference#hooks) +- [Webhooks](/ko/automation/cron-jobs#webhooks) +- [Plugin Architecture](/ko/plugins/architecture#provider-runtime-hooks) — 전체 plugin hook 참조 +- [Configuration](/ko/gateway/configuration-reference#hooks) diff --git a/docs/ko/ci.md b/docs/ko/ci.md index 36d9f510c..ec8016940 100644 --- a/docs/ko/ci.md +++ b/docs/ko/ci.md @@ -1,74 +1,75 @@ --- read_when: - - CI 작업이 실행되었거나 실행되지 않은 이유를 이해해야 할 때 - - 실패한 GitHub Actions 검사를 디버깅하고 있을 때 + - CI 작업이 실행되었는지 또는 실행되지 않았는지 그 이유를 이해해야 합니다. + - 실패한 GitHub Actions 검사를 디버깅하고 있습니다. summary: CI 작업 그래프, 범위 게이트, 그리고 로컬 명령어 대응 항목 title: CI 파이프라인 x-i18n: - generated_at: "2026-04-09T05:56:22Z" + generated_at: "2026-04-11T02:44:28Z" model: gpt-5.4 provider: openai - source_hash: d104f2510fadd674d7952aa08ad73e10f685afebea8d7f19adc1d428e2bdc908 + source_hash: ca7e355b7f73bfe8ea8c6971e78164b8b2e68cbb27966964955e267fed89fce6 source_path: ci.md workflow: 15 --- # CI 파이프라인 -CI는 `main`에 대한 모든 푸시와 모든 풀 리퀘스트에서 실행됩니다. 관련 없는 영역만 변경된 경우 비용이 큰 작업을 건너뛰기 위해 스마트한 범위 지정 방식을 사용합니다. +CI는 `main`에 대한 모든 푸시와 모든 pull request에서 실행됩니다. 스마트 스코프 판정을 사용해 변경과 무관한 영역만 수정된 경우 비용이 큰 작업을 건너뜁니다. ## 작업 개요 -| 작업 | 목적 | 실행 시점 | -| ------------------------ | ------------------------------------------------------------------------------------- | ----------------------------------- | -| `preflight` | 문서 전용 변경, 변경된 범위, 변경된 확장 기능을 감지하고 CI 매니페스트를 빌드 | 초안이 아닌 모든 푸시 및 PR에서 항상 | -| `security-fast` | 비공개 키 감지, `zizmor`를 통한 워크플로 감사, 프로덕션 의존성 감사 | 초안이 아닌 모든 푸시 및 PR에서 항상 | -| `build-artifacts` | `dist/`와 Control UI를 한 번 빌드하고, 후속 작업을 위해 재사용 가능한 아티팩트를 업로드 | Node 관련 변경 시 | -| `checks-fast-core` | 번들/plugin-contract/protocol 검사와 같은 빠른 Linux 정확성 레인 | Node 관련 변경 시 | -| `checks-fast-extensions` | `checks-fast-extensions-shard` 완료 후 확장 기능 샤드 레인을 집계 | Node 관련 변경 시 | -| `extension-fast` | 변경된 번들 plugins만 대상으로 한 집중 테스트 | 확장 기능 변경이 감지된 경우 | -| `check` | CI의 기본 로컬 게이트: `pnpm check`와 `pnpm build:strict-smoke` | Node 관련 변경 시 | -| `check-additional` | 아키텍처, 경계, import-cycle 가드와 게이트웨이 watch 회귀 하네스 | Node 관련 변경 시 | -| `build-smoke` | 빌드된 CLI 스모크 테스트와 시작 메모리 스모크 | Node 관련 변경 시 | -| `checks` | 더 무거운 Linux Node 레인: 전체 테스트, 채널 테스트, 푸시 전용 Node 22 호환성 | Node 관련 변경 시 | -| `check-docs` | 문서 포맷팅, lint, 깨진 링크 검사 | 문서가 변경된 경우 | -| `skills-python` | Python 기반 Skills용 Ruff + pytest | Python Skills 관련 변경 시 | -| `checks-windows` | Windows 전용 테스트 레인 | Windows 관련 변경 시 | -| `macos-node` | 공유 빌드 아티팩트를 사용하는 macOS TypeScript 테스트 레인 | macOS 관련 변경 시 | -| `macos-swift` | macOS 앱용 Swift lint, 빌드, 테스트 | macOS 관련 변경 시 | -| `android` | Android 빌드 및 테스트 매트릭스 | Android 관련 변경 시 | +| 작업 | 목적 | 실행 시점 | +| ------------------------ | ------------------------------------------------------------------------------------- | ---------------------------------- | +| `preflight` | docs 전용 변경, 변경된 스코프, 변경된 확장 프로그램을 감지하고 CI 매니페스트를 빌드합니다 | 초안이 아닌 모든 푸시 및 PR에서 항상 | +| `security-fast` | 개인 키 탐지, `zizmor`를 통한 워크플로 감사, 프로덕션 의존성 감사 | 초안이 아닌 모든 푸시 및 PR에서 항상 | +| `build-artifacts` | `dist/`와 Control UI를 한 번 빌드하고, 후속 작업에서 재사용할 아티팩트를 업로드합니다 | Node 관련 변경 | +| `checks-fast-core` | 번들/플러그인 계약/프로토콜 검사와 같은 빠른 Linux 정확성 레인 | Node 관련 변경 | +| `checks-node-extensions` | 확장 프로그램 스위트 전반에 걸친 전체 번들 플러그인 테스트 샤드 | Node 관련 변경 | +| `checks-node-core-test` | 채널, 번들, 계약, 확장 프로그램 레인을 제외한 코어 Node 테스트 샤드 | Node 관련 변경 | +| `extension-fast` | 변경된 번들 플러그인만 대상으로 하는 집중 테스트 | 확장 프로그램 변경이 감지된 경우 | +| `check` | CI의 주요 로컬 게이트: `pnpm check`와 `pnpm build:strict-smoke` | Node 관련 변경 | +| `check-additional` | 아키텍처, 경계, import-cycle 가드와 gateway watch 회귀 하네스 | Node 관련 변경 | +| `build-smoke` | 빌드된 CLI 스모크 테스트 및 시작 메모리 스모크 | Node 관련 변경 | +| `checks` | 나머지 Linux Node 레인: 채널 테스트 및 푸시 전용 Node 22 호환성 | Node 관련 변경 | +| `check-docs` | docs 포맷팅, lint, 끊어진 링크 검사 | docs 변경 | +| `skills-python` | Python 기반 Skills용 Ruff + pytest | Python Skills 관련 변경 | +| `checks-windows` | Windows 전용 테스트 레인 | Windows 관련 변경 | +| `macos-node` | 공유 빌드 아티팩트를 사용하는 macOS TypeScript 테스트 레인 | macOS 관련 변경 | +| `macos-swift` | macOS 앱용 Swift lint, 빌드, 테스트 | macOS 관련 변경 | +| `android` | Android 빌드 및 테스트 매트릭스 | Android 관련 변경 | -## 빠른 실패 순서 +## Fail-Fast 순서 작업은 비용이 큰 작업이 실행되기 전에 저렴한 검사가 먼저 실패하도록 순서가 정해져 있습니다. -1. `preflight`가 어떤 레인이 실제로 존재하는지 결정합니다. `docs-scope`와 `changed-scope` 로직은 독립 실행형 작업이 아니라 이 작업 내부의 단계입니다. +1. `preflight`가 어떤 레인이 실제로 존재할지를 결정합니다. `docs-scope`와 `changed-scope` 로직은 독립 작업이 아니라 이 작업 내부의 단계입니다. 2. `security-fast`, `check`, `check-additional`, `check-docs`, `skills-python`은 더 무거운 아티팩트 및 플랫폼 매트릭스 작업을 기다리지 않고 빠르게 실패합니다. -3. `build-artifacts`는 빠른 Linux 레인과 겹쳐 실행되므로, 공유 빌드가 준비되는 즉시 후속 소비자가 시작할 수 있습니다. -4. 이후 더 무거운 플랫폼 및 런타임 레인이 분기되어 실행됩니다: `checks-fast-core`, `checks-fast-extensions`, `extension-fast`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, `android`. +3. `build-artifacts`는 빠른 Linux 레인과 겹쳐 실행되므로, 공유 빌드가 준비되는 즉시 후속 소비 작업이 시작될 수 있습니다. +4. 그다음 더 무거운 플랫폼 및 런타임 레인이 분기되어 실행됩니다: `checks-fast-core`, `checks-node-extensions`, `checks-node-core-test`, `extension-fast`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, `android`. -범위 로직은 `scripts/ci-changed-scope.mjs`에 있으며, `src/scripts/ci-changed-scope.test.ts`의 단위 테스트로 검증됩니다. -별도의 `install-smoke` 워크플로는 자체 `preflight` 작업을 통해 동일한 범위 스크립트를 재사용합니다. 더 좁은 changed-smoke 신호에서 `run_install_smoke`를 계산하므로, Docker/install 스모크는 install, 패키징, 컨테이너 관련 변경에 대해서만 실행됩니다. +스코프 로직은 `scripts/ci-changed-scope.mjs`에 있으며, `src/scripts/ci-changed-scope.test.ts`의 단위 테스트로 검증됩니다. +별도의 `install-smoke` 워크플로는 자체 `preflight` 작업을 통해 같은 스코프 스크립트를 재사용합니다. 더 좁은 changed-smoke 신호로부터 `run_install_smoke`를 계산하므로, Docker/install smoke는 설치, 패키징, 컨테이너 관련 변경에 대해서만 실행됩니다. -푸시에서는 `checks` 매트릭스에 푸시 전용 `compat-node22` 레인이 추가됩니다. 풀 리퀘스트에서는 이 레인이 건너뛰어지고, 매트릭스는 일반적인 테스트/채널 레인에 집중된 상태를 유지합니다. +푸시에서는 `checks` 매트릭스에 푸시 전용 `compat-node22` 레인이 추가됩니다. pull request에서는 이 레인이 건너뛰어지고, 매트릭스는 일반 테스트/채널 레인에 집중된 상태를 유지합니다. ## 러너 -| 러너 | 작업 | -| -------------------------------- | ---------------------------------------------------------------------------------------------------- | -| `blacksmith-16vcpu-ubuntu-2404` | `preflight`, `security-fast`, `build-artifacts`, Linux 검사, 문서 검사, Python Skills, `android` | -| `blacksmith-32vcpu-windows-2025` | `checks-windows` | -| `macos-latest` | `macos-node`, `macos-swift` | +| 러너 | 작업 | +| -------------------------------- | ----------------------------------------------------------------------------------------------------- | +| `blacksmith-16vcpu-ubuntu-2404` | `preflight`, `security-fast`, `build-artifacts`, Linux 검사, docs 검사, Python Skills, `android` | +| `blacksmith-32vcpu-windows-2025` | `checks-windows` | +| `macos-latest` | `macos-node`, `macos-swift` | -## 로컬 대응 명령어 +## 로컬 대응 항목 ```bash -pnpm check # 타입 + lint + format +pnpm check # types + lint + format pnpm build:strict-smoke pnpm check:import-cycles pnpm test:gateway:watch-regression pnpm test # vitest 테스트 pnpm test:channels -pnpm check:docs # 문서 format + lint + 깨진 링크 -pnpm build # CI 아티팩트/build-smoke 레인이 중요할 때 dist 빌드 +pnpm check:docs # docs format + lint + broken links +pnpm build # CI artifact/build-smoke 레인이 중요할 때 dist 빌드 ``` diff --git a/docs/ko/concepts/agent-loop.md b/docs/ko/concepts/agent-loop.md index 0ce0d3359..a052cc67a 100644 --- a/docs/ko/concepts/agent-loop.md +++ b/docs/ko/concepts/agent-loop.md @@ -1,174 +1,174 @@ --- read_when: - - 에이전트 루프 또는 수명 주기 이벤트에 대한 정확한 단계별 설명이 필요할 때 -summary: 에이전트 루프 수명 주기, 스트림, 대기 의미 체계 + - 에이전트 루프 또는 수명 주기 이벤트에 대한 정확한 안내가 필요합니다 +summary: 에이전트 루프 수명 주기, 스트림 및 대기 시맨틱 title: 에이전트 루프 x-i18n: - generated_at: "2026-04-09T01:27:57Z" + generated_at: "2026-04-11T02:44:19Z" model: gpt-5.4 provider: openai - source_hash: 32d3a73df8dabf449211a6183a70dcfd2a9b6f584dc76d0c4c9147582b2ca6a1 + source_hash: b6831a5b11e9100e49f650feca51ab44a2bef242ce1b5db2766d0b3b5c5ba729 source_path: concepts/agent-loop.md workflow: 15 --- # 에이전트 루프 (OpenClaw) -에이전트형 루프는 에이전트의 전체 "실제" 실행입니다: 입력 수집 → 컨텍스트 조립 → 모델 추론 → -도구 실행 → 스트리밍 응답 → 영속화. 이는 메시지를 작업과 최종 응답으로 바꾸는 권위 있는 경로이며, +에이전트형 루프는 에이전트의 전체 “실제” 실행입니다: 입력 수집 → 컨텍스트 조립 → 모델 추론 → +도구 실행 → 응답 스트리밍 → 영속화. 이는 메시지를 작업과 최종 응답으로 바꾸는 권위 있는 경로이며, 세션 상태를 일관되게 유지합니다. -OpenClaw에서 루프는 세션당 하나의 직렬화된 실행이며, 모델이 생각하고, 도구를 호출하고, 출력을 스트리밍할 때 -수명 주기 및 스트림 이벤트를 내보냅니다. 이 문서는 이 실제 루프가 엔드 투 엔드로 어떻게 연결되는지 설명합니다. +OpenClaw에서 루프는 세션당 단일 직렬화 실행이며, 모델이 생각하고, 도구를 호출하고, 출력을 스트리밍하는 동안 +수명 주기 및 스트림 이벤트를 내보냅니다. 이 문서는 그 실제 루프가 종단 간에 어떻게 연결되는지 설명합니다. ## 진입점 - Gateway RPC: `agent` 및 `agent.wait`. - CLI: `agent` 명령어. -## 작동 방식(상위 수준) +## 작동 방식 (상위 수준) -1. `agent` RPC는 매개변수를 검증하고, 세션을 확인하며(sessionKey/sessionId), 세션 메타데이터를 영속화하고, 즉시 `{ runId, acceptedAt }`를 반환합니다. +1. `agent` RPC는 매개변수를 검증하고, 세션(sessionKey/sessionId)을 확인하고, 세션 메타데이터를 영속화한 뒤, 즉시 `{ runId, acceptedAt }`를 반환합니다. 2. `agentCommand`가 에이전트를 실행합니다: - - 모델 + thinking/verbose 기본값 확인 - - Skills 스냅샷 로드 - - `runEmbeddedPiAgent` 호출 (`pi-agent-core` 런타임) - - 임베디드 루프가 내보내지 않으면 **수명 주기 end/error** 내보내기 + - 모델 + thinking/verbose 기본값을 확인합니다 + - Skills 스냅샷을 로드합니다 + - `runEmbeddedPiAgent`를 호출합니다 (pi-agent-core 런타임) + - 임베디드 루프가 내보내지 않으면 **수명 주기 end/error**를 내보냅니다 3. `runEmbeddedPiAgent`: - - 세션별 + 전역 큐를 통해 실행 직렬화 - - 모델 + auth 프로필 확인 및 pi 세션 빌드 - - pi 이벤트를 구독하고 assistant/tool 델타 스트리밍 - - 제한 시간 강제 적용 -> 초과 시 실행 중단 - - 페이로드 + 사용량 메타데이터 반환 -4. `subscribeEmbeddedPiSession`이 `pi-agent-core` 이벤트를 OpenClaw `agent` 스트림으로 브리지합니다: + - 세션별 + 전역 큐를 통해 실행을 직렬화합니다 + - 모델 + auth profile을 확인하고 pi 세션을 빌드합니다 + - pi 이벤트를 구독하고 assistant/tool delta를 스트리밍합니다 + - 타임아웃을 적용하고 초과 시 실행을 중단합니다 + - payload와 usage 메타데이터를 반환합니다 +4. `subscribeEmbeddedPiSession`은 pi-agent-core 이벤트를 OpenClaw `agent` 스트림으로 브리지합니다: - 도구 이벤트 => `stream: "tool"` - - assistant 델타 => `stream: "assistant"` + - assistant delta => `stream: "assistant"` - 수명 주기 이벤트 => `stream: "lifecycle"` (`phase: "start" | "end" | "error"`) 5. `agent.wait`는 `waitForAgentRun`을 사용합니다: - - `runId`에 대한 **수명 주기 end/error** 대기 - - `{ status: ok|error|timeout, startedAt, endedAt, error? }` 반환 + - `runId`에 대한 **수명 주기 end/error**를 기다립니다 + - `{ status: ok|error|timeout, startedAt, endedAt, error? }`를 반환합니다 ## 큐잉 + 동시성 -- 실행은 세션 키(세션 레인)별로 직렬화되며, 필요에 따라 전역 레인을 통해서도 직렬화됩니다. -- 이렇게 하면 도구/세션 경쟁 상태를 방지하고 세션 히스토리를 일관되게 유지할 수 있습니다. -- 메시징 채널은 이 레인 시스템에 연결되는 큐 모드(collect/steer/followup)를 선택할 수 있습니다. - [명령 큐](/ko/concepts/queue)를 참고하세요. +- 실행은 세션 키(세션 레인)별로 직렬화되며, 선택적으로 전역 레인을 통해서도 직렬화됩니다. +- 이렇게 하면 도구/세션 경쟁 상태를 방지하고 세션 기록을 일관되게 유지할 수 있습니다. +- 메시징 채널은 이 레인 시스템으로 연결되는 큐 모드(collect/steer/followup)를 선택할 수 있습니다. + 자세한 내용은 [Command Queue](/ko/concepts/queue)를 참고하세요. ## 세션 + 워크스페이스 준비 -- 워크스페이스가 확인되고 생성되며, 샌드박스 실행은 샌드박스 워크스페이스 루트로 리디렉션될 수 있습니다. -- Skills가 로드되거나(또는 스냅샷에서 재사용되거나) env 및 프롬프트에 주입됩니다. -- 부트스트랩/컨텍스트 파일이 확인되고 시스템 프롬프트 보고서에 주입됩니다. -- 세션 쓰기 잠금이 획득되며, 스트리밍 전에 `SessionManager`가 열리고 준비됩니다. +- 워크스페이스를 확인하고 생성하며, 샌드박스 실행은 샌드박스 워크스페이스 루트로 리디렉션될 수 있습니다. +- Skills를 로드하거나(또는 스냅샷에서 재사용하고) env와 프롬프트에 주입합니다. +- bootstrap/context 파일을 확인하고 시스템 프롬프트 보고서에 주입합니다. +- 세션 쓰기 잠금을 획득하고, 스트리밍 전에 `SessionManager`를 열어 준비합니다. ## 프롬프트 조립 + 시스템 프롬프트 -- 시스템 프롬프트는 OpenClaw의 기본 프롬프트, skills 프롬프트, 부트스트랩 컨텍스트, 실행별 오버라이드로 구성됩니다. -- 모델별 제한과 compaction 예약 토큰이 강제 적용됩니다. -- 모델이 무엇을 보는지에 대해서는 [시스템 프롬프트](/ko/concepts/system-prompt)를 참고하세요. +- 시스템 프롬프트는 OpenClaw의 기본 프롬프트, skills 프롬프트, bootstrap 컨텍스트, 실행별 override로 구성됩니다. +- 모델별 제한과 compaction reserve token이 적용됩니다. +- 모델이 무엇을 보는지는 [System prompt](/ko/concepts/system-prompt)를 참고하세요. -## 훅 지점(가로챌 수 있는 위치) +## 훅 지점 (가로챌 수 있는 위치) OpenClaw에는 두 가지 훅 시스템이 있습니다: -- **내부 훅**(Gateway hooks): 명령 및 수명 주기 이벤트를 위한 이벤트 기반 스크립트. +- **내부 훅** (Gateway hooks): 명령어 및 수명 주기 이벤트를 위한 이벤트 기반 스크립트. - **플러그인 훅**: 에이전트/도구 수명 주기 및 gateway 파이프라인 내부의 확장 지점. -### 내부 훅(Gateway hooks) +### 내부 훅 (Gateway hooks) -- **`agent:bootstrap`**: 시스템 프롬프트가 최종 확정되기 전에 부트스트랩 파일을 빌드하는 동안 실행됩니다. - 부트스트랩 컨텍스트 파일을 추가/제거하는 데 사용합니다. -- **명령 훅**: `/new`, `/reset`, `/stop` 및 기타 명령 이벤트(Hooks 문서 참고). +- **`agent:bootstrap`**: 시스템 프롬프트가 최종 확정되기 전에 bootstrap 파일을 빌드하는 동안 실행됩니다. + 이를 사용해 bootstrap 컨텍스트 파일을 추가/제거할 수 있습니다. +- **명령어 훅**: `/new`, `/reset`, `/stop` 및 기타 명령어 이벤트(자세한 내용은 Hooks 문서 참고). -설정 및 예제는 [Hooks](/ko/automation/hooks)를 참고하세요. +설정 및 예시는 [Hooks](/ko/automation/hooks)를 참고하세요. -### 플러그인 훅(에이전트 + gateway 수명 주기) +### 플러그인 훅 (에이전트 + gateway 수명 주기) 이 훅들은 에이전트 루프 또는 gateway 파이프라인 내부에서 실행됩니다: -- **`before_model_resolve`**: 세션 전(`messages` 없음)에 실행되어, 모델 확인 전에 provider/model을 결정적으로 오버라이드합니다. -- **`before_prompt_build`**: 세션 로드 후(`messages` 포함) 실행되어, 프롬프트 제출 전에 `prependContext`, `systemPrompt`, `prependSystemContext`, 또는 `appendSystemContext`를 주입합니다. 턴별 동적 텍스트에는 `prependContext`를 사용하고, 시스템 프롬프트 공간에 배치되어야 하는 안정적인 지침에는 system-context 필드를 사용하세요. -- **`before_agent_start`**: 레거시 호환성 훅으로, 두 단계 중 어느 쪽에서든 실행될 수 있습니다. 가능하면 위의 명시적 훅을 우선 사용하세요. -- **`before_agent_reply`**: 인라인 작업 후, 그리고 LLM 호출 전에 실행되어, 플러그인이 해당 턴을 가져가 합성 응답을 반환하거나 턴 자체를 완전히 무음 처리할 수 있게 합니다. +- **`before_model_resolve`**: 세션 이전(`messages` 없음)에 실행되어 모델 확인 전에 provider/model을 결정적으로 override합니다. +- **`before_prompt_build`**: 세션 로드 후(`messages` 포함) 실행되어 프롬프트 제출 전에 `prependContext`, `systemPrompt`, `prependSystemContext`, `appendSystemContext`를 주입합니다. 턴별 동적 텍스트에는 `prependContext`를 사용하고, 시스템 프롬프트 공간에 놓여야 하는 안정적인 지침에는 system-context 필드를 사용하세요. +- **`before_agent_start`**: 레거시 호환성 훅으로, 어느 단계에서든 실행될 수 있습니다. 가능하면 위의 명시적 훅을 사용하세요. +- **`before_agent_reply`**: 인라인 작업 이후, LLM 호출 전에 실행되며, 플러그인이 턴을 가로채 합성 응답을 반환하거나 턴 전체를 무음 처리할 수 있게 합니다. - **`agent_end`**: 완료 후 최종 메시지 목록과 실행 메타데이터를 검사합니다. - **`before_compaction` / `after_compaction`**: compaction 주기를 관찰하거나 주석을 추가합니다. - **`before_tool_call` / `after_tool_call`**: 도구 매개변수/결과를 가로챕니다. -- **`before_install`**: 내장 스캔 결과를 검사하고 skill 또는 플러그인 설치를 선택적으로 차단합니다. -- **`tool_result_persist`**: 도구 결과가 세션 기록에 기록되기 전에 동기적으로 변환합니다. +- **`before_install`**: 기본 제공 스캔 결과를 검사하고 skill 또는 plugin 설치를 차단할 수 있습니다. +- **`tool_result_persist`**: 세션 transcript에 기록되기 전에 도구 결과를 동기적으로 변환합니다. - **`message_received` / `message_sending` / `message_sent`**: 수신 + 발신 메시지 훅. - **`session_start` / `session_end`**: 세션 수명 주기 경계. - **`gateway_start` / `gateway_stop`**: gateway 수명 주기 이벤트. -발신/도구 가드에 대한 훅 결정 규칙: +발신/도구 가드용 훅 결정 규칙: -- `before_tool_call`: `{ block: true }`는 종료 동작이며 더 낮은 우선순위의 핸들러를 중단합니다. -- `before_tool_call`: `{ block: false }`는 no-op이며 이전 block을 해제하지 않습니다. -- `before_install`: `{ block: true }`는 종료 동작이며 더 낮은 우선순위의 핸들러를 중단합니다. -- `before_install`: `{ block: false }`는 no-op이며 이전 block을 해제하지 않습니다. -- `message_sending`: `{ cancel: true }`는 종료 동작이며 더 낮은 우선순위의 핸들러를 중단합니다. -- `message_sending`: `{ cancel: false }`는 no-op이며 이전 cancel을 해제하지 않습니다. +- `before_tool_call`: `{ block: true }`는 최종적이며 더 낮은 우선순위 핸들러를 중단시킵니다. +- `before_tool_call`: `{ block: false }`는 아무 작업도 하지 않으며 이전 block을 해제하지 않습니다. +- `before_install`: `{ block: true }`는 최종적이며 더 낮은 우선순위 핸들러를 중단시킵니다. +- `before_install`: `{ block: false }`는 아무 작업도 하지 않으며 이전 block을 해제하지 않습니다. +- `message_sending`: `{ cancel: true }`는 최종적이며 더 낮은 우선순위 핸들러를 중단시킵니다. +- `message_sending`: `{ cancel: false }`는 아무 작업도 하지 않으며 이전 cancel을 해제하지 않습니다. -훅 API와 등록 세부 정보는 [플러그인 훅](/ko/plugins/architecture#provider-runtime-hooks)을 참고하세요. +훅 API 및 등록 세부 사항은 [Plugin hooks](/ko/plugins/architecture#provider-runtime-hooks)를 참고하세요. ## 스트리밍 + 부분 응답 -- assistant 델타는 `pi-agent-core`에서 스트리밍되어 `assistant` 이벤트로 내보내집니다. +- Assistant delta는 pi-agent-core에서 스트리밍되어 `assistant` 이벤트로 내보내집니다. - 블록 스트리밍은 `text_end` 또는 `message_end`에서 부분 응답을 내보낼 수 있습니다. -- reasoning 스트리밍은 별도의 스트림으로 또는 블록 응답으로 내보낼 수 있습니다. -- 청킹 및 블록 응답 동작은 [스트리밍](/ko/concepts/streaming)을 참고하세요. +- 추론 스트리밍은 별도 스트림 또는 블록 응답으로 내보낼 수 있습니다. +- 청크 분할 및 블록 응답 동작은 [Streaming](/ko/concepts/streaming)을 참고하세요. ## 도구 실행 + 메시징 도구 -- 도구 start/update/end 이벤트는 `tool` 스트림으로 내보내집니다. -- 도구 결과는 로깅/내보내기 전에 크기와 이미지 페이로드 기준으로 정리됩니다. -- 메시징 도구 전송은 중복된 assistant 확인 메시지를 억제하기 위해 추적됩니다. +- 도구 start/update/end 이벤트는 `tool` 스트림에서 내보내집니다. +- 도구 결과는 로깅/내보내기 전에 크기 및 이미지 payload 기준으로 정리됩니다. +- 메시징 도구 전송은 중복 assistant 확인 응답을 억제하기 위해 추적됩니다. ## 응답 형태 조정 + 억제 -- 최종 페이로드는 다음으로 조립됩니다: +- 최종 payload는 다음으로 조립됩니다: - assistant 텍스트(및 선택적 reasoning) - - 인라인 도구 요약(verbose + 허용 시) - - 모델 오류 발생 시 assistant 오류 텍스트 -- 정확한 무음 토큰 `NO_REPLY` / `no_reply`는 발신 - 페이로드에서 필터링됩니다. -- 메시징 도구 중복 항목은 최종 페이로드 목록에서 제거됩니다. -- 렌더링 가능한 페이로드가 남지 않았고 도구에서 오류가 발생한 경우, 대체 도구 오류 응답이 내보내집니다 + - 인라인 도구 요약(verbose + 허용된 경우) + - 모델 오류 시 assistant 오류 텍스트 +- 정확한 silent token `NO_REPLY` / `no_reply`는 발신 + payload에서 필터링됩니다. +- 메시징 도구 중복 항목은 최종 payload 목록에서 제거됩니다. +- 렌더링 가능한 payload가 하나도 남지 않았고 도구에서 오류가 발생한 경우, fallback 도구 오류 응답이 내보내집니다 (단, 메시징 도구가 이미 사용자에게 보이는 응답을 보낸 경우는 제외). ## Compaction + 재시도 -- 자동 compaction은 `compaction` 스트림 이벤트를 내보내고 재시도를 유발할 수 있습니다. -- 재시도 시, 중복 출력을 방지하기 위해 메모리 내 버퍼와 도구 요약이 재설정됩니다. +- 자동 compaction은 `compaction` 스트림 이벤트를 내보내며 재시도를 유발할 수 있습니다. +- 재시도 시 중복 출력을 방지하기 위해 메모리 내 버퍼와 도구 요약이 초기화됩니다. - compaction 파이프라인은 [Compaction](/ko/concepts/compaction)을 참고하세요. -## 이벤트 스트림(현재) +## 이벤트 스트림 (현재) -- `lifecycle`: `subscribeEmbeddedPiSession`에서 내보냄(`agentCommand`에서 대체용으로도 내보냄) -- `assistant`: `pi-agent-core`의 스트리밍 델타 -- `tool`: `pi-agent-core`의 스트리밍 도구 이벤트 +- `lifecycle`: `subscribeEmbeddedPiSession`에서 내보내며 (`agentCommand`에서도 fallback으로 내보냄) +- `assistant`: pi-agent-core에서 스트리밍된 delta +- `tool`: pi-agent-core에서 스트리밍된 도구 이벤트 ## 채팅 채널 처리 -- assistant 델타는 채팅 `delta` 메시지로 버퍼링됩니다. -- 채팅 `final`은 **수명 주기 end/error**에서 내보내집니다. +- Assistant delta는 채팅 `delta` 메시지로 버퍼링됩니다. +- 채팅 `final`은 **lifecycle end/error** 시 내보내집니다. -## 제한 시간 +## 타임아웃 -- `agent.wait` 기본값: 30초(대기만 해당). `timeoutMs` 매개변수로 재정의합니다. -- 에이전트 런타임: `agents.defaults.timeoutSeconds` 기본값은 172800초(48시간)이며, `runEmbeddedPiAgent`의 abort 타이머에서 강제 적용됩니다. -- LLM 유휴 제한 시간: `agents.defaults.llm.idleTimeoutSeconds`는 유휴 시간 창 안에 응답 청크가 도착하지 않으면 모델 요청을 중단합니다. 느린 로컬 모델 또는 reasoning/도구 호출 provider에 대해 명시적으로 설정하세요. 비활성화하려면 0으로 설정하세요. 설정되지 않은 경우, OpenClaw는 `agents.defaults.timeoutSeconds`가 구성되어 있으면 이를 사용하고, 그렇지 않으면 60초를 사용합니다. 명시적인 LLM 또는 에이전트 제한 시간이 없는 cron 트리거 실행은 유휴 watchdog을 비활성화하고 cron 외부 제한 시간에 의존합니다. +- `agent.wait` 기본값: 30초(대기만 해당). `timeoutMs` 매개변수로 override할 수 있습니다. +- 에이전트 런타임: `agents.defaults.timeoutSeconds` 기본값은 172800초(48시간)이며, `runEmbeddedPiAgent`의 abort timer에서 적용됩니다. +- LLM idle timeout: `agents.defaults.llm.idleTimeoutSeconds`는 idle 기간 내에 응답 청크가 도착하지 않으면 모델 요청을 중단합니다. 느린 로컬 모델 또는 reasoning/tool-call provider에는 이를 명시적으로 설정하세요. 비활성화하려면 0으로 설정하세요. 설정하지 않으면 OpenClaw는 `agents.defaults.timeoutSeconds`가 구성된 경우 이를 사용하고, 그렇지 않으면 120초를 사용합니다. 명시적인 LLM 또는 에이전트 타임아웃이 없는 cron 트리거 실행은 idle watchdog을 비활성화하고 cron 외부 타임아웃에 의존합니다. ## 조기에 종료될 수 있는 위치 -- 에이전트 제한 시간(abort) +- 에이전트 타임아웃(abort) - AbortSignal(cancel) -- Gateway 연결 해제 또는 RPC 제한 시간 -- `agent.wait` 제한 시간(대기만 해당하며, 에이전트를 중지하지는 않음) +- Gateway 연결 끊김 또는 RPC 타임아웃 +- `agent.wait` 타임아웃(대기만 해당하며 에이전트를 중지하지는 않음) -## 관련 문서 +## 관련 항목 -- [도구](/ko/tools) — 사용 가능한 에이전트 도구 +- [Tools](/ko/tools) — 사용 가능한 에이전트 도구 - [Hooks](/ko/automation/hooks) — 에이전트 수명 주기 이벤트에 의해 트리거되는 이벤트 기반 스크립트 - [Compaction](/ko/concepts/compaction) — 긴 대화가 요약되는 방식 - [Exec Approvals](/ko/tools/exec-approvals) — 셸 명령에 대한 승인 게이트 diff --git a/docs/ko/concepts/model-providers.md b/docs/ko/concepts/model-providers.md index 7e1265309..ff8a1b245 100644 --- a/docs/ko/concepts/model-providers.md +++ b/docs/ko/concepts/model-providers.md @@ -1,261 +1,148 @@ --- read_when: - - 제공자별 모델 설정 참고 자료가 필요합니다 + - 제공자별 모델 설정 참조가 필요합니다 - 모델 제공자를 위한 예제 구성이나 CLI 온보딩 명령이 필요합니다 summary: 예제 구성과 CLI 흐름이 포함된 모델 제공자 개요 title: 모델 제공자 x-i18n: - generated_at: "2026-04-09T01:29:44Z" + generated_at: "2026-04-11T02:44:20Z" model: gpt-5.4 provider: openai - source_hash: 53e3141256781002bbe1d7e7b78724a18d061fcf36a203baae04a091b8c9ea1b + source_hash: 910ea7895e74c03910757d9d3e02825754b779b204eca7275b28422647ed0151 source_path: concepts/model-providers.md workflow: 15 --- # 모델 제공자 -이 페이지는 **LLM/모델 제공자**를 다룹니다(WhatsApp/Telegram 같은 채팅 채널이 아님). -모델 선택 규칙은 [/concepts/models](/ko/concepts/models)을 참조하세요. +이 페이지는 **LLM/모델 제공자**를 다룹니다(WhatsApp/Telegram 같은 채팅 채널이 아닙니다). +모델 선택 규칙은 [/concepts/models](/ko/concepts/models)를 참조하세요. ## 빠른 규칙 - 모델 참조는 `provider/model` 형식을 사용합니다(예: `opencode/claude-opus-4-6`). - `agents.defaults.models`를 설정하면 허용 목록이 됩니다. - CLI 도우미: `openclaw onboard`, `openclaw models list`, `openclaw models set `. -- 폴백 런타임 규칙, 쿨다운 프로브, 세션 재정의 지속성은 - [/concepts/model-failover](/ko/concepts/model-failover)에 문서화되어 있습니다. -- `models.providers.*.models[].contextWindow`는 네이티브 모델 메타데이터이고, - `models.providers.*.models[].contextTokens`는 실제 런타임 상한입니다. -- 제공자 플러그인은 `registerProvider({ catalog })`를 통해 모델 카탈로그를 주입할 수 있으며, - OpenClaw는 그 출력을 `models.providers`에 병합한 뒤 - `models.json`을 기록합니다. -- 제공자 매니페스트는 `providerAuthEnvVars`와 - `providerAuthAliases`를 선언할 수 있으므로 일반적인 env 기반 인증 프로브와 제공자 변형은 - 플러그인 런타임을 로드할 필요가 없습니다. 남아 있는 코어 env-var 맵은 이제 - 비플러그인/코어 제공자와 Anthropic API 키 우선 온보딩 같은 몇 가지 일반 우선순위 사례에만 - 사용됩니다. -- 제공자 플러그인은 다음을 통해 제공자 런타임 동작도 소유할 수 있습니다: - `normalizeModelId`, `normalizeTransport`, `normalizeConfig`, - `applyNativeStreamingUsageCompat`, `resolveConfigApiKey`, - `resolveSyntheticAuth`, `shouldDeferSyntheticProfileAuth`, - `resolveDynamicModel`, `prepareDynamicModel`, - `normalizeResolvedModel`, `contributeResolvedModelCompat`, - `capabilities`, `normalizeToolSchemas`, - `inspectToolSchemas`, `resolveReasoningOutputMode`, - `prepareExtraParams`, `createStreamFn`, `wrapStreamFn`, - `resolveTransportTurnState`, `resolveWebSocketSessionPolicy`, - `createEmbeddingProvider`, `formatApiKey`, `refreshOAuth`, - `buildAuthDoctorHint`, - `matchesContextOverflowError`, `classifyFailoverReason`, - `isCacheTtlEligible`, `buildMissingAuthMessage`, `suppressBuiltInModel`, - `augmentModelCatalog`, `isBinaryThinking`, `supportsXHighThinking`, - `resolveDefaultThinkingLevel`, `applyConfigDefaults`, `isModernModelRef`, - `prepareRuntimeAuth`, `resolveUsageAuth`, `fetchUsageSnapshot`, 그리고 - `onModelSelected`. -- 참고: 제공자 런타임 `capabilities`는 공유 러너 메타데이터입니다(제공자 - 계열, 전사 기록/도구 관련 특이점, 전송/캐시 힌트). 이는 - 플러그인이 무엇을 등록하는지(텍스트 추론, 음성 등)를 설명하는 - [공개 capability 모델](/ko/plugins/architecture#public-capability-model)과는 다릅니다. +- 대체 런타임 규칙, 쿨다운 프로브, 세션 재정의 지속성은 [/concepts/model-failover](/ko/concepts/model-failover)에 문서화되어 있습니다. +- `models.providers.*.models[].contextWindow`는 네이티브 모델 메타데이터이고, `models.providers.*.models[].contextTokens`는 실제 런타임 상한입니다. +- 제공자 플러그인은 `registerProvider({ catalog })`를 통해 모델 카탈로그를 주입할 수 있습니다. OpenClaw는 `models.json`을 작성하기 전에 그 출력을 `models.providers`에 병합합니다. +- 제공자 매니페스트는 `providerAuthEnvVars`와 `providerAuthAliases`를 선언할 수 있으므로, 일반적인 환경 변수 기반 인증 프로브와 제공자 변형은 플러그인 런타임을 로드할 필요가 없습니다. 이제 남아 있는 코어 환경 변수 맵은 비플러그인/코어 제공자와 Anthropic API 키 우선 온보딩 같은 일부 일반 우선순위 사례에만 사용됩니다. +- 제공자 플러그인은 `normalizeModelId`, `normalizeTransport`, `normalizeConfig`, `applyNativeStreamingUsageCompat`, `resolveConfigApiKey`, `resolveSyntheticAuth`, `shouldDeferSyntheticProfileAuth`, `resolveDynamicModel`, `prepareDynamicModel`, `normalizeResolvedModel`, `contributeResolvedModelCompat`, `capabilities`, `normalizeToolSchemas`, `inspectToolSchemas`, `resolveReasoningOutputMode`, `prepareExtraParams`, `createStreamFn`, `wrapStreamFn`, `resolveTransportTurnState`, `resolveWebSocketSessionPolicy`, `createEmbeddingProvider`, `formatApiKey`, `refreshOAuth`, `buildAuthDoctorHint`, `matchesContextOverflowError`, `classifyFailoverReason`, `isCacheTtlEligible`, `buildMissingAuthMessage`, `suppressBuiltInModel`, `augmentModelCatalog`, `isBinaryThinking`, `supportsXHighThinking`, `resolveDefaultThinkingLevel`, `applyConfigDefaults`, `isModernModelRef`, `prepareRuntimeAuth`, `resolveUsageAuth`, `fetchUsageSnapshot`, `onModelSelected`를 통해 제공자 런타임 동작도 소유할 수 있습니다. +- 참고: 제공자 런타임 `capabilities`는 공유 러너 메타데이터(제공자 계열, 전사/도구 관련 특성, 전송/캐시 힌트)입니다. 이는 플러그인이 등록하는 항목(텍스트 추론, 음성 등)을 설명하는 [공개 capability 모델](/ko/plugins/architecture#public-capability-model)과는 다릅니다. +- 번들된 `codex` 제공자는 번들된 Codex 에이전트 하니스와 함께 연결됩니다. Codex 소유 로그인, 모델 검색, 네이티브 스레드 재개, 앱 서버 실행이 필요하면 `codex/gpt-*`를 사용하세요. 일반 `openai/gpt-*` 참조는 계속해서 OpenAI 제공자와 일반 OpenClaw 제공자 전송을 사용합니다. Codex 전용 배포에서는 `agents.defaults.embeddedHarness.fallback: "none"`으로 자동 PI 대체를 비활성화할 수 있습니다. 자세한 내용은 [Codex Harness](/ko/plugins/codex-harness)를 참조하세요. ## 플러그인 소유 제공자 동작 -제공자 플러그인은 이제 OpenClaw가 일반 추론 루프를 유지하는 동안 -대부분의 제공자별 로직을 소유할 수 있습니다. +이제 제공자 플러그인은 대부분의 제공자별 로직을 소유할 수 있으며, OpenClaw는 일반 추론 루프를 유지합니다. -일반적인 분할: +일반적인 분리는 다음과 같습니다. - `auth[].run` / `auth[].runNonInteractive`: 제공자가 `openclaw onboard`, `openclaw models auth`, 헤드리스 설정을 위한 온보딩/로그인 흐름을 소유 -- `wizard.setup` / `wizard.modelPicker`: 제공자가 인증 선택 라벨, - 레거시 별칭, 온보딩 허용 목록 힌트, 온보딩/모델 선택기의 설정 항목을 소유 -- `catalog`: 제공자가 `models.providers`에 나타남 -- `normalizeModelId`: 제공자가 조회나 정규화 전에 레거시/프리뷰 모델 id를 정규화 -- `normalizeTransport`: 제공자가 일반 모델 조립 전에 전송 계열 `api` / `baseUrl`을 정규화합니다. OpenClaw는 먼저 일치한 제공자를 확인한 다음, - 실제로 전송을 변경할 때까지 다른 hook 지원 제공자 플러그인을 확인합니다 -- `normalizeConfig`: 제공자가 런타임이 사용하기 전에 `models.providers.` 구성을 정규화합니다. OpenClaw는 먼저 일치한 제공자를 확인한 다음, 실제로 구성을 변경할 때까지 다른 - hook 지원 제공자 플러그인을 확인합니다. 어떤 제공자 hook도 구성을 재작성하지 않으면, - 번들된 Google 계열 도우미가 계속 지원되는 Google 제공자 항목을 - 정규화합니다. +- `wizard.setup` / `wizard.modelPicker`: 제공자가 인증 선택 라벨, 레거시 별칭, 온보딩 허용 목록 힌트, 온보딩/모델 선택기에 표시되는 설정 항목을 소유 +- `catalog`: 제공자가 `models.providers`에 표시됨 +- `normalizeModelId`: 제공자가 조회 또는 정규화 전에 레거시/프리뷰 모델 ID를 정규화 +- `normalizeTransport`: 제공자가 일반 모델 조립 전에 전송 계열 `api` / `baseUrl`을 정규화합니다. OpenClaw는 먼저 일치하는 제공자를 확인한 다음, 실제로 전송을 변경하는 플러그인을 찾을 때까지 다른 훅 지원 제공자 플러그인을 확인합니다. +- `normalizeConfig`: 제공자가 런타임이 사용하기 전에 `models.providers.` 구성을 정규화합니다. OpenClaw는 먼저 일치하는 제공자를 확인한 다음, 실제로 구성을 변경하는 플러그인을 찾을 때까지 다른 훅 지원 제공자 플러그인을 확인합니다. 어떤 제공자 훅도 구성을 다시 쓰지 않으면, 번들된 Google 계열 도우미가 계속해서 지원되는 Google 제공자 항목을 정규화합니다. - `applyNativeStreamingUsageCompat`: 제공자가 구성 제공자에 대해 엔드포인트 기반 네이티브 스트리밍 사용량 호환성 재작성을 적용 -- `resolveConfigApiKey`: 제공자가 전체 런타임 인증 로딩을 강제하지 않고 - 구성 제공자의 env-marker 인증을 해석합니다. - `amazon-bedrock`은 Bedrock 런타임 인증이 AWS SDK 기본 체인을 사용하더라도, - 여기에서 내장 AWS env-marker 해석기도 가집니다. -- `resolveSyntheticAuth`: 제공자가 평문 비밀을 저장하지 않고도 - 로컬/셀프호스트형 또는 기타 구성 기반 인증 가용성을 노출할 수 있음 -- `shouldDeferSyntheticProfileAuth`: 제공자가 저장된 synthetic profile - 플레이스홀더를 env/구성 기반 인증보다 낮은 우선순위로 표시할 수 있음 -- `resolveDynamicModel`: 제공자가 아직 로컬 정적 카탈로그에 없는 - 모델 id를 수용 -- `prepareDynamicModel`: 제공자가 동적 해석을 다시 시도하기 전에 메타데이터 새로 고침이 필요 -- `normalizeResolvedModel`: 제공자에 전송 또는 base URL 재작성이 필요 -- `contributeResolvedModelCompat`: 제공자가 다른 호환 전송을 통해 들어오더라도 - 자사 공급업체 모델에 대한 호환 플래그를 제공 -- `capabilities`: 제공자가 전사 기록/도구/제공자 계열 관련 특이점을 게시 -- `normalizeToolSchemas`: 제공자가 내장 러너가 보기 전에 - 도구 스키마를 정리 -- `inspectToolSchemas`: 제공자가 정규화 후 - 전송별 스키마 경고를 노출 -- `resolveReasoningOutputMode`: 제공자가 네이티브와 태그형 - 추론 출력 계약 중에서 선택 -- `prepareExtraParams`: 제공자가 모델별 요청 파라미터의 기본값을 설정하거나 정규화 -- `createStreamFn`: 제공자가 일반 스트림 경로를 완전히 - 사용자 지정된 전송으로 대체 -- `wrapStreamFn`: 제공자가 요청 헤더/본문/모델 호환 래퍼를 적용 -- `resolveTransportTurnState`: 제공자가 턴별 네이티브 전송 - 헤더나 메타데이터를 제공 -- `resolveWebSocketSessionPolicy`: 제공자가 네이티브 WebSocket 세션 - 헤더나 세션 쿨다운 정책을 제공 -- `createEmbeddingProvider`: 제공자 플러그인 쪽에 속하는 경우 - 제공자가 메모리 임베딩 동작을 소유하고, 코어 임베딩 스위치보드는 사용하지 않음 -- `formatApiKey`: 제공자가 저장된 인증 프로필을 전송이 기대하는 런타임 - `apiKey` 문자열로 형식화 -- `refreshOAuth`: 공유 `pi-ai` - 리프레셔로 충분하지 않을 때 제공자가 OAuth 갱신을 소유 -- `buildAuthDoctorHint`: OAuth 갱신이 - 실패할 때 제공자가 복구 안내를 덧붙임 -- `matchesContextOverflowError`: 제공자가 일반 휴리스틱으로는 놓치는 - 제공자별 컨텍스트 창 초과 오류를 인식 -- `classifyFailoverReason`: 제공자가 제공자별 원시 전송/API - 오류를 rate limit 또는 overload 같은 페일오버 이유로 매핑 -- `isCacheTtlEligible`: 제공자가 어떤 업스트림 모델 id가 프롬프트 캐시 TTL을 지원하는지 결정 -- `buildMissingAuthMessage`: 제공자가 일반 인증 저장소 오류를 - 제공자별 복구 힌트로 대체 -- `suppressBuiltInModel`: 제공자가 오래된 업스트림 행을 숨기고 - 직접 해석 실패에 대해 공급업체 소유 오류를 반환할 수 있음 -- `augmentModelCatalog`: 제공자가 발견 및 구성 병합 후 - synthetic/final 카탈로그 행을 추가 -- `isBinaryThinking`: 제공자가 이진 on/off thinking UX를 소유 -- `supportsXHighThinking`: 제공자가 선택된 모델에 `xhigh`를 활성화 -- `resolveDefaultThinkingLevel`: 제공자가 모델 계열의 기본 `/think` 정책을 소유 -- `applyConfigDefaults`: 제공자가 인증 모드, env 또는 모델 계열에 따라 - 구성 구체화 중 제공자별 전역 기본값을 적용 -- `isModernModelRef`: 제공자가 live/smoke 선호 모델 매칭을 소유 +- `resolveConfigApiKey`: 제공자가 전체 런타임 인증 로딩을 강제하지 않고도 구성 제공자에 대한 환경 변수 마커 인증을 해석합니다. `amazon-bedrock`도 여기에 내장된 AWS 환경 변수 마커 해석기를 갖고 있지만, Bedrock 런타임 인증은 AWS SDK 기본 체인을 사용합니다. +- `resolveSyntheticAuth`: 제공자가 평문 비밀을 저장하지 않고도 로컬/셀프 호스팅 또는 기타 구성 기반 인증 사용 가능 여부를 노출할 수 있음 +- `shouldDeferSyntheticProfileAuth`: 제공자가 저장된 합성 프로필 플레이스홀더를 환경 변수/구성 기반 인증보다 낮은 우선순위로 표시할 수 있음 +- `resolveDynamicModel`: 제공자가 아직 로컬 정적 카탈로그에 없는 모델 ID를 허용 +- `prepareDynamicModel`: 제공자가 동적 해석 재시도 전에 메타데이터 새로 고침이 필요함 +- `normalizeResolvedModel`: 제공자가 전송 또는 기본 URL 재작성이 필요함 +- `contributeResolvedModelCompat`: 제공자가 다른 호환 전송을 통해 도착하더라도 자사 벤더 모델에 대한 호환성 플래그를 제공 +- `capabilities`: 제공자가 전사/도구/제공자 계열 특성을 게시 +- `normalizeToolSchemas`: 제공자가 내장 러너가 보기 전에 도구 스키마를 정리 +- `inspectToolSchemas`: 제공자가 정규화 후 전송별 스키마 경고를 표시 +- `resolveReasoningOutputMode`: 제공자가 네이티브 또는 태그 지정된 추론 출력 계약을 선택 +- `prepareExtraParams`: 제공자가 모델별 요청 매개변수의 기본값을 설정하거나 정규화 +- `createStreamFn`: 제공자가 일반 스트림 경로를 완전히 사용자 정의된 전송으로 대체 +- `wrapStreamFn`: 제공자가 요청 헤더/본문/모델 호환성 래퍼를 적용 +- `resolveTransportTurnState`: 제공자가 턴별 네이티브 전송 헤더 또는 메타데이터를 제공 +- `resolveWebSocketSessionPolicy`: 제공자가 네이티브 WebSocket 세션 헤더 또는 세션 쿨다운 정책을 제공 +- `createEmbeddingProvider`: 메모리 임베딩 동작이 코어 임베딩 스위치보드가 아니라 제공자 플러그인에 속하는 경우, 제공자가 이를 소유 +- `formatApiKey`: 제공자가 저장된 인증 프로필을 전송이 기대하는 런타임 `apiKey` 문자열 형식으로 변환 +- `refreshOAuth`: 공유 `pi-ai` 새로 고침 로직만으로 충분하지 않을 때 제공자가 OAuth 새로 고침을 소유 +- `buildAuthDoctorHint`: OAuth 새로 고침이 실패할 때 제공자가 복구 안내를 추가 +- `matchesContextOverflowError`: 일반 휴리스틱이 놓치는 제공자별 컨텍스트 창 초과 오류를 제공자가 인식 +- `classifyFailoverReason`: 제공자가 제공자별 원시 전송/API 오류를 속도 제한 또는 과부하 같은 대체 사유로 매핑 +- `isCacheTtlEligible`: 제공자가 어떤 업스트림 모델 ID가 프롬프트 캐시 TTL을 지원하는지 결정 +- `buildMissingAuthMessage`: 제공자가 일반 인증 저장소 오류를 제공자별 복구 힌트로 대체 +- `suppressBuiltInModel`: 제공자가 오래된 업스트림 행을 숨기고 직접 해석 실패에 대해 벤더 소유 오류를 반환할 수 있음 +- `augmentModelCatalog`: 제공자가 검색 및 구성 병합 후 합성/최종 카탈로그 행을 추가 +- `isBinaryThinking`: 제공자가 이진 켜기/끄기 사고 UX를 소유 +- `supportsXHighThinking`: 제공자가 선택된 모델에서 `xhigh`를 활성화 +- `resolveDefaultThinkingLevel`: 제공자가 모델 계열에 대한 기본 `/think` 정책을 소유 +- `applyConfigDefaults`: 제공자가 인증 모드, 환경 변수, 모델 계열에 따라 구성 구체화 중 제공자별 전역 기본값을 적용 +- `isModernModelRef`: 제공자가 라이브/스모크 선호 모델 매칭을 소유 - `prepareRuntimeAuth`: 제공자가 구성된 자격 증명을 짧은 수명의 런타임 토큰으로 변환 -- `resolveUsageAuth`: 제공자가 `/usage` 및 관련 상태/보고 표면을 위한 - 사용량/쿼터 자격 증명을 해석 -- `fetchUsageSnapshot`: 제공자가 사용량 엔드포인트 조회/파싱을 소유하고, - 코어는 여전히 요약 셸과 형식화를 소유 -- `onModelSelected`: 제공자가 텔레메트리 또는 제공자 소유 세션 bookkeeping 같은 - 모델 선택 후 부수 효과를 실행 +- `resolveUsageAuth`: 제공자가 `/usage` 및 관련 상태/보고 표면을 위한 사용량/쿼터 자격 증명을 해석 +- `fetchUsageSnapshot`: 제공자가 사용량 엔드포인트 가져오기/파싱을 소유하고, 코어는 계속해서 요약 셸과 형식을 소유 +- `onModelSelected`: 제공자가 텔레메트리 또는 제공자 소유 세션 기록 관리 같은 모델 선택 후 부수 효과를 실행 현재 번들된 예시: -- `anthropic`: Claude 4.6 순방향 호환 폴백, 인증 복구 힌트, 사용량 - 엔드포인트 조회, cache-TTL/제공자 계열 메타데이터, 인증 인지 전역 - 구성 기본값 -- `amazon-bedrock`: Bedrock 전용 throttle/not-ready 오류에 대한 제공자 소유 - 컨텍스트 초과 매칭과 페일오버 이유 분류, 그리고 Anthropic 트래픽의 Claude 전용 리플레이 정책 - 가드를 위한 공유 `anthropic-by-model` 리플레이 계열 -- `anthropic-vertex`: Anthropic-message - 트래픽에 대한 Claude 전용 리플레이 정책 가드 -- `openrouter`: 패스스루 모델 id, 요청 래퍼, 제공자 capability - 힌트, 프록시 Gemini 트래픽에서 Gemini thought-signature 정리, - `openrouter-thinking` 스트림 계열을 통한 프록시 추론 주입, - 라우팅 메타데이터 전달, cache-TTL 정책 -- `github-copilot`: 온보딩/디바이스 로그인, 순방향 호환 모델 폴백, - Claude-thinking 전사 기록 힌트, 런타임 토큰 교환, 사용량 엔드포인트 - 조회 -- `openai`: GPT-5.4 순방향 호환 폴백, 직접 OpenAI 전송 - 정규화, Codex 인지 누락 인증 힌트, Spark 억제, synthetic - OpenAI/Codex 카탈로그 행, thinking/live-model 정책, 사용량 토큰 별칭 - 정규화(`input` / `output` 및 `prompt` / `completion` 계열), 네이티브 OpenAI/Codex - 래퍼를 위한 공유 `openai-responses-defaults` 스트림 계열, - 제공자 계열 메타데이터, `gpt-image-1`용 번들 이미지 생성 제공자 - 등록, `sora-2`용 번들 비디오 생성 제공자 - 등록 -- `google` 및 `google-gemini-cli`: Gemini 3.1 순방향 호환 폴백, - 네이티브 Gemini 리플레이 검증, bootstrap 리플레이 정리, 태그형 - 추론 출력 모드, 최신 모델 매칭, Gemini 이미지 프리뷰 모델용 번들 이미지 생성 - 제공자 등록, Veo 모델용 번들 - 비디오 생성 제공자 등록; Gemini CLI OAuth는 또한 - 인증 프로필 토큰 형식화, 사용량 토큰 파싱, 사용량 표면용 쿼터 엔드포인트 - 조회를 소유 +- `anthropic`: Claude 4.6 순방향 호환 대체, 인증 복구 힌트, 사용량 엔드포인트 가져오기, cache-TTL/제공자 계열 메타데이터, 인증 인식 전역 구성 기본값 +- `amazon-bedrock`: Bedrock 전용 스로틀/준비 안 됨 오류에 대한 제공자 소유 컨텍스트 초과 일치 및 대체 사유 분류, 그리고 Anthropic 트래픽의 Claude 전용 재생 정책 가드를 위한 공유 `anthropic-by-model` 재생 계열 +- `anthropic-vertex`: Anthropic 메시지 트래픽에 대한 Claude 전용 재생 정책 가드 +- `openrouter`: 패스스루 모델 ID, 요청 래퍼, 제공자 capability 힌트, 프록시 Gemini 트래픽에서의 Gemini thought-signature 정리, `openrouter-thinking` 스트림 계열을 통한 프록시 추론 주입, 라우팅 메타데이터 전달, cache-TTL 정책 +- `github-copilot`: 온보딩/디바이스 로그인, 순방향 호환 모델 대체, Claude-thinking 전사 힌트, 런타임 토큰 교환, 사용량 엔드포인트 가져오기 +- `openai`: GPT-5.4 순방향 호환 대체, 직접 OpenAI 전송 정규화, Codex 인식 누락 인증 힌트, Spark 억제, 합성 OpenAI/Codex 카탈로그 행, thinking/라이브 모델 정책, 사용량 토큰 별칭 정규화(`input` / `output` 및 `prompt` / `completion` 계열), 네이티브 OpenAI/Codex 래퍼를 위한 공유 `openai-responses-defaults` 스트림 계열, 제공자 계열 메타데이터, `gpt-image-1`용 번들 이미지 생성 제공자 등록, `sora-2`용 번들 비디오 생성 제공자 등록 +- `google` 및 `google-gemini-cli`: Gemini 3.1 순방향 호환 대체, 네이티브 Gemini 재생 검증, 부트스트랩 재생 정리, 태그 지정된 추론 출력 모드, 최신 모델 매칭, Gemini image-preview 모델용 번들 이미지 생성 제공자 등록, Veo 모델용 번들 비디오 생성 제공자 등록; Gemini CLI OAuth는 사용량 표면을 위한 인증 프로필 토큰 형식화, 사용량 토큰 파싱, 할당량 엔드포인트 가져오기도 소유 - `moonshot`: 공유 전송, 플러그인 소유 thinking 페이로드 정규화 -- `kilocode`: 공유 전송, 플러그인 소유 요청 헤더, 추론 페이로드 - 정규화, 프록시-Gemini thought-signature 정리, cache-TTL - 정책 -- `zai`: GLM-5 순방향 호환 폴백, `tool_stream` 기본값, cache-TTL - 정책, binary-thinking/live-model 정책, 사용량 인증 + 쿼터 조회; - 알 수 없는 `glm-5*` id는 번들된 `glm-4.7` 템플릿에서 synthesize됨 -- `xai`: 네이티브 Responses 전송 정규화, Grok 빠른 변형용 - `/fast` 별칭 재작성, 기본 `tool_stream`, xAI 전용 도구 스키마 / - 추론 페이로드 정리, `grok-imagine-video`용 번들 비디오 생성 제공자 - 등록 +- `kilocode`: 공유 전송, 플러그인 소유 요청 헤더, 추론 페이로드 정규화, 프록시 Gemini thought-signature 정리, cache-TTL 정책 +- `zai`: GLM-5 순방향 호환 대체, `tool_stream` 기본값, cache-TTL 정책, 이진 thinking/라이브 모델 정책, 사용량 인증 + 할당량 가져오기; 알 수 없는 `glm-5*` ID는 번들된 `glm-4.7` 템플릿에서 합성됨 +- `xai`: 네이티브 Responses 전송 정규화, Grok fast 변형용 `/fast` 별칭 재작성, 기본 `tool_stream`, xAI 전용 도구 스키마 / 추론 페이로드 정리, `grok-imagine-video`용 번들 비디오 생성 제공자 등록 - `mistral`: 플러그인 소유 capability 메타데이터 -- `opencode` 및 `opencode-go`: 플러그인 소유 capability 메타데이터와 - 프록시-Gemini thought-signature 정리 -- `alibaba`: `alibaba/wan2.6-t2v` 같은 직접 Wan 모델 참조용 - 플러그인 소유 비디오 생성 카탈로그 -- `byteplus`: 플러그인 소유 카탈로그와 Seedance 텍스트-비디오/이미지-비디오 모델용 - 번들 비디오 생성 제공자 - 등록 -- `fal`: 호스팅된 서드파티 이미지 생성 모델용 - 번들 이미지 생성 제공자 등록과 호스팅된 서드파티 비디오 모델용 - 번들 비디오 생성 제공자 등록 -- `cloudflare-ai-gateway`, `huggingface`, `kimi`, `nvidia`, `qianfan`, - `stepfun`, `synthetic`, `venice`, `vercel-ai-gateway`, `volcengine`: - 플러그인 소유 카탈로그 בלבד -- `qwen`: 텍스트 모델용 플러그인 소유 카탈로그와 멀티모달 표면용 - 공유 media-understanding 및 비디오 생성 제공자 등록; - Qwen 비디오 생성은 `wan2.6-t2v` 및 `wan2.7-r2v` 같은 번들 Wan 모델과 함께 - 표준 DashScope 비디오 엔드포인트를 사용 -- `runway`: `gen4.5` 같은 네이티브 - Runway 작업 기반 모델용 플러그인 소유 비디오 생성 제공자 등록 -- `minimax`: 플러그인 소유 카탈로그, Hailuo 비디오 모델용 번들 비디오 생성 제공자 - 등록, `image-01`용 번들 이미지 생성 제공자 - 등록, 하이브리드 Anthropic/OpenAI 리플레이 정책 - 선택, 사용량 인증/스냅샷 로직 -- `together`: 플러그인 소유 카탈로그와 Wan 비디오 모델용 - 번들 비디오 생성 제공자 등록 +- `opencode` 및 `opencode-go`: 플러그인 소유 capability 메타데이터와 프록시 Gemini thought-signature 정리 +- `alibaba`: `alibaba/wan2.6-t2v` 같은 직접 Wan 모델 참조를 위한 플러그인 소유 비디오 생성 카탈로그 +- `byteplus`: 플러그인 소유 카탈로그와 Seedance 텍스트-비디오/이미지-비디오 모델용 번들 비디오 생성 제공자 등록 +- `fal`: 호스팅된 서드파티 이미지 생성 모델을 위한 번들 이미지 생성 제공자 등록과 호스팅된 서드파티 비디오 모델을 위한 번들 비디오 생성 제공자 등록 +- `cloudflare-ai-gateway`, `huggingface`, `kimi`, `nvidia`, `qianfan`, `stepfun`, `synthetic`, `venice`, `vercel-ai-gateway`, `volcengine`: 플러그인 소유 카탈로그만 제공 +- `qwen`: 텍스트 모델용 플러그인 소유 카탈로그와 멀티모달 표면용 공유 media-understanding 및 비디오 생성 제공자 등록; Qwen 비디오 생성은 `wan2.6-t2v`, `wan2.7-r2v` 같은 번들 Wan 모델과 함께 Standard DashScope 비디오 엔드포인트를 사용 +- `runway`: `gen4.5` 같은 네이티브 Runway 작업 기반 모델용 플러그인 소유 비디오 생성 제공자 등록 +- `minimax`: 플러그인 소유 카탈로그, Hailuo 비디오 모델용 번들 비디오 생성 제공자 등록, `image-01`용 번들 이미지 생성 제공자 등록, 하이브리드 Anthropic/OpenAI 재생 정책 선택, 사용량 인증/스냅샷 로직 +- `together`: 플러그인 소유 카탈로그와 Wan 비디오 모델용 번들 비디오 생성 제공자 등록 - `xiaomi`: 플러그인 소유 카탈로그와 사용량 인증/스냅샷 로직 -번들된 `openai` 플러그인은 이제 두 제공자 id인 `openai`와 -`openai-codex`를 모두 소유합니다. +번들된 `openai` 플러그인은 이제 `openai`와 `openai-codex` 두 제공자 ID를 모두 소유합니다. -여기까지는 여전히 OpenClaw의 일반 전송에 맞는 제공자들입니다. 완전히 사용자 지정된 요청 실행기가 필요한 제공자는 별도의, 더 깊은 확장 표면입니다. +여기까지는 여전히 OpenClaw의 일반 전송에 맞는 제공자들입니다. 완전히 사용자 정의된 요청 실행기가 필요한 제공자는 별도의 더 깊은 확장 표면입니다. ## API 키 순환 -- 선택된 제공자에 대해 일반적인 제공자 키 순환을 지원합니다. +- 선택된 제공자에 대해 일반 제공자 순환을 지원합니다. - 여러 키는 다음을 통해 구성합니다: - - `OPENCLAW_LIVE__KEY`(단일 live override, 최우선) + - `OPENCLAW_LIVE__KEY`(단일 라이브 재정의, 최우선) - `_API_KEYS`(쉼표 또는 세미콜론 목록) - `_API_KEY`(기본 키) - - `_API_KEY_*`(번호가 매겨진 목록, 예: `_API_KEY_1`) -- Google 제공자의 경우 `GOOGLE_API_KEY`도 폴백으로 포함됩니다. -- 키 선택 순서는 우선순위를 보존하고 값을 중복 제거합니다. -- 요청은 rate-limit 응답에서만 다음 키로 재시도됩니다( - 예: `429`, `rate_limit`, `quota`, `resource exhausted`, `Too many -concurrent requests`, `ThrottlingException`, `concurrency limit reached`, - `workers_ai ... quota limit exceeded`, 또는 주기적인 사용량 제한 메시지). -- rate-limit이 아닌 실패는 즉시 실패하며, 키 순환은 시도되지 않습니다. + - `_API_KEY_*`(번호가 붙은 목록, 예: `_API_KEY_1`) +- Google 제공자의 경우 `GOOGLE_API_KEY`도 대체값으로 포함됩니다. +- 키 선택 순서는 우선순위를 유지하면서 값을 중복 제거합니다. +- 요청은 속도 제한 응답에서만 다음 키로 재시도됩니다(예: `429`, `rate_limit`, `quota`, `resource exhausted`, `Too many concurrent requests`, `ThrottlingException`, `concurrency limit reached`, `workers_ai ... quota limit exceeded`, 또는 주기적인 사용량 제한 메시지). +- 속도 제한이 아닌 실패는 즉시 실패하며, 키 순환은 시도되지 않습니다. - 모든 후보 키가 실패하면 마지막 시도의 최종 오류가 반환됩니다. -## 기본 제공 제공자 (pi-ai 카탈로그) +## 내장 제공자(pi-ai 카탈로그) -OpenClaw에는 pi‑ai 카탈로그가 포함되어 있습니다. 이 제공자들은 -`models.providers` 구성이 **필요하지 않습니다**. 인증을 설정하고 모델만 고르면 됩니다. +OpenClaw는 pi‑ai 카탈로그를 함께 제공합니다. 이러한 제공자는 **`models.providers` 구성 없이도** 사용할 수 있으며, 인증을 설정하고 모델만 선택하면 됩니다. ### OpenAI - 제공자: `openai` - 인증: `OPENAI_API_KEY` -- 선택적 순환: `OPENAI_API_KEYS`, `OPENAI_API_KEY_1`, `OPENAI_API_KEY_2`, 그리고 `OPENCLAW_LIVE_OPENAI_KEY`(단일 override) -- 예시 모델: `openai/gpt-5.4`, `openai/gpt-5.4-pro` +- 선택적 순환: `OPENAI_API_KEYS`, `OPENAI_API_KEY_1`, `OPENAI_API_KEY_2`, 그리고 `OPENCLAW_LIVE_OPENAI_KEY`(단일 재정의) +- 예제 모델: `openai/gpt-5.4`, `openai/gpt-5.4-pro` - CLI: `openclaw onboard --auth-choice openai-api-key` -- 기본 전송은 `auto`입니다(WebSocket 우선, SSE 폴백) -- 모델별 재정의는 `agents.defaults.models["openai/"].params.transport`를 통해 수행합니다(`"sse"`, `"websocket"`, 또는 `"auto"`) -- OpenAI Responses WebSocket 워밍업은 `params.openaiWsWarmup`(`true`/`false`)을 통해 기본적으로 활성화됩니다 -- OpenAI priority processing은 `agents.defaults.models["openai/"].params.serviceTier`를 통해 활성화할 수 있습니다 -- `/fast`와 `params.fastMode`는 직접 `openai/*` Responses 요청을 `api.openai.com`의 `service_tier=priority`로 매핑합니다 -- 공유 `/fast` 토글 대신 명시적 티어를 원하면 `params.serviceTier`를 사용하세요 -- 숨겨진 OpenClaw attribution 헤더(`originator`, `version`, - `User-Agent`)는 일반 OpenAI 호환 프록시가 아니라 `api.openai.com`으로 향하는 - 네이티브 OpenAI 트래픽에만 적용됩니다 -- 네이티브 OpenAI 경로는 Responses `store`, 프롬프트 캐시 힌트, - OpenAI 추론 호환 페이로드 형성도 유지하지만, 프록시 경로는 그렇지 않습니다 -- `openai/gpt-5.3-codex-spark`는 live OpenAI API가 이를 거부하므로 OpenClaw에서 의도적으로 숨겨져 있습니다. Spark는 Codex 전용으로 처리됩니다 +- 기본 전송은 `auto`입니다(WebSocket 우선, SSE 대체) +- 모델별 재정의: `agents.defaults.models["openai/"].params.transport` (`"sse"`, `"websocket"`, 또는 `"auto"`) +- OpenAI Responses WebSocket 워밍업은 기본적으로 `params.openaiWsWarmup` (`true`/`false`)을 통해 활성화됩니다 +- OpenAI 우선 처리(priority processing)는 `agents.defaults.models["openai/"].params.serviceTier`를 통해 활성화할 수 있습니다 +- `/fast` 및 `params.fastMode`는 직접 `openai/*` Responses 요청을 `api.openai.com`의 `service_tier=priority`로 매핑합니다 +- 공유 `/fast` 토글 대신 명시적인 티어를 원하면 `params.serviceTier`를 사용하세요 +- 숨겨진 OpenClaw attribution 헤더(`originator`, `version`, `User-Agent`)는 일반 OpenAI 호환 프록시가 아니라 `api.openai.com`에 대한 네이티브 OpenAI 트래픽에만 적용됩니다 +- 네이티브 OpenAI 경로는 Responses `store`, 프롬프트 캐시 힌트, OpenAI 추론 호환 페이로드 형상도 유지하며, 프록시 경로는 그렇지 않습니다 +- `openai/gpt-5.3-codex-spark`는 실제 OpenAI API에서 거부되므로 OpenClaw에서 의도적으로 숨겨집니다. Spark는 Codex 전용으로 취급됩니다 ```json5 { @@ -267,12 +154,12 @@ OpenClaw에는 pi‑ai 카탈로그가 포함되어 있습니다. 이 제공자 - 제공자: `anthropic` - 인증: `ANTHROPIC_API_KEY` -- 선택적 순환: `ANTHROPIC_API_KEYS`, `ANTHROPIC_API_KEY_1`, `ANTHROPIC_API_KEY_2`, 그리고 `OPENCLAW_LIVE_ANTHROPIC_KEY`(단일 override) -- 예시 모델: `anthropic/claude-opus-4-6` +- 선택적 순환: `ANTHROPIC_API_KEYS`, `ANTHROPIC_API_KEY_1`, `ANTHROPIC_API_KEY_2`, 그리고 `OPENCLAW_LIVE_ANTHROPIC_KEY`(단일 재정의) +- 예제 모델: `anthropic/claude-opus-4-6` - CLI: `openclaw onboard --auth-choice apiKey` -- 직접 공개 Anthropic 요청은 `api.anthropic.com`으로 전송되는 API 키 및 OAuth 인증 트래픽을 포함해 공유 `/fast` 토글과 `params.fastMode`를 지원합니다. OpenClaw는 이를 Anthropic `service_tier`(`auto` 대 `standard_only`)에 매핑합니다 -- Anthropic 참고: Anthropic 직원이 OpenClaw 스타일 Claude CLI 사용이 다시 허용된다고 알려주었으므로, Anthropic이 새 정책을 게시하지 않는 한 OpenClaw는 이 통합을 위해 Claude CLI 재사용과 `claude -p` 사용을 승인된 것으로 취급합니다. -- Anthropic setup-token은 계속 지원되는 OpenClaw 토큰 경로로 제공되지만, OpenClaw는 이제 가능하면 Claude CLI 재사용과 `claude -p`를 선호합니다. +- 직접 공개 Anthropic 요청은 `api.anthropic.com`으로 전송되는 API 키 및 OAuth 인증 트래픽을 포함해 공유 `/fast` 토글과 `params.fastMode`도 지원합니다. OpenClaw는 이를 Anthropic `service_tier` (`auto` 대 `standard_only`)로 매핑합니다 +- Anthropic 참고: Anthropic 직원이 OpenClaw 스타일 Claude CLI 사용이 다시 허용된다고 알려주었으므로, Anthropic이 새로운 정책을 발표하지 않는 한 OpenClaw는 Claude CLI 재사용과 `claude -p` 사용을 이 통합에서 허용된 것으로 취급합니다. +- Anthropic setup-token은 계속 지원되는 OpenClaw 토큰 경로로 남아 있지만, OpenClaw는 이제 가능하면 Claude CLI 재사용과 `claude -p`를 우선합니다. ```json5 { @@ -284,17 +171,15 @@ OpenClaw에는 pi‑ai 카탈로그가 포함되어 있습니다. 이 제공자 - 제공자: `openai-codex` - 인증: OAuth (ChatGPT) -- 예시 모델: `openai-codex/gpt-5.4` +- 예제 모델: `openai-codex/gpt-5.4` - CLI: `openclaw onboard --auth-choice openai-codex` 또는 `openclaw models auth login --provider openai-codex` -- 기본 전송은 `auto`입니다(WebSocket 우선, SSE 폴백) -- 모델별 재정의는 `agents.defaults.models["openai-codex/"].params.transport`를 통해 수행합니다(`"sse"`, `"websocket"`, 또는 `"auto"`) -- `params.serviceTier`도 네이티브 Codex Responses 요청(`chatgpt.com/backend-api`)에 전달됩니다 -- 숨겨진 OpenClaw attribution 헤더(`originator`, `version`, - `User-Agent`)는 일반 OpenAI 호환 프록시가 아니라 - `chatgpt.com/backend-api`로 향하는 네이티브 Codex 트래픽에만 첨부됩니다 +- 기본 전송은 `auto`입니다(WebSocket 우선, SSE 대체) +- 모델별 재정의: `agents.defaults.models["openai-codex/"].params.transport` (`"sse"`, `"websocket"`, 또는 `"auto"`) +- `params.serviceTier`도 네이티브 Codex Responses 요청(`chatgpt.com/backend-api`)에서 전달됩니다 +- 숨겨진 OpenClaw attribution 헤더(`originator`, `version`, `User-Agent`)는 일반 OpenAI 호환 프록시가 아니라 `chatgpt.com/backend-api`로 향하는 네이티브 Codex 트래픽에만 첨부됩니다 - 직접 `openai/*`와 동일한 `/fast` 토글 및 `params.fastMode` 구성을 공유하며, OpenClaw는 이를 `service_tier=priority`로 매핑합니다 -- `openai-codex/gpt-5.3-codex-spark`는 Codex OAuth 카탈로그가 이를 노출할 때 계속 사용할 수 있습니다. entitlement에 따라 달라집니다 -- `openai-codex/gpt-5.4`는 네이티브 `contextWindow = 1050000`과 기본 런타임 `contextTokens = 272000`을 유지합니다. 런타임 상한은 `models.providers.openai-codex.models[].contextTokens`로 재정의하세요 +- `openai-codex/gpt-5.3-codex-spark`는 Codex OAuth 카탈로그가 이를 노출할 때 계속 사용할 수 있습니다. 권한 부여 여부에 따라 달라집니다 +- `openai-codex/gpt-5.4`는 네이티브 `contextWindow = 1050000`과 기본 런타임 `contextTokens = 272000`을 유지합니다. 런타임 상한은 `models.providers.openai-codex.models[].contextTokens`로 재정의할 수 있습니다 - 정책 참고: OpenAI Codex OAuth는 OpenClaw 같은 외부 도구/워크플로에 대해 명시적으로 지원됩니다. ```json5 @@ -326,7 +211,7 @@ OpenClaw에는 pi‑ai 카탈로그가 포함되어 있습니다. 이 제공자 - 인증: `OPENCODE_API_KEY`(또는 `OPENCODE_ZEN_API_KEY`) - Zen 런타임 제공자: `opencode` - Go 런타임 제공자: `opencode-go` -- 예시 모델: `opencode/claude-opus-4-6`, `opencode-go/kimi-k2.5` +- 예제 모델: `opencode/claude-opus-4-6`, `opencode-go/kimi-k2.5` - CLI: `openclaw onboard --auth-choice opencode-zen` 또는 `openclaw onboard --auth-choice opencode-go` ```json5 @@ -339,146 +224,123 @@ OpenClaw에는 pi‑ai 카탈로그가 포함되어 있습니다. 이 제공자 - 제공자: `google` - 인증: `GEMINI_API_KEY` -- 선택적 순환: `GEMINI_API_KEYS`, `GEMINI_API_KEY_1`, `GEMINI_API_KEY_2`, `GOOGLE_API_KEY` 폴백, 그리고 `OPENCLAW_LIVE_GEMINI_KEY`(단일 override) -- 예시 모델: `google/gemini-3.1-pro-preview`, `google/gemini-3-flash-preview` +- 선택적 순환: `GEMINI_API_KEYS`, `GEMINI_API_KEY_1`, `GEMINI_API_KEY_2`, `GOOGLE_API_KEY` 대체값, 그리고 `OPENCLAW_LIVE_GEMINI_KEY`(단일 재정의) +- 예제 모델: `google/gemini-3.1-pro-preview`, `google/gemini-3-flash-preview` - 호환성: `google/gemini-3.1-flash-preview`를 사용하는 레거시 OpenClaw 구성은 `google/gemini-3-flash-preview`로 정규화됩니다 - CLI: `openclaw onboard --auth-choice gemini-api-key` -- 직접 Gemini 실행은 또한 제공자 네이티브 - `cachedContents/...` 핸들을 전달하기 위해 `agents.defaults.models["google/"].params.cachedContent` - (또는 레거시 `cached_content`)를 받을 수 있습니다. Gemini 캐시 히트는 OpenClaw `cacheRead`로 표시됩니다 +- 직접 Gemini 실행도 `agents.defaults.models["google/"].params.cachedContent`(또는 레거시 `cached_content`)를 받아 제공자 네이티브 `cachedContents/...` 핸들을 전달합니다. Gemini 캐시 적중은 OpenClaw `cacheRead`로 표시됩니다 ### Google Vertex 및 Gemini CLI - 제공자: `google-vertex`, `google-gemini-cli` - 인증: Vertex는 gcloud ADC를 사용하고, Gemini CLI는 자체 OAuth 흐름을 사용합니다 -- 주의: OpenClaw의 Gemini CLI OAuth는 비공식 통합입니다. 일부 사용자는 서드파티 클라이언트 사용 후 Google 계정 제한을 보고했습니다. 진행하기로 선택한 경우 Google 약관을 검토하고 중요하지 않은 계정을 사용하세요. +- 주의: OpenClaw의 Gemini CLI OAuth는 비공식 통합입니다. 일부 사용자는 서드파티 클라이언트 사용 후 Google 계정 제한을 경험했다고 보고했습니다. 진행하기로 했다면 Google 약관을 검토하고 중요하지 않은 계정을 사용하세요. - Gemini CLI OAuth는 번들된 `google` 플러그인의 일부로 제공됩니다. - - 먼저 Gemini CLI를 설치합니다: + - 먼저 Gemini CLI를 설치하세요: - `brew install gemini-cli` - 또는 `npm install -g @google/gemini-cli` - 활성화: `openclaw plugins enable google` - 로그인: `openclaw models auth login --provider google-gemini-cli --set-default` - 기본 모델: `google-gemini-cli/gemini-3-flash-preview` - - 참고: `openclaw.json`에 client id나 secret을 붙여 넣을 **필요가 없습니다**. CLI 로그인 흐름이 - 게이트웨이 호스트의 인증 프로필에 토큰을 저장합니다. + - 참고: `openclaw.json`에 client id 또는 secret을 붙여넣지 **않습니다**. CLI 로그인 흐름은 게이트웨이 호스트의 인증 프로필에 토큰을 저장합니다. - 로그인 후 요청이 실패하면 게이트웨이 호스트에 `GOOGLE_CLOUD_PROJECT` 또는 `GOOGLE_CLOUD_PROJECT_ID`를 설정하세요. - - Gemini CLI JSON 응답은 `response`에서 파싱되며, 사용량은 `stats`로 폴백되고, - `stats.cached`는 OpenClaw `cacheRead`로 정규화됩니다. + - Gemini CLI JSON 응답은 `response`에서 파싱되며, 사용량은 `stats`로 대체되고 `stats.cached`는 OpenClaw `cacheRead`로 정규화됩니다. ### Z.AI (GLM) - 제공자: `zai` - 인증: `ZAI_API_KEY` -- 예시 모델: `zai/glm-5.1` +- 예제 모델: `zai/glm-5.1` - CLI: `openclaw onboard --auth-choice zai-api-key` - - 별칭: `z.ai/*`와 `z-ai/*`는 `zai/*`로 정규화됩니다 - - `zai-api-key`는 일치하는 Z.AI 엔드포인트를 자동 감지합니다. `zai-coding-global`, `zai-coding-cn`, `zai-global`, `zai-cn`은 특정 표면을 강제로 선택합니다 + - 별칭: `z.ai/*` 및 `z-ai/*`는 `zai/*`로 정규화됩니다 + - `zai-api-key`는 일치하는 Z.AI 엔드포인트를 자동 감지합니다. `zai-coding-global`, `zai-coding-cn`, `zai-global`, `zai-cn`은 특정 표면을 강제합니다 ### Vercel AI Gateway - 제공자: `vercel-ai-gateway` - 인증: `AI_GATEWAY_API_KEY` -- 예시 모델: `vercel-ai-gateway/anthropic/claude-opus-4.6` +- 예제 모델: `vercel-ai-gateway/anthropic/claude-opus-4.6` - CLI: `openclaw onboard --auth-choice ai-gateway-api-key` ### Kilo Gateway - 제공자: `kilocode` - 인증: `KILOCODE_API_KEY` -- 예시 모델: `kilocode/kilo/auto` +- 예제 모델: `kilocode/kilo/auto` - CLI: `openclaw onboard --auth-choice kilocode-api-key` - 기본 URL: `https://api.kilo.ai/api/gateway/` -- 정적 폴백 카탈로그는 `kilocode/kilo/auto`를 포함하며, live - `https://api.kilo.ai/api/gateway/models` 탐색은 런타임 - 카탈로그를 더 확장할 수 있습니다. -- `kilocode/kilo/auto` 뒤의 정확한 업스트림 라우팅은 Kilo Gateway가 소유하며, - OpenClaw에 하드코딩되어 있지 않습니다. +- 정적 대체 카탈로그에는 `kilocode/kilo/auto`가 포함되며, 라이브 `https://api.kilo.ai/api/gateway/models` 검색은 런타임 카탈로그를 더 확장할 수 있습니다. +- `kilocode/kilo/auto` 뒤의 정확한 업스트림 라우팅은 OpenClaw에 하드코딩되어 있지 않고 Kilo Gateway가 소유합니다. -설정 세부 사항은 [/providers/kilocode](/ko/providers/kilocode)를 참조하세요. +설정 세부 정보는 [/providers/kilocode](/ko/providers/kilocode)를 참조하세요. ### 기타 번들 제공자 플러그인 - OpenRouter: `openrouter` (`OPENROUTER_API_KEY`) -- 예시 모델: `openrouter/auto` -- OpenClaw는 요청이 실제로 `openrouter.ai`를 대상으로 할 때만 - OpenRouter의 문서화된 앱 attribution 헤더를 적용합니다 -- OpenRouter 전용 Anthropic `cache_control` 마커도 - 임의 프록시 URL이 아니라 검증된 OpenRouter 경로에만 적용됩니다 -- OpenRouter는 프록시 스타일 OpenAI 호환 경로에 머무르므로, 네이티브 - OpenAI 전용 요청 형성(`serviceTier`, Responses `store`, - 프롬프트 캐시 힌트, OpenAI 추론 호환 페이로드)은 전달되지 않습니다 -- Gemini 기반 OpenRouter 참조는 프록시-Gemini thought-signature 정리만 - 유지합니다. 네이티브 Gemini 리플레이 검증과 bootstrap 재작성은 비활성 상태로 유지됩니다 +- 예제 모델: `openrouter/auto` +- OpenClaw는 요청이 실제로 `openrouter.ai`를 대상으로 할 때만 OpenRouter의 문서화된 앱 attribution 헤더를 적용합니다 +- OpenRouter 전용 Anthropic `cache_control` 마커도 임의 프록시 URL이 아니라 검증된 OpenRouter 경로에서만 적용됩니다 +- OpenRouter는 프록시 스타일 OpenAI 호환 경로에 남아 있으므로 네이티브 OpenAI 전용 요청 형상화(`serviceTier`, Responses `store`, 프롬프트 캐시 힌트, OpenAI 추론 호환 페이로드)는 전달되지 않습니다 +- Gemini 기반 OpenRouter 참조는 프록시 Gemini thought-signature 정리만 유지하며, 네이티브 Gemini 재생 검증 및 부트스트랩 재작성은 비활성 상태로 유지됩니다 - Kilo Gateway: `kilocode` (`KILOCODE_API_KEY`) -- 예시 모델: `kilocode/kilo/auto` -- Gemini 기반 Kilo 참조는 동일한 프록시-Gemini thought-signature - 정리 경로를 유지합니다. `kilocode/kilo/auto`와 기타 프록시 추론 미지원 - 힌트는 프록시 추론 주입을 건너뜁니다 -- MiniMax: `minimax`(API 키) 및 `minimax-portal`(OAuth) +- 예제 모델: `kilocode/kilo/auto` +- Gemini 기반 Kilo 참조는 동일한 프록시 Gemini thought-signature 정리 경로를 유지합니다. `kilocode/kilo/auto` 및 기타 프록시 추론 미지원 힌트는 프록시 추론 주입을 건너뜁니다 +- MiniMax: `minimax` (API 키) 및 `minimax-portal` (OAuth) - 인증: `minimax`에는 `MINIMAX_API_KEY`, `minimax-portal`에는 `MINIMAX_OAUTH_TOKEN` 또는 `MINIMAX_API_KEY` -- 예시 모델: `minimax/MiniMax-M2.7` 또는 `minimax-portal/MiniMax-M2.7` -- MiniMax 온보딩/API 키 설정은 명시적인 M2.7 모델 정의를 - `input: ["text", "image"]`와 함께 기록합니다. 번들된 제공자 카탈로그는 - 해당 제공자 구성이 구체화될 때까지 채팅 참조를 - 텍스트 전용으로 유지합니다 +- 예제 모델: `minimax/MiniMax-M2.7` 또는 `minimax-portal/MiniMax-M2.7` +- MiniMax 온보딩/API 키 설정은 `input: ["text", "image"]`가 포함된 명시적 M2.7 모델 정의를 작성합니다. 번들된 제공자 카탈로그는 해당 제공자 구성이 구체화되기 전까지 채팅 참조를 텍스트 전용으로 유지합니다 - Moonshot: `moonshot` (`MOONSHOT_API_KEY`) -- 예시 모델: `moonshot/kimi-k2.5` +- 예제 모델: `moonshot/kimi-k2.5` - Kimi Coding: `kimi` (`KIMI_API_KEY` 또는 `KIMICODE_API_KEY`) -- 예시 모델: `kimi/kimi-code` +- 예제 모델: `kimi/kimi-code` - Qianfan: `qianfan` (`QIANFAN_API_KEY`) -- 예시 모델: `qianfan/deepseek-v3.2` +- 예제 모델: `qianfan/deepseek-v3.2` - Qwen Cloud: `qwen` (`QWEN_API_KEY`, `MODELSTUDIO_API_KEY`, 또는 `DASHSCOPE_API_KEY`) -- 예시 모델: `qwen/qwen3.5-plus` +- 예제 모델: `qwen/qwen3.5-plus` - NVIDIA: `nvidia` (`NVIDIA_API_KEY`) -- 예시 모델: `nvidia/nvidia/llama-3.1-nemotron-70b-instruct` +- 예제 모델: `nvidia/nvidia/llama-3.1-nemotron-70b-instruct` - StepFun: `stepfun` / `stepfun-plan` (`STEPFUN_API_KEY`) -- 예시 모델: `stepfun/step-3.5-flash`, `stepfun-plan/step-3.5-flash-2603` +- 예제 모델: `stepfun/step-3.5-flash`, `stepfun-plan/step-3.5-flash-2603` - Together: `together` (`TOGETHER_API_KEY`) -- 예시 모델: `together/moonshotai/Kimi-K2.5` +- 예제 모델: `together/moonshotai/Kimi-K2.5` - Venice: `venice` (`VENICE_API_KEY`) - Xiaomi: `xiaomi` (`XIAOMI_API_KEY`) -- 예시 모델: `xiaomi/mimo-v2-flash` +- 예제 모델: `xiaomi/mimo-v2-flash` - Vercel AI Gateway: `vercel-ai-gateway` (`AI_GATEWAY_API_KEY`) - Hugging Face Inference: `huggingface` (`HUGGINGFACE_HUB_TOKEN` 또는 `HF_TOKEN`) - Cloudflare AI Gateway: `cloudflare-ai-gateway` (`CLOUDFLARE_AI_GATEWAY_API_KEY`) - Volcengine: `volcengine` (`VOLCANO_ENGINE_API_KEY`) -- 예시 모델: `volcengine-plan/ark-code-latest` +- 예제 모델: `volcengine-plan/ark-code-latest` - BytePlus: `byteplus` (`BYTEPLUS_API_KEY`) -- 예시 모델: `byteplus-plan/ark-code-latest` +- 예제 모델: `byteplus-plan/ark-code-latest` - xAI: `xai` (`XAI_API_KEY`) - 네이티브 번들 xAI 요청은 xAI Responses 경로를 사용합니다 - - `/fast` 또는 `params.fastMode: true`는 `grok-3`, `grok-3-mini`, - `grok-4`, `grok-4-0709`를 해당 `*-fast` 변형으로 재작성합니다 - - `tool_stream`은 기본적으로 활성화됩니다. - 비활성화하려면 - `agents.defaults.models["xai/"].params.tool_stream`을 `false`로 설정하세요 + - `/fast` 또는 `params.fastMode: true`는 `grok-3`, `grok-3-mini`, `grok-4`, `grok-4-0709`를 해당 `*-fast` 변형으로 다시 씁니다 + - `tool_stream`는 기본적으로 켜져 있습니다. 비활성화하려면 `agents.defaults.models["xai/"].params.tool_stream`를 `false`로 설정하세요 - Mistral: `mistral` (`MISTRAL_API_KEY`) -- 예시 모델: `mistral/mistral-large-latest` +- 예제 모델: `mistral/mistral-large-latest` - CLI: `openclaw onboard --auth-choice mistral-api-key` - Groq: `groq` (`GROQ_API_KEY`) - Cerebras: `cerebras` (`CEREBRAS_API_KEY`) - - Cerebras의 GLM 모델은 `zai-glm-4.7` 및 `zai-glm-4.6` id를 사용합니다. - - OpenAI 호환 base URL: `https://api.cerebras.ai/v1`. + - Cerebras의 GLM 모델은 `zai-glm-4.7` 및 `zai-glm-4.6` ID를 사용합니다. + - OpenAI 호환 기본 URL: `https://api.cerebras.ai/v1`. - GitHub Copilot: `github-copilot` (`COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN`) -- Hugging Face Inference 예시 모델: `huggingface/deepseek-ai/DeepSeek-R1`; CLI: `openclaw onboard --auth-choice huggingface-api-key`. [Hugging Face (Inference)](/ko/providers/huggingface)를 참조하세요. +- Hugging Face Inference 예제 모델: `huggingface/deepseek-ai/DeepSeek-R1`; CLI: `openclaw onboard --auth-choice huggingface-api-key`. [Hugging Face (Inference)](/ko/providers/huggingface)를 참조하세요. -## `models.providers`를 통한 제공자 (커스텀/base URL) +## `models.providers`를 통한 제공자(custom/base URL) -`models.providers`(또는 `models.json`)를 사용해 **커스텀** 제공자 또는 -OpenAI/Anthropic 호환 프록시를 추가할 수 있습니다. +`models.providers`(또는 `models.json`)를 사용해 **사용자 정의** 제공자 또는 OpenAI/Anthropic 호환 프록시를 추가하세요. 아래의 많은 번들 제공자 플러그인은 이미 기본 카탈로그를 게시합니다. -기본 base URL, 헤더 또는 모델 목록을 재정의하려는 경우에만 명시적인 -`models.providers.` 항목을 사용하세요. +기본 base URL, 헤더 또는 모델 목록을 재정의하려는 경우에만 명시적인 `models.providers.` 항목을 사용하세요. ### Moonshot AI (Kimi) -Moonshot은 번들 제공자 플러그인으로 제공됩니다. 기본적으로는 내장 제공자를 사용하고, -base URL이나 모델 메타데이터를 재정의해야 할 때만 명시적인 `models.providers.moonshot` 항목을 추가하세요: +Moonshot은 번들 제공자 플러그인으로 제공됩니다. 기본적으로 내장 제공자를 사용하고, base URL 또는 모델 메타데이터를 재정의해야 할 때만 명시적인 `models.providers.moonshot` 항목을 추가하세요: - 제공자: `moonshot` - 인증: `MOONSHOT_API_KEY` -- 예시 모델: `moonshot/kimi-k2.5` +- 예제 모델: `moonshot/kimi-k2.5` - CLI: `openclaw onboard --auth-choice moonshot-api-key` 또는 `openclaw onboard --auth-choice moonshot-api-key-cn` Kimi K2 모델 ID: @@ -517,7 +379,7 @@ Kimi Coding은 Moonshot AI의 Anthropic 호환 엔드포인트를 사용합니 - 제공자: `kimi` - 인증: `KIMI_API_KEY` -- 예시 모델: `kimi/kimi-code` +- 예제 모델: `kimi/kimi-code` ```json5 { @@ -528,15 +390,15 @@ Kimi Coding은 Moonshot AI의 Anthropic 호환 엔드포인트를 사용합니 } ``` -레거시 `kimi/k2p5`는 계속 호환 모델 id로 허용됩니다. +레거시 `kimi/k2p5`는 호환성 모델 ID로 계속 허용됩니다. ### Volcano Engine (Doubao) -Volcano Engine(화산엔진, 火山引擎)은 중국에서 Doubao 및 기타 모델에 대한 액세스를 제공합니다. +Volcano Engine (火山引擎)은 중국에서 Doubao 및 기타 모델에 대한 액세스를 제공합니다. -- 제공자: `volcengine`(코딩: `volcengine-plan`) +- 제공자: `volcengine` (코딩: `volcengine-plan`) - 인증: `VOLCANO_ENGINE_API_KEY` -- 예시 모델: `volcengine-plan/ark-code-latest` +- 예제 모델: `volcengine-plan/ark-code-latest` - CLI: `openclaw onboard --auth-choice volcengine-api-key` ```json5 @@ -547,12 +409,9 @@ Volcano Engine(화산엔진, 火山引擎)은 중국에서 Doubao 및 기타 모 } ``` -온보딩은 기본적으로 코딩 표면을 선택하지만, 일반 `volcengine/*` -카탈로그도 동시에 등록됩니다. +온보딩은 기본적으로 코딩 표면을 사용하지만, 일반 `volcengine/*` 카탈로그도 동시에 등록됩니다. -온보딩/모델 선택기에서 Volcengine 인증 선택은 `volcengine/*`와 `volcengine-plan/*` 행을 모두 선호합니다. 이 모델들이 아직 로드되지 않았다면, -OpenClaw는 비어 있는 제공자 범위 선택기를 표시하는 대신 -필터링되지 않은 카탈로그로 폴백합니다. +온보딩/모델 구성 선택기에서 Volcengine 인증 선택은 `volcengine/*`와 `volcengine-plan/*` 행을 모두 우선합니다. 해당 모델이 아직 로드되지 않은 경우, OpenClaw는 빈 제공자 범위 선택기를 표시하는 대신 필터링되지 않은 카탈로그로 대체합니다. 사용 가능한 모델: @@ -574,9 +433,9 @@ OpenClaw는 비어 있는 제공자 범위 선택기를 표시하는 대신 BytePlus ARK는 국제 사용자를 위해 Volcano Engine과 동일한 모델에 대한 액세스를 제공합니다. -- 제공자: `byteplus`(코딩: `byteplus-plan`) +- 제공자: `byteplus` (코딩: `byteplus-plan`) - 인증: `BYTEPLUS_API_KEY` -- 예시 모델: `byteplus-plan/ark-code-latest` +- 예제 모델: `byteplus-plan/ark-code-latest` - CLI: `openclaw onboard --auth-choice byteplus-api-key` ```json5 @@ -587,12 +446,9 @@ BytePlus ARK는 국제 사용자를 위해 Volcano Engine과 동일한 모델에 } ``` -온보딩은 기본적으로 코딩 표면을 선택하지만, 일반 `byteplus/*` -카탈로그도 동시에 등록됩니다. +온보딩은 기본적으로 코딩 표면을 사용하지만, 일반 `byteplus/*` 카탈로그도 동시에 등록됩니다. -온보딩/모델 선택기에서 BytePlus 인증 선택은 `byteplus/*`와 `byteplus-plan/*` 행을 모두 선호합니다. 이 모델들이 아직 로드되지 않았다면, -OpenClaw는 비어 있는 제공자 범위 선택기를 표시하는 대신 -필터링되지 않은 카탈로그로 폴백합니다. +온보딩/모델 구성 선택기에서 BytePlus 인증 선택은 `byteplus/*`와 `byteplus-plan/*` 행을 모두 우선합니다. 해당 모델이 아직 로드되지 않은 경우, OpenClaw는 빈 제공자 범위 선택기를 표시하는 대신 필터링되지 않은 카탈로그로 대체합니다. 사용 가능한 모델: @@ -614,7 +470,7 @@ Synthetic는 `synthetic` 제공자 뒤에서 Anthropic 호환 모델을 제공 - 제공자: `synthetic` - 인증: `SYNTHETIC_API_KEY` -- 예시 모델: `synthetic/hf:MiniMaxAI/MiniMax-M2.5` +- 예제 모델: `synthetic/hf:MiniMaxAI/MiniMax-M2.5` - CLI: `openclaw onboard --auth-choice synthetic-api-key` ```json5 @@ -638,28 +494,24 @@ Synthetic는 `synthetic` 제공자 뒤에서 Anthropic 호환 모델을 제공 ### MiniMax -MiniMax는 커스텀 엔드포인트를 사용하므로 `models.providers`를 통해 구성됩니다: +MiniMax는 사용자 정의 엔드포인트를 사용하므로 `models.providers`를 통해 구성됩니다: - MiniMax OAuth (Global): `--auth-choice minimax-global-oauth` - MiniMax OAuth (CN): `--auth-choice minimax-cn-oauth` -- MiniMax API key (Global): `--auth-choice minimax-global-api` -- MiniMax API key (CN): `--auth-choice minimax-cn-api` -- 인증: `minimax`에는 `MINIMAX_API_KEY`, - `minimax-portal`에는 `MINIMAX_OAUTH_TOKEN` 또는 - `MINIMAX_API_KEY` +- MiniMax API 키 (Global): `--auth-choice minimax-global-api` +- MiniMax API 키 (CN): `--auth-choice minimax-cn-api` +- 인증: `minimax`에는 `MINIMAX_API_KEY`, `minimax-portal`에는 `MINIMAX_OAUTH_TOKEN` 또는 `MINIMAX_API_KEY` -설정 세부 사항, 모델 옵션, 구성 스니펫은 [/providers/minimax](/ko/providers/minimax)를 참조하세요. +설정 세부 정보, 모델 옵션, 구성 스니펫은 [/providers/minimax](/ko/providers/minimax)를 참조하세요. -MiniMax의 Anthropic 호환 스트리밍 경로에서 OpenClaw는 -명시적으로 설정하지 않는 한 기본적으로 thinking을 비활성화하며, -`/fast on`은 `MiniMax-M2.7`을 `MiniMax-M2.7-highspeed`로 재작성합니다. +MiniMax의 Anthropic 호환 스트리밍 경로에서 OpenClaw는 명시적으로 설정하지 않는 한 기본적으로 thinking을 비활성화하며, `/fast on`은 `MiniMax-M2.7`을 `MiniMax-M2.7-highspeed`로 다시 씁니다. -플러그인 소유 capability 분할: +플러그인 소유 capability 분리: -- 텍스트/채팅 기본값은 `minimax/MiniMax-M2.7`에 유지 -- 이미지 생성은 `minimax/image-01` 또는 `minimax-portal/image-01` -- 이미지 이해는 두 MiniMax 인증 경로 모두에서 플러그인 소유 `MiniMax-VL-01` -- 웹 검색은 제공자 id `minimax`에 유지 +- 텍스트/채팅 기본값은 `minimax/MiniMax-M2.7`에 유지됩니다 +- 이미지 생성은 `minimax/image-01` 또는 `minimax-portal/image-01`입니다 +- 이미지 이해는 두 MiniMax 인증 경로 모두에서 플러그인 소유 `MiniMax-VL-01`입니다 +- 웹 검색은 제공자 ID `minimax`에 유지됩니다 ### Ollama @@ -667,7 +519,7 @@ Ollama는 번들 제공자 플러그인으로 제공되며 Ollama의 네이티 - 제공자: `ollama` - 인증: 필요 없음(로컬 서버) -- 예시 모델: `ollama/llama3.3` +- 예제 모델: `ollama/llama3.3` - 설치: [https://ollama.com/download](https://ollama.com/download) ```bash @@ -683,27 +535,23 @@ ollama pull llama3.3 } ``` -Ollama는 `OLLAMA_API_KEY`로 opt in하면 로컬의 `http://127.0.0.1:11434`에서 -감지되며, 번들 제공자 플러그인은 Ollama를 직접 -`openclaw onboard`와 모델 선택기에 추가합니다. 온보딩, 클라우드/로컬 모드, 커스텀 구성은 [/providers/ollama](/ko/providers/ollama)를 -참조하세요. +`OLLAMA_API_KEY`로 선택적으로 활성화하면 Ollama는 로컬의 `http://127.0.0.1:11434`에서 감지되며, 번들 제공자 플러그인이 Ollama를 `openclaw onboard`와 모델 선택기에 직접 추가합니다. 온보딩, 클라우드/로컬 모드, 사용자 정의 구성은 [/providers/ollama](/ko/providers/ollama)를 참조하세요. ### vLLM -vLLM은 로컬/셀프호스트형 OpenAI 호환 -서버용 번들 제공자 플러그인으로 제공됩니다: +vLLM은 로컬/셀프 호스팅 OpenAI 호환 서버를 위한 번들 제공자 플러그인으로 제공됩니다: - 제공자: `vllm` - 인증: 선택 사항(서버에 따라 다름) - 기본 base URL: `http://127.0.0.1:8000/v1` -로컬 자동 감지를 opt in하려면(서버가 인증을 강제하지 않으면 어떤 값이든 작동): +로컬 자동 검색에 선택적으로 참여하려면(서버가 인증을 강제하지 않는 경우 어떤 값이든 작동함): ```bash export VLLM_API_KEY="vllm-local" ``` -그런 다음 모델을 설정합니다(`/v1/models`가 반환하는 ID 중 하나로 바꾸세요): +그런 다음 모델을 설정하세요(`/v1/models`가 반환하는 ID 중 하나로 교체): ```json5 { @@ -717,21 +565,19 @@ export VLLM_API_KEY="vllm-local" ### SGLang -SGLang은 빠른 셀프호스트형 -OpenAI 호환 서버용 번들 제공자 플러그인으로 제공됩니다: +SGLang은 빠른 셀프 호스팅 OpenAI 호환 서버를 위한 번들 제공자 플러그인으로 제공됩니다: - 제공자: `sglang` - 인증: 선택 사항(서버에 따라 다름) - 기본 base URL: `http://127.0.0.1:30000/v1` -로컬 자동 감지를 opt in하려면(서버가 -인증을 강제하지 않으면 어떤 값이든 작동): +로컬 자동 검색에 선택적으로 참여하려면(서버가 인증을 강제하지 않는 경우 어떤 값이든 작동함): ```bash export SGLANG_API_KEY="sglang-local" ``` -그런 다음 모델을 설정합니다(`/v1/models`가 반환하는 ID 중 하나로 바꾸세요): +그런 다음 모델을 설정하세요(`/v1/models`가 반환하는 ID 중 하나로 교체): ```json5 { @@ -743,7 +589,7 @@ export SGLANG_API_KEY="sglang-local" 자세한 내용은 [/providers/sglang](/ko/providers/sglang)를 참조하세요. -### 로컬 프록시 (LM Studio, vLLM, LiteLLM 등) +### 로컬 프록시(LM Studio, vLLM, LiteLLM 등) 예시(OpenAI 호환): @@ -780,21 +626,18 @@ export SGLANG_API_KEY="sglang-local" 참고: -- 커스텀 제공자의 경우 `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`는 선택 사항입니다. +- 사용자 정의 제공자의 경우 `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`는 선택 사항입니다. 생략하면 OpenClaw는 다음 기본값을 사용합니다: - `reasoning: false` - `input: ["text"]` - `cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }` - `contextWindow: 200000` - `maxTokens: 8192` -- 권장: 프록시/모델 한도에 맞는 명시적 값을 설정하세요. -- 네이티브 엔드포인트가 아닌 곳(호스트가 `api.openai.com`이 아닌 비어 있지 않은 `baseUrl`)에서 `api: "openai-completions"`를 사용할 경우, OpenClaw는 지원되지 않는 `developer` 역할로 인한 제공자 400 오류를 피하기 위해 `compat.supportsDeveloperRole: false`를 강제합니다. -- 프록시 스타일 OpenAI 호환 경로는 네이티브 OpenAI 전용 요청 - 형성도 건너뜁니다: `service_tier` 없음, Responses `store` 없음, 프롬프트 캐시 힌트 없음, - OpenAI 추론 호환 페이로드 형성 없음, 숨겨진 OpenClaw attribution - 헤더 없음. -- `baseUrl`이 비어 있거나 생략되면 OpenClaw는 기본 OpenAI 동작을 유지합니다(`api.openai.com`으로 해석됨). -- 안전을 위해 명시적인 `compat.supportsDeveloperRole: true`도 비네이티브 `openai-completions` 엔드포인트에서는 여전히 재정의됩니다. +- 권장 사항: 프록시/모델 제한에 맞는 명시적 값을 설정하세요. +- 네이티브가 아닌 엔드포인트에서 `api: "openai-completions"`를 사용할 경우(`api.openai.com`이 아닌 호스트를 가진 비어 있지 않은 `baseUrl`), OpenClaw는 지원되지 않는 `developer` 역할로 인한 제공자 400 오류를 방지하기 위해 `compat.supportsDeveloperRole: false`를 강제합니다. +- 프록시 스타일 OpenAI 호환 경로는 네이티브 OpenAI 전용 요청 형상화도 건너뜁니다. 즉, `service_tier`, Responses `store`, 프롬프트 캐시 힌트, OpenAI 추론 호환 페이로드 형상, 숨겨진 OpenClaw attribution 헤더가 없습니다. +- `baseUrl`이 비어 있거나 생략되면 OpenClaw는 기본 OpenAI 동작(`api.openai.com`으로 해석됨)을 유지합니다. +- 안전을 위해 네이티브가 아닌 `openai-completions` 엔드포인트에서는 명시적인 `compat.supportsDeveloperRole: true`도 계속 재정의됩니다. ## CLI 예시 @@ -804,11 +647,11 @@ openclaw models set opencode/claude-opus-4-6 openclaw models list ``` -전체 구성 예시는 [/gateway/configuration](/ko/gateway/configuration)을 참조하세요. +참조: 전체 구성 예시는 [/gateway/configuration](/ko/gateway/configuration)을 확인하세요. -## 관련 +## 관련 항목 -- [Models](/ko/concepts/models) — 모델 구성 및 별칭 -- [Model Failover](/ko/concepts/model-failover) — 폴백 체인 및 재시도 동작 -- [Configuration Reference](/ko/gateway/configuration-reference#agent-defaults) — 모델 구성 키 -- [Providers](/ko/providers) — 제공자별 설정 가이드 +- [모델](/ko/concepts/models) — 모델 구성 및 별칭 +- [모델 대체](/ko/concepts/model-failover) — 대체 체인 및 재시도 동작 +- [구성 참조](/ko/gateway/configuration-reference#agent-defaults) — 모델 구성 키 +- [제공자](/ko/providers) — 제공자별 설정 가이드 diff --git a/docs/ko/concepts/qa-e2e-automation.md b/docs/ko/concepts/qa-e2e-automation.md index 537a9f808..09d7a4858 100644 --- a/docs/ko/concepts/qa-e2e-automation.md +++ b/docs/ko/concepts/qa-e2e-automation.md @@ -2,50 +2,42 @@ read_when: - qa-lab 또는 qa-channel 확장하기 - 리포지토리 기반 QA 시나리오 추가하기 - - Gateway 대시보드를 중심으로 더 현실적인 QA 자동화 구축하기 -summary: qa-lab, qa-channel, 시드된 시나리오, 프로토콜 보고서를 위한 비공개 QA 자동화 구조 + - Gateway 대시보드를 중심으로 더 높은 현실성의 QA 자동화 구축하기 +summary: qa-lab, qa-channel, 시드된 시나리오, 그리고 프로토콜 보고서를 위한 비공개 QA 자동화 구조 title: QA E2E 자동화 x-i18n: - generated_at: "2026-04-10T05:59:51Z" + generated_at: "2026-04-11T02:44:22Z" model: gpt-5.4 provider: openai - source_hash: 357d6698304ff7a8c4aa8a7be97f684d50f72b524740050aa761ac0ee68266de + source_hash: 5427b505e26bfd542e984e3920c3f7cb825473959195ba9737eff5da944c60d0 source_path: concepts/qa-e2e-automation.md workflow: 15 --- # QA E2E 자동화 -비공개 QA 스택은 단일 단위 테스트보다 더 현실적이고, -채널 형태에 가까운 방식으로 OpenClaw를 검증하기 위한 것입니다. +비공개 QA 스택은 단일 단위 테스트로는 어려운, 더 현실적이고 채널 형태에 가까운 방식으로 OpenClaw를 검증하기 위한 것입니다. 현재 구성 요소: -- `extensions/qa-channel`: DM, 채널, 스레드, - 리액션, 편집, 삭제 인터페이스를 갖춘 합성 메시지 채널 -- `extensions/qa-lab`: 대화 기록을 관찰하고, - 인바운드 메시지를 주입하고, Markdown 보고서를 내보내기 위한 디버거 UI 및 QA 버스 -- `qa/`: 시작 작업과 기본 QA - 시나리오를 위한 리포지토리 기반 시드 자산 +- `extensions/qa-channel`: DM, 채널, 스레드, 리액션, 수정, 삭제 표면을 갖춘 합성 메시지 채널 +- `extensions/qa-lab`: 대화 내용을 관찰하고, 인바운드 메시지를 주입하고, Markdown 보고서를 내보내기 위한 디버거 UI 및 QA 버스 +- `qa/`: 시작 작업과 기준 QA 시나리오를 위한 리포지토리 기반 시드 자산 -현재 QA 운영자 흐름은 2개 패널로 구성된 QA 사이트입니다: +현재 QA 운영자 흐름은 2패널 QA 사이트입니다. - 왼쪽: 에이전트가 있는 Gateway 대시보드(Control UI) -- 오른쪽: Slack과 유사한 대화 기록과 시나리오 계획을 보여주는 QA Lab +- 오른쪽: Slack과 비슷한 대화 내용과 시나리오 계획을 보여주는 QA Lab -다음 명령으로 실행합니다: +다음으로 실행합니다: ```bash pnpm qa:lab:up ``` -이 명령은 QA 사이트를 빌드하고, Docker 기반 Gateway 레인을 시작하며, -운영자 또는 자동화 루프가 에이전트에 QA -미션을 부여하고, 실제 채널 동작을 관찰하고, 무엇이 작동했고, 실패했고, 계속 막혀 있었는지 기록할 수 있는 -QA Lab 페이지를 노출합니다. +이 명령은 QA 사이트를 빌드하고, Docker 기반 게이트웨이 레인을 시작하며, 운영자나 자동화 루프가 에이전트에 QA 미션을 부여하고, 실제 채널 동작을 관찰하고, 무엇이 성공했는지, 실패했는지, 또는 여전히 막혀 있는지를 기록할 수 있는 QA Lab 페이지를 노출합니다. -매번 Docker 이미지를 다시 빌드하지 않고 더 빠르게 QA Lab UI를 반복 개발하려면, -바인드 마운트된 QA Lab 번들로 스택을 시작하세요: +Docker 이미지를 매번 다시 빌드하지 않고 QA Lab UI를 더 빠르게 반복 개발하려면, 바인드 마운트된 QA Lab 번들로 스택을 시작하세요: ```bash pnpm openclaw qa docker-build-image @@ -54,24 +46,45 @@ pnpm qa:lab:up:fast pnpm qa:lab:watch ``` -`qa:lab:up:fast`는 Docker 서비스를 사전 빌드된 이미지로 유지하고 -`extensions/qa-lab/web/dist`를 `qa-lab` 컨테이너에 바인드 마운트합니다. `qa:lab:watch`는 -변경 시 해당 번들을 다시 빌드하며, QA Lab 자산 해시가 바뀌면 브라우저가 자동으로 다시 로드됩니다. +`qa:lab:up:fast`는 미리 빌드된 이미지에서 Docker 서비스를 유지하고 `extensions/qa-lab/web/dist`를 `qa-lab` 컨테이너에 바인드 마운트합니다. `qa:lab:watch`는 변경 시 해당 번들을 다시 빌드하고, QA Lab 자산 해시가 바뀌면 브라우저가 자동으로 다시 로드됩니다. -QA 경로에 Docker를 포함하지 않는 일회용 Linux VM 레인의 경우 다음을 실행하세요: +실제 전송 계층 기반 Matrix 스모크 레인을 실행하려면 다음을 사용하세요: + +```bash +pnpm openclaw qa matrix +``` + +이 레인은 Docker에서 일회용 Tuwunel 홈서버를 프로비저닝하고, 임시 드라이버, SUT, 옵저버 사용자를 등록하고, 하나의 비공개 방을 만든 다음, QA 게이트웨이 자식 프로세스 안에서 실제 Matrix plugin을 실행합니다. 라이브 전송 레인은 자식 설정을 테스트 중인 전송 계층에 한정해서 적용하므로, Matrix는 자식 설정에서 `qa-channel` 없이 실행됩니다. + +실제 전송 계층 기반 Telegram 스모크 레인을 실행하려면 다음을 사용하세요: + +```bash +pnpm openclaw qa telegram +``` + +이 레인은 일회용 서버를 프로비저닝하는 대신 실제 비공개 Telegram 그룹 하나를 대상으로 합니다. 이를 위해서는 `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`, `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`이 필요하며, 동일한 비공개 그룹 안에 서로 다른 두 개의 봇이 있어야 합니다. SUT 봇은 Telegram 사용자 이름이 있어야 하며, 두 봇 모두 `@BotFather`에서 Bot-to-Bot Communication Mode를 활성화했을 때 봇 간 관찰이 가장 잘 동작합니다. + +이제 라이브 전송 레인들은 각자 고유한 시나리오 목록 구조를 정의하는 대신, 하나의 더 작은 공용 계약을 공유합니다. + +`qa-channel`은 여전히 폭넓은 합성 제품 동작 스위트이며 라이브 전송 커버리지 매트릭스에는 포함되지 않습니다. + +| 레인 | 카나리아 | 멘션 게이팅 | 허용 목록 차단 | 최상위 답장 | 재시작 복구 | 스레드 후속 응답 | 스레드 격리 | 리액션 관찰 | 도움말 명령 | +| -------- | -------- | ----------- | -------------- | ----------- | ----------- | ---------------- | ----------- | ----------- | ----------- | +| Matrix | x | x | x | x | x | x | x | x | | +| Telegram | x | | | | | | | | x | + +이를 통해 `qa-channel`은 폭넓은 제품 동작 스위트로 유지되고, Matrix, Telegram, 그리고 향후 라이브 전송 계층들은 하나의 명시적인 전송 계약 체크리스트를 공유하게 됩니다. + +QA 경로에 Docker를 포함하지 않는 일회용 Linux VM 레인을 실행하려면 다음을 사용하세요: ```bash pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline ``` -이 명령은 새 Multipass 게스트를 부팅하고, 의존성을 설치하고, 게스트 내부에서 OpenClaw를 빌드하고, -`qa suite`를 실행한 다음, 일반 QA 보고서와 -요약을 다시 호스트의 `.artifacts/qa-e2e/...`로 복사합니다. -시나리오 선택 동작은 호스트에서의 `qa suite`와 동일하게 재사용합니다. -라이브 실행은 게스트에서 실용적으로 사용할 수 있는 지원 QA 인증 입력을 전달합니다: -환경 변수 기반 제공자 키, QA 라이브 제공자 구성 경로, -그리고 존재할 경우 `CODEX_HOME`입니다. 게스트가 -마운트된 워크스페이스를 통해 다시 쓸 수 있도록 `--output-dir`은 리포지토리 루트 아래에 유지하세요. +이 명령은 새 Multipass 게스트를 부팅하고, 의존성을 설치하고, 게스트 내부에서 OpenClaw를 빌드하고, `qa suite`를 실행한 다음, 일반 QA 보고서와 요약을 호스트의 `.artifacts/qa-e2e/...`로 다시 복사합니다. +시나리오 선택 동작은 호스트에서의 `qa suite`와 동일하게 재사용합니다. +호스트와 Multipass 스위트 실행은 기본적으로 선택된 여러 시나리오를 격리된 게이트웨이 워커로 병렬 실행하며, 최대 64개 워커 또는 선택된 시나리오 수만큼 실행합니다. 워커 수를 조정하려면 `--concurrency `를 사용하고, 직렬 실행하려면 `--concurrency 1`을 사용하세요. +라이브 실행은 게스트에서 실용적으로 전달 가능한 지원 QA 인증 입력을 전달합니다: env 기반 provider 키, QA 라이브 provider 설정 경로, 그리고 존재하는 경우 `CODEX_HOME`입니다. 게스트가 마운트된 워크스페이스를 통해 다시 쓸 수 있도록 `--output-dir`은 리포지토리 루트 아래에 유지하세요. ## 리포지토리 기반 시드 @@ -80,9 +93,7 @@ pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline - `qa/scenarios/index.md` - `qa/scenarios/*.md` -이 항목들은 QA 계획이 사람과 -에이전트 모두에게 보이도록 의도적으로 git에 포함됩니다. 기본 목록은 다음을 포괄할 수 있을 만큼 -충분히 넓어야 합니다: +이 파일들은 QA 계획이 사람과 에이전트 모두에게 보이도록 의도적으로 git에 포함됩니다. 기준 목록은 다음을 포괄할 만큼 충분히 넓어야 합니다: - DM 및 채널 채팅 - 스레드 동작 @@ -90,22 +101,21 @@ pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline - cron 콜백 - 메모리 회상 - 모델 전환 -- 하위 에이전트 핸드오프 +- 서브에이전트 핸드오프 - 리포지토리 읽기 및 문서 읽기 -- Lobster Invaders와 같은 작은 빌드 작업 하나 +- Lobster Invaders 같은 작은 빌드 작업 하나 ## 보고 -`qa-lab`은 관찰된 버스 타임라인에서 Markdown 프로토콜 보고서를 내보냅니다. +`qa-lab`은 관찰된 버스 타임라인으로부터 Markdown 프로토콜 보고서를 내보냅니다. 이 보고서는 다음에 답해야 합니다: -- 무엇이 작동했는가 +- 무엇이 잘 작동했는가 - 무엇이 실패했는가 -- 무엇이 계속 막혀 있었는가 +- 무엇이 여전히 막혀 있었는가 - 어떤 후속 시나리오를 추가할 가치가 있는가 -캐릭터 및 스타일 점검을 위해, 동일한 시나리오를 여러 라이브 모델 ref에 걸쳐 실행하고 -판정된 Markdown 보고서를 작성하세요: +캐릭터 및 스타일 검사를 위해, 동일한 시나리오를 여러 라이브 모델 ref에 걸쳐 실행하고 평가된 Markdown 보고서를 작성하세요: ```bash pnpm openclaw qa character-eval \ @@ -124,38 +134,16 @@ pnpm openclaw qa character-eval \ --judge-concurrency 16 ``` -이 명령은 Docker가 아니라 로컬 QA Gateway 자식 프로세스를 실행합니다. 캐릭터 평가 -시나리오는 `SOUL.md`를 통해 페르소나를 설정한 다음, 채팅, 워크스페이스 도움말, -작은 파일 작업과 같은 일반 사용자 턴을 실행해야 합니다. 후보 모델에는 -평가 중이라는 사실을 알려주면 안 됩니다. 이 명령은 각 전체 대화 기록을 보존하고, -기본 실행 통계를 기록한 다음, 판정 모델에 빠른 모드와 -`xhigh` 추론으로 실행 결과를 자연스러움, 분위기, 유머 기준으로 순위를 매기도록 요청합니다. -제공자 간 비교 시에는 `--blind-judge-models`를 사용하세요. 판정 프롬프트는 여전히 -모든 대화 기록과 실행 상태를 받지만, 후보 ref는 -`candidate-01` 같은 중립적인 레이블로 대체됩니다. 이후 보고서는 파싱 후 순위를 실제 ref에 다시 매핑합니다. -후보 실행은 기본적으로 `high` 추론을 사용하며, 이를 지원하는 OpenAI 모델의 경우 `xhigh`를 사용합니다. -특정 후보를 개별적으로 덮어쓰려면 -`--model provider/model,thinking=`을 사용하세요. `--thinking `은 여전히 -전역 대체값을 설정하며, 이전의 `--model-thinking ` 형식도 -호환성을 위해 유지됩니다. -OpenAI 후보 ref는 제공자가 지원하는 경우 우선 처리에 fast 모드를 사용하도록 기본 설정됩니다. -단일 후보 또는 판정자에 대해 재정의가 필요하면 인라인으로 `,fast`, `,no-fast`, 또는 `,fast=false`를 추가하세요. -모든 후보 모델에 fast 모드를 강제로 적용하려는 경우에만 `--fast`를 전달하세요. 후보 및 -판정 모델 실행 시간은 벤치마크 분석을 위해 보고서에 기록되지만, -판정 프롬프트에는 속도로 순위를 매기지 말라고 명시되어 있습니다. -후보 및 판정 모델 실행은 둘 다 기본 동시성 16을 사용합니다. 제공자 제한 또는 로컬 Gateway -부하로 인해 실행 결과에 노이즈가 너무 많다면 `--concurrency` 또는 `--judge-concurrency`를 낮추세요. -후보 `--model`이 전달되지 않으면, 캐릭터 평가는 기본적으로 -`openai/gpt-5.4`, `openai/gpt-5.2`, `openai/gpt-5`, `anthropic/claude-opus-4-6`, -`anthropic/claude-sonnet-4-6`, `zai/glm-5.1`, -`moonshot/kimi-k2.5`, 그리고 -`google/gemini-3.1-pro-preview`를 사용합니다. -판정 `--judge-model`이 전달되지 않으면, 판정자는 기본적으로 -`openai/gpt-5.4,thinking=xhigh,fast` 및 -`anthropic/claude-opus-4-6,thinking=high`를 사용합니다. +이 명령은 Docker가 아니라 로컬 QA 게이트웨이 자식 프로세스를 실행합니다. 캐릭터 평가 시나리오는 `SOUL.md`를 통해 페르소나를 설정한 뒤, 채팅, 워크스페이스 도움말, 작은 파일 작업 같은 일반 사용자 턴을 실행해야 합니다. 후보 모델에는 자신이 평가 중이라는 사실을 알려서는 안 됩니다. 이 명령은 각 전체 대화 내용을 보존하고, 기본 실행 통계를 기록한 뒤, 자연스러움, 분위기, 유머를 기준으로 실행 결과의 순위를 매기도록 빠른 모드의 심사 모델에 `xhigh` 추론과 함께 요청합니다. +provider를 비교할 때는 `--blind-judge-models`를 사용하세요. 이 경우 심사 프롬프트는 여전히 모든 대화 내용과 실행 상태를 받지만, 후보 ref는 `candidate-01` 같은 중립적인 레이블로 대체됩니다. 보고서는 파싱 후 순위를 실제 ref에 다시 매핑합니다. +후보 실행은 기본적으로 `high` 사고 수준을 사용하며, 이를 지원하는 OpenAI 모델은 `xhigh`를 사용합니다. 특정 후보를 개별적으로 재정의하려면 `--model provider/model,thinking=`을 사용하세요. `--thinking `은 여전히 전역 폴백을 설정하며, 이전의 `--model-thinking ` 형식도 호환성을 위해 유지됩니다. +OpenAI 후보 ref는 provider가 이를 지원하는 경우 우선 처리에 빠른 모드를 기본 적용합니다. 특정 후보나 심사자에 대해 재정의가 필요하면 `,fast`, `,no-fast`, 또는 `,fast=false`를 인라인으로 추가하세요. 모든 후보 모델에 빠른 모드를 강제로 켜고 싶을 때만 `--fast`를 전달하세요. 후보와 심사자의 실행 시간은 벤치마크 분석을 위해 보고서에 기록되지만, 심사 프롬프트에는 속도로 순위를 매기지 말라고 명시되어 있습니다. +후보와 심사 모델 실행은 모두 기본적으로 동시성 16을 사용합니다. provider 제한이나 로컬 게이트웨이 부하 때문에 실행이 너무 불안정해지면 `--concurrency` 또는 `--judge-concurrency`를 낮추세요. +후보 `--model`이 전달되지 않으면, 캐릭터 평가는 기본적으로 `openai/gpt-5.4`, `openai/gpt-5.2`, `openai/gpt-5`, `anthropic/claude-opus-4-6`, `anthropic/claude-sonnet-4-6`, `zai/glm-5.1`, `moonshot/kimi-k2.5`, `google/gemini-3.1-pro-preview`를 사용합니다. +심사 `--judge-model`이 전달되지 않으면, 기본 심사자는 `openai/gpt-5.4,thinking=xhigh,fast`와 `anthropic/claude-opus-4-6,thinking=high`입니다. ## 관련 문서 -- [테스트](/ko/help/testing) +- [테스팅](/ko/help/testing) - [QA Channel](/ko/channels/qa-channel) - [대시보드](/web/dashboard) diff --git a/docs/ko/gateway/cli-backends.md b/docs/ko/gateway/cli-backends.md index 5d1a7e715..44405e50a 100644 --- a/docs/ko/gateway/cli-backends.md +++ b/docs/ko/gateway/cli-backends.md @@ -1,41 +1,44 @@ --- read_when: - - API 제공자가 실패할 때 안정적인 폴백이 필요합니다 + - API 제공자가 실패할 때를 대비해 신뢰할 수 있는 폴백이 필요합니다 - Codex CLI 또는 다른 로컬 AI CLI를 실행 중이며 이를 재사용하고 싶습니다 - CLI 백엔드 도구 액세스를 위한 MCP 루프백 브리지를 이해하고 싶습니다 -summary: 'CLI 백엔드: 선택적 MCP 도구 브리지와 함께 사용하는 로컬 AI CLI 폴백' +summary: 'CLI 백엔드: 선택적 MCP 도구 브리지를 포함한 로컬 AI CLI 폴백' title: CLI 백엔드 x-i18n: - generated_at: "2026-04-09T01:28:04Z" + generated_at: "2026-04-11T02:44:21Z" model: gpt-5.4 provider: openai - source_hash: 9b458f9fe6fa64c47864c8c180f3dedfd35c5647de470a2a4d31c26165663c20 + source_hash: d108dbea043c260a80d15497639298f71a6b4d800f68d7b39bc129f7667ca608 source_path: gateway/cli-backends.md workflow: 15 --- # CLI 백엔드(폴백 런타임) -OpenClaw는 API 제공자가 중단되거나, 속도 제한에 걸리거나, 일시적으로 오작동할 때 **텍스트 전용 폴백**으로 **로컬 AI CLI**를 실행할 수 있습니다. 이는 의도적으로 보수적으로 설계되었습니다. +OpenClaw는 API 제공자가 다운되었거나, 속도 제한에 걸렸거나, 일시적으로 오작동할 때 **텍스트 전용 폴백**으로 **로컬 AI CLI**를 실행할 수 있습니다. +이 동작은 의도적으로 보수적으로 설계되었습니다. -- **OpenClaw 도구는 직접 주입되지 않지만**, `bundleMcp: true`가 설정된 백엔드는 루프백 MCP 브리지를 통해 게이트웨이 도구를 받을 수 있습니다. +- **OpenClaw 도구는 직접 주입되지 않지만**, `bundleMcp: true`인 백엔드는 루프백 MCP 브리지를 통해 게이트웨이 도구를 받을 수 있습니다. - 이를 지원하는 CLI를 위한 **JSONL 스트리밍** - **세션 지원**(후속 턴의 일관성 유지) -- CLI가 이미지 경로를 허용하면 **이미지 전달 가능** +- CLI가 이미지 경로를 받아들일 수 있다면 **이미지 전달 가능** -이는 기본 경로라기보다 **안전망**으로 설계되었습니다. 외부 API에 의존하지 않고 “항상 동작하는” 텍스트 응답이 필요할 때 사용하세요. +이 기능은 기본 경로라기보다 **안전망**으로 설계되었습니다. 외부 API에 의존하지 않으면서도 “항상 동작하는” 텍스트 응답이 필요할 때 사용하세요. -ACP 세션 제어, 백그라운드 작업, 스레드/대화 바인딩, 영구적인 외부 코딩 세션을 포함한 전체 하네스 런타임이 필요하다면 대신 [ACP Agents](/ko/tools/acp-agents)를 사용하세요. CLI 백엔드는 ACP가 아닙니다. +ACP 세션 제어, 백그라운드 작업, 스레드/대화 바인딩, 영속적인 외부 코딩 세션을 포함한 전체 하니스 런타임이 필요하다면 +[ACP Agents](/ko/tools/acp-agents)를 사용하세요. CLI 백엔드는 ACP가 아닙니다. -## 초보자용 빠른 시작 +## 초보자를 위한 빠른 시작 -Codex CLI는 **아무 설정 없이도** 사용할 수 있습니다(번들 OpenAI plugin이 기본 백엔드를 등록합니다). +Codex CLI는 **설정 없이도** 사용할 수 있습니다(번들된 OpenAI 플러그인이 기본 백엔드를 등록합니다). ```bash openclaw agent --message "hi" --model codex-cli/gpt-5.4 ``` -게이트웨이가 launchd/systemd 아래에서 실행되고 PATH가 최소화되어 있다면 명령 경로만 추가하세요. +게이트웨이가 launchd/systemd 아래에서 실행되고 PATH가 최소화되어 있다면, +명령 경로만 추가하면 됩니다. ```json5 { @@ -51,9 +54,12 @@ openclaw agent --message "hi" --model codex-cli/gpt-5.4 } ``` -이것으로 충분합니다. CLI 자체 외에는 키도, 추가 인증 설정도 필요하지 않습니다. +이게 전부입니다. CLI 자체 외에는 키도, 추가 인증 설정도 필요하지 않습니다. -번들 CLI 백엔드를 게이트웨이 호스트의 **기본 메시지 제공자**로 사용하는 경우, 이제 OpenClaw는 구성에서 모델 ref 또는 `agents.defaults.cliBackends` 아래에 해당 백엔드를 명시적으로 참조하면 소유 번들 plugin을 자동으로 로드합니다. +번들된 CLI 백엔드를 게이트웨이 호스트에서 **기본 메시지 제공자**로 사용하는 경우, OpenClaw는 이제 +구성에서 모델 ref 또는 +`agents.defaults.cliBackends` 아래에서 해당 백엔드를 명시적으로 참조하면 +해당 번들 플러그인을 자동으로 로드합니다. ## 폴백으로 사용하기 @@ -79,7 +85,8 @@ CLI 백엔드를 폴백 목록에 추가하면 기본 모델이 실패할 때만 참고: - `agents.defaults.models`(허용 목록)를 사용하는 경우, CLI 백엔드 모델도 여기에 포함해야 합니다. -- 기본 제공자가 실패하면(auth, 속도 제한, 시간 초과) OpenClaw가 다음으로 CLI 백엔드를 시도합니다. +- 기본 제공자가 실패하면(인증, 속도 제한, 타임아웃), OpenClaw는 + 다음으로 CLI 백엔드를 시도합니다. ## 구성 개요 @@ -96,7 +103,7 @@ provider id는 모델 ref의 왼쪽 부분이 됩니다. / ``` -### 예시 구성 +### 구성 예시 ```json5 { @@ -137,60 +144,80 @@ provider id는 모델 ref의 왼쪽 부분이 됩니다. ## 작동 방식 1. provider 접두사(`codex-cli/...`)를 기준으로 **백엔드를 선택**합니다. -2. 동일한 OpenClaw 프롬프트 + 워크스페이스 컨텍스트를 사용해 **시스템 프롬프트를 구성**합니다. -3. 기록의 일관성을 유지하기 위해 지원되는 경우 세션 id와 함께 **CLI를 실행**합니다. +2. 동일한 OpenClaw 프롬프트 + 작업공간 컨텍스트를 사용해 **시스템 프롬프트를 구성**합니다. +3. 기록의 일관성을 유지하기 위해 세션 id(지원되는 경우)와 함께 **CLI를 실행**합니다. 4. **출력을 파싱**(JSON 또는 일반 텍스트)하고 최종 텍스트를 반환합니다. -5. **백엔드별로 세션 id를 유지**하여 후속 요청에서 동일한 CLI 세션을 재사용합니다. +5. 백엔드별로 **세션 id를 저장**하여 후속 요청에서 동일한 CLI 세션을 재사용합니다. -번들 Anthropic `claude-cli` 백엔드가 다시 지원됩니다. Anthropic 직원이 OpenClaw 스타일 Claude CLI 사용이 다시 허용된다고 알려주었으므로, Anthropic이 새로운 정책을 발표하지 않는 한 OpenClaw는 이 통합에 대해 `claude -p` 사용을 허용된 것으로 간주합니다. +번들된 Anthropic `claude-cli` 백엔드가 다시 지원됩니다. Anthropic 직원이 +OpenClaw 스타일 Claude CLI 사용이 다시 허용된다고 알려주었으므로, Anthropic이 +새 정책을 발표하지 않는 한 OpenClaw는 이 통합에 대해 +`claude -p` 사용을 허용된 것으로 간주합니다. -번들 OpenAI `codex-cli` 백엔드는 OpenClaw의 시스템 프롬프트를 Codex의 `model_instructions_file` 구성 재정의(`-c -model_instructions_file="..."`)를 통해 전달합니다. Codex는 Claude 스타일 `--append-system-prompt` 플래그를 제공하지 않으므로, OpenClaw는 새 Codex CLI 세션마다 조합된 프롬프트를 임시 파일에 기록합니다. +번들된 OpenAI `codex-cli` 백엔드는 OpenClaw의 시스템 프롬프트를 +Codex의 `model_instructions_file` 구성 오버라이드(`-c +model_instructions_file="..."`)를 통해 전달합니다. Codex는 Claude 스타일의 +`--append-system-prompt` 플래그를 제공하지 않으므로, OpenClaw는 새 Codex CLI 세션마다 +조합된 프롬프트를 임시 파일에 씁니다. + +번들된 Anthropic `claude-cli` 백엔드는 OpenClaw Skills 스냅샷을 +두 가지 방식으로 받습니다. 하나는 추가된 시스템 프롬프트 안의 간결한 OpenClaw Skills 카탈로그이고, +다른 하나는 `--plugin-dir`로 전달되는 임시 Claude Code 플러그인입니다. +이 플러그인에는 해당 에이전트/세션에 적합한 Skills만 포함되므로, Claude Code의 네이티브 스킬 +해결기는 OpenClaw가 프롬프트에서 알렸을 것과 동일하게 필터링된 집합을 보게 됩니다. +Skill env/API 키 오버라이드는 여전히 실행 시 OpenClaw가 자식 프로세스 환경에 적용합니다. ## 세션 -- CLI가 세션을 지원하면 `sessionArg`(예: `--session-id`) 또는 여러 플래그에 ID를 삽입해야 할 때 `sessionArgs`(플레이스홀더 `{sessionId}`)를 설정하세요. -- CLI가 다른 플래그를 사용하는 **재개 서브커맨드**를 사용한다면 `resumeArgs`(`args`를 대체)를 설정하고, 선택적으로 `resumeOutput`(JSON이 아닌 재개용)을 설정하세요. +- CLI가 세션을 지원하는 경우, `sessionArg`(예: `--session-id`) 또는 + id를 여러 플래그에 삽입해야 할 때 `sessionArgs`(플레이스홀더 `{sessionId}`)를 설정하세요. +- CLI가 다른 플래그를 가진 **resume 하위 명령**을 사용하는 경우, + `resumeArgs`(`args`를 대체)를 설정하고 필요하면 `resumeOutput` + (JSON이 아닌 재개용 출력)도 설정하세요. - `sessionMode`: - - `always`: 항상 세션 id를 보냅니다(저장된 값이 없으면 새 UUID 생성). + - `always`: 항상 세션 id를 보냅니다(저장된 값이 없으면 새 UUID). - `existing`: 이전에 저장된 세션 id가 있을 때만 보냅니다. - `none`: 세션 id를 절대 보내지 않습니다. -직렬화 참고: +직렬화 관련 참고: -- `serialize: true`는 동일한 레인에서의 실행 순서를 유지합니다. +- `serialize: true`는 동일 레인 실행의 순서를 유지합니다. - 대부분의 CLI는 하나의 provider 레인에서 직렬화됩니다. -- OpenClaw는 백엔드 인증 상태가 변경되면 저장된 CLI 세션 재사용을 중단합니다. 여기에는 재로그인, 토큰 교체, 인증 프로필 자격 증명 변경이 포함됩니다. +- OpenClaw는 백엔드 인증 상태가 변경되면 저장된 CLI 세션 재사용을 해제합니다. 여기에는 재로그인, 토큰 교체, 인증 프로필 자격 증명 변경이 포함됩니다. -## 이미지(전달) +## 이미지(패스스루) -CLI가 이미지 경로를 허용하면 `imageArg`를 설정하세요. +CLI가 이미지 경로를 받아들일 수 있다면 `imageArg`를 설정하세요. ```json5 imageArg: "--image", imageMode: "repeat" ``` -OpenClaw는 base64 이미지를 임시 파일에 기록합니다. `imageArg`가 설정되어 있으면 해당 경로가 CLI 인수로 전달됩니다. `imageArg`가 없으면 OpenClaw는 파일 경로를 프롬프트에 추가합니다(경로 주입). 이는 일반 경로에서 로컬 파일을 자동 로드하는 CLI에는 충분합니다. +OpenClaw는 base64 이미지를 임시 파일로 씁니다. `imageArg`가 설정되어 있으면 해당 +경로가 CLI 인수로 전달됩니다. `imageArg`가 없으면 OpenClaw는 파일 경로를 프롬프트에 추가합니다(경로 주입). 이는 +일반 경로에서 로컬 파일을 자동으로 로드하는 CLI에는 충분합니다. ## 입력 / 출력 -- `output: "json"`(기본값)은 JSON을 파싱하고 텍스트 + 세션 id를 추출하려고 시도합니다. -- Gemini CLI JSON 출력의 경우 `usage`가 없거나 비어 있으면 OpenClaw는 `response`에서 응답 텍스트를, `stats`에서 사용량을 읽습니다. -- `output: "jsonl"`은 JSONL 스트림(예: Codex CLI `--json`)을 파싱하고 존재할 경우 최종 에이전트 메시지와 세션 식별자를 추출합니다. -- `output: "text"`는 stdout을 최종 응답으로 처리합니다. +- `output: "json"`(기본값)은 JSON을 파싱해 텍스트와 세션 id를 추출하려고 시도합니다. +- Gemini CLI JSON 출력의 경우, `usage`가 없거나 비어 있으면 OpenClaw는 + `response`에서 응답 텍스트를, `stats`에서 사용량을 읽습니다. +- `output: "jsonl"`은 JSONL 스트림(예: Codex CLI `--json`)을 파싱하고, 존재할 경우 최종 에이전트 메시지와 세션 + 식별자를 추출합니다. +- `output: "text"`는 stdout을 최종 응답으로 취급합니다. 입력 모드: - `input: "arg"`(기본값)는 프롬프트를 마지막 CLI 인수로 전달합니다. -- `input: "stdin"`은 stdin을 통해 프롬프트를 보냅니다. +- `input: "stdin"`은 프롬프트를 stdin으로 보냅니다. - 프롬프트가 매우 길고 `maxPromptArgChars`가 설정되어 있으면 stdin이 사용됩니다. -## 기본값(plugin 소유) +## 기본값(플러그인 소유) -번들 OpenAI plugin도 `codex-cli`에 대한 기본값을 등록합니다. +번들된 OpenAI 플러그인은 `codex-cli`에 대한 기본값도 등록합니다. - `command: "codex"` - `args: ["exec","--json","--color","never","--sandbox","workspace-write","--skip-git-repo-check"]` @@ -201,7 +228,7 @@ OpenClaw는 base64 이미지를 임시 파일에 기록합니다. `imageArg`가 - `imageArg: "--image"` - `sessionMode: "existing"` -번들 Google plugin도 `google-gemini-cli`에 대한 기본값을 등록합니다. +번들된 Google 플러그인은 `google-gemini-cli`에 대한 기본값도 등록합니다. - `command: "gemini"` - `args: ["--output-format", "json", "--prompt", "{prompt}"]` @@ -212,57 +239,93 @@ OpenClaw는 base64 이미지를 임시 파일에 기록합니다. `imageArg`가 - `sessionMode: "existing"` - `sessionIdFields: ["session_id", "sessionId"]` -전제 조건: 로컬 Gemini CLI가 설치되어 있어야 하며 `PATH`에서 `gemini`로 사용할 수 있어야 합니다(`brew install gemini-cli` 또는 `npm install -g @google/gemini-cli`). +사전 요구 사항: 로컬 Gemini CLI가 설치되어 있어야 하며 +`PATH`에서 `gemini`로 사용할 수 있어야 합니다(`brew install gemini-cli` 또는 +`npm install -g @google/gemini-cli`). Gemini CLI JSON 참고: - 응답 텍스트는 JSON `response` 필드에서 읽습니다. -- `usage`가 없거나 비어 있으면 사용량은 `stats`로 폴백합니다. +- 사용량은 `usage`가 없거나 비어 있으면 `stats`를 대체값으로 사용합니다. - `stats.cached`는 OpenClaw `cacheRead`로 정규화됩니다. -- `stats.input`이 없으면 OpenClaw는 `stats.input_tokens - stats.cached`에서 입력 토큰 수를 계산합니다. +- `stats.input`이 없으면 OpenClaw는 + `stats.input_tokens - stats.cached`에서 입력 토큰 수를 계산합니다. 필요한 경우에만 재정의하세요(일반적으로는 절대 `command` 경로). -## plugin 소유 기본값 +## 플러그인 소유 기본값 -CLI 백엔드 기본값은 이제 plugin 표면의 일부입니다. +CLI 백엔드 기본값은 이제 플러그인 표면의 일부입니다. -- plugin은 `api.registerCliBackend(...)`로 이를 등록합니다. -- 백엔드 `id`는 모델 ref의 provider 접두사가 됩니다. -- `agents.defaults.cliBackends.`의 사용자 구성은 여전히 plugin 기본값을 재정의합니다. -- 백엔드별 구성 정리는 선택적 `normalizeConfig` 훅을 통해 계속 plugin 소유로 유지됩니다. +- 플러그인은 `api.registerCliBackend(...)`로 이를 등록합니다. +- 백엔드 `id`는 모델 ref에서 provider 접두사가 됩니다. +- `agents.defaults.cliBackends.`의 사용자 구성은 여전히 플러그인 기본값을 재정의합니다. +- 백엔드별 구성 정리는 선택적 + `normalizeConfig` 훅을 통해 계속 플러그인 소유로 유지됩니다. + +작은 프롬프트/메시지 호환성 shim이 필요한 플러그인은 provider나 CLI 백엔드를 교체하지 않고도 +양방향 텍스트 변환을 선언할 수 있습니다. + +```typescript +api.registerTextTransforms({ + input: [ + { from: /red basket/g, to: "blue basket" }, + { from: /paper ticket/g, to: "digital ticket" }, + { from: /left shelf/g, to: "right shelf" }, + ], + output: [ + { from: /blue basket/g, to: "red basket" }, + { from: /digital ticket/g, to: "paper ticket" }, + { from: /right shelf/g, to: "left shelf" }, + ], +}); +``` + +`input`은 CLI에 전달되는 시스템 프롬프트와 사용자 프롬프트를 다시 씁니다. `output`은 +OpenClaw가 자체 제어 마커 및 채널 전달을 처리하기 전에 +스트리밍된 어시스턴트 델타와 파싱된 최종 텍스트를 다시 씁니다. + +Claude Code stream-json 호환 JSONL을 출력하는 CLI의 경우, +해당 백엔드 구성에 `jsonlDialect: "claude-stream-json"`을 설정하세요. ## 번들 MCP 오버레이 -CLI 백엔드는 **OpenClaw 도구 호출을 직접 받지 않지만**, 백엔드는 `bundleMcp: true`로 생성된 MCP 구성 오버레이 사용을 선택할 수 있습니다. +CLI 백엔드는 OpenClaw 도구 호출을 **직접** 받지 않지만, 백엔드는 +`bundleMcp: true`로 생성된 MCP 구성 오버레이를 선택적으로 사용할 수 있습니다. 현재 번들 동작: - `claude-cli`: 생성된 strict MCP 구성 파일 -- `codex-cli`: `mcp_servers`에 대한 인라인 구성 재정의 +- `codex-cli`: `mcp_servers`용 인라인 구성 오버라이드 - `google-gemini-cli`: 생성된 Gemini 시스템 설정 파일 bundle MCP가 활성화되면 OpenClaw는 다음을 수행합니다. -- 게이트웨이 도구를 CLI 프로세스에 노출하는 루프백 HTTP MCP 서버를 시작합니다. +- CLI 프로세스에 게이트웨이 도구를 노출하는 루프백 HTTP MCP 서버를 시작합니다. - 세션별 토큰(`OPENCLAW_MCP_TOKEN`)으로 브리지를 인증합니다. - 현재 세션, 계정, 채널 컨텍스트로 도구 액세스 범위를 제한합니다. -- 현재 워크스페이스에서 활성화된 bundle-MCP 서버를 로드합니다. -- 이를 기존 백엔드 MCP 구성/설정 형태와 병합합니다. -- 소유 확장의 백엔드 소유 통합 모드를 사용해 시작 구성을 다시 작성합니다. +- 현재 작업공간에 대해 활성화된 bundle-MCP 서버를 로드합니다. +- 기존 백엔드 MCP 구성/설정 형태와 병합합니다. +- 소유 확장의 백엔드 소유 통합 모드를 사용해 실행 구성을 다시 씁니다. -활성화된 MCP 서버가 없더라도, 백엔드가 bundle MCP 사용을 선택한 경우 OpenClaw는 백그라운드 실행이 격리된 상태를 유지하도록 strict 구성을 계속 주입합니다. +활성화된 MCP 서버가 없더라도, 백엔드가 bundle MCP를 선택한 경우 +백그라운드 실행이 격리된 상태를 유지하도록 OpenClaw는 여전히 strict 구성을 주입합니다. ## 제한 사항 -- **직접 OpenClaw 도구 호출 없음.** OpenClaw는 CLI 백엔드 프로토콜에 도구 호출을 주입하지 않습니다. 백엔드는 `bundleMcp: true`를 선택한 경우에만 게이트웨이 도구를 볼 수 있습니다. -- **스트리밍은 백엔드별입니다.** 일부 백엔드는 JSONL을 스트리밍하고, 다른 백엔드는 종료 시까지 버퍼링합니다. +- **직접적인 OpenClaw 도구 호출은 없습니다.** OpenClaw는 CLI 백엔드 프로토콜에 + 도구 호출을 주입하지 않습니다. 백엔드는 `bundleMcp: true`를 선택한 경우에만 + 게이트웨이 도구를 볼 수 있습니다. +- **스트리밍은 백엔드별입니다.** 일부 백엔드는 JSONL을 스트리밍하고, 다른 백엔드는 + 종료될 때까지 버퍼링합니다. - **구조화된 출력**은 CLI의 JSON 형식에 따라 달라집니다. -- **Codex CLI 세션**은 텍스트 출력(JSONL 아님)으로 재개되므로 초기 `--json` 실행보다 구조가 덜 엄격합니다. OpenClaw 세션 자체는 여전히 정상적으로 동작합니다. +- **Codex CLI 세션**은 텍스트 출력으로 재개됩니다(JSONL 없음). 따라서 구조화 수준이 + 초기 `--json` 실행보다 낮습니다. OpenClaw 세션 자체는 여전히 정상적으로 동작합니다. ## 문제 해결 - **CLI를 찾을 수 없음**: `command`를 전체 경로로 설정하세요. - **잘못된 모델 이름**: `modelAliases`를 사용해 `provider/model` → CLI 모델로 매핑하세요. -- **세션 연속성 없음**: `sessionArg`가 설정되어 있고 `sessionMode`가 `none`이 아닌지 확인하세요(Codex CLI는 현재 JSON 출력으로 재개할 수 없음). +- **세션 연속성 없음**: `sessionArg`가 설정되어 있고 `sessionMode`가 + `none`이 아닌지 확인하세요(Codex CLI는 현재 JSON 출력으로 재개할 수 없습니다). - **이미지가 무시됨**: `imageArg`를 설정하고(CLI가 파일 경로를 지원하는지도 확인하세요). diff --git a/docs/ko/gateway/configuration-reference.md b/docs/ko/gateway/configuration-reference.md index a28c1433d..325e08308 100644 --- a/docs/ko/gateway/configuration-reference.md +++ b/docs/ko/gateway/configuration-reference.md @@ -1,35 +1,35 @@ --- read_when: - - 정확한 필드 수준의 구성 의미 또는 기본값이 필요합니다 + - 정확한 필드 수준의 구성 의미나 기본값이 필요합니다 - 채널, 모델, 게이트웨이 또는 도구 구성 블록을 검증하고 있습니다 -summary: 핵심 OpenClaw 키, 기본값, 그리고 전용 하위 시스템 참조 링크를 위한 Gateway 구성 참조 +summary: 핵심 OpenClaw 키, 기본값, 그리고 전용 하위 시스템 참조로의 링크를 위한 Gateway 구성 참조 title: 구성 참조 x-i18n: - generated_at: "2026-04-10T05:59:56Z" + generated_at: "2026-04-11T02:44:20Z" model: gpt-5.4 provider: openai - source_hash: c6aa34e3a9096c4dabef26b9cdfda4bd7693e16da43a88c1641cfad8ba1ec237 + source_hash: 32acb82e756e4740d13ef12277842081f4c90df7b67850c34f8a76701fcd37d0 source_path: gateway/configuration-reference.md workflow: 15 --- # 구성 참조 -`~/.openclaw/openclaw.json`용 핵심 구성 참조입니다. 작업 중심 개요는 [구성](/ko/gateway/configuration)을 참조하세요. +`~/.openclaw/openclaw.json`용 핵심 구성 참조입니다. 작업 중심 개요는 [Configuration](/ko/gateway/configuration)을 참고하세요. -이 페이지는 OpenClaw의 주요 구성 표면을 다루며, 하위 시스템에 더 깊은 자체 참조 문서가 있는 경우 해당 문서로 연결합니다. 이 페이지는 모든 채널/플러그인 소유 명령 카탈로그나 모든 심층 메모리/QMD 조정 항목을 한 페이지에 인라인으로 담으려는 목적이 **아닙니다**. +이 페이지는 OpenClaw의 주요 구성 표면을 다루며, 하위 시스템에 자체적인 더 깊은 참조가 있는 경우 해당 링크를 제공합니다. 이 페이지는 모든 채널/플러그인 소유 명령 카탈로그나 모든 심층 메모리/QMD 조절 항목을 한 페이지에 인라인으로 담으려 하지 않습니다. -코드 기준 진실: +코드 기준 원본: -- `openclaw config schema`는 검증과 Control UI에 사용되는 현재 JSON 스키마를 출력하며, 사용 가능한 경우 번들/플러그인/채널 메타데이터가 병합됩니다 +- `openclaw config schema`는 검증과 Control UI에 사용되는 현재 JSON Schema를 출력하며, 사용 가능한 경우 번들/플러그인/채널 메타데이터가 병합되어 포함됩니다 - `config.schema.lookup`은 드릴다운 도구용으로 경로 범위가 지정된 단일 스키마 노드를 반환합니다 -- `pnpm config:docs:check` / `pnpm config:docs:gen`은 현재 스키마 표면에 대해 구성 문서 기준 해시를 검증합니다 +- `pnpm config:docs:check` / `pnpm config:docs:gen`은 현재 스키마 표면에 대해 config-doc 기준선 해시를 검증합니다 -전용 심화 참조: +전용 심층 참조: -- `agents.defaults.memorySearch.*`, `memory.qmd.*`, `memory.citations`, 그리고 `plugins.entries.memory-core.config.dreaming` 아래의 dreaming 구성을 위한 [메모리 구성 참조](/ko/reference/memory-config) -- 현재 기본 제공 + 번들 명령 카탈로그를 위한 [슬래시 명령어](/ko/tools/slash-commands) -- 채널별 명령 표면을 위한 해당 채널/플러그인 페이지 +- `agents.defaults.memorySearch.*`, `memory.qmd.*`, `memory.citations`, 그리고 `plugins.entries.memory-core.config.dreaming` 아래의 dreaming 구성은 [Memory configuration reference](/ko/reference/memory-config)를 참고하세요 +- 현재 내장 + 번들 명령 카탈로그는 [Slash Commands](/ko/tools/slash-commands)를 참고하세요 +- 채널별 명령 표면은 해당 채널/플러그인 페이지를 참고하세요 구성 형식은 **JSON5**입니다(주석 + 후행 쉼표 허용). 모든 필드는 선택 사항이며, 생략하면 OpenClaw가 안전한 기본값을 사용합니다. @@ -41,30 +41,30 @@ x-i18n: ### DM 및 그룹 접근 -모든 채널은 DM 정책과 그룹 정책을 지원합니다. +모든 채널은 DM 정책과 그룹 정책을 지원합니다: -| DM 정책 | 동작 | -| ------------------- | -------------------------------------------------------------- | -| `pairing` (기본값) | 알 수 없는 발신자는 1회용 페어링 코드를 받으며, 소유자가 승인해야 함 | -| `allowlist` | `allowFrom`(또는 페어링된 허용 저장소)에 있는 발신자만 허용 | -| `open` | 모든 수신 DM 허용(`allowFrom: ["*"]` 필요) | -| `disabled` | 모든 수신 DM 무시 | +| DM 정책 | 동작 | +| ------------------- | --------------------------------------------------------------- | +| `pairing` (기본값) | 알 수 없는 발신자는 일회성 페어링 코드를 받으며, 소유자가 승인해야 합니다 | +| `allowlist` | `allowFrom`(또는 페어링된 허용 저장소)에 있는 발신자만 허용합니다 | +| `open` | 모든 수신 DM을 허용합니다(`allowFrom: ["*"]` 필요) | +| `disabled` | 모든 수신 DM을 무시합니다 | -| 그룹 정책 | 동작 | -| ---------------------- | -------------------------------------------------------- | -| `allowlist` (기본값) | 구성된 허용 목록과 일치하는 그룹만 허용 | -| `open` | 그룹 허용 목록 우회(멘션 게이팅은 계속 적용됨) | -| `disabled` | 모든 그룹/룸 메시지 차단 | +| 그룹 정책 | 동작 | +| --------------------- | -------------------------------------------------------- | +| `allowlist` (기본값) | 구성된 허용 목록과 일치하는 그룹만 허용합니다 | +| `open` | 그룹 허용 목록을 우회합니다(멘션 게이팅은 계속 적용됨) | +| `disabled` | 모든 그룹/룸 메시지를 차단합니다 | `channels.defaults.groupPolicy`는 제공자의 `groupPolicy`가 설정되지 않았을 때 기본값을 설정합니다. 페어링 코드는 1시간 후 만료됩니다. 대기 중인 DM 페어링 요청은 **채널당 3개**로 제한됩니다. -제공자 블록이 완전히 없으면(`channels.` 없음), 런타임 그룹 정책은 시작 시 경고와 함께 `allowlist`(실패 시 닫힘)로 대체됩니다. +제공자 블록이 완전히 누락된 경우(`channels.` 없음), 런타임 그룹 정책은 시작 경고와 함께 `allowlist`(기본 차단)로 대체됩니다. ### 채널 모델 재정의 -특정 채널 ID를 모델에 고정하려면 `channels.modelByChannel`을 사용하세요. 값은 `provider/model` 또는 구성된 모델 별칭을 허용합니다. 채널 매핑은 세션에 이미 모델 재정의가 없는 경우에 적용됩니다(예: `/model`로 설정한 경우). +특정 채널 ID를 모델에 고정하려면 `channels.modelByChannel`을 사용하세요. 값은 `provider/model` 또는 구성된 모델 별칭을 허용합니다. 이 채널 매핑은 세션에 이미 모델 재정의가 없는 경우(예: `/model`로 설정된 경우)에 적용됩니다. ```json5 { @@ -87,7 +87,7 @@ x-i18n: ### 채널 기본값 및 하트비트 -제공자 간에 공유되는 그룹 정책 및 하트비트 동작에는 `channels.defaults`를 사용하세요. +제공자 간에 공유되는 그룹 정책 및 하트비트 동작에는 `channels.defaults`를 사용하세요: ```json5 { @@ -105,11 +105,11 @@ x-i18n: } ``` -- `channels.defaults.groupPolicy`: 제공자 수준 `groupPolicy`가 설정되지 않았을 때의 대체 그룹 정책입니다. -- `channels.defaults.contextVisibility`: 모든 채널의 기본 보조 컨텍스트 표시 모드입니다. 값: `all`(기본값, 모든 인용/스레드/기록 컨텍스트 포함), `allowlist`(허용 목록에 있는 발신자의 컨텍스트만 포함), `allowlist_quote`(allowlist와 동일하지만 명시적 인용/답글 컨텍스트는 유지). 채널별 재정의: `channels..contextVisibility`. +- `channels.defaults.groupPolicy`: 제공자 수준의 `groupPolicy`가 설정되지 않았을 때 대체 그룹 정책입니다. +- `channels.defaults.contextVisibility`: 모든 채널의 기본 보조 컨텍스트 표시 모드입니다. 값: `all`(기본값, 인용/스레드/기록 컨텍스트를 모두 포함), `allowlist`(허용 목록에 있는 발신자의 컨텍스트만 포함), `allowlist_quote`(allowlist와 동일하지만 명시적 인용/답글 컨텍스트는 유지). 채널별 재정의: `channels..contextVisibility`. - `channels.defaults.heartbeat.showOk`: 정상 채널 상태를 하트비트 출력에 포함합니다. -- `channels.defaults.heartbeat.showAlerts`: 성능 저하/오류 상태를 하트비트 출력에 포함합니다. -- `channels.defaults.heartbeat.useIndicator`: 간결한 표시기 스타일 하트비트 출력을 렌더링합니다. +- `channels.defaults.heartbeat.showAlerts`: 저하/오류 상태를 하트비트 출력에 포함합니다. +- `channels.defaults.heartbeat.useIndicator`: 간결한 인디케이터 스타일 하트비트 출력을 렌더링합니다. ### WhatsApp @@ -124,7 +124,7 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 textChunkLimit: 4000, chunkMode: "length", // length | newline mediaMaxMb: 50, - sendReadReceipts: true, // 파란 체크 표시(self-chat 모드에서는 false) + sendReadReceipts: true, // blue ticks (false in self-chat mode) groups: { "*": { requireMention: true }, }, @@ -164,8 +164,8 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 } ``` -- 발신 명령은 `default` 계정이 있으면 기본적으로 해당 계정을 사용하고, 없으면 첫 번째로 구성된 계정 ID(정렬된 순서)를 사용합니다. -- 선택적 `channels.whatsapp.defaultAccount`는 구성된 계정 ID와 일치할 때 그 대체 기본 계정 선택을 재정의합니다. +- 발신 명령은 `default` 계정이 있으면 기본적으로 해당 계정을 사용하고, 없으면 첫 번째로 구성된 계정 ID(정렬 순서 기준)를 사용합니다. +- 선택 사항인 `channels.whatsapp.defaultAccount`는 구성된 계정 ID와 일치할 때 이 대체 기본 계정 선택을 재정의합니다. - 레거시 단일 계정 Baileys 인증 디렉터리는 `openclaw doctor`에 의해 `whatsapp/default`로 마이그레이션됩니다. - 계정별 재정의: `channels.whatsapp.accounts..sendReadReceipts`, `channels.whatsapp.accounts..dmPolicy`, `channels.whatsapp.accounts..allowFrom`. @@ -202,7 +202,7 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 historyLimit: 50, replyToMode: "first", // off | first | all | batched linkPreview: true, - streaming: "partial", // off | partial | block | progress (기본값: off, 미리보기 편집 속도 제한을 피하려면 명시적으로 opt in) + streaming: "partial", // off | partial | block | progress (default: off; opt in explicitly to avoid preview-edit rate limits) actions: { reactions: true, sendMessage: true }, reactionNotifications: "own", // off | own | all mediaMaxMb: 100, @@ -225,13 +225,13 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 } ``` -- 봇 토큰: `channels.telegram.botToken` 또는 `channels.telegram.tokenFile`(일반 파일만 허용, 심볼릭 링크는 거부), 기본 계정의 대체값으로 `TELEGRAM_BOT_TOKEN` 사용 가능. -- 선택적 `channels.telegram.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. -- 다중 계정 설정(계정 ID 2개 이상)에서는 대체 라우팅을 피하기 위해 명시적인 기본값(`channels.telegram.defaultAccount` 또는 `channels.telegram.accounts.default`)을 설정하세요. 이것이 없거나 유효하지 않으면 `openclaw doctor`가 경고합니다. -- `configWrites: false`는 Telegram에서 시작된 구성 쓰기(supergroup ID 마이그레이션, `/config set|unset`)를 차단합니다. -- `type: "acp"`인 최상위 `bindings[]` 항목은 포럼 토픽용 영구 ACP 바인딩을 구성합니다(`match.peer.id`에는 정식 `chatId:topic:topicId` 사용). 필드 의미는 [ACP Agents](/ko/tools/acp-agents#channel-specific-settings)에서 공통으로 정의됩니다. -- Telegram 스트림 미리보기는 `sendMessage` + `editMessageText`를 사용합니다(직접 채팅과 그룹 채팅 모두에서 작동). -- 재시도 정책: [재시도 정책](/ko/concepts/retry)을 참조하세요. +- 봇 토큰: `channels.telegram.botToken` 또는 `channels.telegram.tokenFile`(일반 파일만 허용되며 심볼릭 링크는 거부됨), 기본 계정의 대체값으로 `TELEGRAM_BOT_TOKEN`을 사용할 수 있습니다. +- 선택 사항인 `channels.telegram.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- 다중 계정 설정(계정 ID 2개 이상)에서는 대체 라우팅을 피하기 위해 명시적 기본값(`channels.telegram.defaultAccount` 또는 `channels.telegram.accounts.default`)을 설정하세요. 이 값이 없거나 올바르지 않으면 `openclaw doctor`가 경고합니다. +- `configWrites: false`는 Telegram에서 시작된 구성 쓰기(슈퍼그룹 ID 마이그레이션, `/config set|unset`)를 차단합니다. +- `type: "acp"`인 최상위 `bindings[]` 항목은 포럼 주제용 영구 ACP 바인딩을 구성합니다(`match.peer.id`에는 정규 `chatId:topic:topicId`를 사용). 필드 의미는 [ACP Agents](/ko/tools/acp-agents#channel-specific-settings)와 공유됩니다. +- Telegram 스트림 미리보기는 `sendMessage` + `editMessageText`를 사용합니다(직접 채팅과 그룹 채팅 모두에서 동작). +- 재시도 정책: [Retry policy](/ko/concepts/retry)를 참고하세요. ### Discord @@ -286,7 +286,7 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 historyLimit: 20, textChunkLimit: 2000, chunkMode: "length", // length | newline - streaming: "off", // off | partial | block | progress (progress는 Discord에서 partial로 매핑됨) + streaming: "off", // off | partial | block | progress (progress maps to partial on Discord) maxLinesPerMessage: 17, ui: { components: { @@ -297,7 +297,7 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 enabled: true, idleHours: 24, maxAgeHours: 0, - spawnSubagentSessions: false, // sessions_spawn({ thread: true })에 대한 opt-in + spawnSubagentSessions: false, // opt-in for sessions_spawn({ thread: true }) }, voice: { enabled: true, @@ -333,36 +333,36 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 } ``` -- 토큰: `channels.discord.token`, 기본 계정의 대체값으로 `DISCORD_BOT_TOKEN` 사용 가능. +- 토큰: `channels.discord.token`, 기본 계정의 대체값으로 `DISCORD_BOT_TOKEN`을 사용할 수 있습니다. - 명시적인 Discord `token`을 제공하는 직접 발신 호출은 해당 호출에 그 토큰을 사용합니다. 계정 재시도/정책 설정은 여전히 활성 런타임 스냅샷에서 선택된 계정에서 가져옵니다. -- 선택적 `channels.discord.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. -- 전달 대상에는 `user:`(DM) 또는 `channel:`(길드 채널)를 사용하세요. 숫자 ID만 단독으로 쓰면 거부됩니다. -- 길드 슬러그는 소문자이며 공백은 `-`로 바뀝니다. 채널 키는 슬러그화된 이름을 사용합니다(`#` 없음). 길드 ID 사용을 권장합니다. -- 봇이 작성한 메시지는 기본적으로 무시됩니다. `allowBots: true`로 이를 활성화할 수 있으며, `allowBots: "mentions"`를 사용하면 봇을 멘션하는 봇 메시지만 수락합니다(자체 메시지는 여전히 필터링됨). -- `channels.discord.guilds..ignoreOtherMentions`(및 채널 재정의)는 봇은 멘션하지 않고 다른 사용자나 역할을 멘션한 메시지를 삭제합니다(`@everyone`/`@here` 제외). -- `maxLinesPerMessage`(기본값 17)는 메시지가 2000자 미만이어도 줄 수가 많으면 분할합니다. -- `channels.discord.threadBindings`는 Discord 스레드 바인딩 라우팅을 제어합니다. +- 선택 사항인 `channels.discord.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- 전달 대상에는 `user:`(DM) 또는 `channel:`(길드 채널)를 사용하세요. 숫자 ID만 단독으로 사용하는 형식은 거부됩니다. +- 길드 슬러그는 소문자이며 공백은 `-`로 대체됩니다. 채널 키는 슬러그 처리된 이름을 사용합니다(`#` 없음). 가능하면 길드 ID를 사용하는 것이 좋습니다. +- 봇이 작성한 메시지는 기본적으로 무시됩니다. `allowBots: true`로 이를 활성화할 수 있으며, `allowBots: "mentions"`를 사용하면 봇을 멘션한 봇 메시지만 허용됩니다(자기 자신의 메시지는 계속 필터링됨). +- `channels.discord.guilds..ignoreOtherMentions`(및 채널 재정의)는 다른 사용자나 역할을 멘션하지만 봇은 멘션하지 않은 메시지를 삭제합니다(`@everyone`/`@here` 제외). +- `maxLinesPerMessage`(기본값 17)는 2000자 미만이더라도 줄 수가 많은 메시지를 분할합니다. +- `channels.discord.threadBindings`는 Discord 스레드 바인딩 라우팅을 제어합니다: - `enabled`: 스레드 바인딩 세션 기능(`/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age`, 그리고 바인딩된 전달/라우팅)에 대한 Discord 재정의 - - `idleHours`: 비활성 자동 포커스 해제 시간(시간 단위)에 대한 Discord 재정의(`0`은 비활성화) - - `maxAgeHours`: 하드 최대 수명 시간(시간 단위)에 대한 Discord 재정의(`0`은 비활성화) - - `spawnSubagentSessions`: `sessions_spawn({ thread: true })` 자동 스레드 생성/바인딩에 대한 opt-in 스위치 -- `type: "acp"`인 최상위 `bindings[]` 항목은 채널과 스레드에 대한 영구 ACP 바인딩을 구성합니다(`match.peer.id`에 채널/스레드 ID 사용). 필드 의미는 [ACP Agents](/ko/tools/acp-agents#channel-specific-settings)에서 공통으로 정의됩니다. + - `idleHours`: 비활성 자동 언포커스 시간(시간 단위)에 대한 Discord 재정의(`0`이면 비활성화) + - `maxAgeHours`: 하드 최대 유지 시간(시간 단위)에 대한 Discord 재정의(`0`이면 비활성화) + - `spawnSubagentSessions`: `sessions_spawn({ thread: true })` 자동 스레드 생성/바인딩용 opt-in 스위치 +- `type: "acp"`인 최상위 `bindings[]` 항목은 채널과 스레드용 영구 ACP 바인딩을 구성합니다(`match.peer.id`에는 채널/스레드 id 사용). 필드 의미는 [ACP Agents](/ko/tools/acp-agents#channel-specific-settings)와 공유됩니다. - `channels.discord.ui.components.accentColor`는 Discord components v2 컨테이너의 강조 색상을 설정합니다. -- `channels.discord.voice`는 Discord 음성 채널 대화와 선택적 자동 참가 + TTS 재정의를 활성화합니다. -- `channels.discord.voice.daveEncryption` 및 `channels.discord.voice.decryptionFailureTolerance`는 `@discordjs/voice` DAVE 옵션에 그대로 전달됩니다(기본값은 각각 `true`와 `24`). -- OpenClaw는 또한 반복적인 복호화 실패 후 음성 세션을 나갔다가 다시 참가하여 음성 수신 복구를 시도합니다. -- `channels.discord.streaming`은 정식 스트림 모드 키입니다. 레거시 `streamMode` 및 불리언 `streaming` 값은 자동 마이그레이션됩니다. -- `channels.discord.autoPresence`는 런타임 가용성을 봇 상태에 매핑합니다(정상 => online, 성능 저하 => idle, 소진 => dnd). 선택적 상태 텍스트 재정의도 허용합니다. -- `channels.discord.dangerouslyAllowNameMatching`는 변경 가능한 이름/태그 매칭을 다시 활성화합니다(비상 호환성 모드). +- `channels.discord.voice`는 Discord 음성 채널 대화와 선택적 자동 참여 + TTS 재정의를 활성화합니다. +- `channels.discord.voice.daveEncryption` 및 `channels.discord.voice.decryptionFailureTolerance`는 `@discordjs/voice` DAVE 옵션으로 그대로 전달됩니다(기본값은 각각 `true`, `24`). +- OpenClaw는 추가로 반복적인 복호화 실패 후 음성 세션에서 나갔다가 다시 참여하여 음성 수신 복구를 시도합니다. +- `channels.discord.streaming`은 정식 스트림 모드 키입니다. 레거시 `streamMode` 및 불리언 `streaming` 값은 자동으로 마이그레이션됩니다. +- `channels.discord.autoPresence`는 런타임 가용성을 봇 상태로 매핑합니다(정상 => online, 저하 => idle, 고갈 => dnd). 선택적 상태 텍스트 재정의도 허용합니다. +- `channels.discord.dangerouslyAllowNameMatching`은 변경 가능한 이름/태그 매칭을 다시 활성화합니다(비상 호환성 모드). - `channels.discord.execApprovals`: Discord 네이티브 exec 승인 전달 및 승인자 권한 부여. - - `enabled`: `true`, `false`, 또는 `"auto"`(기본값). 자동 모드에서는 `approvers` 또는 `commands.ownerAllowFrom`에서 승인자를 확인할 수 있으면 exec 승인이 활성화됩니다. + - `enabled`: `true`, `false`, 또는 `"auto"`(기본값). auto 모드에서는 `approvers` 또는 `commands.ownerAllowFrom`에서 승인자를 확인할 수 있을 때 exec 승인이 활성화됩니다. - `approvers`: exec 요청을 승인할 수 있는 Discord 사용자 ID입니다. 생략하면 `commands.ownerAllowFrom`으로 대체됩니다. - - `agentFilter`: 선택적 에이전트 ID 허용 목록입니다. 생략하면 모든 에이전트의 승인을 전달합니다. + - `agentFilter`: 선택적 에이전트 ID 허용 목록입니다. 생략하면 모든 에이전트에 대한 승인을 전달합니다. - `sessionFilter`: 선택적 세션 키 패턴(부분 문자열 또는 정규식)입니다. - - `target`: 승인 프롬프트를 보낼 위치입니다. `"dm"`(기본값)은 승인자 DM으로 보내고, `"channel"`은 원래 채널로 보내며, `"both"`는 둘 다로 보냅니다. 대상에 `"channel"`이 포함되면 버튼은 확인된 승인자만 사용할 수 있습니다. + - `target`: 승인 프롬프트를 보낼 위치입니다. `"dm"`(기본값)은 승인자 DM으로 전송하고, `"channel"`은 원래 채널로 전송하며, `"both"`는 둘 다 전송합니다. 대상에 `"channel"`이 포함된 경우 버튼은 확인된 승인자만 사용할 수 있습니다. - `cleanupAfterResolve`: `true`이면 승인, 거부 또는 시간 초과 후 승인 DM을 삭제합니다. -**반응 알림 모드:** `off`(없음), `own`(봇의 메시지, 기본값), `all`(모든 메시지), `allowlist`(모든 메시지에서 `guilds..users` 기준). +**반응 알림 모드:** `off`(없음), `own`(봇 메시지, 기본값), `all`(모든 메시지), `allowlist`(모든 메시지에서 `guilds..users` 기준). ### Google Chat @@ -393,11 +393,11 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 } ``` -- 서비스 계정 JSON: 인라인(`serviceAccount`) 또는 파일 기반(`serviceAccountFile`)입니다. +- 서비스 계정 JSON: 인라인(`serviceAccount`) 또는 파일 기반(`serviceAccountFile`). - 서비스 계정 SecretRef도 지원됩니다(`serviceAccountRef`). - 환경 변수 대체값: `GOOGLE_CHAT_SERVICE_ACCOUNT` 또는 `GOOGLE_CHAT_SERVICE_ACCOUNT_FILE`. - 전달 대상에는 `spaces/` 또는 `users/`를 사용하세요. -- `channels.googlechat.dangerouslyAllowNameMatching`는 변경 가능한 이메일 프린시펄 매칭을 다시 활성화합니다(비상 호환성 모드). +- `channels.googlechat.dangerouslyAllowNameMatching`은 변경 가능한 이메일 principal 매칭을 다시 활성화합니다(비상 호환성 모드). ### Slack @@ -449,7 +449,7 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 chunkMode: "length", streaming: { mode: "partial", // off | partial | block | progress - nativeTransport: true, // mode=partial일 때 Slack 네이티브 스트리밍 API 사용 + nativeTransport: true, // use Slack native streaming API when mode=partial }, mediaMaxMb: 20, execApprovals: { @@ -464,30 +464,34 @@ WhatsApp은 게이트웨이의 웹 채널(Baileys Web)을 통해 실행됩니다 } ``` -- **Socket 모드**는 `botToken`과 `appToken` 둘 다 필요합니다(기본 계정 환경 변수 대체값은 `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN`). -- **HTTP 모드**는 `botToken`과 `signingSecret`(루트 또는 계정별)이 필요합니다. -- `botToken`, `appToken`, `signingSecret`, `userToken`은 일반 텍스트 문자열 또는 SecretRef 객체를 허용합니다. -- Slack 계정 스냅샷은 `botTokenSource`, `botTokenStatus`, `appTokenStatus`, 그리고 HTTP 모드에서는 `signingSecretStatus` 같은 자격 증명별 출처/상태 필드를 노출합니다. `configured_unavailable`는 계정이 SecretRef를 통해 구성되었지만 현재 명령/런타임 경로에서 비밀값을 확인할 수 없음을 의미합니다. +- **Socket 모드**에는 `botToken`과 `appToken`이 모두 필요합니다(기본 계정 환경 변수 대체값은 `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN`). +- **HTTP 모드**에는 `botToken`과 `signingSecret`(루트 또는 계정별)이 필요합니다. +- `botToken`, `appToken`, `signingSecret`, `userToken`은 일반 텍스트 + 문자열 또는 SecretRef 객체를 허용합니다. +- Slack 계정 스냅샷은 `botTokenSource`, `botTokenStatus`, `appTokenStatus`, 그리고 HTTP 모드에서는 + `signingSecretStatus` 같은 자격 증명별 소스/상태 필드를 노출합니다. + `configured_unavailable`은 해당 계정이 SecretRef를 통해 구성되었지만 현재 명령/런타임 경로에서 + 비밀 값 해석이 불가능했음을 의미합니다. - `configWrites: false`는 Slack에서 시작된 구성 쓰기를 차단합니다. -- 선택적 `channels.slack.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. -- `channels.slack.streaming.mode`는 정식 Slack 스트림 모드 키입니다. `channels.slack.streaming.nativeTransport`는 Slack의 네이티브 스트리밍 전송을 제어합니다. 레거시 `streamMode`, 불리언 `streaming`, `nativeStreaming` 값은 자동 마이그레이션됩니다. +- 선택 사항인 `channels.slack.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- `channels.slack.streaming.mode`는 정식 Slack 스트림 모드 키입니다. `channels.slack.streaming.nativeTransport`는 Slack의 네이티브 스트리밍 전송을 제어합니다. 레거시 `streamMode`, 불리언 `streaming`, `nativeStreaming` 값은 자동으로 마이그레이션됩니다. - 전달 대상에는 `user:`(DM) 또는 `channel:`를 사용하세요. **반응 알림 모드:** `off`, `own`(기본값), `all`, `allowlist`(`reactionAllowlist` 기준). -**스레드 세션 격리:** `thread.historyScope`는 스레드별(기본값) 또는 채널 전체 공유입니다. `thread.inheritParent`는 상위 채널 대화를 새 스레드에 복사합니다. +**스레드 세션 격리:** `thread.historyScope`는 스레드별(기본값) 또는 채널 전체 공유입니다. `thread.inheritParent`는 부모 채널의 대화 기록을 새 스레드로 복사합니다. -- Slack 네이티브 스트리밍과 Slack assistant 스타일의 "is typing..." 스레드 상태는 답글 스레드 대상을 필요로 합니다. 최상위 DM은 기본적으로 스레드 밖이므로, 스레드 스타일 미리보기 대신 `typingReaction` 또는 일반 전달을 사용합니다. -- `typingReaction`은 답글이 실행되는 동안 수신된 Slack 메시지에 임시 반응을 추가하고, 완료 시 제거합니다. `"hourglass_flowing_sand"` 같은 Slack 이모지 쇼트코드를 사용하세요. -- `channels.slack.execApprovals`: Slack 네이티브 exec 승인 전달 및 승인자 권한 부여. Discord와 동일한 스키마입니다: `enabled`(`true`/`false`/`"auto"`), `approvers`(Slack 사용자 ID), `agentFilter`, `sessionFilter`, `target`(`"dm"`, `"channel"`, 또는 `"both"`). +- Slack 네이티브 스트리밍과 Slack assistant 스타일의 "is typing..." 스레드 상태는 답글 스레드 대상을 필요로 합니다. 최상위 DM은 기본적으로 스레드 밖에 유지되므로, 스레드 스타일 미리보기 대신 `typingReaction` 또는 일반 전달을 사용합니다. +- `typingReaction`은 답글이 실행되는 동안 수신 Slack 메시지에 임시 반응을 추가한 뒤, 완료 시 제거합니다. `"hourglass_flowing_sand"` 같은 Slack 이모지 단축 코드를 사용하세요. +- `channels.slack.execApprovals`: Slack 네이티브 exec 승인 전달 및 승인자 권한 부여. Discord와 동일한 스키마를 사용합니다: `enabled` (`true`/`false`/`"auto"`), `approvers` (Slack 사용자 ID), `agentFilter`, `sessionFilter`, `target` (`"dm"`, `"channel"`, 또는 `"both"`). -| 작업 그룹 | 기본값 | 참고 | -| ----------- | ------- | ---------------------- | -| reactions | 활성화됨 | 반응 추가 + 반응 목록 | -| messages | 활성화됨 | 읽기/보내기/편집/삭제 | -| pins | 활성화됨 | 고정/해제/목록 | -| memberInfo | 활성화됨 | 멤버 정보 | -| emojiList | 활성화됨 | 사용자 정의 이모지 목록 | +| 작업 그룹 | 기본값 | 참고 | +| ------------ | ------- | ------------------------ | +| reactions | 활성화됨 | 반응 추가 + 반응 목록 조회 | +| messages | 활성화됨 | 읽기/전송/편집/삭제 | +| pins | 활성화됨 | 고정/해제/목록 | +| memberInfo | 활성화됨 | 멤버 정보 | +| emojiList | 활성화됨 | 사용자 지정 이모지 목록 | ### Mattermost @@ -511,7 +515,7 @@ Mattermost는 플러그인으로 제공됩니다: `openclaw plugins install @ope native: true, // opt-in nativeSkills: true, callbackPath: "/api/channels/mattermost/command", - // 리버스 프록시/공개 배포용 선택적 명시적 URL + // reverse-proxy/public deployment를 위한 선택적 명시 URL callbackUrl: "https://gateway.example.com/api/channels/mattermost/command", }, textChunkLimit: 4000, @@ -523,16 +527,21 @@ Mattermost는 플러그인으로 제공됩니다: `openclaw plugins install @ope 채팅 모드: `oncall`(@-멘션 시 응답, 기본값), `onmessage`(모든 메시지), `onchar`(트리거 접두사로 시작하는 메시지). -Mattermost 네이티브 명령이 활성화되면: +Mattermost 네이티브 명령이 활성화된 경우: - `commands.callbackPath`는 전체 URL이 아니라 경로여야 합니다(예: `/api/channels/mattermost/command`). -- `commands.callbackUrl`은 OpenClaw 게이트웨이 엔드포인트로 해석되어야 하며 Mattermost 서버에서 접근 가능해야 합니다. -- 네이티브 슬래시 콜백은 슬래시 명령 등록 중 Mattermost가 반환한 명령별 토큰으로 인증됩니다. 등록에 실패하거나 활성화된 명령이 없으면 OpenClaw는 `Unauthorized: invalid command token.`으로 콜백을 거부합니다. -- 비공개/tailnet/내부 콜백 호스트의 경우 Mattermost에서 `ServiceSettings.AllowedUntrustedInternalConnections`에 콜백 호스트/도메인을 포함해야 할 수 있습니다. 전체 URL이 아니라 호스트/도메인 값을 사용하세요. +- `commands.callbackUrl`은 OpenClaw gateway 엔드포인트로 해석되어야 하며 Mattermost 서버에서 접근 가능해야 합니다. +- 네이티브 슬래시 콜백은 + Mattermost가 슬래시 명령 등록 중 반환하는 명령별 토큰으로 인증됩니다. + 등록에 실패하거나 활성화된 명령이 없으면 OpenClaw는 다음과 함께 콜백을 거부합니다: + `Unauthorized: invalid command token.` +- 비공개/tailnet/내부 콜백 호스트의 경우 Mattermost는 + `ServiceSettings.AllowedUntrustedInternalConnections`에 콜백 호스트/도메인이 포함되어야 할 수 있습니다. + 전체 URL이 아니라 호스트/도메인 값을 사용하세요. - `channels.mattermost.configWrites`: Mattermost에서 시작된 구성 쓰기를 허용하거나 거부합니다. - `channels.mattermost.requireMention`: 채널에서 응답하기 전에 `@mention`을 요구합니다. -- `channels.mattermost.groups..requireMention`: 채널별 멘션 게이팅 재정의입니다(기본값은 `"*"`). -- 선택적 `channels.mattermost.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- `channels.mattermost.groups..requireMention`: 채널별 멘션 게이팅 재정의(`"*"`는 기본값). +- 선택 사항인 `channels.mattermost.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. ### Signal @@ -557,7 +566,7 @@ Mattermost 네이티브 명령이 활성화되면: - `channels.signal.account`: 채널 시작을 특정 Signal 계정 식별자에 고정합니다. - `channels.signal.configWrites`: Signal에서 시작된 구성 쓰기를 허용하거나 거부합니다. -- 선택적 `channels.signal.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- 선택 사항인 `channels.signal.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. ### BlueBubbles @@ -570,20 +579,20 @@ BlueBubbles는 권장되는 iMessage 경로입니다(플러그인 기반, `chann enabled: true, dmPolicy: "pairing", // serverUrl, password, webhookPath, group controls, and advanced actions: - // /channels/bluebubbles 참조 + // see /channels/bluebubbles }, }, } ``` -- 여기서 다루는 핵심 키 경로: `channels.bluebubbles`, `channels.bluebubbles.dmPolicy`. -- 선택적 `channels.bluebubbles.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. -- `type: "acp"`인 최상위 `bindings[]` 항목은 BlueBubbles 대화를 영구 ACP 세션에 바인딩할 수 있습니다. `match.peer.id`에는 BlueBubbles 핸들 또는 대상 문자열(`chat_id:*`, `chat_guid:*`, `chat_identifier:*`)을 사용하세요. 공통 필드 의미: [ACP Agents](/ko/tools/acp-agents#channel-specific-settings). +- 여기에서 다루는 핵심 키 경로: `channels.bluebubbles`, `channels.bluebubbles.dmPolicy`. +- 선택 사항인 `channels.bluebubbles.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- `type: "acp"`인 최상위 `bindings[]` 항목은 BlueBubbles 대화를 영구 ACP 세션에 바인딩할 수 있습니다. `match.peer.id`에는 BlueBubbles handle 또는 대상 문자열(`chat_id:*`, `chat_guid:*`, `chat_identifier:*`)을 사용하세요. 공유 필드 의미: [ACP Agents](/ko/tools/acp-agents#channel-specific-settings). - 전체 BlueBubbles 채널 구성은 [BlueBubbles](/ko/channels/bluebubbles)에 문서화되어 있습니다. ### iMessage -OpenClaw는 `imsg rpc`(stdio를 통한 JSON-RPC)를 실행합니다. 데몬이나 포트가 필요하지 않습니다. +OpenClaw는 `imsg rpc`(stdio를 통한 JSON-RPC)를 실행합니다. 데몬이나 포트는 필요하지 않습니다. ```json5 { @@ -607,17 +616,17 @@ OpenClaw는 `imsg rpc`(stdio를 통한 JSON-RPC)를 실행합니다. 데몬이 } ``` -- 선택적 `channels.imessage.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- 선택 사항인 `channels.imessage.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. - Messages DB에 대한 전체 디스크 접근 권한이 필요합니다. -- `chat_id:` 대상을 사용하는 것을 권장합니다. 채팅 목록은 `imsg chats --limit 20`으로 확인하세요. +- `chat_id:` 대상을 우선 사용하세요. 채팅 목록은 `imsg chats --limit 20`으로 확인할 수 있습니다. - `cliPath`는 SSH 래퍼를 가리킬 수 있습니다. SCP 첨부 파일 가져오기를 위해 `remoteHost`(`host` 또는 `user@host`)를 설정하세요. -- `attachmentRoots` 및 `remoteAttachmentRoots`는 수신 첨부 파일 경로를 제한합니다(기본값: `/Users/*/Library/Messages/Attachments`). -- SCP는 엄격한 호스트 키 검사를 사용하므로 릴레이 호스트 키가 이미 `~/.ssh/known_hosts`에 있어야 합니다. +- `attachmentRoots`와 `remoteAttachmentRoots`는 수신 첨부 파일 경로를 제한합니다(기본값: `/Users/*/Library/Messages/Attachments`). +- SCP는 엄격한 호스트 키 검사를 사용하므로, 릴레이 호스트 키가 이미 `~/.ssh/known_hosts`에 있어야 합니다. - `channels.imessage.configWrites`: iMessage에서 시작된 구성 쓰기를 허용하거나 거부합니다. -- `type: "acp"`인 최상위 `bindings[]` 항목은 iMessage 대화를 영구 ACP 세션에 바인딩할 수 있습니다. `match.peer.id`에는 정규화된 핸들 또는 명시적 채팅 대상(`chat_id:*`, `chat_guid:*`, `chat_identifier:*`)을 사용하세요. 공통 필드 의미: [ACP Agents](/ko/tools/acp-agents#channel-specific-settings). +- `type: "acp"`인 최상위 `bindings[]` 항목은 iMessage 대화를 영구 ACP 세션에 바인딩할 수 있습니다. `match.peer.id`에는 정규화된 handle 또는 명시적 채팅 대상(`chat_id:*`, `chat_guid:*`, `chat_identifier:*`)을 사용하세요. 공유 필드 의미: [ACP Agents](/ko/tools/acp-agents#channel-specific-settings). - + ```bash #!/usr/bin/env bash @@ -659,20 +668,20 @@ Matrix는 확장 기반이며 `channels.matrix` 아래에서 구성됩니다. ``` - 토큰 인증은 `accessToken`을 사용하고, 비밀번호 인증은 `userId` + `password`를 사용합니다. -- `channels.matrix.proxy`는 Matrix HTTP 트래픽을 명시적인 HTTP(S) 프록시를 통해 라우팅합니다. 명명된 계정은 `channels.matrix.accounts..proxy`로 이를 재정의할 수 있습니다. +- `channels.matrix.proxy`는 Matrix HTTP 트래픽을 명시적인 HTTP(S) 프록시를 통해 라우팅합니다. 이름 있는 계정은 `channels.matrix.accounts..proxy`로 이를 재정의할 수 있습니다. - `channels.matrix.network.dangerouslyAllowPrivateNetwork`는 비공개/내부 homeserver를 허용합니다. `proxy`와 이 네트워크 opt-in은 서로 독립적인 제어입니다. -- `channels.matrix.defaultAccount`는 다중 계정 구성에서 선호 계정을 선택합니다. -- `channels.matrix.autoJoin`의 기본값은 `off`이므로 `autoJoin: "allowlist"`와 `autoJoinAllowlist` 또는 `autoJoin: "always"`를 설정할 때까지 초대된 룸과 새 DM 스타일 초대는 무시됩니다. +- `channels.matrix.defaultAccount`는 다중 계정 설정에서 선호 계정을 선택합니다. +- `channels.matrix.autoJoin`의 기본값은 `off`이므로, `autoJoin: "allowlist"`와 `autoJoinAllowlist` 또는 `autoJoin: "always"`를 설정할 때까지 초대된 룸과 새 DM 스타일 초대는 무시됩니다. - `channels.matrix.execApprovals`: Matrix 네이티브 exec 승인 전달 및 승인자 권한 부여. - - `enabled`: `true`, `false`, 또는 `"auto"`(기본값). 자동 모드에서는 `approvers` 또는 `commands.ownerAllowFrom`에서 승인자를 확인할 수 있으면 exec 승인이 활성화됩니다. + - `enabled`: `true`, `false`, 또는 `"auto"`(기본값). auto 모드에서는 `approvers` 또는 `commands.ownerAllowFrom`에서 승인자를 확인할 수 있을 때 exec 승인이 활성화됩니다. - `approvers`: exec 요청을 승인할 수 있는 Matrix 사용자 ID(예: `@owner:example.org`)입니다. - - `agentFilter`: 선택적 에이전트 ID 허용 목록입니다. 생략하면 모든 에이전트의 승인을 전달합니다. + - `agentFilter`: 선택적 에이전트 ID 허용 목록입니다. 생략하면 모든 에이전트에 대한 승인을 전달합니다. - `sessionFilter`: 선택적 세션 키 패턴(부분 문자열 또는 정규식)입니다. - `target`: 승인 프롬프트를 보낼 위치입니다. `"dm"`(기본값), `"channel"`(원래 룸), 또는 `"both"`. - 계정별 재정의: `channels.matrix.accounts..execApprovals`. -- `channels.matrix.dm.sessionScope`는 Matrix DM이 세션으로 그룹화되는 방식을 제어합니다. `per-user`(기본값)는 라우팅된 피어별로 공유하고, `per-room`은 각 DM 룸을 분리합니다. +- `channels.matrix.dm.sessionScope`는 Matrix DM이 세션으로 묶이는 방식을 제어합니다: `per-user`(기본값)는 라우팅된 피어별로 공유하고, `per-room`은 각 DM 룸을 분리합니다. - Matrix 상태 프로브와 라이브 디렉터리 조회는 런타임 트래픽과 동일한 프록시 정책을 사용합니다. -- 전체 Matrix 구성, 대상 지정 규칙, 설정 예제는 [Matrix](/ko/channels/matrix)에 문서화되어 있습니다. +- 전체 Matrix 구성, 대상 지정 규칙, 설정 예시는 [Matrix](/ko/channels/matrix)에 문서화되어 있습니다. ### Microsoft Teams @@ -685,13 +694,13 @@ Microsoft Teams는 확장 기반이며 `channels.msteams` 아래에서 구성됩 enabled: true, configWrites: true, // appId, appPassword, tenantId, webhook, team/channel policies: - // /channels/msteams 참조 + // see /channels/msteams }, }, } ``` -- 여기서 다루는 핵심 키 경로: `channels.msteams`, `channels.msteams.configWrites`. +- 여기에서 다루는 핵심 키 경로: `channels.msteams`, `channels.msteams.configWrites`. - 전체 Teams 구성(자격 증명, webhook, DM/그룹 정책, 팀별/채널별 재정의)은 [Microsoft Teams](/ko/channels/msteams)에 문서화되어 있습니다. ### IRC @@ -717,13 +726,13 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. } ``` -- 여기서 다루는 핵심 키 경로: `channels.irc`, `channels.irc.dmPolicy`, `channels.irc.configWrites`, `channels.irc.nickserv.*`. -- 선택적 `channels.irc.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. +- 여기에서 다루는 핵심 키 경로: `channels.irc`, `channels.irc.dmPolicy`, `channels.irc.configWrites`, `channels.irc.nickserv.*`. +- 선택 사항인 `channels.irc.defaultAccount`는 구성된 계정 ID와 일치할 때 기본 계정 선택을 재정의합니다. - 전체 IRC 채널 구성(호스트/포트/TLS/채널/허용 목록/멘션 게이팅)은 [IRC](/ko/channels/irc)에 문서화되어 있습니다. ### 다중 계정(모든 채널) -채널별로 여러 계정을 실행할 수 있습니다(각각 고유한 `accountId` 보유). +채널별로 여러 계정을 실행할 수 있습니다(각각 고유한 `accountId` 보유): ```json5 { @@ -747,23 +756,23 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. - `accountId`를 생략하면 `default`가 사용됩니다(CLI + 라우팅). - 환경 변수 토큰은 **default** 계정에만 적용됩니다. - 기본 채널 설정은 계정별로 재정의하지 않는 한 모든 계정에 적용됩니다. -- 각 계정을 다른 에이전트로 라우팅하려면 `bindings[].match.accountId`를 사용하세요. -- 단일 계정 최상위 채널 구성 상태에서 `openclaw channels add`(또는 채널 온보딩)를 통해 비기본 계정을 추가하면, OpenClaw는 원래 계정이 계속 작동하도록 계정 범위 최상위 단일 계정 값을 먼저 채널 계정 맵으로 승격합니다. 대부분의 채널은 이를 `channels..accounts.default`로 이동하며, Matrix는 대신 기존의 일치하는 명명된/default 대상을 유지할 수 있습니다. -- 기존 채널 전용 바인딩(`accountId` 없음)은 계속 기본 계정과 일치하며, 계정 범위 바인딩은 여전히 선택 사항입니다. -- `openclaw doctor --fix`도 혼합된 형태를 복구하며, 계정 범위 최상위 단일 계정 값을 해당 채널에 대해 선택된 승격 계정으로 이동합니다. 대부분의 채널은 `accounts.default`를 사용하고, Matrix는 기존의 일치하는 명명된/default 대상을 유지할 수 있습니다. +- `bindings[].match.accountId`를 사용해 각 계정을 다른 에이전트로 라우팅하세요. +- 단일 계정 최상위 채널 구성 상태에서 `openclaw channels add`(또는 채널 온보딩)를 통해 기본이 아닌 계정을 추가하면, OpenClaw는 원래 계정이 계속 동작하도록 계정 범위의 최상위 단일 계정 값을 먼저 채널 계정 맵으로 승격합니다. 대부분의 채널은 이를 `channels..accounts.default`로 옮기며, Matrix는 기존의 일치하는 named/default 대상을 대신 유지할 수 있습니다. +- 기존의 채널 전용 바인딩(`accountId` 없음)은 계속 기본 계정과 매칭됩니다. 계정 범위 바인딩은 여전히 선택 사항입니다. +- `openclaw doctor --fix`도 혼합된 형태를 복구하여 계정 범위의 최상위 단일 계정 값을 해당 채널에 대해 선택된 승격 계정으로 이동합니다. 대부분의 채널은 `accounts.default`를 사용하며, Matrix는 기존의 일치하는 named/default 대상을 대신 유지할 수 있습니다. ### 기타 확장 채널 많은 확장 채널은 `channels.`로 구성되며 전용 채널 페이지에 문서화되어 있습니다(예: Feishu, Matrix, LINE, Nostr, Zalo, Nextcloud Talk, Synology Chat, Twitch). -전체 채널 색인은 [채널](/ko/channels)을 참조하세요. +전체 채널 색인은 [Channels](/ko/channels)를 참고하세요. ### 그룹 채팅 멘션 게이팅 -그룹 메시지는 기본적으로 **멘션 필요**입니다(메타데이터 멘션 또는 안전한 정규식 패턴). WhatsApp, Telegram, Discord, Google Chat, iMessage 그룹 채팅에 적용됩니다. +그룹 메시지는 기본적으로 **멘션 필요**로 설정됩니다(메타데이터 멘션 또는 안전한 정규식 패턴). WhatsApp, Telegram, Discord, Google Chat, iMessage 그룹 채팅에 적용됩니다. **멘션 유형:** -- **메타데이터 멘션**: 네이티브 플랫폼 @-멘션. WhatsApp self-chat 모드에서는 무시됩니다. +- **메타데이터 멘션**: 플랫폼 고유의 @-멘션입니다. WhatsApp self-chat 모드에서는 무시됩니다. - **텍스트 패턴**: `agents.list[].groupChat.mentionPatterns`의 안전한 정규식 패턴입니다. 잘못된 패턴과 안전하지 않은 중첩 반복은 무시됩니다. - 멘션 게이팅은 감지가 가능한 경우에만 적용됩니다(네이티브 멘션 또는 최소 하나의 패턴이 있을 때). @@ -778,7 +787,7 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. } ``` -`messages.groupChat.historyLimit`는 전역 기본값을 설정합니다. 채널은 `channels..historyLimit`(또는 계정별)로 이를 재정의할 수 있습니다. 비활성화하려면 `0`으로 설정하세요. +`messages.groupChat.historyLimit`은 전역 기본값을 설정합니다. 채널은 `channels..historyLimit`(또는 계정별 설정)로 이를 재정의할 수 있습니다. 비활성화하려면 `0`으로 설정하세요. #### DM 기록 제한 @@ -799,9 +808,9 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. 지원 대상: `telegram`, `whatsapp`, `discord`, `slack`, `signal`, `imessage`, `msteams`. -#### Self-chat 모드 +#### self-chat 모드 -자기 번호를 `allowFrom`에 포함하면 self-chat 모드가 활성화됩니다(네이티브 @-멘션은 무시하고 텍스트 패턴에만 응답). +자기 자신의 번호를 `allowFrom`에 포함하면 self-chat 모드가 활성화됩니다(네이티브 @-멘션은 무시하고 텍스트 패턴에만 응답): ```json5 { @@ -822,21 +831,21 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. } ``` -### 명령어(채팅 명령 처리) +### 명령(채팅 명령 처리) ```json5 { commands: { - native: "auto", // 지원될 때 네이티브 명령 등록 - nativeSkills: "auto", // 지원될 때 네이티브 스킬 명령 등록 + native: "auto", // 지원되는 경우 네이티브 명령 등록 + nativeSkills: "auto", // 지원되는 경우 네이티브 Skills 명령 등록 text: true, // 채팅 메시지에서 /commands 파싱 - bash: false, // ! 허용(별칭: /bash) + bash: false, // ! 허용 (별칭: /bash) bashForegroundMs: 2000, config: false, // /config 허용 mcp: false, // /mcp 허용 plugins: false, // /plugins 허용 debug: false, // /debug 허용 - restart: true, // /restart + gateway restart 도구 허용 + restart: true, // /restart + gateway restart tool 허용 ownerAllowFrom: ["discord:123456789012345678"], ownerDisplay: "raw", // raw | hash ownerDisplaySecret: "${OWNER_ID_HASH_SECRET}", @@ -849,32 +858,32 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. } ``` - + -- 이 블록은 명령어 표면을 구성합니다. 현재 기본 제공 + 번들 명령 카탈로그는 [슬래시 명령어](/ko/tools/slash-commands)를 참조하세요. -- 이 페이지는 전체 명령 카탈로그가 아니라 **구성 키 참조**입니다. QQ Bot `/bot-ping` `/bot-help` `/bot-logs`, LINE `/card`, device-pair `/pair`, memory `/dreaming`, phone-control `/phone`, Talk `/voice` 같은 채널/플러그인 소유 명령은 해당 채널/플러그인 페이지와 [슬래시 명령어](/ko/tools/slash-commands)에 문서화되어 있습니다. -- 텍스트 명령은 반드시 앞에 `/`가 붙은 **독립형** 메시지여야 합니다. +- 이 블록은 명령 표면을 구성합니다. 현재 내장 + 번들 명령 카탈로그는 [Slash Commands](/ko/tools/slash-commands)를 참고하세요. +- 이 페이지는 전체 명령 카탈로그가 아니라 **구성 키 참조**입니다. QQ Bot `/bot-ping` `/bot-help` `/bot-logs`, LINE `/card`, device-pair `/pair`, memory `/dreaming`, phone-control `/phone`, Talk `/voice` 같은 채널/플러그인 소유 명령은 해당 채널/플러그인 페이지와 [Slash Commands](/ko/tools/slash-commands)에 문서화되어 있습니다. +- 텍스트 명령은 앞에 `/`가 붙은 **독립 실행형** 메시지여야 합니다. - `native: "auto"`는 Discord/Telegram의 네이티브 명령을 켜고, Slack은 끕니다. - `nativeSkills: "auto"`는 Discord/Telegram의 네이티브 Skills 명령을 켜고, Slack은 끕니다. - 채널별 재정의: `channels.discord.commands.native`(bool 또는 `"auto"`). `false`는 이전에 등록된 명령을 지웁니다. -- `channels..commands.nativeSkills`로 채널별 네이티브 Skills 등록을 재정의합니다. -- `channels.telegram.customCommands`는 추가 Telegram 봇 메뉴 항목을 추가합니다. -- `bash: true`는 호스트 셸용 `! `를 활성화합니다. `tools.elevated.enabled`와 발신자가 `tools.elevated.allowFrom.`에 있어야 합니다. -- `config: true`는 `/config`를 활성화합니다(`openclaw.json` 읽기/쓰기). gateway `chat.send` 클라이언트의 경우 영구 `/config set|unset` 쓰기에는 `operator.admin`도 필요합니다. 읽기 전용 `/config show`는 일반 쓰기 범위 operator 클라이언트에도 계속 제공됩니다. +- `channels..commands.nativeSkills`로 채널별 네이티브 skill 등록을 재정의합니다. +- `channels.telegram.customCommands`는 Telegram 봇 메뉴 항목을 추가합니다. +- `bash: true`는 호스트 셸용 `! `를 활성화합니다. `tools.elevated.enabled`와 `tools.elevated.allowFrom.`에 발신자가 포함되어 있어야 합니다. +- `config: true`는 `/config`를 활성화합니다(`openclaw.json` 읽기/쓰기). gateway `chat.send` 클라이언트의 경우 영구적인 `/config set|unset` 쓰기에는 `operator.admin`도 필요합니다. 읽기 전용 `/config show`는 일반 쓰기 범위 operator 클라이언트에서도 계속 사용할 수 있습니다. - `mcp: true`는 `mcp.servers` 아래의 OpenClaw 관리 MCP 서버 구성용 `/mcp`를 활성화합니다. - `plugins: true`는 플러그인 검색, 설치, 활성화/비활성화 제어용 `/plugins`를 활성화합니다. - `channels..configWrites`는 채널별 구성 변경을 제어합니다(기본값: true). - 다중 계정 채널의 경우 `channels..accounts..configWrites`도 해당 계정을 대상으로 하는 쓰기(예: `/allowlist --config --account ` 또는 `/config set channels..accounts....`)를 제어합니다. -- `restart: false`는 `/restart`와 gateway 재시작 도구 작업을 비활성화합니다. 기본값: `true`. -- `ownerAllowFrom`은 소유자 전용 명령/도구를 위한 명시적 소유자 허용 목록입니다. `allowFrom`과는 별개입니다. -- `ownerDisplay: "hash"`는 시스템 프롬프트에서 소유자 ID를 해시 처리합니다. 해시를 제어하려면 `ownerDisplaySecret`를 설정하세요. +- `restart: false`는 `/restart`와 gateway restart tool 작업을 비활성화합니다. 기본값: `true`. +- `ownerAllowFrom`은 소유자 전용 명령/도구를 위한 명시적인 소유자 허용 목록입니다. `allowFrom`과는 별개입니다. +- `ownerDisplay: "hash"`는 시스템 프롬프트에서 소유자 ID를 해시합니다. 해싱을 제어하려면 `ownerDisplaySecret`을 설정하세요. - `allowFrom`은 제공자별입니다. 설정되면 이것이 **유일한** 권한 부여 소스가 됩니다(채널 허용 목록/페어링과 `useAccessGroups`는 무시됨). -- `useAccessGroups: false`는 `allowFrom`이 설정되지 않았을 때 명령이 접근 그룹 정책을 우회할 수 있게 합니다. +- `useAccessGroups: false`는 `allowFrom`이 설정되지 않았을 때 명령이 access-group 정책을 우회할 수 있게 합니다. - 명령 문서 맵: - - 기본 제공 + 번들 카탈로그: [슬래시 명령어](/ko/tools/slash-commands) - - 채널별 명령 표면: [채널](/ko/channels) + - 내장 + 번들 카탈로그: [Slash Commands](/ko/tools/slash-commands) + - 채널별 명령 표면: [Channels](/ko/channels) - QQ Bot 명령: [QQ Bot](/ko/channels/qqbot) - - 페어링 명령: [페어링](/ko/channels/pairing) + - 페어링 명령: [Pairing](/ko/channels/pairing) - LINE 카드 명령: [LINE](/ko/channels/line) - memory dreaming: [Dreaming](/ko/concepts/dreaming) @@ -896,7 +905,7 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. ### `agents.defaults.repoRoot` -시스템 프롬프트의 Runtime 줄에 표시되는 선택적 저장소 루트입니다. 설정되지 않으면 OpenClaw가 workspace에서 위로 탐색하며 자동 감지합니다. +시스템 프롬프트의 Runtime 줄에 표시되는 선택적 저장소 루트입니다. 설정하지 않으면 OpenClaw가 workspace에서 위쪽으로 탐색하며 자동 감지합니다. ```json5 { @@ -906,7 +915,8 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. ### `agents.defaults.skills` -`agents.list[].skills`를 설정하지 않은 에이전트에 대한 선택적 기본 Skills 허용 목록입니다. +`agents.list[].skills`를 설정하지 않은 에이전트에 대한 +선택적 기본 skill 허용 목록입니다. ```json5 { @@ -915,16 +925,17 @@ IRC는 확장 기반이며 `channels.irc` 아래에서 구성됩니다. list: [ { id: "writer" }, // github, weather 상속 { id: "docs", skills: ["docs-search"] }, // 기본값 대체 - { id: "locked-down", skills: [] }, // Skills 없음 + { id: "locked-down", skills: [] }, // skill 없음 ], }, } ``` -- 기본적으로 Skills 무제한으로 하려면 `agents.defaults.skills`를 생략하세요. +- 기본적으로 skills를 제한하지 않으려면 `agents.defaults.skills`를 생략하세요. - 기본값을 상속하려면 `agents.list[].skills`를 생략하세요. -- Skills를 사용하지 않으려면 `agents.list[].skills: []`로 설정하세요. -- 비어 있지 않은 `agents.list[].skills` 목록은 해당 에이전트의 최종 집합이며, 기본값과 병합되지 않습니다. +- skill이 없도록 하려면 `agents.list[].skills: []`로 설정하세요. +- 비어 있지 않은 `agents.list[].skills` 목록은 해당 에이전트의 최종 집합이며, + 기본값과 병합되지 않습니다. ### `agents.defaults.skipBootstrap` @@ -938,9 +949,9 @@ workspace bootstrap 파일(`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `U ### `agents.defaults.contextInjection` -workspace bootstrap 파일을 시스템 프롬프트에 언제 주입할지 제어합니다. 기본값: `"always"`. +workspace bootstrap 파일이 시스템 프롬프트에 주입되는 시점을 제어합니다. 기본값: `"always"`. -- `"continuation-skip"`: 안전한 연속 턴(완료된 assistant 응답 이후)에서는 workspace bootstrap 재주입을 건너뛰어 프롬프트 크기를 줄입니다. 하트비트 실행과 압축 후 재시도에서는 여전히 컨텍스트를 다시 구성합니다. +- `"continuation-skip"`: 안전한 연속 턴(완료된 assistant 응답 이후)에서는 workspace bootstrap 재주입을 건너뛰어 프롬프트 크기를 줄입니다. Heartbeat 실행과 압축 후 재시도에서는 여전히 컨텍스트를 다시 빌드합니다. ```json5 { @@ -950,7 +961,7 @@ workspace bootstrap 파일을 시스템 프롬프트에 언제 주입할지 제 ### `agents.defaults.bootstrapMaxChars` -잘리기 전 workspace bootstrap 파일당 최대 문자 수입니다. 기본값: `20000`. +잘리기 전 각 workspace bootstrap 파일의 최대 문자 수입니다. 기본값: `20000`. ```json5 { @@ -970,12 +981,12 @@ workspace bootstrap 파일을 시스템 프롬프트에 언제 주입할지 제 ### `agents.defaults.bootstrapPromptTruncationWarning` -bootstrap 컨텍스트가 잘릴 때 에이전트에게 표시되는 경고 텍스트를 제어합니다. +bootstrap 컨텍스트가 잘릴 때 에이전트에 표시되는 경고 텍스트를 제어합니다. 기본값: `"once"`. - `"off"`: 시스템 프롬프트에 경고 텍스트를 절대 주입하지 않습니다. -- `"once"`: 고유한 잘림 시그니처마다 경고를 한 번 주입합니다(권장). -- `"always"`: 잘림이 존재하면 매 실행마다 경고를 주입합니다. +- `"once"`: 고유한 잘림 시그니처마다 한 번만 경고를 주입합니다(권장). +- `"always"`: 잘림이 존재할 때마다 모든 실행에 경고를 주입합니다. ```json5 { @@ -985,11 +996,11 @@ bootstrap 컨텍스트가 잘릴 때 에이전트에게 표시되는 경고 텍 ### `agents.defaults.imageMaxDimensionPx` -provider 호출 전에 transcript/tool 이미지 블록에서 가장 긴 이미지 변의 최대 픽셀 크기입니다. +제공자 호출 전에 transcript/tool 이미지 블록에서 이미지의 가장 긴 변에 허용되는 최대 픽셀 크기입니다. 기본값: `1200`. -값을 낮추면 보통 비전 토큰 사용량과 스크린샷이 많은 실행의 요청 페이로드 크기가 줄어듭니다. -값을 높이면 더 많은 시각적 세부 정보를 유지합니다. +값을 낮추면 일반적으로 스크린샷이 많은 실행에서 비전 토큰 사용량과 요청 페이로드 크기가 줄어듭니다. +값을 높이면 더 많은 시각적 세부 정보를 유지할 수 있습니다. ```json5 { @@ -1048,6 +1059,10 @@ provider 호출 전에 transcript/tool 이미지 블록에서 가장 긴 이미 fallbacks: ["openai/gpt-5.4-mini"], }, params: { cacheRetention: "long" }, // 전역 기본 provider params + embeddedHarness: { + runtime: "auto", // auto | pi | registered harness id, e.g. codex + fallback: "pi", // pi | none + }, pdfMaxBytesMb: 10, pdfMaxPages: 20, thinkingDefault: "low", @@ -1064,43 +1079,71 @@ provider 호출 전에 transcript/tool 이미지 블록에서 가장 긴 이미 - `model`: 문자열(`"provider/model"`) 또는 객체(`{ primary, fallbacks }`)를 허용합니다. - 문자열 형식은 기본 모델만 설정합니다. - - 객체 형식은 기본 모델과 순서가 있는 장애 조치 모델을 함께 설정합니다. + - 객체 형식은 기본 모델과 순서가 지정된 장애 조치 모델을 함께 설정합니다. - `imageModel`: 문자열(`"provider/model"`) 또는 객체(`{ primary, fallbacks }`)를 허용합니다. - `image` 도구 경로에서 비전 모델 구성으로 사용됩니다. - 선택된/기본 모델이 이미지 입력을 받을 수 없을 때 대체 라우팅에도 사용됩니다. - `imageGenerationModel`: 문자열(`"provider/model"`) 또는 객체(`{ primary, fallbacks }`)를 허용합니다. - - 공유 이미지 생성 기능과 향후 이미지를 생성하는 모든 도구/플러그인 표면에서 사용됩니다. - - 일반적인 값: Gemini 기본 이미지 생성을 위한 `google/gemini-3.1-flash-image-preview`, fal용 `fal/fal-ai/flux/dev`, OpenAI Images용 `openai/gpt-image-1`. - - provider/model을 직접 선택하는 경우, 일치하는 provider 인증/API 키도 구성해야 합니다(예: `google/*`용 `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY`, `openai/*`용 `OPENAI_API_KEY`, `fal/*`용 `FAL_KEY`). - - 생략해도 `image_generate`는 인증이 설정된 provider 기본값을 추론할 수 있습니다. 현재 기본 provider를 먼저 시도한 뒤, 나머지 등록된 이미지 생성 provider를 provider ID 순서로 시도합니다. + - 공용 이미지 생성 기능과 향후 이미지를 생성하는 모든 도구/플러그인 표면에서 사용됩니다. + - 일반적인 값: Gemini 기본 이미지 생성용 `google/gemini-3.1-flash-image-preview`, fal용 `fal/fal-ai/flux/dev`, 또는 OpenAI Images용 `openai/gpt-image-1`. + - 제공자/모델을 직접 선택하는 경우, 일치하는 제공자 인증/API 키도 구성하세요(예: `google/*`용 `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY`, `openai/*`용 `OPENAI_API_KEY`, `fal/*`용 `FAL_KEY`). + - 생략하더라도 `image_generate`는 인증이 있는 제공자 기본값을 추론할 수 있습니다. 먼저 현재 기본 제공자를 시도한 뒤, 나머지 등록된 이미지 생성 제공자를 provider-id 순서로 시도합니다. - `musicGenerationModel`: 문자열(`"provider/model"`) 또는 객체(`{ primary, fallbacks }`)를 허용합니다. - - 공유 음악 생성 기능과 기본 제공 `music_generate` 도구에서 사용됩니다. + - 공용 음악 생성 기능과 내장 `music_generate` 도구에서 사용됩니다. - 일반적인 값: `google/lyria-3-clip-preview`, `google/lyria-3-pro-preview`, 또는 `minimax/music-2.5+`. - - 생략해도 `music_generate`는 인증이 설정된 provider 기본값을 추론할 수 있습니다. 현재 기본 provider를 먼저 시도한 뒤, 나머지 등록된 음악 생성 provider를 provider ID 순서로 시도합니다. - - provider/model을 직접 선택하는 경우, 일치하는 provider 인증/API 키도 구성해야 합니다. + - 생략하더라도 `music_generate`는 인증이 있는 제공자 기본값을 추론할 수 있습니다. 먼저 현재 기본 제공자를 시도한 뒤, 나머지 등록된 음악 생성 제공자를 provider-id 순서로 시도합니다. + - 제공자/모델을 직접 선택하는 경우, 일치하는 제공자 인증/API 키도 구성하세요. - `videoGenerationModel`: 문자열(`"provider/model"`) 또는 객체(`{ primary, fallbacks }`)를 허용합니다. - - 공유 비디오 생성 기능과 기본 제공 `video_generate` 도구에서 사용됩니다. + - 공용 비디오 생성 기능과 내장 `video_generate` 도구에서 사용됩니다. - 일반적인 값: `qwen/wan2.6-t2v`, `qwen/wan2.6-i2v`, `qwen/wan2.6-r2v`, `qwen/wan2.6-r2v-flash`, 또는 `qwen/wan2.7-r2v`. - - 생략해도 `video_generate`는 인증이 설정된 provider 기본값을 추론할 수 있습니다. 현재 기본 provider를 먼저 시도한 뒤, 나머지 등록된 비디오 생성 provider를 provider ID 순서로 시도합니다. - - provider/model을 직접 선택하는 경우, 일치하는 provider 인증/API 키도 구성해야 합니다. - - 번들 Qwen 비디오 생성 provider는 최대 출력 비디오 1개, 입력 이미지 1개, 입력 비디오 4개, 길이 10초, 그리고 provider 수준 `size`, `aspectRatio`, `resolution`, `audio`, `watermark` 옵션을 지원합니다. + - 생략하더라도 `video_generate`는 인증이 있는 제공자 기본값을 추론할 수 있습니다. 먼저 현재 기본 제공자를 시도한 뒤, 나머지 등록된 비디오 생성 제공자를 provider-id 순서로 시도합니다. + - 제공자/모델을 직접 선택하는 경우, 일치하는 제공자 인증/API 키도 구성하세요. + - 번들된 Qwen 비디오 생성 제공자는 최대 출력 비디오 1개, 입력 이미지 1개, 입력 비디오 4개, 길이 10초, 그리고 제공자 수준의 `size`, `aspectRatio`, `resolution`, `audio`, `watermark` 옵션을 지원합니다. - `pdfModel`: 문자열(`"provider/model"`) 또는 객체(`{ primary, fallbacks }`)를 허용합니다. - `pdf` 도구의 모델 라우팅에 사용됩니다. - - 생략하면 PDF 도구는 `imageModel`로 대체하고, 그다음 해석된 세션/기본 모델로 대체합니다. -- `pdfMaxBytesMb`: 호출 시점에 `maxBytesMb`가 전달되지 않았을 때 `pdf` 도구에 적용되는 기본 PDF 크기 제한입니다. + - 생략하면 PDF 도구는 `imageModel`, 그다음 확인된 세션/기본 모델로 대체됩니다. +- `pdfMaxBytesMb`: 호출 시 `maxBytesMb`가 전달되지 않았을 때 `pdf` 도구의 기본 PDF 크기 제한입니다. - `pdfMaxPages`: `pdf` 도구의 추출 대체 모드에서 고려하는 기본 최대 페이지 수입니다. -- `verboseDefault`: 에이전트의 기본 상세 출력 수준입니다. 값: `"off"`, `"on"`, `"full"`. 기본값: `"off"`. -- `elevatedDefault`: 에이전트의 기본 elevated 출력 수준입니다. 값: `"off"`, `"on"`, `"ask"`, `"full"`. 기본값: `"on"`. -- `model.primary`: 형식은 `provider/model`입니다(예: `openai/gpt-5.4`). provider를 생략하면 OpenClaw는 먼저 별칭을 시도하고, 그다음 해당 정확한 모델 ID에 대한 고유한 구성 provider 일치를 시도하며, 마지막으로 구성된 기본 provider로 대체합니다(더 이상 권장되지 않는 호환 동작이므로 명시적인 `provider/model` 사용 권장). 해당 provider가 더 이상 구성된 기본 모델을 제공하지 않으면 OpenClaw는 오래된 제거된-provider 기본값을 표시하는 대신 첫 번째 구성된 provider/model로 대체합니다. -- `models`: `/model`용 구성된 모델 카탈로그 및 허용 목록입니다. 각 항목에는 `alias`(바로가기)와 `params`(provider별, 예: `temperature`, `maxTokens`, `cacheRetention`, `context1m`)를 포함할 수 있습니다. -- `params`: 모든 모델에 적용되는 전역 기본 provider 매개변수입니다. `agents.defaults.params`에 설정합니다(예: `{ cacheRetention: "long" }`). -- `params` 병합 우선순위(구성): `agents.defaults.params`(전역 기본값)는 `agents.defaults.models["provider/model"].params`(모델별)로 재정의되고, 그다음 `agents.list[].params`(일치하는 에이전트 ID)가 키별로 재정의합니다. 자세한 내용은 [프롬프트 캐싱](/ko/reference/prompt-caching)을 참조하세요. -- 이 필드를 변경하는 구성 작성기(예: `/models set`, `/models set-image`, fallback 추가/제거 명령)는 정식 객체 형식으로 저장하며, 가능하면 기존 fallback 목록을 유지합니다. -- `maxConcurrent`: 세션 전반에서 병렬로 실행할 수 있는 최대 에이전트 수입니다(각 세션은 여전히 직렬화됨). 기본값: 4. +- `verboseDefault`: 에이전트의 기본 자세한 출력 수준입니다. 값: `"off"`, `"on"`, `"full"`. 기본값: `"off"`. +- `elevatedDefault`: 에이전트의 기본 elevated-output 수준입니다. 값: `"off"`, `"on"`, `"ask"`, `"full"`. 기본값: `"on"`. +- `model.primary`: 형식은 `provider/model`입니다(예: `openai/gpt-5.4`). 제공자를 생략하면 OpenClaw는 먼저 별칭을 시도하고, 그다음 정확히 일치하는 모델 id에 대한 고유한 구성 제공자 일치를 찾고, 마지막으로 구성된 기본 제공자로 대체합니다(더 이상 권장되지 않는 호환 동작이므로 명시적인 `provider/model`을 권장). 해당 제공자가 더 이상 구성된 기본 모델을 노출하지 않으면, OpenClaw는 오래된 제거된 제공자 기본값을 그대로 표시하는 대신 첫 번째 구성된 제공자/모델로 대체합니다. +- `models`: `/model`용 구성된 모델 카탈로그 및 허용 목록입니다. 각 항목에는 `alias`(단축 이름)와 `params`(예: `temperature`, `maxTokens`, `cacheRetention`, `context1m` 같은 제공자별 값)를 포함할 수 있습니다. +- `params`: 모든 모델에 적용되는 전역 기본 provider parameters입니다. `agents.defaults.params`에 설정합니다(예: `{ cacheRetention: "long" }`). +- `params` 병합 우선순위(구성): `agents.defaults.params`(전역 기본값)는 `agents.defaults.models["provider/model"].params`(모델별)로 재정의되고, 그다음 `agents.list[].params`(일치하는 에이전트 id)가 키별로 재정의합니다. 자세한 내용은 [Prompt Caching](/ko/reference/prompt-caching)을 참고하세요. +- `embeddedHarness`: 기본 저수준 내장 에이전트 런타임 정책입니다. 등록된 플러그인 harness가 지원 모델을 선택하도록 하려면 `runtime: "auto"`를 사용하고, 내장 PI harness를 강제하려면 `runtime: "pi"`를, `runtime: "codex"`처럼 등록된 harness id를 직접 사용할 수도 있습니다. 자동 PI 대체를 비활성화하려면 `fallback: "none"`으로 설정하세요. +- 이 필드를 변경하는 구성 작성기(예: `/models set`, `/models set-image`, fallback 추가/제거 명령)는 정규 객체 형식으로 저장하고 가능하면 기존 fallback 목록을 보존합니다. +- `maxConcurrent`: 세션 전반에서 동시에 실행할 수 있는 최대 병렬 에이전트 실행 수입니다(각 세션은 여전히 직렬화됨). 기본값: 4. -**기본 제공 별칭 단축형** (`agents.defaults.models`에 모델이 있을 때만 적용): +### `agents.defaults.embeddedHarness` -| 별칭 | 모델 | +`embeddedHarness`는 내장 에이전트 턴을 어떤 저수준 실행기가 처리할지 제어합니다. +대부분의 배포에서는 기본값 `{ runtime: "auto", fallback: "pi" }`를 유지하면 됩니다. +번들된 +Codex app-server harness처럼 신뢰할 수 있는 플러그인이 네이티브 harness를 제공할 때 사용하세요. + +```json5 +{ + agents: { + defaults: { + model: "codex/gpt-5.4", + embeddedHarness: { + runtime: "codex", + fallback: "none", + }, + }, + }, +} +``` + +- `runtime`: `"auto"`, `"pi"`, 또는 등록된 플러그인 harness id입니다. 번들된 Codex 플러그인은 `codex`를 등록합니다. +- `fallback`: `"pi"` 또는 `"none"`. `"pi"`는 내장 PI harness를 호환성 대체값으로 유지합니다. `"none"`은 누락되었거나 지원되지 않는 플러그인 harness 선택 시 조용히 PI를 사용하는 대신 실패하게 만듭니다. +- 환경 변수 재정의: `OPENCLAW_AGENT_RUNTIME=`는 `runtime`을 재정의하고, `OPENCLAW_AGENT_HARNESS_FALLBACK=none`은 해당 프로세스에서 PI 대체를 비활성화합니다. +- Codex 전용 배포의 경우 `model: "codex/gpt-5.4"`, `embeddedHarness.runtime: "codex"`, `embeddedHarness.fallback: "none"`으로 설정하세요. +- 이것은 내장 채팅 harness만 제어합니다. 미디어 생성, 비전, PDF, 음악, 비디오, TTS는 여전히 각자의 provider/model 설정을 사용합니다. + +**내장 alias 단축 이름** (`agents.defaults.models`에 해당 모델이 있을 때만 적용됨): + +| Alias | Model | | ------------------- | -------------------------------------- | | `opus` | `anthropic/claude-opus-4-6` | | `sonnet` | `anthropic/claude-sonnet-4-6` | @@ -1111,15 +1154,15 @@ provider 호출 전에 transcript/tool 이미지 블록에서 가장 긴 이미 | `gemini-flash` | `google/gemini-3-flash-preview` | | `gemini-flash-lite` | `google/gemini-3.1-flash-lite-preview` | -구성한 별칭은 항상 기본값보다 우선합니다. +구성한 alias는 항상 기본값보다 우선합니다. Z.AI GLM-4.x 모델은 `--thinking off`를 설정하거나 `agents.defaults.models["zai/"].params.thinking`을 직접 정의하지 않는 한 자동으로 thinking 모드를 활성화합니다. Z.AI 모델은 도구 호출 스트리밍을 위해 기본적으로 `tool_stream`을 활성화합니다. 비활성화하려면 `agents.defaults.models["zai/"].params.tool_stream`을 `false`로 설정하세요. -Anthropic Claude 4.6 모델은 명시적인 thinking 수준이 설정되지 않으면 기본적으로 `adaptive` thinking을 사용합니다. +Anthropic Claude 4.6 모델은 명시적인 thinking 수준이 설정되지 않은 경우 기본적으로 `adaptive` thinking을 사용합니다. ### `agents.defaults.cliBackends` -도구 호출이 없는 텍스트 전용 대체 실행을 위한 선택적 CLI 백엔드입니다. API provider가 실패할 때 백업으로 유용합니다. +텍스트 전용 대체 실행(도구 호출 없음)을 위한 선택적 CLI 백엔드입니다. API 제공자가 실패할 때 백업으로 유용합니다. ```json5 { @@ -1148,12 +1191,12 @@ Anthropic Claude 4.6 모델은 명시적인 thinking 수준이 설정되지 않 ``` - CLI 백엔드는 텍스트 우선이며, 도구는 항상 비활성화됩니다. -- `sessionArg`가 설정되면 세션이 지원됩니다. +- `sessionArg`가 설정된 경우 세션을 지원합니다. - `imageArg`가 파일 경로를 받을 수 있으면 이미지 전달도 지원됩니다. ### `agents.defaults.systemPromptOverride` -OpenClaw가 조합한 전체 시스템 프롬프트를 고정 문자열로 대체합니다. 기본 수준(`agents.defaults.systemPromptOverride`) 또는 에이전트별(`agents.list[].systemPromptOverride`)로 설정합니다. 에이전트별 값이 우선하며, 비어 있거나 공백만 있는 값은 무시됩니다. 통제된 프롬프트 실험에 유용합니다. +OpenClaw가 조합한 전체 시스템 프롬프트를 고정 문자열로 대체합니다. 기본 수준(`agents.defaults.systemPromptOverride`) 또는 에이전트별(`agents.list[].systemPromptOverride`)로 설정할 수 있습니다. 에이전트별 값이 우선하며, 빈 문자열 또는 공백만 있는 값은 무시됩니다. 통제된 프롬프트 실험에 유용합니다. ```json5 { @@ -1167,26 +1210,27 @@ OpenClaw가 조합한 전체 시스템 프롬프트를 고정 문자열로 대 ### `agents.defaults.heartbeat` -주기적인 하트비트 실행입니다. +주기적인 heartbeat 실행입니다. ```json5 { agents: { defaults: { heartbeat: { - every: "30m", // 0m이면 비활성화 + every: "30m", // 0m disables model: "openai/gpt-5.4-mini", includeReasoning: false, - includeSystemPromptSection: true, // 기본값: true; false이면 시스템 프롬프트에서 Heartbeat 섹션 생략 - lightContext: false, // 기본값: false; true이면 workspace bootstrap 파일 중 HEARTBEAT.md만 유지 - isolatedSession: false, // 기본값: false; true이면 각 하트비트를 새 세션에서 실행(대화 기록 없음) + includeSystemPromptSection: true, // default: true; false omits the Heartbeat section from the system prompt + lightContext: false, // default: false; true keeps only HEARTBEAT.md from workspace bootstrap files + isolatedSession: false, // default: false; true runs each heartbeat in a fresh session (no conversation history) session: "main", to: "+15555550123", - directPolicy: "allow", // allow (기본값) | block - target: "none", // 기본값: none | 옵션: last | whatsapp | telegram | discord | ... + directPolicy: "allow", // allow (default) | block + target: "none", // default: none | options: last | whatsapp | telegram | discord | ... prompt: "Read HEARTBEAT.md if it exists...", ackMaxChars: 300, suppressToolErrorWarnings: false, + timeoutSeconds: 45, }, }, }, @@ -1195,12 +1239,13 @@ OpenClaw가 조합한 전체 시스템 프롬프트를 고정 문자열로 대 - `every`: 기간 문자열(ms/s/m/h)입니다. 기본값: `30m`(API 키 인증) 또는 `1h`(OAuth 인증). 비활성화하려면 `0m`으로 설정하세요. - `includeSystemPromptSection`: false이면 시스템 프롬프트에서 Heartbeat 섹션을 생략하고 bootstrap 컨텍스트에 `HEARTBEAT.md`를 주입하지 않습니다. 기본값: `true`. -- `suppressToolErrorWarnings`: true이면 하트비트 실행 중 도구 오류 경고 페이로드를 숨깁니다. -- `directPolicy`: direct/DM 전달 정책입니다. `allow`(기본값)는 direct 대상 전달을 허용합니다. `block`은 direct 대상 전달을 막고 `reason=dm-blocked`를 출력합니다. -- `lightContext`: true이면 하트비트 실행에서 경량 bootstrap 컨텍스트를 사용하고 workspace bootstrap 파일 중 `HEARTBEAT.md`만 유지합니다. -- `isolatedSession`: true이면 각 하트비트를 이전 대화 기록이 없는 새 세션에서 실행합니다. cron `sessionTarget: "isolated"`와 동일한 격리 패턴입니다. 하트비트당 토큰 비용을 약 100K에서 약 2-5K 토큰으로 줄입니다. -- 에이전트별 설정: `agents.list[].heartbeat`를 사용하세요. 어떤 에이전트든 `heartbeat`를 정의하면 **해당 에이전트들만** 하트비트를 실행합니다. -- 하트비트는 전체 에이전트 턴을 실행하므로, 간격이 짧을수록 더 많은 토큰을 사용합니다. +- `suppressToolErrorWarnings`: true이면 heartbeat 실행 중 도구 오류 경고 페이로드를 숨깁니다. +- `timeoutSeconds`: heartbeat 에이전트 턴이 중단되기 전까지 허용되는 최대 시간(초)입니다. 설정하지 않으면 `agents.defaults.timeoutSeconds`를 사용합니다. +- `directPolicy`: direct/DM 전달 정책입니다. `allow`(기본값)는 직접 대상 전달을 허용합니다. `block`은 직접 대상 전달을 차단하고 `reason=dm-blocked`를 발생시킵니다. +- `lightContext`: true이면 heartbeat 실행은 경량 bootstrap 컨텍스트를 사용하고 workspace bootstrap 파일 중 `HEARTBEAT.md`만 유지합니다. +- `isolatedSession`: true이면 각 heartbeat 실행은 이전 대화 기록이 없는 새 세션에서 실행됩니다. cron `sessionTarget: "isolated"`와 동일한 격리 패턴입니다. heartbeat당 토큰 비용을 약 100K에서 약 2~5K 토큰으로 줄여줍니다. +- 에이전트별 설정: `agents.list[].heartbeat`를 사용하세요. 어떤 에이전트든 `heartbeat`를 정의하면 **해당 에이전트들만** heartbeat를 실행합니다. +- Heartbeat는 완전한 에이전트 턴을 실행하므로, 간격이 짧을수록 더 많은 토큰을 소모합니다. ### `agents.defaults.compaction` @@ -1210,19 +1255,19 @@ OpenClaw가 조합한 전체 시스템 프롬프트를 고정 문자열로 대 defaults: { compaction: { mode: "safeguard", // default | safeguard - provider: "my-provider", // 등록된 compaction provider plugin의 ID(선택 사항) + provider: "my-provider", // 등록된 compaction provider plugin의 id (선택 사항) timeoutSeconds: 900, reserveTokensFloor: 24000, identifierPolicy: "strict", // strict | off | custom identifierInstructions: "배포 ID, 티켓 ID, host:port 쌍을 정확히 보존하세요.", // identifierPolicy=custom일 때 사용 postCompactionSections: ["Session Startup", "Red Lines"], // []이면 재주입 비활성화 model: "openrouter/anthropic/claude-sonnet-4-6", // 선택적 compaction 전용 모델 재정의 - notifyUser: true, // compaction 시작 시 짧은 알림 전송(기본값: false) + notifyUser: true, // compaction 시작 시 짧은 알림 전송 (기본값: false) memoryFlush: { enabled: true, softThresholdTokens: 6000, - systemPrompt: "세션이 compaction에 가까워졌습니다. 지속될 메모리를 지금 저장하세요.", - prompt: "lasting notes가 있으면 memory/YYYY-MM-DD.md에 작성하고, 저장할 내용이 없으면 정확히 무응답 토큰 NO_REPLY로 응답하세요.", + systemPrompt: "세션이 compaction에 가까워지고 있습니다. 지금 내구성 있는 메모리를 저장하세요.", + prompt: "지속되어야 하는 메모리를 memory/YYYY-MM-DD.md에 기록하고, 저장할 내용이 없으면 정확히 무음 토큰 NO_REPLY로 응답하세요.", }, }, }, @@ -1230,19 +1275,19 @@ OpenClaw가 조합한 전체 시스템 프롬프트를 고정 문자열로 대 } ``` -- `mode`: `default` 또는 `safeguard`(긴 기록을 위한 청크 단위 요약)입니다. [Compaction](/ko/concepts/compaction)을 참조하세요. -- `provider`: 등록된 compaction provider plugin의 ID입니다. 설정하면 기본 제공 LLM 요약 대신 해당 provider의 `summarize()`가 호출됩니다. 실패 시 기본 제공 방식으로 대체됩니다. provider를 설정하면 `mode: "safeguard"`가 강제됩니다. [Compaction](/ko/concepts/compaction)을 참조하세요. +- `mode`: `default` 또는 `safeguard`(긴 기록에 대한 청크 단위 요약)입니다. [Compaction](/ko/concepts/compaction)을 참고하세요. +- `provider`: 등록된 compaction provider plugin의 id입니다. 설정하면 내장 LLM 요약 대신 제공자의 `summarize()`가 호출됩니다. 실패 시 내장 방식으로 대체됩니다. provider를 설정하면 `mode: "safeguard"`가 강제됩니다. [Compaction](/ko/concepts/compaction)을 참고하세요. - `timeoutSeconds`: OpenClaw가 중단하기 전 단일 compaction 작업에 허용되는 최대 시간(초)입니다. 기본값: `900`. -- `identifierPolicy`: `strict`(기본값), `off`, 또는 `custom`입니다. `strict`는 compaction 요약 중 기본 제공 불투명 식별자 보존 지침을 앞에 추가합니다. +- `identifierPolicy`: `strict`(기본값), `off`, 또는 `custom`입니다. `strict`는 compaction 요약 중 불투명 식별자 보존에 대한 내장 지침을 앞에 추가합니다. - `identifierInstructions`: `identifierPolicy=custom`일 때 사용되는 선택적 사용자 지정 식별자 보존 텍스트입니다. -- `postCompactionSections`: compaction 후 다시 주입할 선택적 AGENTS.md H2/H3 섹션 이름입니다. 기본값은 `["Session Startup", "Red Lines"]`이며, 재주입을 비활성화하려면 `[]`로 설정하세요. 설정하지 않았거나 명시적으로 그 기본 쌍으로 설정한 경우, 이전 `Every Session`/`Safety` 헤딩도 레거시 대체값으로 허용됩니다. -- `model`: compaction 요약에만 적용되는 선택적 `provider/model-id` 재정의입니다. 기본 세션은 한 모델을 유지하고 compaction 요약은 다른 모델에서 실행해야 할 때 사용하세요. 설정하지 않으면 compaction은 세션의 기본 모델을 사용합니다. -- `notifyUser`: `true`이면 compaction이 시작될 때 사용자에게 짧은 알림을 보냅니다(예: "Compacting context..."). compaction을 조용히 유지하기 위해 기본적으로 비활성화되어 있습니다. -- `memoryFlush`: 자동 compaction 전에 지속 메모리를 저장하기 위한 무음 agentic 턴입니다. workspace가 읽기 전용이면 건너뜁니다. +- `postCompactionSections`: compaction 후 재주입할 선택적 AGENTS.md H2/H3 섹션 이름입니다. 기본값은 `["Session Startup", "Red Lines"]`이며, 재주입을 비활성화하려면 `[]`로 설정하세요. 설정되지 않았거나 이 기본 쌍으로 명시적으로 설정된 경우, 레거시 대체값으로 예전 `Every Session`/`Safety` 제목도 허용됩니다. +- `model`: compaction 요약 전용의 선택적 `provider/model-id` 재정의입니다. 기본 세션은 한 모델을 유지하되 compaction 요약은 다른 모델에서 실행하려는 경우 사용하세요. 설정하지 않으면 compaction은 세션의 기본 모델을 사용합니다. +- `notifyUser`: `true`이면 compaction 시작 시 사용자에게 짧은 알림(예: "Compacting context...")을 보냅니다. 기본적으로는 compaction을 조용히 유지하기 위해 비활성화되어 있습니다. +- `memoryFlush`: 자동 compaction 전에 내구성 있는 메모리를 저장하기 위한 무음 agentic turn입니다. workspace가 읽기 전용이면 건너뜁니다. ### `agents.defaults.contextPruning` -LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 결과**를 제거합니다. 디스크의 세션 기록은 수정하지 않습니다. +LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 결과**를 정리합니다. 디스크의 세션 기록은 수정하지 않습니다. ```json5 { @@ -1250,13 +1295,13 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 defaults: { contextPruning: { mode: "cache-ttl", // off | cache-ttl - ttl: "1h", // 기간(ms/s/m/h), 기본 단위: 분 + ttl: "1h", // 기간 (ms/s/m/h), 기본 단위: 분 keepLastAssistants: 3, softTrimRatio: 0.3, hardClearRatio: 0.5, minPrunableToolChars: 50000, softTrim: { maxChars: 4000, headChars: 1500, tailChars: 1500 }, - hardClear: { enabled: true, placeholder: "[Old tool result content cleared]" }, + hardClear: { enabled: true, placeholder: "[오래된 도구 결과 내용이 삭제됨]" }, tools: { deny: ["browser", "canvas"] }, }, }, @@ -1266,9 +1311,9 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 -- `mode: "cache-ttl"`은 제거 패스를 활성화합니다. -- `ttl`은 마지막 캐시 터치 이후 제거가 다시 실행될 수 있는 빈도를 제어합니다. -- 제거는 먼저 큰 도구 결과를 soft-trim하고, 필요하면 더 오래된 도구 결과를 hard-clear합니다. +- `mode: "cache-ttl"`은 정리 패스를 활성화합니다. +- `ttl`은 마지막 캐시 접근 이후 다시 정리를 실행할 수 있는 빈도를 제어합니다. +- 정리는 먼저 큰 도구 결과를 soft-trim하고, 필요하면 더 오래된 도구 결과를 hard-clear합니다. **Soft-trim**은 앞부분 + 끝부분을 유지하고 중간에 `...`를 삽입합니다. @@ -1276,13 +1321,13 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 참고: -- 이미지 블록은 절대 잘리거나 지워지지 않습니다. -- 비율은 문자 기준(근사치)이며, 정확한 토큰 수 기준이 아닙니다. -- assistant 메시지가 `keepLastAssistants`보다 적으면 제거는 건너뜁니다. +- 이미지 블록은 절대 잘리거나 삭제되지 않습니다. +- 비율은 정확한 토큰 수가 아니라 문자 수 기준의 근사치입니다. +- `keepLastAssistants`보다 적은 assistant 메시지만 있으면 정리는 건너뜁니다. -동작 세부 사항은 [세션 제거](/ko/concepts/session-pruning)를 참조하세요. +동작 세부 정보는 [Session Pruning](/ko/concepts/session-pruning)을 참고하세요. ### 블록 스트리밍 @@ -1300,13 +1345,13 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 } ``` -- Telegram이 아닌 채널은 블록 응답을 활성화하려면 명시적인 `*.blockStreaming: true`가 필요합니다. -- 채널 재정의: `channels..blockStreamingCoalesce`(및 계정별 변형). Signal/Slack/Discord/Google Chat의 기본값은 `minChars: 1500`입니다. -- `humanDelay`: 블록 응답 사이의 무작위 지연입니다. `natural` = 800–2500ms. 에이전트별 재정의: `agents.list[].humanDelay`. +- Telegram이 아닌 채널은 블록 응답을 활성화하려면 명시적으로 `*.blockStreaming: true`가 필요합니다. +- 채널 재정의: `channels..blockStreamingCoalesce`(및 계정별 변형). Signal/Slack/Discord/Google Chat의 기본 `minChars`는 `1500`입니다. +- `humanDelay`: 블록 응답 사이의 무작위 대기입니다. `natural` = 800–2500ms. 에이전트별 재정의: `agents.list[].humanDelay`. -동작 및 청킹 세부 사항은 [스트리밍](/ko/concepts/streaming)을 참조하세요. +동작 및 청킹 세부 정보는 [Streaming](/ko/concepts/streaming)을 참고하세요. -### 입력 중 표시기 +### 타이핑 표시기 ```json5 { @@ -1319,16 +1364,16 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 } ``` -- 기본값: direct 채팅/멘션에는 `instant`, 멘션되지 않은 그룹 채팅에는 `message`. +- 기본값: 직접 채팅/멘션에는 `instant`, 멘션되지 않은 그룹 채팅에는 `message`. - 세션별 재정의: `session.typingMode`, `session.typingIntervalSeconds`. -[입력 중 표시기](/ko/concepts/typing-indicators)를 참조하세요. +[Typing Indicators](/ko/concepts/typing-indicators)를 참고하세요. ### `agents.defaults.sandbox` -임베디드 에이전트를 위한 선택적 sandboxing입니다. 전체 가이드는 [Sandboxing](/ko/gateway/sandboxing)을 참조하세요. +내장 에이전트를 위한 선택적 샌드박싱입니다. 전체 가이드는 [Sandboxing](/ko/gateway/sandboxing)을 참고하세요. ```json5 { @@ -1374,7 +1419,7 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 identityFile: "~/.ssh/id_ed25519", certificateFile: "~/.ssh/id_ed25519-cert.pub", knownHostsFile: "~/.ssh/known_hosts", - // SecretRef / 인라인 내용도 지원: + // SecretRefs / inline contents도 지원: // identityData: { source: "env", provider: "default", id: "SSH_IDENTITY" }, // certificateData: { source: "env", provider: "default", id: "SSH_CERTIFICATE" }, // knownHostsData: { source: "env", provider: "default", id: "SSH_KNOWN_HOSTS" }, @@ -1423,7 +1468,7 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 } ``` - + **백엔드:** @@ -1431,45 +1476,46 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 - `ssh`: 일반 SSH 기반 원격 런타임 - `openshell`: OpenShell 런타임 -`backend: "openshell"`을 선택하면 런타임별 설정은 `plugins.entries.openshell.config`로 이동합니다. +`backend: "openshell"`을 선택하면 런타임별 설정은 +`plugins.entries.openshell.config`로 이동합니다. **SSH 백엔드 구성:** - `target`: `user@host[:port]` 형식의 SSH 대상 - `command`: SSH 클라이언트 명령(기본값: `ssh`) -- `workspaceRoot`: 범위별 workspace에 사용하는 절대 원격 루트 +- `workspaceRoot`: 범위별 workspace에 사용되는 절대 원격 루트 - `identityFile` / `certificateFile` / `knownHostsFile`: OpenSSH에 전달되는 기존 로컬 파일 - `identityData` / `certificateData` / `knownHostsData`: OpenClaw가 런타임에 임시 파일로 구체화하는 인라인 내용 또는 SecretRef -- `strictHostKeyChecking` / `updateHostKeys`: OpenSSH 호스트 키 정책 옵션 +- `strictHostKeyChecking` / `updateHostKeys`: OpenSSH 호스트 키 정책 설정 **SSH 인증 우선순위:** -- `identityData`가 `identityFile`보다 우선 -- `certificateData`가 `certificateFile`보다 우선 -- `knownHostsData`가 `knownHostsFile`보다 우선 -- SecretRef 기반 `*Data` 값은 sandbox 세션 시작 전에 활성 secrets 런타임 스냅샷에서 해석됩니다 +- `identityData`가 `identityFile`보다 우선합니다 +- `certificateData`가 `certificateFile`보다 우선합니다 +- `knownHostsData`가 `knownHostsFile`보다 우선합니다 +- SecretRef 기반 `*Data` 값은 샌드박스 세션 시작 전에 활성 secrets 런타임 스냅샷에서 해석됩니다 **SSH 백엔드 동작:** -- 생성 또는 재생성 후 원격 workspace를 한 번 시드함 -- 이후 원격 SSH workspace를 정식 기준으로 유지함 -- `exec`, 파일 도구, 미디어 경로를 SSH를 통해 라우팅함 -- 원격 변경 사항을 호스트에 자동으로 다시 동기화하지 않음 -- sandbox 브라우저 컨테이너는 지원하지 않음 +- 생성 또는 재생성 후 원격 workspace를 한 번 시드합니다 +- 이후 원격 SSH workspace를 정식 기준으로 유지합니다 +- `exec`, 파일 도구, 미디어 경로를 SSH를 통해 라우팅합니다 +- 원격 변경 사항을 호스트로 자동 동기화하지 않습니다 +- 샌드박스 브라우저 컨테이너를 지원하지 않습니다 **Workspace 접근:** -- `none`: `~/.openclaw/sandboxes` 아래의 범위별 sandbox workspace -- `ro`: `/workspace`의 sandbox workspace, `/agent`에 읽기 전용으로 마운트된 agent workspace -- `rw`: agent workspace를 `/workspace`에 읽기/쓰기로 마운트 +- `none`: `~/.openclaw/sandboxes` 아래의 범위별 샌드박스 workspace +- `ro`: `/workspace`의 샌드박스 workspace, `/agent`에 에이전트 workspace를 읽기 전용으로 마운트 +- `rw`: 에이전트 workspace를 `/workspace`에 읽기/쓰기 가능으로 마운트 **범위:** - `session`: 세션별 컨테이너 + workspace -- `agent`: 에이전트별 컨테이너 + workspace 1개(기본값) -- `shared`: 공유 컨테이너 및 workspace(세션 간 격리 없음) +- `agent`: 에이전트별 컨테이너 + workspace(기본값) +- `shared`: 공유 컨테이너와 workspace(세션 간 격리 없음) -**OpenShell plugin 구성:** +**OpenShell 플러그인 구성:** ```json5 { @@ -1484,7 +1530,7 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 remoteAgentWorkspaceDir: "/agent", gateway: "lab", // 선택 사항 gatewayEndpoint: "https://lab.example", // 선택 사항 - policy: "strict", // 선택적 OpenShell policy id + policy: "strict", // 선택적 OpenShell 정책 id providers: ["openai"], // 선택 사항 autoProviders: true, timeoutSeconds: 120, @@ -1497,30 +1543,30 @@ LLM으로 보내기 전에 메모리 내 컨텍스트에서 **오래된 도구 **OpenShell 모드:** -- `mirror`: 실행 전 로컬에서 원격으로 시드하고, 실행 후 다시 동기화함. 로컬 workspace가 정식 기준으로 유지됨 -- `remote`: sandbox가 생성될 때 원격을 한 번 시드한 뒤, 원격 workspace를 정식 기준으로 유지함 +- `mirror`: exec 전에 원격을 로컬에서 시드하고, exec 후 다시 동기화합니다. 로컬 workspace가 정식 기준으로 유지됩니다 +- `remote`: 샌드박스 생성 시 한 번만 원격을 시드하고, 이후 원격 workspace를 정식 기준으로 유지합니다 -`remote` 모드에서는 시드 단계 이후 OpenClaw 외부에서 이루어진 호스트 로컬 편집이 sandbox에 자동으로 동기화되지 않습니다. -전송은 OpenShell sandbox로의 SSH를 사용하지만, plugin이 sandbox 수명 주기와 선택적 mirror 동기화를 관리합니다. +`remote` 모드에서는 시드 단계 이후 OpenClaw 외부에서 수행된 호스트 로컬 편집이 샌드박스로 자동 동기화되지 않습니다. +전송은 OpenShell 샌드박스로의 SSH이지만, 플러그인이 샌드박스 수명 주기와 선택적 mirror sync를 소유합니다. -**`setupCommand`**는 컨테이너 생성 후 한 번 실행됩니다(`sh -lc` 사용). 네트워크 송신, 쓰기 가능한 루트, root 사용자가 필요합니다. +**`setupCommand`**는 컨테이너 생성 후 한 번 실행됩니다(`sh -lc` 사용). 네트워크 송신, 쓰기 가능한 루트, 루트 사용자가 필요합니다. **컨테이너는 기본적으로 `network: "none"`입니다** — 에이전트에 외부 접근이 필요하면 `"bridge"`(또는 사용자 지정 브리지 네트워크)로 설정하세요. `"host"`는 차단됩니다. `"container:"`는 기본적으로 차단되며, -`sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true`를 명시적으로 설정한 경우에만 허용됩니다(비상 수단). +명시적으로 `sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true`를 설정한 경우에만 허용됩니다(비상 모드). **수신 첨부 파일**은 활성 workspace의 `media/inbound/*`에 스테이징됩니다. -**`docker.binds`**는 추가 호스트 디렉터리를 마운트합니다. 전역 및 에이전트별 bind는 병합됩니다. +**`docker.binds`**는 추가 호스트 디렉터리를 마운트하며, 전역 및 에이전트별 binds가 병합됩니다. -**Sandboxed browser** (`sandbox.browser.enabled`): 컨테이너 안의 Chromium + CDP입니다. noVNC URL이 시스템 프롬프트에 주입됩니다. `openclaw.json`에서 `browser.enabled`가 필요하지 않습니다. -noVNC 관찰자 접근은 기본적으로 VNC 인증을 사용하며, OpenClaw는 공유 URL에 비밀번호를 노출하는 대신 짧은 수명의 토큰 URL을 발급합니다. +**샌드박스 브라우저** (`sandbox.browser.enabled`): 컨테이너 안의 Chromium + CDP입니다. noVNC URL이 시스템 프롬프트에 주입됩니다. `openclaw.json`에서 `browser.enabled`가 필요하지 않습니다. +noVNC 관찰자 접근은 기본적으로 VNC 인증을 사용하며, OpenClaw는 공유 URL에 비밀번호를 노출하는 대신 짧은 수명의 토큰 URL을 생성합니다. -- `allowHostControl: false`(기본값)는 sandbox 세션이 호스트 브라우저를 대상으로 지정하는 것을 차단합니다. -- `network`의 기본값은 `openclaw-sandbox-browser`(전용 브리지 네트워크)입니다. 전역 브리지 연결이 명시적으로 필요할 때만 `bridge`로 설정하세요. +- `allowHostControl: false`(기본값)는 샌드박스 세션이 호스트 브라우저를 대상으로 삼는 것을 차단합니다. +- `network`의 기본값은 `openclaw-sandbox-browser`(전용 브리지 네트워크)입니다. 전역 브리지 연결이 명시적으로 필요한 경우에만 `bridge`로 설정하세요. - `cdpSourceRange`는 선택적으로 컨테이너 경계에서 CDP 유입을 CIDR 범위(예: `172.21.0.1/32`)로 제한합니다. -- `sandbox.browser.binds`는 추가 호스트 디렉터리를 sandbox 브라우저 컨테이너에만 마운트합니다. 설정되면(`[]` 포함) 브라우저 컨테이너에는 `docker.binds` 대신 이것이 사용됩니다. -- 시작 기본값은 `scripts/sandbox-browser-entrypoint.sh`에 정의되어 있으며 컨테이너 호스트에 맞게 조정되어 있습니다. +- `sandbox.browser.binds`는 추가 호스트 디렉터리를 샌드박스 브라우저 컨테이너에만 마운트합니다. 이 값이 설정되면(`[]` 포함) 브라우저 컨테이너에서는 `docker.binds`를 대체합니다. +- 시작 기본값은 `scripts/sandbox-browser-entrypoint.sh`에 정의되어 있으며 컨테이너 호스트에 맞게 조정되어 있습니다: - `--remote-debugging-address=127.0.0.1` - `--remote-debugging-port=` - `--user-data-dir=${HOME}/.chrome` @@ -1538,24 +1584,30 @@ noVNC 관찰자 접근은 기본적으로 VNC 인증을 사용하며, OpenClaw - `--no-zygote` - `--metrics-recording-only` - `--disable-extensions`(기본적으로 활성화됨) - - `--disable-3d-apis`, `--disable-software-rasterizer`, `--disable-gpu`는 기본적으로 활성화되어 있으며, WebGL/3D 사용에 필요하면 `OPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0`으로 비활성화할 수 있습니다. - - 워크플로가 확장 기능에 의존하면 `OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0`으로 확장 기능을 다시 활성화합니다. - - `--renderer-process-limit=2`는 `OPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=`으로 변경할 수 있습니다. Chromium 기본 프로세스 제한을 사용하려면 `0`으로 설정하세요. - - 또한 `noSandbox`가 활성화되면 `--no-sandbox` 및 `--disable-setuid-sandbox`가 추가됩니다. - - 기본값은 컨테이너 이미지 기준값입니다. 컨테이너 기본값을 변경하려면 사용자 지정 엔트리포인트가 있는 사용자 지정 브라우저 이미지를 사용하세요. + - `--disable-3d-apis`, `--disable-software-rasterizer`, `--disable-gpu`는 + 기본적으로 활성화되며, WebGL/3D 사용에 필요할 경우 + `OPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0`으로 비활성화할 수 있습니다. + - 워크플로가 확장 기능에 의존하는 경우 + `OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0`으로 확장 기능을 다시 활성화할 수 있습니다. + - `--renderer-process-limit=2`는 + `OPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=`으로 변경할 수 있습니다. Chromium의 + 기본 프로세스 제한을 사용하려면 `0`으로 설정하세요. + - `noSandbox`가 활성화된 경우 `--no-sandbox` 및 `--disable-setuid-sandbox`도 추가됩니다. + - 기본값은 컨테이너 이미지 기준선입니다. 컨테이너 기본값을 변경하려면 + 사용자 지정 entrypoint가 있는 사용자 지정 브라우저 이미지를 사용하세요. -브라우저 sandboxing과 `sandbox.docker.binds`는 Docker 전용입니다. +브라우저 샌드박싱과 `sandbox.docker.binds`는 Docker 전용입니다. 이미지 빌드: ```bash -scripts/sandbox-setup.sh # 기본 sandbox 이미지 +scripts/sandbox-setup.sh # 메인 샌드박스 이미지 scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 ``` -### `agents.list`(에이전트별 재정의) +### `agents.list` (에이전트별 재정의) ```json5 { @@ -1568,9 +1620,10 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 workspace: "~/.openclaw/workspace", agentDir: "~/.openclaw/agents/main/agent", model: "anthropic/claude-opus-4-6", // 또는 { primary, fallbacks } - thinkingDefault: "high", // 에이전트별 기본 thinking 수준 재정의 - reasoningDefault: "on", // 에이전트별 기본 reasoning 표시 재정의 - fastModeDefault: false, // 에이전트별 기본 fast mode 재정의 + thinkingDefault: "high", // 에이전트별 thinking 수준 재정의 + reasoningDefault: "on", // 에이전트별 reasoning 표시 재정의 + fastModeDefault: false, // 에이전트별 fast mode 재정의 + embeddedHarness: { runtime: "auto", fallback: "pi" }, params: { cacheRetention: "none" }, // 일치하는 defaults.models params를 키별로 재정의 skills: ["docs-search"], // 설정 시 agents.defaults.skills를 대체 identity: { @@ -1603,26 +1656,27 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 } ``` -- `id`: 안정적인 에이전트 ID입니다(필수). -- `default`: 여러 개가 설정되면 첫 번째가 적용됩니다(경고 로그 기록). 아무것도 설정되지 않으면 목록의 첫 번째 항목이 기본값입니다. -- `model`: 문자열 형식은 `primary`만 재정의하고, 객체 형식 `{ primary, fallbacks }`는 둘 다 재정의합니다(`[]`는 전역 fallback 비활성화). `primary`만 재정의하는 cron 작업은 `fallbacks: []`를 설정하지 않는 한 여전히 기본 fallback을 상속합니다. -- `params`: 선택된 모델 항목의 `agents.defaults.models` 위에 병합되는 에이전트별 스트림 매개변수입니다. 전체 모델 카탈로그를 복제하지 않고 `cacheRetention`, `temperature`, `maxTokens` 같은 에이전트별 재정의에 사용하세요. -- `skills`: 선택적 에이전트별 Skills 허용 목록입니다. 생략하면 `agents.defaults.skills`가 설정된 경우 이를 상속합니다. 명시적 목록은 병합하지 않고 기본값을 대체하며, `[]`는 Skills 없음을 의미합니다. -- `thinkingDefault`: 선택적 에이전트별 기본 thinking 수준(`off | minimal | low | medium | high | xhigh | adaptive`)입니다. 메시지별 또는 세션별 재정의가 없을 때 이 에이전트의 `agents.defaults.thinkingDefault`를 재정의합니다. -- `reasoningDefault`: 선택적 에이전트별 기본 reasoning 표시 설정(`on | off | stream`)입니다. 메시지별 또는 세션별 reasoning 재정의가 없을 때 적용됩니다. -- `fastModeDefault`: 선택적 에이전트별 기본 fast mode 설정(`true | false`)입니다. 메시지별 또는 세션별 fast-mode 재정의가 없을 때 적용됩니다. -- `runtime`: 선택적 에이전트별 런타임 설명자입니다. 에이전트가 기본적으로 ACP harness 세션을 사용해야 할 때 `type: "acp"`와 `runtime.acp` 기본값(`agent`, `backend`, `mode`, `cwd`)을 사용하세요. -- `identity.avatar`: workspace 상대 경로, `http(s)` URL 또는 `data:` URI입니다. -- `identity`는 기본값을 파생합니다. `ackReaction`은 `emoji`에서, `mentionPatterns`는 `name`/`emoji`에서 파생됩니다. -- `subagents.allowAgents`: `sessions_spawn`용 에이전트 ID 허용 목록입니다(`["*"]` = 아무 에이전트나, 기본값: 동일 에이전트만). -- Sandbox 상속 보호: 요청 세션이 sandbox 상태이면 `sessions_spawn`은 sandbox 없이 실행될 대상을 거부합니다. +- `id`: 안정적인 에이전트 id입니다(필수). +- `default`: 여러 개가 설정되면 첫 번째가 우선합니다(경고 로그 기록). 아무것도 설정되지 않으면 목록의 첫 번째 항목이 기본값입니다. +- `model`: 문자열 형식은 `primary`만 재정의하고, 객체 형식 `{ primary, fallbacks }`는 둘 다 재정의합니다(`[]`는 전역 fallback 비활성화). `primary`만 재정의하는 cron 작업은 `fallbacks: []`를 설정하지 않는 한 기본 fallback을 계속 상속합니다. +- `params`: `agents.defaults.models`의 선택된 모델 항목 위에 병합되는 에이전트별 스트림 params입니다. 전체 모델 카탈로그를 복제하지 않고 `cacheRetention`, `temperature`, `maxTokens` 같은 에이전트별 재정의에 사용하세요. +- `skills`: 선택적 에이전트별 skill 허용 목록입니다. 생략하면 에이전트는 설정된 경우 `agents.defaults.skills`를 상속합니다. 명시적 목록은 병합하지 않고 기본값을 대체하며, `[]`는 skill 없음을 의미합니다. +- `thinkingDefault`: 선택적 에이전트별 기본 thinking 수준(`off | minimal | low | medium | high | xhigh | adaptive`)입니다. 메시지별 또는 세션별 재정의가 없을 때 이 에이전트에 대해 `agents.defaults.thinkingDefault`를 재정의합니다. +- `reasoningDefault`: 선택적 에이전트별 기본 reasoning 표시 수준(`on | off | stream`)입니다. 메시지별 또는 세션별 reasoning 재정의가 없을 때 적용됩니다. +- `fastModeDefault`: 선택적 에이전트별 기본 fast mode 값(`true | false`)입니다. 메시지별 또는 세션별 fast-mode 재정의가 없을 때 적용됩니다. +- `embeddedHarness`: 선택적 에이전트별 저수준 harness 정책 재정의입니다. 한 에이전트만 Codex 전용으로 만들고 다른 에이전트는 기본 PI fallback을 유지하려면 `{ runtime: "codex", fallback: "none" }`를 사용하세요. +- `runtime`: 선택적 에이전트별 런타임 설명자입니다. 에이전트가 기본적으로 ACP harness 세션을 사용해야 하는 경우 `type: "acp"`와 `runtime.acp` 기본값(`agent`, `backend`, `mode`, `cwd`)을 사용하세요. +- `identity.avatar`: workspace 기준 경로, `http(s)` URL 또는 `data:` URI입니다. +- `identity`는 기본값을 파생합니다: `emoji`에서 `ackReaction`, `name`/`emoji`에서 `mentionPatterns`. +- `subagents.allowAgents`: `sessions_spawn`용 에이전트 id 허용 목록입니다(`["*"]` = 아무 에이전트나 가능, 기본값: 동일 에이전트만). +- 샌드박스 상속 가드: 요청 세션이 샌드박스 상태이면 `sessions_spawn`은 샌드박스 없이 실행될 대상을 거부합니다. - `subagents.requireAgentId`: true이면 `agentId`를 생략한 `sessions_spawn` 호출을 차단합니다(명시적 프로필 선택 강제, 기본값: false). --- ## 다중 에이전트 라우팅 -하나의 Gateway 안에서 여러 개의 격리된 에이전트를 실행합니다. [다중 에이전트](/ko/concepts/multi-agent)를 참조하세요. +하나의 Gateway 안에서 여러 개의 격리된 에이전트를 실행합니다. [Multi-Agent](/ko/concepts/multi-agent)를 참고하세요. ```json5 { @@ -1639,31 +1693,31 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 } ``` -### 바인딩 일치 필드 +### 바인딩 매치 필드 -- `type`(선택 사항): 일반 라우팅은 `route`(`type`이 없으면 기본값은 route), 영구 ACP 대화 바인딩은 `acp` +- `type`(선택 사항): 일반 라우팅용 `route`(type이 없으면 route가 기본값), 영구 ACP 대화 바인딩용 `acp`. - `match.channel`(필수) - `match.accountId`(선택 사항, `*` = 모든 계정, 생략 = 기본 계정) - `match.peer`(선택 사항, `{ kind: direct|group|channel, id }`) - `match.guildId` / `match.teamId`(선택 사항, 채널별) - `acp`(선택 사항, `type: "acp"`일 때만): `{ mode, label, cwd, backend }` -**결정적 일치 순서:** +**결정적 매치 순서:** 1. `match.peer` 2. `match.guildId` 3. `match.teamId` -4. `match.accountId`(정확히 일치, peer/guild/team 없음) -5. `match.accountId: "*"`(채널 전체) +4. `match.accountId` (정확 일치, peer/guild/team 없음) +5. `match.accountId: "*"` (채널 전체) 6. 기본 에이전트 -각 단계 안에서는 첫 번째로 일치하는 `bindings` 항목이 적용됩니다. +같은 단계 안에서는 처음으로 일치한 `bindings` 항목이 우선합니다. -`type: "acp"` 항목의 경우 OpenClaw는 정확한 대화 식별자(`match.channel` + account + `match.peer.id`)로 해석하며, 위의 route 바인딩 단계 순서는 사용하지 않습니다. +`type: "acp"` 항목의 경우 OpenClaw는 정확한 대화 식별자(`match.channel` + account + `match.peer.id`)로 해석하며 위의 route 바인딩 단계 순서를 사용하지 않습니다. ### 에이전트별 접근 프로필 - + ```json5 { @@ -1756,7 +1810,7 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 -우선순위 세부 사항은 [다중 에이전트 샌드박스 및 도구](/ko/tools/multi-agent-sandbox-tools)를 참조하세요. +우선순위 세부 정보는 [Multi-Agent Sandbox & Tools](/ko/tools/multi-agent-sandbox-tools)를 참고하세요. --- @@ -1782,7 +1836,7 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 }, resetTriggers: ["/new", "/reset"], store: "~/.openclaw/agents/{agentId}/sessions/sessions.json", - parentForkMaxTokens: 100000, // 이 토큰 수를 넘으면 parent-thread 포크 건너뜀(0이면 비활성화) + parentForkMaxTokens: 100000, // 이 토큰 수를 초과하면 부모 스레드 포크 건너뜀 (0이면 비활성화) maintenance: { mode: "warn", // warn | enforce pruneAfter: "30d", @@ -1794,8 +1848,8 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 }, threadBindings: { enabled: true, - idleHours: 24, // 기본 비활성 자동 포커스 해제 시간(`0`이면 비활성화) - maxAgeHours: 0, // 기본 하드 최대 수명 시간(`0`이면 비활성화) + idleHours: 24, // 기본 비활성 자동 언포커스 시간(시간 단위) (`0`이면 비활성화) + maxAgeHours: 0, // 기본 하드 최대 유지 시간(시간 단위) (`0`이면 비활성화) }, mainKey: "main", // 레거시(런타임은 항상 "main" 사용) agentToAgent: { maxPingPongTurns: 5 }, @@ -1810,34 +1864,34 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 - **`scope`**: 그룹 채팅 컨텍스트의 기본 세션 그룹화 전략입니다. - - `per-sender`(기본값): 채널 컨텍스트 내에서 각 발신자마다 격리된 세션을 사용합니다. + - `per-sender`(기본값): 채널 컨텍스트 내에서 각 발신자가 격리된 세션을 가집니다. - `global`: 채널 컨텍스트의 모든 참여자가 하나의 세션을 공유합니다(공유 컨텍스트가 의도된 경우에만 사용). - **`dmScope`**: DM을 그룹화하는 방식입니다. - - `main`: 모든 DM이 기본 세션을 공유합니다. - - `per-peer`: 채널 전반에서 발신자 ID별로 격리합니다. + - `main`: 모든 DM이 메인 세션을 공유합니다. + - `per-peer`: 채널 전반에서 발신자 id 기준으로 격리합니다. - `per-channel-peer`: 채널 + 발신자별로 격리합니다(다중 사용자 받은편지함에 권장). - `per-account-channel-peer`: 계정 + 채널 + 발신자별로 격리합니다(다중 계정에 권장). -- **`identityLinks`**: 채널 간 세션 공유를 위해 정식 ID를 provider 접두사가 붙은 peer에 매핑합니다. -- **`reset`**: 기본 초기화 정책입니다. `daily`는 로컬 시간 `atHour`에 초기화되고, `idle`은 `idleMinutes` 후 초기화됩니다. 둘 다 구성되면 먼저 만료되는 쪽이 적용됩니다. +- **`identityLinks`**: 채널 간 세션 공유를 위해 정규 id를 provider 접두사가 있는 peer에 매핑합니다. +- **`reset`**: 기본 reset 정책입니다. `daily`는 로컬 시간 `atHour`에 reset되고, `idle`은 `idleMinutes` 후 reset됩니다. 둘 다 구성된 경우 먼저 만료되는 쪽이 우선합니다. - **`resetByType`**: 유형별 재정의(`direct`, `group`, `thread`)입니다. 레거시 `dm`도 `direct`의 별칭으로 허용됩니다. -- **`parentForkMaxTokens`**: 포크된 스레드 세션을 만들 때 허용되는 상위 세션 `totalTokens`의 최대값입니다(기본값 `100000`). - - 상위 `totalTokens`가 이 값을 초과하면 OpenClaw는 상위 transcript 기록을 상속하는 대신 새 스레드 세션을 시작합니다. - - 이 보호를 비활성화하고 항상 상위 포크를 허용하려면 `0`으로 설정하세요. -- **`mainKey`**: 레거시 필드입니다. 런타임은 기본 direct-chat 버킷에 항상 `"main"`을 사용합니다. -- **`agentToAgent.maxPingPongTurns`**: 에이전트 간 교환 중 답장-재답장 턴의 최대 횟수입니다(정수, 범위: `0`–`5`). `0`은 ping-pong 체인을 비활성화합니다. -- **`sendPolicy`**: `channel`, `chatType`(`direct|group|channel`, 레거시 `dm` 별칭 포함), `keyPrefix`, 또는 `rawKeyPrefix`로 일치시킵니다. 첫 번째 deny가 우선합니다. +- **`parentForkMaxTokens`**: 포크된 스레드 세션을 만들 때 허용되는 부모 세션 `totalTokens`의 최대값입니다(기본값 `100000`). + - 부모 `totalTokens`가 이 값을 초과하면 OpenClaw는 부모 transcript 기록을 상속하는 대신 새 스레드 세션을 시작합니다. + - 이 가드를 비활성화하고 항상 부모 포크를 허용하려면 `0`으로 설정하세요. +- **`mainKey`**: 레거시 필드입니다. 런타임은 항상 메인 direct-chat 버킷에 `"main"`을 사용합니다. +- **`agentToAgent.maxPingPongTurns`**: 에이전트 간 교환 중 에이전트 사이의 최대 응답 왕복 턴 수입니다(정수, 범위: `0`–`5`). `0`은 ping-pong 연결을 비활성화합니다. +- **`sendPolicy`**: `channel`, `chatType`(`direct|group|channel`, 레거시 `dm` 별칭 포함), `keyPrefix`, 또는 `rawKeyPrefix`로 매치합니다. 첫 번째 deny가 우선합니다. - **`maintenance`**: 세션 저장소 정리 + 보존 제어입니다. - `mode`: `warn`은 경고만 출력하고, `enforce`는 정리를 적용합니다. - - `pruneAfter`: 오래된 항목의 기간 기준값입니다(기본값 `30d`). + - `pruneAfter`: 오래된 항목의 만료 기준 기간입니다(기본값 `30d`). - `maxEntries`: `sessions.json`의 최대 항목 수입니다(기본값 `500`). - - `rotateBytes`: `sessions.json`이 이 크기를 넘으면 회전합니다(기본값 `10mb`). + - `rotateBytes`: `sessions.json`이 이 크기를 초과하면 회전합니다(기본값 `10mb`). - `resetArchiveRetention`: `*.reset.` transcript 아카이브의 보존 기간입니다. 기본값은 `pruneAfter`이며, 비활성화하려면 `false`로 설정하세요. - - `maxDiskBytes`: 선택적 세션 디렉터리 디스크 예산입니다. `warn` 모드에서는 경고를 기록하고, `enforce` 모드에서는 가장 오래된 아티팩트/세션부터 제거합니다. + - `maxDiskBytes`: 선택적 sessions 디렉터리 디스크 예산입니다. `warn` 모드에서는 경고를 기록하고, `enforce` 모드에서는 가장 오래된 아티팩트/세션부터 제거합니다. - `highWaterBytes`: 예산 정리 후의 선택적 목표값입니다. 기본값은 `maxDiskBytes`의 `80%`입니다. - **`threadBindings`**: 스레드 바인딩 세션 기능의 전역 기본값입니다. - - `enabled`: 마스터 기본 스위치입니다(provider가 재정의할 수 있으며, Discord는 `channels.discord.threadBindings.enabled` 사용) - - `idleHours`: 비활성 자동 포커스 해제의 기본 시간 수입니다(`0`은 비활성화, provider가 재정의 가능) - - `maxAgeHours`: 하드 최대 수명의 기본 시간 수입니다(`0`은 비활성화, provider가 재정의 가능) + - `enabled`: 마스터 기본 스위치입니다(제공자가 재정의 가능, Discord는 `channels.discord.threadBindings.enabled` 사용) + - `idleHours`: 기본 비활성 자동 언포커스 시간(시간 단위, `0`이면 비활성화, 제공자가 재정의 가능) + - `maxAgeHours`: 기본 하드 최대 유지 시간(시간 단위, `0`이면 비활성화, 제공자가 재정의 가능) @@ -1877,17 +1931,17 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 채널/계정별 재정의: `channels..responsePrefix`, `channels..accounts..responsePrefix`. -해결 순서(가장 구체적인 것이 우선): account → channel → global. `""`는 비활성화하며 상위 단계 탐색도 중단합니다. `"auto"`는 `[{identity.name}]`를 파생합니다. +해결 순서(가장 구체적인 값이 우선): 계정 → 채널 → 전역. `""`는 비활성화하며 상위 단계 탐색도 중단합니다. `"auto"`는 `[{identity.name}]`를 생성합니다. **템플릿 변수:** -| 변수 | 설명 | 예시 | -| ----------------- | --------------------- | --------------------------- | -| `{model}` | 짧은 모델 이름 | `claude-opus-4-6` | -| `{modelFull}` | 전체 모델 식별자 | `anthropic/claude-opus-4-6` | -| `{provider}` | provider 이름 | `anthropic` | -| `{thinkingLevel}` | 현재 thinking 수준 | `high`, `low`, `off` | -| `{identity.name}` | 에이전트 identity 이름 | (`"auto"`와 동일) | +| Variable | 설명 | 예시 | +| ----------------- | ------------------- | --------------------------- | +| `{model}` | 짧은 모델 이름 | `claude-opus-4-6` | +| `{modelFull}` | 전체 모델 식별자 | `anthropic/claude-opus-4-6` | +| `{provider}` | 제공자 이름 | `anthropic` | +| `{thinkingLevel}` | 현재 thinking 수준 | `high`, `low`, `off` | +| `{identity.name}` | 에이전트 identity 이름 | (`"auto"`와 동일) | 변수는 대소문자를 구분하지 않습니다. `{think}`는 `{thinkingLevel}`의 별칭입니다. @@ -1895,18 +1949,18 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 - 기본값은 활성 에이전트의 `identity.emoji`이고, 없으면 `"👀"`입니다. 비활성화하려면 `""`로 설정하세요. - 채널별 재정의: `channels..ackReaction`, `channels..accounts..ackReaction`. -- 해결 순서: account → channel → `messages.ackReaction` → identity 대체값. +- 해결 순서: 계정 → 채널 → `messages.ackReaction` → identity 대체값. - 범위: `group-mentions`(기본값), `group-all`, `direct`, `all`. -- `removeAckAfterReply`: Slack, Discord, Telegram에서 응답 후 확인 반응을 제거합니다. +- `removeAckAfterReply`: Slack, Discord, Telegram에서 응답 후 ack를 제거합니다. - `messages.statusReactions.enabled`: Slack, Discord, Telegram에서 수명 주기 상태 반응을 활성화합니다. - Slack과 Discord에서는 설정하지 않으면 확인 반응이 활성화되어 있을 때 상태 반응도 활성화된 상태를 유지합니다. - Telegram에서는 수명 주기 상태 반응을 활성화하려면 이를 명시적으로 `true`로 설정하세요. + Slack과 Discord에서는 이 값을 설정하지 않으면 ack 반응이 활성화되어 있을 때 상태 반응도 활성 상태를 유지합니다. + Telegram에서는 수명 주기 상태 반응을 활성화하려면 이를 명시적으로 `true`로 설정해야 합니다. -### 수신 debounce +### 수신 디바운스 -같은 발신자의 빠른 텍스트 전용 메시지를 하나의 에이전트 턴으로 묶습니다. 미디어/첨부 파일은 즉시 flush됩니다. 제어 명령은 debounce를 우회합니다. +같은 발신자의 빠른 텍스트 전용 메시지를 하나의 에이전트 턴으로 묶습니다. 미디어/첨부 파일은 즉시 플러시됩니다. 제어 명령은 디바운싱을 우회합니다. -### TTS(텍스트 음성 변환) +### TTS (text-to-speech) ```json5 { @@ -1947,18 +2001,18 @@ scripts/sandbox-browser-setup.sh # 선택적 브라우저 이미지 } ``` -- `auto`는 기본 자동 TTS 모드를 제어합니다: `off`, `always`, `inbound`, 또는 `tagged`. `/tts on|off`는 로컬 기본 설정을 재정의할 수 있으며, `/tts status`는 실제 적용 상태를 보여줍니다. -- `summaryModel`은 자동 요약에 대해 `agents.defaults.model.primary`를 재정의합니다. +- `auto`는 기본 자동 TTS 모드를 제어합니다: `off`, `always`, `inbound`, `tagged`. `/tts on|off`는 로컬 기본 설정을 재정의할 수 있고, `/tts status`는 실제 적용 상태를 보여줍니다. +- `summaryModel`은 자동 요약용으로 `agents.defaults.model.primary`를 재정의합니다. - `modelOverrides`는 기본적으로 활성화되어 있으며, `modelOverrides.allowProvider`의 기본값은 `false`입니다(opt-in). -- API 키는 `ELEVENLABS_API_KEY`/`XI_API_KEY` 및 `OPENAI_API_KEY`로 대체됩니다. -- `openai.baseUrl`은 OpenAI TTS 엔드포인트를 재정의합니다. 해결 순서는 config, 그다음 `OPENAI_TTS_BASE_URL`, 그다음 `https://api.openai.com/v1`입니다. -- `openai.baseUrl`이 OpenAI가 아닌 엔드포인트를 가리키면 OpenClaw는 이를 OpenAI 호환 TTS 서버로 처리하고 model/voice 검증을 완화합니다. +- API 키는 `ELEVENLABS_API_KEY`/`XI_API_KEY`와 `OPENAI_API_KEY`로 대체됩니다. +- `openai.baseUrl`은 OpenAI TTS 엔드포인트를 재정의합니다. 해결 순서는 구성, 그다음 `OPENAI_TTS_BASE_URL`, 그다음 `https://api.openai.com/v1`입니다. +- `openai.baseUrl`이 OpenAI가 아닌 엔드포인트를 가리키면 OpenClaw는 이를 OpenAI 호환 TTS 서버로 간주하고 모델/음성 검증을 완화합니다. --- ## Talk -Talk 모드의 기본값입니다(macOS/iOS/Android). +Talk 모드(macOS/iOS/Android)의 기본값입니다. ```json5 { @@ -1984,11 +2038,11 @@ Talk 모드의 기본값입니다(macOS/iOS/Android). - 여러 Talk provider가 구성된 경우 `talk.provider`는 `talk.providers`의 키와 일치해야 합니다. - 레거시 평면 Talk 키(`talk.voiceId`, `talk.voiceAliases`, `talk.modelId`, `talk.outputFormat`, `talk.apiKey`)는 호환성 전용이며 `talk.providers.`로 자동 마이그레이션됩니다. -- 음성 ID는 `ELEVENLABS_VOICE_ID` 또는 `SAG_VOICE_ID`로 대체됩니다. +- Voice ID는 `ELEVENLABS_VOICE_ID` 또는 `SAG_VOICE_ID`로 대체됩니다. - `providers.*.apiKey`는 일반 텍스트 문자열 또는 SecretRef 객체를 허용합니다. - `ELEVENLABS_API_KEY` 대체값은 Talk API 키가 구성되지 않은 경우에만 적용됩니다. -- `providers.*.voiceAliases`는 Talk 지시문에서 친숙한 이름을 사용할 수 있게 합니다. -- `silenceTimeoutMs`는 사용자가 침묵한 뒤 Talk 모드가 transcript를 보내기 전에 기다리는 시간을 제어합니다. 설정하지 않으면 플랫폼 기본 일시정지 창이 유지됩니다(`macOS와 Android는 700 ms, iOS는 900 ms`). +- `providers.*.voiceAliases`를 사용하면 Talk 지시문에서 친숙한 이름을 사용할 수 있습니다. +- `silenceTimeoutMs`는 사용자 침묵 후 transcript를 전송하기 전에 Talk 모드가 기다리는 시간을 제어합니다. 설정하지 않으면 플랫폼 기본 일시 정지 창이 유지됩니다(`macOS와 Android에서는 700 ms, iOS에서는 900 ms`). --- @@ -1996,22 +2050,22 @@ Talk 모드의 기본값입니다(macOS/iOS/Android). ### 도구 프로필 -`tools.profile`은 `tools.allow`/`tools.deny` 전에 기본 허용 목록을 설정합니다. +`tools.profile`은 `tools.allow`/`tools.deny` 전에 적용되는 기본 허용 목록을 설정합니다: -로컬 온보딩은 설정되지 않은 새 로컬 구성에 기본적으로 `tools.profile: "coding"`을 설정합니다(기존의 명시적 프로필은 유지됨). +로컬 온보딩은 설정되지 않은 새 로컬 구성에 대해 기본적으로 `tools.profile: "coding"`을 사용합니다(기존의 명시적 프로필은 유지됨). -| 프로필 | 포함 항목 | -| ---------- | ------------------------------------------------------------------------------------------------------------------------------ | -| `minimal` | `session_status`만 | -| `coding` | `group:fs`, `group:runtime`, `group:web`, `group:sessions`, `group:memory`, `cron`, `image`, `image_generate`, `video_generate` | -| `messaging` | `group:messaging`, `sessions_list`, `sessions_history`, `sessions_send`, `session_status` | -| `full` | 제한 없음(설정하지 않은 경우와 동일) | +| Profile | 포함 항목 | +| ----------- | --------------------------------------------------------------------------------------------------------------------------- | +| `minimal` | `session_status`만 | +| `coding` | `group:fs`, `group:runtime`, `group:web`, `group:sessions`, `group:memory`, `cron`, `image`, `image_generate`, `video_generate` | +| `messaging` | `group:messaging`, `sessions_list`, `sessions_history`, `sessions_send`, `session_status` | +| `full` | 제한 없음(설정하지 않은 경우와 동일) | ### 도구 그룹 -| 그룹 | 도구 | +| Group | 도구 | | ------------------ | ----------------------------------------------------------------------------------------------------------------------- | -| `group:runtime` | `exec`, `process`, `code_execution` (`bash`는 `exec`의 별칭으로 허용됨) | +| `group:runtime` | `exec`, `process`, `code_execution` (`bash`는 `exec`의 별칭으로 허용됨) | | `group:fs` | `read`, `write`, `edit`, `apply_patch` | | `group:sessions` | `sessions_list`, `sessions_history`, `sessions_send`, `sessions_spawn`, `sessions_yield`, `subagents`, `session_status` | | `group:memory` | `memory_search`, `memory_get` | @@ -2022,11 +2076,11 @@ Talk 모드의 기본값입니다(macOS/iOS/Android). | `group:nodes` | `nodes` | | `group:agents` | `agents_list` | | `group:media` | `image`, `image_generate`, `video_generate`, `tts` | -| `group:openclaw` | 모든 기본 제공 도구(provider plugins 제외) | +| `group:openclaw` | 모든 내장 도구(제공자 플러그인 제외) | ### `tools.allow` / `tools.deny` -전역 도구 허용/거부 정책입니다(거부 우선). 대소문자를 구분하지 않으며 `*` 와일드카드를 지원합니다. Docker sandbox가 꺼져 있어도 적용됩니다. +전역 도구 허용/거부 정책입니다(거부가 우선). 대소문자를 구분하지 않으며 `*` 와일드카드를 지원합니다. Docker 샌드박스가 꺼져 있어도 적용됩니다. ```json5 { @@ -2036,7 +2090,7 @@ Talk 모드의 기본값입니다(macOS/iOS/Android). ### `tools.byProvider` -특정 provider 또는 모델에 대해 도구를 추가로 제한합니다. 순서: 기본 프로필 → provider 프로필 → allow/deny. +특정 제공자 또는 모델에 대해 도구를 추가로 제한합니다. 순서: 기본 프로필 → 제공자 프로필 → allow/deny. ```json5 { @@ -2052,7 +2106,7 @@ Talk 모드의 기본값입니다(macOS/iOS/Android). ### `tools.elevated` -sandbox 외부의 elevated exec 접근을 제어합니다. +샌드박스 외부의 elevated exec 접근을 제어합니다: ```json5 { @@ -2068,9 +2122,9 @@ sandbox 외부의 elevated exec 접근을 제어합니다. } ``` -- 에이전트별 재정의(`agents.list[].tools.elevated`)는 더 제한하는 경우에만 가능합니다. -- `/elevated on|off|ask|full`은 상태를 세션별로 저장하며, 인라인 지시문은 단일 메시지에만 적용됩니다. -- Elevated `exec`는 sandboxing을 우회하며 구성된 탈출 경로를 사용합니다(`gateway`가 기본값이고, exec 대상이 `node`이면 `node` 사용). +- 에이전트별 재정의(`agents.list[].tools.elevated`)는 더 제한하는 방향으로만 가능합니다. +- `/elevated on|off|ask|full`은 세션별 상태를 저장하며, 인라인 지시문은 단일 메시지에 적용됩니다. +- Elevated `exec`는 샌드박싱을 우회하고 구성된 탈출 경로(`gateway`가 기본값, exec 대상이 `node`일 때는 `node`)를 사용합니다. ### `tools.exec` @@ -2094,8 +2148,8 @@ sandbox 외부의 elevated exec 접근을 제어합니다. ### `tools.loopDetection` -도구 루프 안전성 검사는 기본적으로 **비활성화**되어 있습니다. 탐지를 활성화하려면 `enabled: true`를 설정하세요. -설정은 전역 `tools.loopDetection`에 정의할 수 있고, `agents.list[].tools.loopDetection`에서 에이전트별로 재정의할 수 있습니다. +도구 루프 안전성 검사는 기본적으로 **비활성화**되어 있습니다. 감지를 활성화하려면 `enabled: true`를 설정하세요. +설정은 전역 `tools.loopDetection`에 정의할 수 있으며 에이전트별로 `agents.list[].tools.loopDetection`에서 재정의할 수 있습니다. ```json5 { @@ -2117,13 +2171,13 @@ sandbox 외부의 elevated exec 접근을 제어합니다. ``` - `historySize`: 루프 분석을 위해 유지되는 최대 도구 호출 기록 수입니다. -- `warningThreshold`: 경고를 발생시키는 반복적인 무진전 패턴 임계값입니다. -- `criticalThreshold`: 심각한 루프를 차단하는 더 높은 반복 임계값입니다. -- `globalCircuitBreakerThreshold`: 모든 무진전 실행에 대한 하드 중단 임계값입니다. -- `detectors.genericRepeat`: 동일 도구/동일 인자 호출 반복 시 경고합니다. -- `detectors.knownPollNoProgress`: 알려진 폴링 도구(`process.poll`, `command_status` 등)의 무진전 상태를 경고/차단합니다. -- `detectors.pingPong`: 교대하는 무진전 쌍 패턴을 경고/차단합니다. -- `warningThreshold >= criticalThreshold` 또는 `criticalThreshold >= globalCircuitBreakerThreshold`이면 검증이 실패합니다. +- `warningThreshold`: 경고를 위한 반복적인 무진전 패턴 임계값입니다. +- `criticalThreshold`: 심각한 루프를 차단하기 위한 더 높은 반복 임계값입니다. +- `globalCircuitBreakerThreshold`: 무진전 실행에 대한 하드 중단 임계값입니다. +- `detectors.genericRepeat`: 같은 도구/같은 인자 호출의 반복에 대해 경고합니다. +- `detectors.knownPollNoProgress`: 알려진 폴링 도구(`process.poll`, `command_status` 등)의 무진전에 대해 경고/차단합니다. +- `detectors.pingPong`: 번갈아 나타나는 무진전 쌍 패턴에 대해 경고/차단합니다. +- `warningThreshold >= criticalThreshold` 또는 `criticalThreshold >= globalCircuitBreakerThreshold`이면 검증에 실패합니다. ### `tools.web` @@ -2140,7 +2194,7 @@ sandbox 외부의 elevated exec 접근을 제어합니다. }, fetch: { enabled: true, - provider: "firecrawl", // 선택 사항, 자동 감지를 원하면 생략 + provider: "firecrawl", // 선택 사항; 자동 감지를 원하면 생략 maxChars: 50000, maxCharsCap: 50000, maxResponseBytes: 2000000, @@ -2157,7 +2211,7 @@ sandbox 외부의 elevated exec 접근을 제어합니다. ### `tools.media` -수신 미디어 이해(image/audio/video)를 구성합니다. +수신 미디어 이해(image/audio/video)를 구성합니다: ```json5 { @@ -2193,14 +2247,14 @@ sandbox 외부의 elevated exec 접근을 제어합니다. **Provider 항목** (`type: "provider"` 또는 생략): -- `provider`: API provider ID(`openai`, `anthropic`, `google`/`gemini`, `groq` 등) -- `model`: 모델 ID 재정의 +- `provider`: API provider id (`openai`, `anthropic`, `google`/`gemini`, `groq` 등) +- `model`: 모델 id 재정의 - `profile` / `preferredProfile`: `auth-profiles.json` 프로필 선택 **CLI 항목** (`type: "cli"`): - `command`: 실행할 실행 파일 -- `args`: 템플릿 인자(`{{MediaPath}}`, `{{Prompt}}`, `{{MaxChars}}` 등 지원) +- `args`: 템플릿화된 인자(`{{MediaPath}}`, `{{Prompt}}`, `{{MaxChars}}` 등 지원) **공통 필드:** @@ -2212,7 +2266,9 @@ Provider 인증은 표준 순서를 따릅니다: `auth-profiles.json` → 환 **비동기 완료 필드:** -- `asyncCompletion.directSend`: `true`이면 완료된 비동기 `music_generate` 및 `video_generate` 작업이 먼저 채널 직접 전달을 시도합니다. 기본값: `false`(레거시 요청자 세션 깨우기/모델 전달 경로). +- `asyncCompletion.directSend`: `true`이면 완료된 비동기 `music_generate` + 및 `video_generate` 작업이 먼저 직접 채널 전달을 시도합니다. 기본값: `false` + (레거시 요청자 세션 깨우기/모델 전달 경로). @@ -2231,9 +2287,9 @@ Provider 인증은 표준 순서를 따릅니다: `auth-profiles.json` → 환 ### `tools.sessions` -세션 도구(`sessions_list`, `sessions_history`, `sessions_send`)가 대상으로 지정할 수 있는 세션을 제어합니다. +세션 도구(`sessions_list`, `sessions_history`, `sessions_send`)가 어떤 세션을 대상으로 할 수 있는지 제어합니다. -기본값: `tree`(현재 세션 + 현재 세션이 생성한 세션, 예: 하위 에이전트). +기본값: `tree`(현재 세션 + 해당 세션이 생성한 세션, 예: subagent). ```json5 { @@ -2249,10 +2305,10 @@ Provider 인증은 표준 순서를 따릅니다: `auth-profiles.json` → 환 참고: - `self`: 현재 세션 키만. -- `tree`: 현재 세션 + 현재 세션이 생성한 세션(하위 에이전트). -- `agent`: 현재 에이전트 ID에 속한 모든 세션(같은 에이전트 ID 아래에서 발신자별 세션을 실행하면 다른 사용자도 포함될 수 있음). +- `tree`: 현재 세션 + 현재 세션이 생성한 세션(subagent). +- `agent`: 현재 에이전트 id에 속한 모든 세션(같은 에이전트 id 아래에서 per-sender 세션을 실행하는 경우 다른 사용자를 포함할 수 있음). - `all`: 모든 세션. 에이전트 간 대상 지정에는 여전히 `tools.agentToAgent`가 필요합니다. -- Sandbox clamp: 현재 세션이 sandbox 상태이고 `agents.defaults.sandbox.sessionToolsVisibility="spawned"`이면, `tools.sessions.visibility="all"`이어도 visibility는 강제로 `tree`가 됩니다. +- 샌드박스 클램프: 현재 세션이 샌드박스 상태이고 `agents.defaults.sandbox.sessionToolsVisibility="spawned"`이면 `tools.sessions.visibility="all"`이어도 visibility는 `tree`로 강제됩니다. ### `tools.sessions_spawn` @@ -2277,15 +2333,15 @@ Provider 인증은 표준 순서를 따릅니다: `auth-profiles.json` → 환 참고: - 첨부 파일은 `runtime: "subagent"`에서만 지원됩니다. ACP 런타임은 이를 거부합니다. -- 파일은 `.manifest.json`과 함께 자식 workspace의 `.openclaw/attachments//`에 구체화됩니다. -- 첨부 파일 내용은 transcript 영속화에서 자동으로 숨김 처리됩니다. -- Base64 입력은 엄격한 알파벳/패딩 검사와 디코딩 전 크기 보호를 통해 검증됩니다. -- 파일 권한은 디렉터리 `0700`, 파일 `0600`입니다. -- 정리는 `cleanup` 정책을 따릅니다. `delete`는 항상 첨부를 제거하고, `keep`은 `retainOnSessionKeep: true`일 때만 유지합니다. +- 파일은 자식 workspace의 `.openclaw/attachments//`에 `.manifest.json`과 함께 구체화됩니다. +- 첨부 파일 내용은 transcript 저장에서 자동으로 redaction됩니다. +- Base64 입력은 엄격한 알파벳/패딩 검사와 디코딩 전 크기 가드로 검증됩니다. +- 파일 권한은 디렉터리에 `0700`, 파일에 `0600`이 적용됩니다. +- 정리는 `cleanup` 정책을 따릅니다: `delete`는 항상 첨부를 제거하고, `keep`은 `retainOnSessionKeep: true`일 때만 유지합니다. ### `tools.experimental` -실험적 기본 제공 도구 플래그입니다. 런타임별 자동 활성화 규칙이 적용되지 않는 한 기본값은 off입니다. +실험적 내장 도구 플래그입니다. strict-agentic GPT-5 자동 활성화 규칙이 적용되지 않는 한 기본값은 꺼짐입니다. ```json5 { @@ -2300,8 +2356,8 @@ Provider 인증은 표준 순서를 따릅니다: `auth-profiles.json` → 환 참고: - `planTool`: 사소하지 않은 다단계 작업 추적을 위한 구조화된 `update_plan` 도구를 활성화합니다. -- 기본값: OpenAI가 아닌 provider에서는 `false`. OpenAI 및 OpenAI Codex 실행은 설정되지 않았을 때 이를 자동 활성화하며, 비활성화하려면 `false`로 설정하세요. -- 활성화되면 시스템 프롬프트에도 사용 지침이 추가되어 모델이 실질적인 작업에만 이를 사용하고 `in_progress` 단계는 최대 하나만 유지하도록 합니다. +- 기본값: `agents.defaults.embeddedPi.executionContract`(또는 에이전트별 재정의)가 OpenAI 또는 OpenAI Codex GPT-5 계열 실행에 대해 `"strict-agentic"`으로 설정되지 않은 한 `false`입니다. 이 범위 밖에서도 강제로 도구를 켜려면 `true`, strict-agentic GPT-5 실행에서도 끄려면 `false`로 설정하세요. +- 활성화되면 시스템 프롬프트에도 사용 지침이 추가되어 모델이 실질적인 작업에만 이를 사용하고 항상 최대 한 단계만 `in_progress`로 유지하도록 합니다. ### `agents.defaults.subagents` @@ -2321,16 +2377,16 @@ Provider 인증은 표준 순서를 따릅니다: `auth-profiles.json` → 환 } ``` -- `model`: 생성된 하위 에이전트의 기본 모델입니다. 생략하면 하위 에이전트는 호출자의 모델을 상속합니다. -- `allowAgents`: 요청 에이전트가 자체 `subagents.allowAgents`를 설정하지 않았을 때 `sessions_spawn` 대상 에이전트 ID의 기본 허용 목록입니다(`["*"]` = 아무 에이전트나, 기본값: 동일 에이전트만). -- `runTimeoutSeconds`: 도구 호출에서 `runTimeoutSeconds`를 생략했을 때 `sessions_spawn`의 기본 시간 제한(초)입니다. `0`은 시간 제한 없음입니다. -- 하위 에이전트별 도구 정책: `tools.subagents.tools.allow` / `tools.subagents.tools.deny`. +- `model`: 생성된 sub-agent의 기본 모델입니다. 생략하면 sub-agent는 호출자의 모델을 상속합니다. +- `allowAgents`: 요청 에이전트가 자체 `subagents.allowAgents`를 설정하지 않았을 때 `sessions_spawn`용 대상 에이전트 id의 기본 허용 목록입니다(`["*"]` = 아무 에이전트나 가능, 기본값: 동일 에이전트만). +- `runTimeoutSeconds`: 도구 호출에서 `runTimeoutSeconds`를 생략했을 때 `sessions_spawn`의 기본 시간 제한(초)입니다. `0`은 시간 제한 없음을 의미합니다. +- sub-agent별 도구 정책: `tools.subagents.tools.allow` / `tools.subagents.tools.deny`. --- -## 사용자 지정 provider와 base URL +## 사용자 지정 provider 및 base URL -OpenClaw는 기본 제공 모델 카탈로그를 사용합니다. 사용자 지정 provider는 config의 `models.providers` 또는 `~/.openclaw/agents//agent/models.json`을 통해 추가하세요. +OpenClaw는 내장 모델 카탈로그를 사용합니다. 사용자 지정 provider는 구성의 `models.providers` 또는 `~/.openclaw/agents//agent/models.json`을 통해 추가합니다. ```json5 { @@ -2360,47 +2416,47 @@ OpenClaw는 기본 제공 모델 카탈로그를 사용합니다. 사용자 지 ``` - 사용자 지정 인증이 필요하면 `authHeader: true` + `headers`를 사용하세요. -- `OPENCLAW_AGENT_DIR`로 agent config 루트를 재정의할 수 있습니다(또는 레거시 환경 변수 별칭인 `PI_CODING_AGENT_DIR`). +- 에이전트 구성 루트는 `OPENCLAW_AGENT_DIR`(또는 레거시 환경 변수 별칭 `PI_CODING_AGENT_DIR`)로 재정의할 수 있습니다. - 일치하는 provider ID에 대한 병합 우선순위: - - 비어 있지 않은 agent `models.json` `baseUrl` 값이 우선합니다. - - 비어 있지 않은 agent `apiKey` 값은 현재 config/auth-profile 컨텍스트에서 해당 provider가 SecretRef로 관리되지 않을 때만 우선합니다. - - SecretRef로 관리되는 provider `apiKey` 값은 해석된 비밀을 저장하는 대신 소스 마커(`ENV_VAR_NAME`은 환경 변수 참조, `secretref-managed`는 file/exec 참조)에서 새로 고쳐집니다. - - SecretRef로 관리되는 provider header 값은 소스 마커(`secretref-env:ENV_VAR_NAME`은 환경 변수 참조, `secretref-managed`는 file/exec 참조)에서 새로 고쳐집니다. - - 비어 있거나 없는 agent `apiKey`/`baseUrl`은 config의 `models.providers`로 대체됩니다. - - 일치하는 모델의 `contextWindow`/`maxTokens`는 명시적 config 값과 암시적 카탈로그 값 중 더 큰 값을 사용합니다. - - 일치하는 모델의 `contextTokens`는 명시적인 런타임 상한이 있으면 이를 유지합니다. 기본 모델 메타데이터를 바꾸지 않고 실제 컨텍스트를 제한할 때 사용하세요. - - config가 `models.json`을 완전히 다시 쓰게 하려면 `models.mode: "replace"`를 사용하세요. - - 마커 영속성은 소스 권위를 따릅니다. 마커는 해석된 런타임 비밀값이 아니라 활성 소스 config 스냅샷(해석 전)에서 기록됩니다. + - 비어 있지 않은 에이전트 `models.json`의 `baseUrl` 값이 우선합니다. + - 비어 있지 않은 에이전트 `apiKey` 값은 현재 config/auth-profile 컨텍스트에서 해당 provider가 SecretRef로 관리되지 않는 경우에만 우선합니다. + - SecretRef로 관리되는 provider `apiKey` 값은 해석된 비밀을 유지하는 대신 소스 마커(`env` 참조는 `ENV_VAR_NAME`, 파일/exec 참조는 `secretref-managed`)에서 새로 고쳐집니다. + - SecretRef로 관리되는 provider 헤더 값은 소스 마커(`env` 참조는 `secretref-env:ENV_VAR_NAME`, 파일/exec 참조는 `secretref-managed`)에서 새로 고쳐집니다. + - 비어 있거나 누락된 에이전트 `apiKey`/`baseUrl`은 구성의 `models.providers`로 대체됩니다. + - 일치하는 모델의 `contextWindow`/`maxTokens`는 명시적 구성값과 암시적 카탈로그 값 중 더 큰 값을 사용합니다. + - 일치하는 모델의 `contextTokens`는 명시적인 런타임 상한이 있으면 이를 유지합니다. 기본 모델 메타데이터를 바꾸지 않고 유효 컨텍스트를 제한할 때 사용하세요. + - 구성으로 `models.json`을 완전히 다시 쓰려면 `models.mode: "replace"`를 사용하세요. + - 마커 저장은 소스 기준입니다. 마커는 해석된 런타임 비밀 값이 아니라 활성 소스 구성 스냅샷(해석 전)에서 기록됩니다. ### Provider 필드 세부 정보 - `models.mode`: provider 카탈로그 동작입니다(`merge` 또는 `replace`). -- `models.providers`: provider ID를 키로 하는 사용자 지정 provider 맵입니다. +- `models.providers`: provider id를 키로 하는 사용자 지정 provider 맵입니다. - `models.providers.*.api`: 요청 어댑터입니다(`openai-completions`, `openai-responses`, `anthropic-messages`, `google-generative-ai` 등). - `models.providers.*.apiKey`: provider 자격 증명입니다(SecretRef/환경 변수 치환 권장). - `models.providers.*.auth`: 인증 전략입니다(`api-key`, `token`, `oauth`, `aws-sdk`). -- `models.providers.*.injectNumCtxForOpenAICompat`: Ollama + `openai-completions`용으로 요청에 `options.num_ctx`를 주입합니다(기본값: `true`). -- `models.providers.*.authHeader`: 필요할 때 `Authorization` 헤더를 통한 자격 증명 전달을 강제합니다. +- `models.providers.*.injectNumCtxForOpenAICompat`: Ollama + `openai-completions` 조합에서 요청에 `options.num_ctx`를 주입합니다(기본값: `true`). +- `models.providers.*.authHeader`: 필요할 때 자격 증명을 `Authorization` 헤더로 강제 전송합니다. - `models.providers.*.baseUrl`: 업스트림 API base URL입니다. -- `models.providers.*.headers`: 프록시/테넌트 라우팅을 위한 추가 정적 헤더입니다. -- `models.providers.*.request`: model-provider HTTP 요청의 전송 재정의입니다. - - `request.headers`: 추가 헤더입니다(provider 기본값과 병합). 값은 SecretRef를 허용합니다. - - `request.auth`: 인증 전략 재정의입니다. 모드: `"provider-default"`(provider의 기본 제공 인증 사용), `"authorization-bearer"`(`token`과 함께 사용), `"header"`(`headerName`, `value`, 선택적 `prefix`와 함께 사용). +- `models.providers.*.headers`: 프록시/테넌트 라우팅용 추가 정적 헤더입니다. +- `models.providers.*.request`: model-provider HTTP 요청용 전송 재정의입니다. + - `request.headers`: 추가 헤더입니다(provider 기본값과 병합됨). 값은 SecretRef를 허용합니다. + - `request.auth`: 인증 전략 재정의입니다. 모드: `"provider-default"`(provider 내장 인증 사용), `"authorization-bearer"`(`token`과 함께 사용), `"header"`(`headerName`, `value`, 선택적 `prefix`와 함께 사용). - `request.proxy`: HTTP 프록시 재정의입니다. 모드: `"env-proxy"`(`HTTP_PROXY`/`HTTPS_PROXY` 환경 변수 사용), `"explicit-proxy"`(`url`과 함께 사용). 두 모드 모두 선택적 `tls` 하위 객체를 허용합니다. - `request.tls`: 직접 연결용 TLS 재정의입니다. 필드: `ca`, `cert`, `key`, `passphrase`(모두 SecretRef 허용), `serverName`, `insecureSkipVerify`. - - `request.allowPrivateNetwork`: `true`이면 provider HTTP fetch 보호를 통해 DNS가 private, CGNAT 또는 유사 범위로 해석되는 `baseUrl`에 대한 HTTPS를 허용합니다(신뢰된 자체 호스팅 OpenAI 호환 엔드포인트를 위한 operator opt-in). WebSocket은 헤더/TLS에 동일한 `request`를 사용하지만 해당 fetch SSRF 게이트는 사용하지 않습니다. 기본값은 `false`입니다. -- `models.providers.*.models`: 명시적인 provider 모델 카탈로그 항목입니다. + - `request.allowPrivateNetwork`: `true`이면 DNS가 private, CGNAT 또는 유사 범위로 해석될 때 provider HTTP fetch 가드를 통해 `baseUrl`에 대한 HTTPS를 허용합니다(신뢰된 자체 호스팅 OpenAI 호환 엔드포인트를 위한 operator opt-in). WebSocket은 헤더/TLS에는 동일한 `request`를 사용하지만 해당 fetch SSRF 게이트는 사용하지 않습니다. 기본값 `false`. +- `models.providers.*.models`: 명시적 provider 모델 카탈로그 항목입니다. - `models.providers.*.models.*.contextWindow`: 기본 모델 컨텍스트 창 메타데이터입니다. -- `models.providers.*.models.*.contextTokens`: 선택적 런타임 컨텍스트 상한입니다. 모델의 기본 `contextWindow`보다 더 작은 실제 컨텍스트 예산을 원할 때 사용하세요. -- `models.providers.*.models.*.compat.supportsDeveloperRole`: 선택적 호환성 힌트입니다. 비어 있지 않은 비기본 `baseUrl`(호스트가 `api.openai.com`이 아님)을 사용하는 `api: "openai-completions"`의 경우 OpenClaw는 런타임에 이를 강제로 `false`로 설정합니다. 비어 있거나 생략된 `baseUrl`은 기본 OpenAI 동작을 유지합니다. -- `models.providers.*.models.*.compat.requiresStringContent`: 문자열 전용 OpenAI 호환 채팅 엔드포인트를 위한 선택적 호환성 힌트입니다. `true`이면 OpenClaw는 요청을 보내기 전에 순수 텍스트 `messages[].content` 배열을 일반 문자열로 평탄화합니다. -- `plugins.entries.amazon-bedrock.config.discovery`: Bedrock 자동 탐지 설정 루트입니다. -- `plugins.entries.amazon-bedrock.config.discovery.enabled`: 암시적 탐지를 켜거나 끕니다. -- `plugins.entries.amazon-bedrock.config.discovery.region`: 탐지에 사용할 AWS 리전입니다. -- `plugins.entries.amazon-bedrock.config.discovery.providerFilter`: 대상 탐지를 위한 선택적 provider ID 필터입니다. -- `plugins.entries.amazon-bedrock.config.discovery.refreshInterval`: 탐지 새로 고침의 폴링 간격입니다. -- `plugins.entries.amazon-bedrock.config.discovery.defaultContextWindow`: 탐지된 모델에 대한 대체 컨텍스트 창입니다. -- `plugins.entries.amazon-bedrock.config.discovery.defaultMaxTokens`: 탐지된 모델에 대한 대체 최대 출력 토큰 수입니다. +- `models.providers.*.models.*.contextTokens`: 선택적 런타임 컨텍스트 상한입니다. 모델의 기본 `contextWindow`보다 더 작은 유효 컨텍스트 예산을 원할 때 사용하세요. +- `models.providers.*.models.*.compat.supportsDeveloperRole`: 선택적 호환성 힌트입니다. 비어 있지 않은 비기본 `baseUrl`(호스트가 `api.openai.com`이 아님)과 함께 `api: "openai-completions"`을 사용할 경우, OpenClaw는 런타임에 이를 강제로 `false`로 설정합니다. 비어 있거나 생략된 `baseUrl`은 기본 OpenAI 동작을 유지합니다. +- `models.providers.*.models.*.compat.requiresStringContent`: 문자열만 허용하는 OpenAI 호환 chat 엔드포인트를 위한 선택적 호환성 힌트입니다. `true`이면 OpenClaw는 요청을 보내기 전에 순수 텍스트 `messages[].content` 배열을 일반 문자열로 평탄화합니다. +- `plugins.entries.amazon-bedrock.config.discovery`: Bedrock 자동 검색 설정 루트입니다. +- `plugins.entries.amazon-bedrock.config.discovery.enabled`: 암시적 검색을 켜거나 끕니다. +- `plugins.entries.amazon-bedrock.config.discovery.region`: 검색에 사용할 AWS 리전입니다. +- `plugins.entries.amazon-bedrock.config.discovery.providerFilter`: 대상 검색용 선택적 provider-id 필터입니다. +- `plugins.entries.amazon-bedrock.config.discovery.refreshInterval`: 검색 새로 고침의 폴링 간격입니다. +- `plugins.entries.amazon-bedrock.config.discovery.defaultContextWindow`: 검색된 모델에 대한 대체 컨텍스트 창입니다. +- `plugins.entries.amazon-bedrock.config.discovery.defaultMaxTokens`: 검색된 모델에 대한 대체 최대 출력 토큰입니다. ### Provider 예시 @@ -2455,7 +2511,7 @@ Cerebras에는 `cerebras/zai-glm-4.7`을 사용하세요. Z.AI 직접 연결에 } ``` -`OPENCODE_API_KEY`(또는 `OPENCODE_ZEN_API_KEY`)를 설정하세요. Zen 카탈로그에는 `opencode/...` 참조를, Go 카탈로그에는 `opencode-go/...` 참조를 사용하세요. 바로가기: `openclaw onboard --auth-choice opencode-zen` 또는 `openclaw onboard --auth-choice opencode-go`. +`OPENCODE_API_KEY`(또는 `OPENCODE_ZEN_API_KEY`)를 설정하세요. Zen 카탈로그에는 `opencode/...` 참조를, Go 카탈로그에는 `opencode-go/...` 참조를 사용하세요. 단축 경로: `openclaw onboard --auth-choice opencode-zen` 또는 `openclaw onboard --auth-choice opencode-go`. @@ -2472,11 +2528,11 @@ Cerebras에는 `cerebras/zai-glm-4.7`을 사용하세요. Z.AI 직접 연결에 } ``` -`ZAI_API_KEY`를 설정하세요. `z.ai/*`와 `z-ai/*`는 허용되는 별칭입니다. 바로가기: `openclaw onboard --auth-choice zai-api-key`. +`ZAI_API_KEY`를 설정하세요. `z.ai/*`와 `z-ai/*`는 허용되는 별칭입니다. 단축 경로: `openclaw onboard --auth-choice zai-api-key`. - 일반 엔드포인트: `https://api.z.ai/api/paas/v4` - 코딩 엔드포인트(기본값): `https://api.z.ai/api/coding/paas/v4` -- 일반 엔드포인트를 사용하려면 base URL 재정의가 포함된 사용자 지정 provider를 정의하세요. +- 일반 엔드포인트를 사용하려면 base URL 재정의가 있는 사용자 지정 provider를 정의하세요. @@ -2517,7 +2573,9 @@ Cerebras에는 `cerebras/zai-glm-4.7`을 사용하세요. Z.AI 직접 연결에 중국 엔드포인트의 경우: `baseUrl: "https://api.moonshot.cn/v1"` 또는 `openclaw onboard --auth-choice moonshot-api-key-cn`. -기본 Moonshot 엔드포인트는 공유 `openai-completions` 전송에서 스트리밍 사용 호환성을 광고하며, OpenClaw는 내장 provider ID만이 아니라 엔드포인트 기능을 기준으로 이를 판단합니다. +기본 Moonshot 엔드포인트는 공유 +`openai-completions` 전송에서 스트리밍 사용 호환성을 알리며, OpenClaw는 내장 provider id만이 아니라 +엔드포인트 기능을 기준으로 이를 판단합니다. @@ -2535,7 +2593,7 @@ Cerebras에는 `cerebras/zai-glm-4.7`을 사용하세요. Z.AI 직접 연결에 } ``` -Anthropic 호환 기본 제공 provider입니다. 바로가기: `openclaw onboard --auth-choice kimi-code-api-key`. +Anthropic 호환 내장 provider입니다. 단축 경로: `openclaw onboard --auth-choice kimi-code-api-key`. @@ -2574,7 +2632,7 @@ Anthropic 호환 기본 제공 provider입니다. 바로가기: `openclaw onboar } ``` -base URL은 `/v1`을 포함하지 않아야 합니다(Anthropic 클라이언트가 이를 추가함). 바로가기: `openclaw onboard --auth-choice synthetic-api-key`. +Base URL에는 `/v1`를 포함하지 마세요(Anthropic 클라이언트가 이를 추가함). 단축 경로: `openclaw onboard --auth-choice synthetic-api-key`. @@ -2614,17 +2672,20 @@ base URL은 `/v1`을 포함하지 않아야 합니다(Anthropic 클라이언트 } ``` -`MINIMAX_API_KEY`를 설정하세요. 바로가기: +`MINIMAX_API_KEY`를 설정하세요. 단축 경로: `openclaw onboard --auth-choice minimax-global-api` 또는 `openclaw onboard --auth-choice minimax-cn-api`. 모델 카탈로그 기본값은 M2.7만 포함합니다. -Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설정하지 않는 한 기본적으로 MiniMax thinking을 비활성화합니다. `/fast on` 또는 `params.fastMode: true`는 `MiniMax-M2.7`을 `MiniMax-M2.7-highspeed`로 다시 씁니다. +Anthropic 호환 스트리밍 경로에서 OpenClaw는 MiniMax thinking을 +직접 `thinking`을 설정하지 않는 한 기본적으로 비활성화합니다. `/fast on` 또는 +`params.fastMode: true`는 `MiniMax-M2.7`을 +`MiniMax-M2.7-highspeed`로 다시 씁니다. -[로컬 모델](/ko/gateway/local-models)을 참조하세요. 요약: 충분한 하드웨어에서 LM Studio Responses API를 통해 대형 로컬 모델을 실행하고, fallback용으로 호스팅 모델은 병합된 상태로 유지하세요. +[Local Models](/ko/gateway/local-models)를 참고하세요. 요약: 충분한 하드웨어에서 LM Studio Responses API를 통해 대형 로컬 모델을 실행하고, 대체 경로를 위해 호스팅 모델은 병합 상태로 유지하세요. @@ -2655,12 +2716,14 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 } ``` -- `allowBundled`: 번들 Skills 전용 선택적 허용 목록입니다(managed/workspace Skills는 영향 없음). -- `load.extraDirs`: 추가 공유 Skills 루트입니다(가장 낮은 우선순위). -- `install.preferBrew`: `true`이면 `brew`를 사용할 수 있을 때 다른 설치 방식으로 대체하기 전에 Homebrew 설치를 우선 사용합니다. -- `install.nodeManager`: `metadata.openclaw.install` 사양용 node 설치 관리자 선호도입니다(`npm` | `pnpm` | `yarn` | `bun`). -- `entries..enabled: false`는 번들/설치된 Skill이라도 비활성화합니다. -- `entries..apiKey`: 기본 환경 변수를 선언하는 Skills를 위한 편의 필드입니다(일반 텍스트 문자열 또는 SecretRef 객체). +- `allowBundled`: 번들된 Skills 전용의 선택적 허용 목록입니다(관리형/workspace Skills에는 영향 없음). +- `load.extraDirs`: 추가 공유 skill 루트입니다(가장 낮은 우선순위). +- `install.preferBrew`: true이면 `brew`를 사용할 수 있을 때 + 다른 설치 방식으로 대체하기 전에 Homebrew 설치를 우선합니다. +- `install.nodeManager`: `metadata.openclaw.install` + 사양용 node 설치 관리자 우선순위입니다(`npm` | `pnpm` | `yarn` | `bun`). +- `entries..enabled: false`는 skill이 번들되었거나 설치되어 있어도 비활성화합니다. +- `entries..apiKey`: 기본 env var를 선언하는 skill을 위한 편의 항목입니다(일반 텍스트 문자열 또는 SecretRef 객체). --- @@ -2689,42 +2752,42 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 ``` - `~/.openclaw/extensions`, `/.openclaw/extensions`, 그리고 `plugins.load.paths`에서 로드됩니다. -- 탐지는 기본 OpenClaw plugins뿐 아니라 호환되는 Codex 번들과 Claude 번들도 허용하며, manifest가 없는 Claude 기본 레이아웃 번들도 포함합니다. +- 검색은 네이티브 OpenClaw 플러그인뿐 아니라 호환되는 Codex 번들과 Claude 번들도 허용하며, 매니페스트가 없는 Claude 기본 레이아웃 번들도 포함합니다. - **구성 변경에는 gateway 재시작이 필요합니다.** -- `allow`: 선택적 허용 목록입니다(목록에 있는 plugins만 로드됨). `deny`가 우선합니다. -- `plugins.entries..apiKey`: plugin 수준 API 키 편의 필드입니다(plugin이 지원하는 경우). -- `plugins.entries..env`: plugin 범위 환경 변수 맵입니다. -- `plugins.entries..hooks.allowPromptInjection`: `false`이면 core는 `before_prompt_build`를 차단하고 레거시 `before_agent_start`의 프롬프트 변경 필드를 무시하며, 레거시 `modelOverride`와 `providerOverride`는 유지합니다. 기본 plugin hooks와 지원되는 번들 제공 hook 디렉터리에 적용됩니다. -- `plugins.entries..subagent.allowModelOverride`: 이 plugin이 백그라운드 하위 에이전트 실행에 대해 실행별 `provider` 및 `model` 재정의를 요청할 수 있도록 명시적으로 신뢰합니다. -- `plugins.entries..subagent.allowedModels`: 신뢰된 하위 에이전트 재정의를 위한 선택적 정식 `provider/model` 대상 허용 목록입니다. 어떤 모델이든 허용하려는 의도가 명확할 때만 `"*"`를 사용하세요. -- `plugins.entries..config`: plugin이 정의한 구성 객체입니다(가능한 경우 기본 OpenClaw plugin 스키마로 검증됨). -- `plugins.entries.firecrawl.config.webFetch`: Firecrawl web-fetch provider 설정입니다. +- `allow`: 선택적 허용 목록입니다(목록에 있는 플러그인만 로드됨). `deny`가 우선합니다. +- `plugins.entries..apiKey`: 플러그인 수준 API 키 편의 필드입니다(플러그인이 지원하는 경우). +- `plugins.entries..env`: 플러그인 범위 환경 변수 맵입니다. +- `plugins.entries..hooks.allowPromptInjection`: `false`이면 core가 `before_prompt_build`를 차단하고 레거시 `before_agent_start`의 프롬프트 변형 필드를 무시하며, 레거시 `modelOverride`와 `providerOverride`는 유지합니다. 네이티브 플러그인 훅과 지원되는 번들 제공 훅 디렉터리에 적용됩니다. +- `plugins.entries..subagent.allowModelOverride`: 이 플러그인이 백그라운드 subagent 실행에 대해 실행별 `provider` 및 `model` 재정의를 요청하도록 명시적으로 신뢰합니다. +- `plugins.entries..subagent.allowedModels`: 신뢰된 subagent 재정의를 위한 정규 `provider/model` 대상의 선택적 허용 목록입니다. 어떤 모델이든 허용하려는 의도가 명확할 때만 `"*"`를 사용하세요. +- `plugins.entries..config`: 플러그인 정의 구성 객체입니다(사용 가능한 경우 네이티브 OpenClaw 플러그인 스키마로 검증됨). +- `plugins.entries.firecrawl.config.webFetch`: Firecrawl 웹 가져오기 provider 설정입니다. - `apiKey`: Firecrawl API 키입니다(SecretRef 허용). `plugins.entries.firecrawl.config.webSearch.apiKey`, 레거시 `tools.web.fetch.firecrawl.apiKey`, 또는 `FIRECRAWL_API_KEY` 환경 변수로 대체됩니다. - `baseUrl`: Firecrawl API base URL입니다(기본값: `https://api.firecrawl.dev`). - - `onlyMainContent`: 페이지에서 본문 콘텐츠만 추출합니다(기본값: `true`). + - `onlyMainContent`: 페이지의 본문 콘텐츠만 추출합니다(기본값: `true`). - `maxAgeMs`: 최대 캐시 유효 기간(밀리초)입니다(기본값: `172800000` / 2일). - `timeoutSeconds`: 스크레이프 요청 시간 제한(초)입니다(기본값: `60`). - `plugins.entries.xai.config.xSearch`: xAI X Search(Grok 웹 검색) 설정입니다. - `enabled`: X Search provider를 활성화합니다. - `model`: 검색에 사용할 Grok 모델입니다(예: `"grok-4-1-fast"`). -- `plugins.entries.memory-core.config.dreaming`: memory dreaming(실험적) 설정입니다. 단계와 임계값은 [Dreaming](/ko/concepts/dreaming)을 참조하세요. +- `plugins.entries.memory-core.config.dreaming`: memory dreaming(실험적) 설정입니다. 단계와 임계값은 [Dreaming](/ko/concepts/dreaming)을 참고하세요. - `enabled`: dreaming 마스터 스위치입니다(기본값 `false`). - `frequency`: 각 전체 dreaming 스윕의 cron 주기입니다(기본값 `"0 3 * * *"`). - - 단계 정책과 임계값은 구현 세부 사항이며(사용자 대상 구성 키 아님). -- 전체 memory 구성은 [메모리 구성 참조](/ko/reference/memory-config)에 있습니다. + - 단계 정책과 임계값은 구현 세부 사항이며 사용자 대상 구성 키가 아닙니다. +- 전체 memory 구성은 [Memory configuration reference](/ko/reference/memory-config)에 있습니다: - `agents.defaults.memorySearch.*` - `memory.backend` - `memory.citations` - `memory.qmd.*` - `plugins.entries.memory-core.config.dreaming` -- 활성화된 Claude 번들 plugins는 `settings.json`의 내장 Pi 기본값도 제공할 수 있습니다. OpenClaw는 이를 원시 OpenClaw config 패치가 아니라 정제된 에이전트 설정으로 적용합니다. -- `plugins.slots.memory`: 활성 memory plugin ID를 선택하거나, memory plugins를 비활성화하려면 `"none"`을 사용합니다. -- `plugins.slots.contextEngine`: 활성 context engine plugin ID를 선택합니다. 다른 engine을 설치하고 선택하지 않는 한 기본값은 `"legacy"`입니다. +- 활성화된 Claude 번들 플러그인은 `settings.json`에서 내장 Pi 기본값도 제공할 수 있습니다. OpenClaw는 이를 원시 OpenClaw 구성 패치가 아니라 정제된 에이전트 설정으로 적용합니다. +- `plugins.slots.memory`: 활성 memory 플러그인 id를 선택하거나, memory 플러그인을 비활성화하려면 `"none"`을 사용합니다. +- `plugins.slots.contextEngine`: 활성 context engine 플러그인 id를 선택합니다. 다른 engine을 설치하고 선택하지 않았다면 기본값은 `"legacy"`입니다. - `plugins.installs`: `openclaw plugins update`에서 사용하는 CLI 관리 설치 메타데이터입니다. - `source`, `spec`, `sourcePath`, `installPath`, `version`, `resolvedName`, `resolvedVersion`, `resolvedSpec`, `integrity`, `shasum`, `resolvedAt`, `installedAt`를 포함합니다. - - `plugins.installs.*`는 관리되는 상태로 취급하세요. 수동 편집보다 CLI 명령 사용을 권장합니다. + - `plugins.installs.*`는 관리 상태로 취급하고 수동 편집보다 CLI 명령을 우선 사용하세요. -[플러그인](/ko/tools/plugin)을 참조하세요. +[Plugins](/ko/tools/plugin)를 참고하세요. --- @@ -2737,7 +2800,7 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 evaluateEnabled: true, defaultProfile: "user", ssrfPolicy: { - dangerouslyAllowPrivateNetwork: true, // 기본 신뢰 네트워크 모드 + // dangerouslyAllowPrivateNetwork: true, // 신뢰된 private-network 접근에만 opt in // allowPrivateNetwork: true, // 레거시 별칭 // hostnameAllowlist: ["*.example.com", "example.com"], // allowedHostnames: ["localhost"], @@ -2765,22 +2828,28 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 ``` - `evaluateEnabled: false`는 `act:evaluate`와 `wait --fn`을 비활성화합니다. -- `ssrfPolicy.dangerouslyAllowPrivateNetwork`는 설정되지 않았을 때 기본값이 `true`입니다(신뢰 네트워크 모델). -- 엄격한 공개 전용 브라우저 탐색을 원하면 `ssrfPolicy.dangerouslyAllowPrivateNetwork: false`로 설정하세요. -- 엄격 모드에서는 원격 CDP 프로필 엔드포인트(`profiles.*.cdpUrl`)도 도달 가능성/탐지 검사 중 동일한 사설 네트워크 차단의 적용을 받습니다. +- `ssrfPolicy.dangerouslyAllowPrivateNetwork`는 설정하지 않으면 비활성화되므로, 브라우저 탐색은 기본적으로 엄격하게 유지됩니다. +- private-network 브라우저 탐색을 의도적으로 신뢰하는 경우에만 `ssrfPolicy.dangerouslyAllowPrivateNetwork: true`를 설정하세요. +- 엄격 모드에서는 원격 CDP 프로필 엔드포인트(`profiles.*.cdpUrl`)도 도달 가능성/검색 검사 중 동일한 private-network 차단 대상이 됩니다. - `ssrfPolicy.allowPrivateNetwork`는 레거시 별칭으로 계속 지원됩니다. -- 엄격 모드에서는 명시적 예외에 `ssrfPolicy.hostnameAllowlist`와 `ssrfPolicy.allowedHostnames`를 사용하세요. -- 원격 프로필은 attach-only입니다(시작/중지/초기화 비활성화). +- 엄격 모드에서는 명시적 예외를 위해 `ssrfPolicy.hostnameAllowlist`와 `ssrfPolicy.allowedHostnames`를 사용하세요. +- 원격 프로필은 attach-only입니다(시작/중지/reset 비활성화). - `profiles.*.cdpUrl`은 `http://`, `https://`, `ws://`, `wss://`를 허용합니다. - OpenClaw가 `/json/version`을 탐지하게 하려면 HTTP(S)를 사용하세요. - provider가 직접 DevTools WebSocket URL을 제공하는 경우 WS(S)를 사용하세요. + `/json/version`을 OpenClaw가 검색하게 하려면 HTTP(S)를 사용하고, provider가 + 직접 DevTools WebSocket URL을 제공한다면 WS(S)를 사용하세요. - `existing-session` 프로필은 호스트 전용이며 CDP 대신 Chrome MCP를 사용합니다. -- `existing-session` 프로필은 Brave 또는 Edge 같은 특정 Chromium 기반 브라우저 프로필을 대상으로 삼기 위해 `userDataDir`를 설정할 수 있습니다. -- `existing-session` 프로필은 현재 Chrome MCP 경로 제한을 유지합니다. CSS 선택자 대상 지정 대신 snapshot/ref 기반 작업, 단일 파일 업로드 hook, 대화 상자 시간 제한 재정의 없음, `wait --load networkidle` 없음, `responsebody`, PDF 내보내기, 다운로드 가로채기, 배치 작업도 지원하지 않습니다. -- 로컬 관리형 `openclaw` 프로필은 `cdpPort`와 `cdpUrl`을 자동 할당합니다. 원격 CDP에만 `cdpUrl`을 명시적으로 설정하세요. -- 자동 감지 순서: 기본 브라우저가 Chromium 기반이면 먼저 사용 → Chrome → Brave → Edge → Chromium → Chrome Canary. -- 제어 서비스: loopback 전용(포트는 `gateway.port`에서 파생되며 기본값은 `18791`). -- `extraArgs`는 로컬 Chromium 시작에 추가 실행 플래그를 덧붙입니다(예: `--disable-gpu`, 창 크기 조정, 디버그 플래그). +- `existing-session` 프로필은 특정 + Chromium 기반 브라우저 프로필(예: Brave 또는 Edge)을 대상으로 삼기 위해 `userDataDir`을 설정할 수 있습니다. +- `existing-session` 프로필은 현재 Chrome MCP 경로 제한을 유지합니다: + CSS 선택자 타기팅 대신 snapshot/ref 기반 작업, 단일 파일 업로드 + 훅, 대화상자 시간 초과 재정의 없음, `wait --load networkidle` 없음, 그리고 + `responsebody`, PDF 내보내기, 다운로드 가로채기, 배치 작업 없음. +- 로컬 관리형 `openclaw` 프로필은 `cdpPort`와 `cdpUrl`을 자동 할당하므로 원격 CDP가 아닌 이상 + `cdpUrl`을 명시적으로 설정하지 마세요. +- 자동 감지 순서: 기본 브라우저가 Chromium 기반인 경우 해당 브라우저 → Chrome → Brave → Edge → Chromium → Chrome Canary. +- 제어 서비스: loopback 전용(port는 `gateway.port`에서 파생되며 기본값 `18791`). +- `extraArgs`는 로컬 Chromium 시작에 추가 실행 플래그를 붙입니다(예: + `--disable-gpu`, 창 크기 지정, 디버그 플래그). --- @@ -2798,7 +2867,7 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 } ``` -- `seamColor`: 기본 앱 UI 크롬의 강조 색상입니다(Talk Mode 버블 틴트 등). +- `seamColor`: 네이티브 앱 UI 크롬의 강조 색상입니다(Talk Mode 말풍선 틴트 등). - `assistant`: Control UI identity 재정의입니다. 활성 에이전트 identity로 대체됩니다. --- @@ -2815,7 +2884,7 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 mode: "token", // none | token | password | trusted-proxy token: "your-token", // password: "your-password", // 또는 OPENCLAW_GATEWAY_PASSWORD - // trustedProxy: { userHeader: "x-forwarded-user" }, // mode=trusted-proxy용, /gateway/trusted-proxy-auth 참조 + // trustedProxy: { userHeader: "x-forwarded-user" }, // mode=trusted-proxy용; /gateway/trusted-proxy-auth 참고 allowTailscale: true, rateLimit: { maxAttempts: 10, @@ -2833,7 +2902,7 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 basePath: "/openclaw", // root: "dist/control-ui", // allowedOrigins: ["https://control.example.com"], // loopback이 아닌 Control UI에는 필수 - // dangerouslyAllowHostHeaderOriginFallback: false, // 위험한 Host-header origin 대체 모드 + // dangerouslyAllowHostHeaderOriginFallback: false, // 위험한 Host-header origin fallback 모드 // allowInsecureAuth: false, // dangerouslyDisableDeviceAuth: false, }, @@ -2844,7 +2913,7 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 // password: "your-password", }, trustedProxies: ["10.0.0.1"], - // 선택 사항. 기본값 false. + // 선택 사항. 기본값은 false. allowRealIpFallback: false, tools: { // 추가 /tools/invoke HTTP 거부 @@ -2866,41 +2935,43 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 -- `mode`: `local`(gateway 실행) 또는 `remote`(원격 gateway 연결)입니다. Gateway는 `local`이 아니면 시작을 거부합니다. +- `mode`: `local`(gateway 실행) 또는 `remote`(원격 gateway 연결)입니다. gateway는 `local`이 아니면 시작을 거부합니다. - `port`: WS + HTTP용 단일 멀티플렉스 포트입니다. 우선순위: `--port` > `OPENCLAW_GATEWAY_PORT` > `gateway.port` > `18789`. -- `bind`: `auto`, `loopback`(기본값), `lan`(`0.0.0.0`), `tailnet`(Tailscale IP만), 또는 `custom`. -- **레거시 bind 별칭**: `gateway.bind`에는 호스트 별칭(`0.0.0.0`, `127.0.0.1`, `localhost`, `::`, `::1`)이 아니라 bind 모드 값(`auto`, `loopback`, `lan`, `tailnet`, `custom`)을 사용하세요. -- **Docker 참고**: 기본 `loopback` bind는 컨테이너 내부의 `127.0.0.1`에서 수신 대기합니다. Docker 브리지 네트워킹(`-p 18789:18789`)에서는 트래픽이 `eth0`로 도착하므로 gateway에 접근할 수 없습니다. `--network host`를 사용하거나, 모든 인터페이스에서 수신 대기하도록 `bind: "lan"`(또는 `customBindHost: "0.0.0.0"`를 사용하는 `bind: "custom"`)을 설정하세요. -- **인증**: 기본적으로 필요합니다. loopback이 아닌 bind에는 gateway 인증이 필요합니다. 실제로는 공유 token/password 또는 `gateway.auth.mode: "trusted-proxy"`를 사용하는 identity-aware reverse proxy를 의미합니다. 온보딩 마법사는 기본적으로 token을 생성합니다. -- `gateway.auth.token`과 `gateway.auth.password`가 둘 다 구성된 경우(SecretRef 포함), `gateway.auth.mode`를 `token` 또는 `password`로 명시적으로 설정하세요. 둘 다 구성되어 있고 mode가 설정되지 않으면 시작 및 서비스 설치/복구 흐름이 실패합니다. -- `gateway.auth.mode: "none"`: 명시적 무인증 모드입니다. 신뢰된 로컬 loopback 설정에서만 사용하세요. 이는 의도적으로 온보딩 프롬프트에서 제공되지 않습니다. -- `gateway.auth.mode: "trusted-proxy"`: 인증을 identity-aware reverse proxy에 위임하고 `gateway.trustedProxies`의 identity 헤더를 신뢰합니다([신뢰 프록시 인증](/ko/gateway/trusted-proxy-auth) 참조). 이 모드는 **loopback이 아닌** 프록시 소스를 기대합니다. 같은 호스트의 loopback reverse proxy는 trusted-proxy 인증 조건을 만족하지 않습니다. -- `gateway.auth.allowTailscale`: `true`이면 Tailscale Serve identity 헤더가 Control UI/WebSocket 인증을 만족할 수 있습니다(`tailscale whois`로 검증). HTTP API 엔드포인트는 해당 Tailscale 헤더 인증을 사용하지 않으며, 대신 gateway의 일반 HTTP 인증 모드를 따릅니다. 이 token 없는 흐름은 gateway 호스트가 신뢰된다는 전제를 둡니다. `tailscale.mode = "serve"`일 때 기본값은 `true`입니다. -- `gateway.auth.rateLimit`: 선택적 인증 실패 제한기입니다. 클라이언트 IP와 인증 범위별로 적용됩니다(공유 비밀과 device-token은 독립적으로 추적됨). 차단된 시도는 `429` + `Retry-After`를 반환합니다. - - 비동기 Tailscale Serve Control UI 경로에서는 동일한 `{scope, clientIp}`에 대한 실패 시도가 실패 기록 전에 직렬화됩니다. 따라서 같은 클라이언트의 동시 잘못된 시도는 둘 다 단순 불일치로 통과하는 대신 두 번째 요청에서 제한기에 걸릴 수 있습니다. - - `gateway.auth.rateLimit.exemptLoopback`의 기본값은 `true`입니다. localhost 트래픽에도 의도적으로 rate limit을 적용하려면(`테스트 설정이나 엄격한 프록시 배포 등`) `false`로 설정하세요. -- 브라우저 출처 WS 인증 시도는 loopback 예외를 비활성화한 상태로 항상 제한됩니다(브라우저 기반 localhost brute force에 대한 심층 방어). -- loopback에서는 이러한 브라우저 출처 lockout이 정규화된 `Origin` 값별로 격리되므로, 한 localhost origin의 반복 실패가 다른 origin까지 자동으로 잠그지는 않습니다. +- `bind`: `auto`, `loopback`(기본값), `lan`(`0.0.0.0`), `tailnet`(Tailscale IP 전용), 또는 `custom`. +- **레거시 bind 별칭**: `gateway.bind`에는 호스트 별칭(`0.0.0.0`, `127.0.0.1`, `localhost`, `::`, `::1`)이 아니라 bind mode 값(`auto`, `loopback`, `lan`, `tailnet`, `custom`)을 사용하세요. +- **Docker 참고**: 기본 `loopback` bind는 컨테이너 내부의 `127.0.0.1`에서 수신합니다. Docker 브리지 네트워킹(`-p 18789:18789`)에서는 트래픽이 `eth0`로 들어오므로 gateway에 접근할 수 없습니다. `--network host`를 사용하거나, 모든 인터페이스에서 수신하도록 `bind: "lan"`(또는 `customBindHost: "0.0.0.0"`와 함께 `bind: "custom"`)을 설정하세요. +- **인증**: 기본적으로 필요합니다. loopback이 아닌 bind에는 gateway 인증이 필요합니다. 실제로는 공유 토큰/비밀번호 또는 `gateway.auth.mode: "trusted-proxy"`를 사용하는 ID 인식 역방향 프록시를 의미합니다. 온보딩 마법사는 기본적으로 토큰을 생성합니다. +- `gateway.auth.token`과 `gateway.auth.password`가 둘 다 구성된 경우(SecretRef 포함), `gateway.auth.mode`를 `token` 또는 `password`로 명시적으로 설정하세요. 둘 다 구성되어 있는데 mode가 설정되지 않으면 시작과 서비스 설치/복구 흐름이 실패합니다. +- `gateway.auth.mode: "none"`: 명시적 무인증 모드입니다. 신뢰된 로컬 loopback 설정에서만 사용하세요. 온보딩 프롬프트에서는 의도적으로 제공되지 않습니다. +- `gateway.auth.mode: "trusted-proxy"`: 인증을 ID 인식 역방향 프록시에 위임하고 `gateway.trustedProxies`의 ID 헤더를 신뢰합니다([Trusted Proxy Auth](/ko/gateway/trusted-proxy-auth) 참고). 이 모드는 **loopback이 아닌** 프록시 소스를 기대합니다. 동일 호스트의 loopback 역방향 프록시는 trusted-proxy 인증 조건을 충족하지 않습니다. +- `gateway.auth.allowTailscale`: `true`이면 Tailscale Serve ID 헤더가 Control UI/WebSocket 인증을 충족할 수 있습니다(`tailscale whois`로 검증). HTTP API 엔드포인트는 이 Tailscale 헤더 인증을 사용하지 않으며, gateway의 일반 HTTP 인증 모드를 따릅니다. 이 토큰 없는 흐름은 gateway 호스트가 신뢰된다고 가정합니다. `tailscale.mode = "serve"`일 때 기본값은 `true`입니다. +- `gateway.auth.rateLimit`: 선택적 인증 실패 제한기입니다. 클라이언트 IP별 및 인증 범위별(공유 비밀과 device-token은 별도로 추적됨)로 적용됩니다. 차단된 시도는 `429` + `Retry-After`를 반환합니다. + - 비동기 Tailscale Serve Control UI 경로에서는 동일한 `{scope, clientIp}`에 대한 실패 시도가 실패 기록 전에 직렬화됩니다. 따라서 동일 클라이언트의 동시 잘못된 시도는 둘 다 단순 불일치로 통과하는 경쟁 상태 대신 두 번째 요청에서 제한기에 걸릴 수 있습니다. + - `gateway.auth.rateLimit.exemptLoopback`의 기본값은 `true`입니다. localhost 트래픽도 의도적으로 속도 제한하려면(`test` 설정 또는 엄격한 프록시 배포) `false`로 설정하세요. +- 브라우저 origin의 WS 인증 시도는 항상 loopback 예외가 비활성화된 상태로 제한됩니다(localhost에 대한 브라우저 기반 무차별 대입 방어 심화). +- loopback에서는 이러한 브라우저 origin 잠금이 정규화된 `Origin` + 값별로 격리되므로, 하나의 localhost origin에서 반복 실패가 발생해도 + 다른 origin이 자동으로 잠기지는 않습니다. - `tailscale.mode`: `serve`(tailnet 전용, loopback bind) 또는 `funnel`(공개, 인증 필요). -- `controlUi.allowedOrigins`: Gateway WebSocket 연결용 명시적 브라우저 origin 허용 목록입니다. browser 클라이언트가 loopback이 아닌 origin에서 올 것으로 예상되면 필수입니다. -- `controlUi.dangerouslyAllowHostHeaderOriginFallback`: Host-header origin 정책에 의도적으로 의존하는 배포를 위해 Host-header origin 대체를 활성화하는 위험한 모드입니다. +- `controlUi.allowedOrigins`: Gateway WebSocket 연결을 위한 명시적 브라우저 origin 허용 목록입니다. loopback이 아닌 origin에서 브라우저 클라이언트를 예상하는 경우 필요합니다. +- `controlUi.dangerouslyAllowHostHeaderOriginFallback`: Host-header origin 정책에 의도적으로 의존하는 배포를 위해 Host-header origin fallback을 활성화하는 위험한 모드입니다. - `remote.transport`: `ssh`(기본값) 또는 `direct`(ws/wss). `direct`의 경우 `remote.url`은 `ws://` 또는 `wss://`여야 합니다. -- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`: 신뢰된 사설 네트워크 IP에 대한 평문 `ws://`를 허용하는 클라이언트 측 비상 수단 재정의입니다. 기본값은 여전히 loopback 전용 평문 허용입니다. -- `gateway.remote.token` / `.password`는 원격 클라이언트 자격 증명 필드입니다. 이것만으로 gateway 인증을 구성하지는 않습니다. -- `gateway.push.apns.relay.baseUrl`: 공식/TestFlight iOS 빌드가 relay 기반 등록을 gateway에 게시한 뒤 사용하는 외부 APNs relay의 기본 HTTPS URL입니다. 이 URL은 iOS 빌드에 컴파일된 relay URL과 일치해야 합니다. +- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`: 신뢰된 private-network IP에 대한 일반 텍스트 `ws://`를 허용하는 클라이언트 측 비상 재정의입니다. 일반 텍스트의 기본값은 여전히 loopback 전용입니다. +- `gateway.remote.token` / `.password`는 원격 클라이언트 자격 증명 필드입니다. 이것만으로 gateway 인증이 구성되지는 않습니다. +- `gateway.push.apns.relay.baseUrl`: 공식/TestFlight iOS 빌드가 relay 기반 등록을 gateway에 게시한 후 사용하는 외부 APNs relay의 기본 HTTPS URL입니다. 이 URL은 iOS 빌드에 컴파일된 relay URL과 일치해야 합니다. - `gateway.push.apns.relay.timeoutMs`: gateway에서 relay로 보내는 시간 제한(밀리초)입니다. 기본값은 `10000`입니다. -- Relay 기반 등록은 특정 gateway identity에 위임됩니다. 페어링된 iOS 앱은 `gateway.identity.get`을 가져오고, 그 identity를 relay 등록에 포함하며, 등록 범위 send grant를 gateway로 전달합니다. 다른 gateway는 저장된 해당 등록을 재사용할 수 없습니다. -- `OPENCLAW_APNS_RELAY_BASE_URL` / `OPENCLAW_APNS_RELAY_TIMEOUT_MS`: 위 relay 구성에 대한 임시 환경 변수 재정의입니다. -- `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true`: loopback HTTP relay URL을 위한 개발 전용 비상 탈출구입니다. 운영 relay URL은 HTTPS를 유지해야 합니다. -- `gateway.channelHealthCheckMinutes`: 채널 상태 모니터 간격(분)입니다. 상태 모니터 재시작을 전역으로 비활성화하려면 `0`으로 설정하세요. 기본값: `5`. -- `gateway.channelStaleEventThresholdMinutes`: 오래된 소켓 임계값(분)입니다. 이는 `gateway.channelHealthCheckMinutes`보다 크거나 같아야 합니다. 기본값: `30`. -- `gateway.channelMaxRestartsPerHour`: 이동하는 1시간 동안 채널/계정별 상태 모니터 재시작 최대 횟수입니다. 기본값: `10`. -- `channels..healthMonitor.enabled`: 전역 모니터는 유지하면서 상태 모니터 재시작만 채널별로 opt-out하는 설정입니다. -- `channels..accounts..healthMonitor.enabled`: 다중 계정 채널용 계정별 재정의입니다. 설정되면 채널 수준 재정의보다 우선합니다. +- Relay 기반 등록은 특정 gateway identity에 위임됩니다. 페어링된 iOS 앱은 `gateway.identity.get`을 가져오고, relay 등록에 해당 identity를 포함하며, 등록 범위 send grant를 gateway로 전달합니다. 다른 gateway는 이 저장된 등록을 재사용할 수 없습니다. +- `OPENCLAW_APNS_RELAY_BASE_URL` / `OPENCLAW_APNS_RELAY_TIMEOUT_MS`: 위 relay 구성을 위한 임시 환경 변수 재정의입니다. +- `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true`: loopback HTTP relay URL용 개발 전용 비상 탈출구입니다. 프로덕션 relay URL은 HTTPS를 유지해야 합니다. +- `gateway.channelHealthCheckMinutes`: 채널 health-monitor 간격(분)입니다. 전역적으로 health-monitor 재시작을 비활성화하려면 `0`으로 설정하세요. 기본값: `5`. +- `gateway.channelStaleEventThresholdMinutes`: 오래된 소켓 임계값(분)입니다. `gateway.channelHealthCheckMinutes`보다 크거나 같게 유지하세요. 기본값: `30`. +- `gateway.channelMaxRestartsPerHour`: 이동 1시간 동안 채널/계정별 최대 health-monitor 재시작 횟수입니다. 기본값: `10`. +- `channels..healthMonitor.enabled`: 전역 monitor는 유지한 채 health-monitor 재시작을 채널별로 opt-out합니다. +- `channels..accounts..healthMonitor.enabled`: 다중 계정 채널의 계정별 재정의입니다. 설정되면 채널 수준 재정의보다 우선합니다. - 로컬 gateway 호출 경로는 `gateway.auth.*`가 설정되지 않은 경우에만 `gateway.remote.*`를 대체값으로 사용할 수 있습니다. -- `gateway.auth.token` / `gateway.auth.password`가 SecretRef로 명시적으로 구성되어 있으나 해석되지 않으면, 해석은 닫힌 상태로 실패합니다(원격 대체가 이를 가리지 않음). -- `trustedProxies`: TLS를 종료하거나 전달된 클라이언트 헤더를 주입하는 reverse proxy IP입니다. 직접 제어하는 프록시만 나열하세요. loopback 항목도 동일 호스트 프록시/로컬 탐지 설정(예: Tailscale Serve 또는 로컬 reverse proxy)에는 여전히 유효하지만, loopback 요청이 `gateway.auth.mode: "trusted-proxy"` 대상이 되도록 만들지는 않습니다. -- `allowRealIpFallback`: `true`이면 `X-Forwarded-For`가 없을 때 gateway가 `X-Real-IP`를 허용합니다. 실패 시 닫힘 동작을 위해 기본값은 `false`입니다. +- `gateway.auth.token` / `gateway.auth.password`가 SecretRef를 통해 명시적으로 구성되었지만 해석되지 않으면, 해석은 실패 시 닫힘 방식으로 처리되며(실패 은폐용 원격 대체 없음). +- `trustedProxies`: TLS를 종료하거나 전달된 클라이언트 헤더를 주입하는 역방향 프록시 IP입니다. 제어하는 프록시만 나열하세요. loopback 항목도 동일 호스트 프록시/로컬 감지 설정(예: Tailscale Serve 또는 로컬 역방향 프록시)에는 여전히 유효하지만, loopback 요청이 `gateway.auth.mode: "trusted-proxy"` 대상이 되도록 하지는 않습니다. +- `allowRealIpFallback`: `true`이면 `X-Forwarded-For`가 없을 때 gateway가 `X-Real-IP`를 허용합니다. 기본값은 실패 시 닫힘 동작을 위한 `false`입니다. - `gateway.tools.deny`: HTTP `POST /tools/invoke`에 대해 차단할 추가 도구 이름입니다(기본 거부 목록 확장). - `gateway.tools.allow`: 기본 HTTP 거부 목록에서 도구 이름을 제거합니다. @@ -2914,13 +2985,14 @@ Anthropic 호환 스트리밍 경로에서 OpenClaw는 `thinking`을 직접 설 - `gateway.http.endpoints.responses.maxUrlParts` - `gateway.http.endpoints.responses.files.urlAllowlist` - `gateway.http.endpoints.responses.images.urlAllowlist` - 빈 허용 목록은 설정되지 않은 것으로 처리됩니다. URL 가져오기를 비활성화하려면 `gateway.http.endpoints.responses.files.allowUrl=false` 및/또는 `gateway.http.endpoints.responses.images.allowUrl=false`를 사용하세요. + 빈 허용 목록은 설정되지 않은 것으로 처리됩니다. URL 가져오기를 비활성화하려면 `gateway.http.endpoints.responses.files.allowUrl=false` + 및/또는 `gateway.http.endpoints.responses.images.allowUrl=false`를 사용하세요. - 선택적 응답 강화 헤더: - - `gateway.http.securityHeaders.strictTransportSecurity`(직접 제어하는 HTTPS origin에만 설정하세요. [신뢰 프록시 인증](/ko/gateway/trusted-proxy-auth#tls-termination-and-hsts) 참조) + - `gateway.http.securityHeaders.strictTransportSecurity`(제어하는 HTTPS origin에만 설정하세요. [Trusted Proxy Auth](/ko/gateway/trusted-proxy-auth#tls-termination-and-hsts) 참고) ### 다중 인스턴스 격리 -고유한 포트와 상태 디렉터리로 한 호스트에서 여러 gateway를 실행합니다. +하나의 호스트에서 고유한 포트와 상태 디렉터리로 여러 gateway를 실행합니다: ```bash OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \ @@ -2930,7 +3002,7 @@ openclaw gateway --port 19001 편의 플래그: `--dev`(`~/.openclaw-dev` + 포트 `19001` 사용), `--profile `(`~/.openclaw-` 사용). -[여러 Gateway](/ko/gateway/multiple-gateways)를 참조하세요. +[Multiple Gateways](/ko/gateway/multiple-gateways)를 참고하세요. ### `gateway.tls` @@ -2949,7 +3021,7 @@ openclaw gateway --port 19001 ``` - `enabled`: gateway 리스너에서 TLS 종료(HTTPS/WSS)를 활성화합니다(기본값: `false`). -- `autoGenerate`: 명시적인 파일이 구성되지 않았을 때 로컬 자체 서명 cert/key 쌍을 자동 생성합니다. 로컬/개발 전용입니다. +- `autoGenerate`: 명시적 파일이 구성되지 않은 경우 로컬 자체 서명 cert/key 쌍을 자동 생성합니다. 로컬/개발 용도로만 사용하세요. - `certPath`: TLS 인증서 파일의 파일 시스템 경로입니다. - `keyPath`: TLS 개인 키 파일의 파일 시스템 경로입니다. 권한을 제한해 두세요. - `caPath`: 클라이언트 검증 또는 사용자 지정 신뢰 체인을 위한 선택적 CA 번들 경로입니다. @@ -2968,17 +3040,17 @@ openclaw gateway --port 19001 } ``` -- `mode`: 구성 편집이 런타임에 적용되는 방식을 제어합니다. - - `"off"`: 실시간 편집을 무시합니다. 변경 사항에는 명시적 재시작이 필요합니다. +- `mode`: 구성 편집을 런타임에 어떻게 적용할지 제어합니다. + - `"off"`: 라이브 편집을 무시합니다. 변경 사항에는 명시적 재시작이 필요합니다. - `"restart"`: 구성 변경 시 항상 gateway 프로세스를 재시작합니다. - - `"hot"`: 재시작 없이 프로세스 내에서 변경 사항을 적용합니다. + - `"hot"`: 재시작 없이 프로세스 내에서 변경을 적용합니다. - `"hybrid"`(기본값): 먼저 hot reload를 시도하고, 필요하면 재시작으로 대체합니다. -- `debounceMs`: 구성 변경을 적용하기 전의 debounce 창(밀리초)입니다(음수가 아닌 정수). -- `deferralTimeoutMs`: 진행 중인 작업을 기다리다가 재시작을 강제하기 전까지의 최대 시간(밀리초)입니다(기본값: `300000` = 5분). +- `debounceMs`: 구성 변경을 적용하기 전 디바운스 창(ms)입니다(음수가 아닌 정수). +- `deferralTimeoutMs`: 진행 중 작업을 기다린 뒤 강제로 재시작하기까지의 최대 시간(ms)입니다(기본값: `300000` = 5분). --- -## Hooks +## 훅 ```json5 { @@ -3001,7 +3073,7 @@ openclaw gateway --port 19001 wakeMode: "now", name: "Gmail", sessionKey: "hook:gmail:{{messages[0].id}}", - messageTemplate: "From: {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}", + messageTemplate: "보낸사람: {{messages[0].from}}\n제목: {{messages[0].subject}}\n{{messages[0].snippet}}", deliver: true, channel: "last", model: "openai/gpt-5.4-mini", @@ -3012,14 +3084,14 @@ openclaw gateway --port 19001 ``` 인증: `Authorization: Bearer ` 또는 `x-openclaw-token: `. -쿼리 문자열 hook token은 거부됩니다. +쿼리 문자열 훅 토큰은 거부됩니다. 검증 및 안전 참고: - `hooks.enabled=true`에는 비어 있지 않은 `hooks.token`이 필요합니다. -- `hooks.token`은 `gateway.auth.token`과 **달라야** 합니다. Gateway token 재사용은 거부됩니다. -- `hooks.path`는 `/`일 수 없습니다. `/hooks` 같은 전용 하위 경로를 사용하세요. -- `hooks.allowRequestSessionKey=true`이면 `hooks.allowedSessionKeyPrefixes`를 제한하세요(예: `["hook:"]`). +- `hooks.token`은 `gateway.auth.token`과 **달라야** 합니다. Gateway 토큰 재사용은 거부됩니다. +- `hooks.path`는 `/`가 될 수 없습니다. `/hooks` 같은 전용 하위 경로를 사용하세요. +- `hooks.allowRequestSessionKey=true`라면 `hooks.allowedSessionKeyPrefixes`를 제한하세요(예: `["hook:"]`). **엔드포인트:** @@ -3030,18 +3102,18 @@ openclaw gateway --port 19001 -- `match.path`는 `/hooks` 뒤의 하위 경로와 일치합니다(예: `/hooks/gmail` → `gmail`). -- `match.source`는 일반 경로용 페이로드 필드와 일치합니다. +- `match.path`는 `/hooks` 뒤의 하위 경로와 매치합니다(예: `/hooks/gmail` → `gmail`). +- `match.source`는 일반 경로에 대해 페이로드 필드와 매치합니다. - `{{messages[0].subject}}` 같은 템플릿은 페이로드에서 값을 읽습니다. -- `transform`은 hook 작업을 반환하는 JS/TS 모듈을 가리킬 수 있습니다. - - `transform.module`은 상대 경로여야 하며 `hooks.transformsDir` 내부에 머물러야 합니다(절대 경로와 경로 탐색은 거부됨). +- `transform`은 hook action을 반환하는 JS/TS 모듈을 가리킬 수 있습니다. + - `transform.module`은 상대 경로여야 하며 `hooks.transformsDir` 내부에 머물러야 합니다(절대 경로와 경로 순회는 거부됨). - `agentId`는 특정 에이전트로 라우팅합니다. 알 수 없는 ID는 기본값으로 대체됩니다. - `allowedAgentIds`: 명시적 라우팅을 제한합니다(`*` 또는 생략 = 모두 허용, `[]` = 모두 거부). -- `defaultSessionKey`: 명시적 `sessionKey`가 없는 hook 에이전트 실행에 대한 선택적 고정 세션 키입니다. -- `allowRequestSessionKey`: `/hooks/agent` 호출자가 `sessionKey`를 설정할 수 있게 합니다(기본값: `false`). -- `allowedSessionKeyPrefixes`: 명시적 `sessionKey` 값(요청 + 매핑)에 대한 선택적 접두사 허용 목록입니다. 예: `["hook:"]`. -- `deliver: true`는 최종 응답을 채널로 보냅니다. `channel`의 기본값은 `last`입니다. -- `model`은 이 hook 실행의 LLM을 재정의합니다(모델 카탈로그가 설정되어 있으면 허용된 모델이어야 함). +- `defaultSessionKey`: 명시적인 `sessionKey`가 없는 hook agent 실행을 위한 선택적 고정 세션 키입니다. +- `allowRequestSessionKey`: `/hooks/agent` 호출자가 `sessionKey`를 설정하도록 허용합니다(기본값: `false`). +- `allowedSessionKeyPrefixes`: 명시적 `sessionKey` 값(요청 + 매핑)에 대한 선택적 접두사 허용 목록입니다(예: `["hook:"]`). +- `deliver: true`는 최종 응답을 채널로 전송하며, `channel`의 기본값은 `last`입니다. +- `model`은 이 hook 실행의 LLM을 재정의합니다(모델 카탈로그가 설정된 경우 허용된 모델이어야 함). @@ -3068,8 +3140,8 @@ openclaw gateway --port 19001 } ``` -- 구성되면 Gateway는 부팅 시 자동으로 `gog gmail watch serve`를 시작합니다. 비활성화하려면 `OPENCLAW_SKIP_GMAIL_WATCHER=1`을 설정하세요. -- Gateway와 함께 별도의 `gog gmail watch serve`를 실행하지 마세요. +- 구성된 경우 gateway는 부팅 시 `gog gmail watch serve`를 자동 시작합니다. 비활성화하려면 `OPENCLAW_SKIP_GMAIL_WATCHER=1`을 설정하세요. +- Gateway와 별도로 `gog gmail watch serve`를 실행하지 마세요. --- @@ -3085,22 +3157,22 @@ openclaw gateway --port 19001 } ``` -- Gateway 포트 아래 HTTP로 에이전트가 편집 가능한 HTML/CSS/JS와 A2UI를 제공합니다. +- 에이전트가 편집 가능한 HTML/CSS/JS와 A2UI를 Gateway 포트 아래의 HTTP로 제공합니다: - `http://:/__openclaw__/canvas/` - `http://:/__openclaw__/a2ui/` - 로컬 전용: `gateway.bind: "loopback"`(기본값)을 유지하세요. -- loopback이 아닌 bind: canvas 경로는 다른 Gateway HTTP 표면과 동일하게 Gateway 인증(token/password/trusted-proxy)이 필요합니다. -- Node WebView는 일반적으로 인증 헤더를 보내지 않습니다. node가 페어링되고 연결되면 Gateway는 canvas/A2UI 접근용 node 범위 capability URL을 광고합니다. -- Capability URL은 활성 node WS 세션에 바인딩되며 빠르게 만료됩니다. IP 기반 대체는 사용되지 않습니다. -- 제공되는 HTML에 live-reload 클라이언트를 삽입합니다. +- loopback이 아닌 bind의 경우 canvas 경로는 다른 Gateway HTTP 표면과 동일하게 Gateway 인증(token/password/trusted-proxy)이 필요합니다. +- Node WebView는 일반적으로 인증 헤더를 보내지 않습니다. 노드가 페어링되고 연결되면 Gateway는 canvas/A2UI 접근용 노드 범위 capability URL을 광고합니다. +- Capability URL은 활성 노드 WS 세션에 바인딩되며 빠르게 만료됩니다. IP 기반 대체는 사용하지 않습니다. +- 제공되는 HTML에 live-reload 클라이언트를 주입합니다. - 비어 있으면 시작용 `index.html`을 자동 생성합니다. -- `/__openclaw__/a2ui/`에서도 A2UI를 제공합니다. +- `/__openclaw__/a2ui/`에서 A2UI도 제공합니다. - 변경 사항에는 gateway 재시작이 필요합니다. -- 디렉터리가 크거나 `EMFILE` 오류가 발생하면 live reload를 비활성화하세요. +- 대규모 디렉터리이거나 `EMFILE` 오류가 발생하면 live reload를 비활성화하세요. --- -## 탐색 +## 검색 ### mDNS (Bonjour) @@ -3118,7 +3190,7 @@ openclaw gateway --port 19001 - `full`: `cliPath` + `sshPort`를 포함합니다. - 호스트 이름 기본값은 `openclaw`입니다. `OPENCLAW_MDNS_HOSTNAME`으로 재정의하세요. -### 광역(Wide-area, DNS-SD) +### 광역 (DNS-SD) ```json5 { @@ -3128,7 +3200,7 @@ openclaw gateway --port 19001 } ``` -`~/.openclaw/dns/` 아래에 유니캐스트 DNS-SD 존을 기록합니다. 네트워크 간 탐색을 위해 DNS 서버(CoreDNS 권장) + Tailscale 분할 DNS와 함께 사용하세요. +`~/.openclaw/dns/` 아래에 유니캐스트 DNS-SD 영역을 기록합니다. 네트워크 간 검색을 위해 DNS 서버(CoreDNS 권장) + Tailscale 분할 DNS와 함께 사용하세요. 설정: `openclaw dns setup --apply`. @@ -3136,7 +3208,7 @@ openclaw gateway --port 19001 ## 환경 -### `env`(인라인 환경 변수) +### `env` (인라인 환경 변수) ```json5 { @@ -3154,13 +3226,13 @@ openclaw gateway --port 19001 ``` - 인라인 환경 변수는 프로세스 환경에 해당 키가 없을 때만 적용됩니다. -- `.env` 파일: CWD의 `.env` + `~/.openclaw/.env`(둘 다 기존 변수를 재정의하지 않음). +- `.env` 파일: 현재 작업 디렉터리의 `.env` + `~/.openclaw/.env`(둘 다 기존 변수를 재정의하지 않음). - `shellEnv`: 로그인 셸 프로필에서 누락된 예상 키를 가져옵니다. -- 전체 우선순위는 [환경](/ko/help/environment)을 참조하세요. +- 전체 우선순위는 [Environment](/ko/help/environment)를 참고하세요. ### 환경 변수 치환 -어떤 구성 문자열에서든 `${VAR_NAME}`으로 환경 변수를 참조할 수 있습니다. +모든 구성 문자열에서 `${VAR_NAME}`으로 환경 변수를 참조할 수 있습니다: ```json5 { @@ -3170,20 +3242,20 @@ openclaw gateway --port 19001 } ``` -- 대문자 이름만 일치합니다: `[A-Z_][A-Z0-9_]*`. -- 누락되거나 빈 변수는 구성 로드 시 오류를 발생시킵니다. -- 리터럴 `${VAR}`는 `$${VAR}`로 이스케이프하세요. -- `$include`와 함께 작동합니다. +- 대문자 이름만 매치됩니다: `[A-Z_][A-Z0-9_]*`. +- 누락되었거나 빈 변수는 구성 로드 시 오류를 발생시킵니다. +- 리터럴 `${VAR}`은 `$${VAR}`로 이스케이프하세요. +- `$include`와 함께 동작합니다. --- -## 비밀 +## Secrets -SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니다. +Secret ref는 추가형입니다. 일반 텍스트 값도 계속 동작합니다. ### `SecretRef` -하나의 객체 형태를 사용하세요. +하나의 객체 형태를 사용하세요: ```json5 { source: "env" | "file" | "exec", provider: "default", id: "..." } @@ -3195,15 +3267,15 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 - `source: "env"` id 패턴: `^[A-Z][A-Z0-9_]{0,127}$` - `source: "file"` id: 절대 JSON 포인터(예: `"/providers/openai/apiKey"`) - `source: "exec"` id 패턴: `^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$` -- `source: "exec"` ID에는 `.` 또는 `..` 슬래시 구분 경로 세그먼트가 포함되면 안 됩니다(예: `a/../b`는 거부됨) +- `source: "exec"` id에는 `.` 또는 `..` 슬래시 구분 경로 세그먼트가 포함되면 안 됩니다(예: `a/../b`는 거부됨) ### 지원되는 자격 증명 표면 -- 정식 매트릭스: [SecretRef 자격 증명 표면](/ko/reference/secretref-credential-surface) +- 정규 매트릭스: [SecretRef Credential Surface](/ko/reference/secretref-credential-surface) - `secrets apply`는 지원되는 `openclaw.json` 자격 증명 경로를 대상으로 합니다. -- `auth-profiles.json` 참조는 런타임 해석 및 감사 범위에도 포함됩니다. +- `auth-profiles.json` ref는 런타임 해석과 감사 범위에도 포함됩니다. -### 비밀 provider 구성 +### Secret provider 구성 ```json5 { @@ -3235,11 +3307,11 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 - `file` provider는 `mode: "json"`과 `mode: "singleValue"`를 지원합니다(`singleValue` 모드에서는 `id`가 `"value"`여야 함). - `exec` provider는 절대 `command` 경로가 필요하며 stdin/stdout의 프로토콜 페이로드를 사용합니다. -- 기본적으로 심볼릭 링크 command 경로는 거부됩니다. 해석된 대상 경로를 검증하면서 심볼릭 링크 경로를 허용하려면 `allowSymlinkCommand: true`를 설정하세요. -- `trustedDirs`가 구성된 경우 trusted-dir 검사는 해석된 대상 경로에 적용됩니다. -- `exec` 하위 프로세스 환경은 기본적으로 최소화되어 있습니다. 필요한 변수는 `passEnv`로 명시적으로 전달하세요. -- SecretRef는 활성화 시점에 메모리 내 스냅샷으로 해석되며, 이후 요청 경로는 해당 스냅샷만 읽습니다. -- 활성 표면 필터링은 활성화 중에 적용됩니다. 활성화된 표면의 해석되지 않은 참조는 시작/리로드를 실패시키고, 비활성 표면은 진단과 함께 건너뜁니다. +- 기본적으로 심볼릭 링크 command 경로는 거부됩니다. 해결된 대상 경로를 검증하면서 심볼릭 링크 경로를 허용하려면 `allowSymlinkCommand: true`를 설정하세요. +- `trustedDirs`가 구성된 경우 trusted-dir 검사는 해결된 대상 경로에 적용됩니다. +- `exec` 자식 환경은 기본적으로 최소화되어 있습니다. 필요한 변수는 `passEnv`로 명시적으로 전달하세요. +- Secret ref는 활성화 시 메모리 내 스냅샷으로 해석되며, 이후 요청 경로는 이 스냅샷만 읽습니다. +- 활성 표면 필터링은 활성화 중 적용됩니다. 활성화된 표면의 해석되지 않은 ref는 시작/리로드를 실패시키고, 비활성 표면은 진단과 함께 건너뜁니다. --- @@ -3262,11 +3334,11 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 ``` - 에이전트별 프로필은 `/auth-profiles.json`에 저장됩니다. -- `auth-profiles.json`은 정적 자격 증명 모드에 대해 값 수준 참조(`api_key`용 `keyRef`, `token`용 `tokenRef`)를 지원합니다. +- `auth-profiles.json`은 정적 자격 증명 모드에 대해 값 수준 ref(`api_key`용 `keyRef`, `token`용 `tokenRef`)를 지원합니다. - OAuth 모드 프로필(`auth.profiles..mode = "oauth"`)은 SecretRef 기반 auth-profile 자격 증명을 지원하지 않습니다. -- 정적 런타임 자격 증명은 메모리 내 해석 스냅샷에서 가져오며, 레거시 정적 `auth.json` 항목은 발견 시 제거됩니다. -- 레거시 OAuth는 `~/.openclaw/credentials/oauth.json`에서 가져옵니다. -- [OAuth](/ko/concepts/oauth)를 참조하세요. +- 정적 런타임 자격 증명은 메모리 내 해석 스냅샷에서 오며, 레거시 정적 `auth.json` 항목은 발견 시 제거됩니다. +- 레거시 OAuth 가져오기는 `~/.openclaw/credentials/oauth.json`에서 수행됩니다. +- [OAuth](/ko/concepts/oauth)를 참고하세요. - Secrets 런타임 동작과 `audit/configure/apply` 도구: [Secrets Management](/ko/gateway/secrets). ### `auth.cooldowns` @@ -3289,15 +3361,20 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 } ``` -- `billingBackoffHours`: 실제 청구/크레딧 부족 오류로 프로필이 실패할 때의 기본 백오프 시간(시간 단위)입니다(기본값: `5`). 명시적인 청구 관련 텍스트는 `401`/`403` 응답에서도 여기에 들어올 수 있지만, provider별 텍스트 매처는 해당 provider 범위 안에만 유지됩니다(예: OpenRouter `Key limit exceeded`). 재시도 가능한 HTTP `402` 사용량 창 또는 organization/workspace 지출 한도 메시지는 대신 `rate_limit` 경로에 머뭅니다. +- `billingBackoffHours`: 프로필이 실제 + 청구/잔액 부족 오류로 실패할 때의 기본 백오프 시간(시간)입니다(기본값: `5`). 명시적인 청구 관련 텍스트는 + `401`/`403` 응답에서도 여기에 포함될 수 있지만, provider별 텍스트 + 매처는 여전히 해당 provider 범위 안에서만 적용됩니다(예: OpenRouter + `Key limit exceeded`). 재시도 가능한 HTTP `402` 사용량 창 또는 + 조직/워크스페이스 지출 한도 메시지는 대신 `rate_limit` 경로에 남습니다. - `billingBackoffHoursByProvider`: 청구 백오프 시간에 대한 선택적 provider별 재정의입니다. -- `billingMaxHours`: 청구 백오프 지수 증가의 상한(시간 단위)입니다(기본값: `24`). -- `authPermanentBackoffMinutes`: 신뢰도 높은 `auth_permanent` 실패에 대한 기본 백오프(분 단위)입니다(기본값: `10`). -- `authPermanentMaxMinutes`: `auth_permanent` 백오프 증가의 상한(분 단위)입니다(기본값: `60`). -- `failureWindowHours`: 백오프 카운터에 사용되는 이동 창(시간 단위)입니다(기본값: `24`). -- `overloadedProfileRotations`: 모델 fallback으로 전환하기 전 과부하 오류에 대해 허용되는 동일 provider auth-profile 회전 최대 횟수입니다(기본값: `1`). `ModelNotReadyException` 같은 provider busy 형태가 여기에 포함됩니다. -- `overloadedBackoffMs`: 과부하된 provider/profile 회전을 재시도하기 전의 고정 지연(밀리초)입니다(기본값: `0`). -- `rateLimitedProfileRotations`: 모델 fallback으로 전환하기 전 rate-limit 오류에 대해 허용되는 동일 provider auth-profile 회전 최대 횟수입니다(기본값: `1`). 이 rate-limit 버킷에는 `Too many concurrent requests`, `ThrottlingException`, `concurrency limit reached`, `workers_ai ... quota limit exceeded`, `resource exhausted` 같은 provider 형태 텍스트가 포함됩니다. +- `billingMaxHours`: 청구 백오프 지수 증가의 최대 상한(시간)입니다(기본값: `24`). +- `authPermanentBackoffMinutes`: 신뢰도 높은 `auth_permanent` 실패에 대한 기본 백오프 시간(분)입니다(기본값: `10`). +- `authPermanentMaxMinutes`: `auth_permanent` 백오프 증가의 최대 상한(분)입니다(기본값: `60`). +- `failureWindowHours`: 백오프 카운터에 사용되는 롤링 윈도우(시간)입니다(기본값: `24`). +- `overloadedProfileRotations`: 모델 fallback으로 전환하기 전 overloaded 오류에 대해 같은 provider auth-profile을 회전할 수 있는 최대 횟수입니다(기본값: `1`). `ModelNotReadyException` 같은 provider-busy 형태가 여기에 포함됩니다. +- `overloadedBackoffMs`: overloaded provider/profile 회전을 재시도하기 전의 고정 지연입니다(기본값: `0`). +- `rateLimitedProfileRotations`: 모델 fallback으로 전환하기 전 rate-limit 오류에 대해 같은 provider auth-profile을 회전할 수 있는 최대 횟수입니다(기본값: `1`). 이 rate-limit 버킷에는 `Too many concurrent requests`, `ThrottlingException`, `concurrency limit reached`, `workers_ai ... quota limit exceeded`, `resource exhausted` 같은 provider 형태 텍스트가 포함됩니다. --- @@ -3317,9 +3394,9 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 ``` - 기본 로그 파일: `/tmp/openclaw/openclaw-YYYY-MM-DD.log`. -- 고정 경로를 원하면 `logging.file`을 설정하세요. +- 고정 경로를 사용하려면 `logging.file`을 설정하세요. - `consoleLevel`은 `--verbose`일 때 `debug`로 올라갑니다. -- `maxFileBytes`: 쓰기가 억제되기 전 로그 파일 최대 크기(바이트)입니다(양의 정수, 기본값: `524288000` = 500 MB). 운영 배포에서는 외부 로그 회전을 사용하세요. +- `maxFileBytes`: 쓰기가 억제되기 전 최대 로그 파일 크기(바이트)입니다(양의 정수, 기본값: `524288000` = 500 MB). 프로덕션 배포에서는 외부 로그 로테이션을 사용하세요. --- @@ -3358,18 +3435,18 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 - `enabled`: 계측 출력의 마스터 토글입니다(기본값: `true`). - `flags`: 대상 로그 출력을 활성화하는 플래그 문자열 배열입니다(`"telegram.*"` 또는 `"*"` 같은 와일드카드 지원). -- `stuckSessionWarnMs`: 세션이 처리 상태로 남아 있는 동안 정체된 세션 경고를 출력하는 기준 시간(밀리초)입니다. +- `stuckSessionWarnMs`: 세션이 처리 상태에 머무는 동안 stuck-session 경고를 발생시키는 나이 임계값(ms)입니다. - `otel.enabled`: OpenTelemetry 내보내기 파이프라인을 활성화합니다(기본값: `false`). -- `otel.endpoint`: OTel 내보내기용 수집기 URL입니다. -- `otel.protocol`: `"http/protobuf"`(기본값) 또는 `"grpc"`. +- `otel.endpoint`: OTel 내보내기용 collector URL입니다. +- `otel.protocol`: `"http/protobuf"`(기본값) 또는 `"grpc"`입니다. - `otel.headers`: OTel 내보내기 요청과 함께 전송되는 추가 HTTP/gRPC 메타데이터 헤더입니다. - `otel.serviceName`: 리소스 속성용 서비스 이름입니다. -- `otel.traces` / `otel.metrics` / `otel.logs`: trace, metrics, 또는 log 내보내기를 활성화합니다. -- `otel.sampleRate`: trace 샘플링 비율 `0`–`1`. -- `otel.flushIntervalMs`: 주기적 telemetry flush 간격(밀리초)입니다. -- `cacheTrace.enabled`: 임베디드 실행용 캐시 추적 스냅샷을 기록합니다(기본값: `false`). -- `cacheTrace.filePath`: 캐시 추적 JSONL의 출력 경로입니다(기본값: `$OPENCLAW_STATE_DIR/logs/cache-trace.jsonl`). -- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`: 캐시 추적 출력에 무엇을 포함할지 제어합니다(기본값은 모두 `true`). +- `otel.traces` / `otel.metrics` / `otel.logs`: trace, metrics 또는 log 내보내기를 활성화합니다. +- `otel.sampleRate`: trace 샘플링 비율 `0`–`1`입니다. +- `otel.flushIntervalMs`: 주기적 telemetry flush 간격(ms)입니다. +- `cacheTrace.enabled`: 내장 실행용 cache trace 스냅샷을 기록합니다(기본값: `false`). +- `cacheTrace.filePath`: cache trace JSONL 출력 경로입니다(기본값: `$OPENCLAW_STATE_DIR/logs/cache-trace.jsonl`). +- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`: cache trace 출력에 무엇을 포함할지 제어합니다(모두 기본값: `true`). --- @@ -3393,10 +3470,10 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 - `channel`: npm/git 설치용 릴리스 채널입니다 — `"stable"`, `"beta"`, 또는 `"dev"`. - `checkOnStart`: gateway 시작 시 npm 업데이트를 확인합니다(기본값: `true`). -- `auto.enabled`: 패키지 설치에 대한 백그라운드 자동 업데이트를 활성화합니다(기본값: `false`). -- `auto.stableDelayHours`: stable 채널 자동 적용 전 최소 지연 시간(시간 단위)입니다(기본값: `6`; 최대: `168`). -- `auto.stableJitterHours`: stable 채널 배포 분산을 위한 추가 시간 창입니다(기본값: `12`; 최대: `168`). -- `auto.betaCheckIntervalHours`: beta 채널 확인이 실행되는 간격(시간 단위)입니다(기본값: `1`; 최대: `24`). +- `auto.enabled`: 패키지 설치용 백그라운드 자동 업데이트를 활성화합니다(기본값: `false`). +- `auto.stableDelayHours`: stable 채널 자동 적용 전 최소 지연 시간(시간)입니다(기본값: `6`, 최대: `168`). +- `auto.stableJitterHours`: stable 채널 롤아웃 분산용 추가 시간 창(시간)입니다(기본값: `12`, 최대: `168`). +- `auto.betaCheckIntervalHours`: beta 채널 확인이 실행되는 주기(시간)입니다(기본값: `1`, 최대: `24`). --- @@ -3430,21 +3507,21 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 ``` - `enabled`: 전역 ACP 기능 게이트입니다(기본값: `false`). -- `dispatch.enabled`: ACP 세션 턴 디스패치를 위한 독립 게이트입니다(기본값: `true`). ACP 명령은 계속 사용 가능하게 두되 실행을 막으려면 `false`로 설정하세요. -- `backend`: 기본 ACP 런타임 backend ID입니다(등록된 ACP 런타임 plugin과 일치해야 함). -- `defaultAgent`: 생성 시 명시적 대상이 지정되지 않았을 때의 대체 ACP 대상 에이전트 ID입니다. -- `allowedAgents`: ACP 런타임 세션에 허용되는 에이전트 ID 허용 목록입니다. 비어 있으면 추가 제한이 없음을 의미합니다. -- `maxConcurrentSessions`: 동시에 활성 상태일 수 있는 ACP 세션의 최대 수입니다. -- `stream.coalesceIdleMs`: 스트리밍 텍스트용 유휴 flush 창(밀리초)입니다. -- `stream.maxChunkChars`: 스트리밍 블록 프로젝션을 분할하기 전 최대 청크 크기입니다. -- `stream.repeatSuppression`: 턴별로 반복된 상태/도구 줄을 억제합니다(기본값: `true`). +- `dispatch.enabled`: ACP 세션 턴 디스패치용 독립 게이트입니다(기본값: `true`). ACP 명령은 계속 사용 가능하게 두고 실행만 막으려면 `false`로 설정하세요. +- `backend`: 기본 ACP 런타임 backend id입니다(등록된 ACP 런타임 플러그인과 일치해야 함). +- `defaultAgent`: spawn이 명시적 대상을 지정하지 않았을 때의 대체 ACP 대상 에이전트 id입니다. +- `allowedAgents`: ACP 런타임 세션에 허용되는 에이전트 id의 허용 목록입니다. 비어 있으면 추가 제한이 없음을 의미합니다. +- `maxConcurrentSessions`: 동시에 활성화될 수 있는 ACP 세션의 최대 수입니다. +- `stream.coalesceIdleMs`: 스트리밍 텍스트의 유휴 flush 창(ms)입니다. +- `stream.maxChunkChars`: 스트리밍 블록 투영을 분할하기 전 최대 청크 크기입니다. +- `stream.repeatSuppression`: 턴당 반복되는 상태/도구 줄을 억제합니다(기본값: `true`). - `stream.deliveryMode`: `"live"`는 점진적으로 스트리밍하고, `"final_only"`는 턴 종료 이벤트까지 버퍼링합니다. -- `stream.hiddenBoundarySeparator`: 숨겨진 도구 이벤트 뒤에 표시되는 텍스트 앞에 넣을 구분자입니다(기본값: `"paragraph"`). -- `stream.maxOutputChars`: ACP 턴당 투영되는 assistant 출력 최대 문자 수입니다. +- `stream.hiddenBoundarySeparator`: 숨겨진 도구 이벤트 뒤에 보이는 텍스트 앞에 넣는 구분자입니다(기본값: `"paragraph"`). +- `stream.maxOutputChars`: ACP 턴당 투영되는 assistant 출력의 최대 문자 수입니다. - `stream.maxSessionUpdateChars`: 투영되는 ACP 상태/업데이트 줄의 최대 문자 수입니다. -- `stream.tagVisibility`: 스트리밍 이벤트용 태그 이름별 불리언 표시 재정의 레코드입니다. -- `runtime.ttlMinutes`: 정리 대상이 되기 전 ACP 세션 워커의 유휴 TTL(분 단위)입니다. -- `runtime.installCommand`: ACP 런타임 환경 bootstrap 시 실행할 선택적 설치 명령입니다. +- `stream.tagVisibility`: 스트리밍 이벤트의 태그 이름별 불리언 표시 재정의 기록입니다. +- `runtime.ttlMinutes`: ACP 세션 작업자가 정리 대상이 되기 전까지의 유휴 TTL(분)입니다. +- `runtime.installCommand`: ACP 런타임 환경 부트스트랩 시 실행할 선택적 설치 명령입니다. --- @@ -3460,17 +3537,17 @@ SecretRef는 추가 기능입니다. 일반 텍스트 값도 계속 작동합니 } ``` -- `cli.banner.taglineMode`는 배너 태그라인 스타일을 제어합니다. +- `cli.banner.taglineMode`는 배너 태그라인 스타일을 제어합니다: - `"random"`(기본값): 순환하는 재미있는/계절성 태그라인. - - `"default"`: 고정된 중립 태그라인(`모든 채팅을 하나의 OpenClaw로.`). - - `"off"`: 태그라인 텍스트 없음(배너 제목/버전은 계속 표시). + - `"default"`: 고정된 중립 태그라인(`All your chats, one OpenClaw.`). + - `"off"`: 태그라인 텍스트 없음(배너 제목/버전은 계속 표시됨). - 전체 배너를 숨기려면(태그라인만이 아니라) 환경 변수 `OPENCLAW_HIDE_BANNER=1`을 설정하세요. --- ## 마법사 -CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 메타데이터입니다. +CLI 가이드 설정 흐름(`onboard`, `configure`, `doctor`)이 기록하는 메타데이터입니다: ```json5 { @@ -3488,15 +3565,15 @@ CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 ## Identity -[에이전트 기본값](#agent-defaults) 아래의 `agents.list` identity 필드를 참조하세요. +[Agent defaults](#agent-defaults)의 `agents.list` identity 필드를 참고하세요. --- -## Bridge(레거시, 제거됨) +## Bridge (레거시, 제거됨) -현재 빌드에는 더 이상 TCP bridge가 포함되지 않습니다. node는 Gateway WebSocket을 통해 연결됩니다. `bridge.*` 키는 더 이상 구성 스키마의 일부가 아닙니다(제거할 때까지 검증이 실패하며, `openclaw doctor --fix`로 알 수 없는 키를 제거할 수 있습니다). +현재 빌드에는 더 이상 TCP bridge가 포함되지 않습니다. 노드는 Gateway WebSocket을 통해 연결됩니다. `bridge.*` 키는 더 이상 구성 스키마의 일부가 아니며(제거할 때까지 검증 실패, `openclaw doctor --fix`로 알 수 없는 키 제거 가능). - + ```json { @@ -3524,21 +3601,21 @@ CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 enabled: true, maxConcurrentRuns: 2, webhook: "https://example.invalid/legacy", // 저장된 notify:true 작업용 deprecated 대체값 - webhookToken: "replace-with-dedicated-token", // 발신 webhook 인증용 선택적 bearer token + webhookToken: "replace-with-dedicated-token", // 발신 webhook 인증용 선택적 bearer 토큰 sessionRetention: "24h", // 기간 문자열 또는 false runLog: { - maxBytes: "2mb", // 기본값 2_000_000 바이트 + maxBytes: "2mb", // 기본값 2_000_000 bytes keepLines: 2000, // 기본값 2000 }, }, } ``` -- `sessionRetention`: 완료된 격리 cron 실행 세션을 `sessions.json`에서 제거하기 전까지 유지할 기간입니다. 보관된 삭제 cron transcript 정리도 제어합니다. 기본값: `24h`; 비활성화하려면 `false`로 설정하세요. -- `runLog.maxBytes`: 제거 전 실행 로그 파일(`cron/runs/.jsonl`)당 최대 크기입니다. 기본값: `2_000_000` 바이트. -- `runLog.keepLines`: 실행 로그 제거가 트리거될 때 유지되는 최신 줄 수입니다. 기본값: `2000`. -- `webhookToken`: cron webhook `POST` 전달(`delivery.mode = "webhook"`)에 사용되는 bearer token입니다. 생략하면 인증 헤더를 보내지 않습니다. -- `webhook`: 저장된 작업 중 여전히 `notify: true`가 설정된 작업에만 사용되는 deprecated 레거시 대체 webhook URL(http/https)입니다. +- `sessionRetention`: 완료된 격리 cron 실행 세션을 `sessions.json`에서 정리하기 전까지 보관하는 기간입니다. 보관된 삭제 cron transcript의 정리도 함께 제어합니다. 기본값: `24h`; 비활성화하려면 `false`로 설정하세요. +- `runLog.maxBytes`: 정리 전 실행 로그 파일(`cron/runs/.jsonl`)당 최대 크기입니다. 기본값: `2_000_000` bytes. +- `runLog.keepLines`: 실행 로그 정리가 트리거될 때 유지되는 최신 줄 수입니다. 기본값: `2000`. +- `webhookToken`: cron webhook POST 전달(`delivery.mode = "webhook"`)에 사용하는 bearer 토큰입니다. 생략하면 인증 헤더가 전송되지 않습니다. +- `webhook`: deprecated 레거시 대체 webhook URL(http/https)로, 여전히 `notify: true`가 있는 저장된 작업에만 사용됩니다. ### `cron.retry` @@ -3554,9 +3631,9 @@ CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 } ``` -- `maxAttempts`: 일회성 작업에서 일시적 오류가 발생했을 때의 최대 재시도 횟수입니다(기본값: `3`; 범위: `0`–`10`). -- `backoffMs`: 각 재시도 시도에 대한 백오프 지연 시간(밀리초) 배열입니다(기본값: `[30000, 60000, 300000]`; 항목 수 1–10개). -- `retryOn`: 재시도를 트리거하는 오류 유형입니다 — `"rate_limit"`, `"overloaded"`, `"network"`, `"timeout"`, `"server_error"`. 생략하면 모든 일시적 유형을 재시도합니다. +- `maxAttempts`: 일회성 작업에서 일시적 오류 발생 시 최대 재시도 횟수입니다(기본값: `3`, 범위: `0`–`10`). +- `backoffMs`: 각 재시도 시도의 백오프 지연(ms) 배열입니다(기본값: `[30000, 60000, 300000]`, 1–10개 항목). +- `retryOn`: 재시도를 트리거하는 오류 유형 — `"rate_limit"`, `"overloaded"`, `"network"`, `"timeout"`, `"server_error"`. 생략하면 모든 일시적 유형을 재시도합니다. 일회성 cron 작업에만 적용됩니다. 반복 작업은 별도의 실패 처리 방식을 사용합니다. @@ -3578,9 +3655,9 @@ CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 - `enabled`: cron 작업 실패 알림을 활성화합니다(기본값: `false`). - `after`: 알림이 발생하기 전까지의 연속 실패 횟수입니다(양의 정수, 최소값: `1`). -- `cooldownMs`: 같은 작업에 대해 반복 알림을 보내기 전 최소 간격(밀리초)입니다(0 이상의 정수). -- `mode`: 전달 모드입니다 — `"announce"`는 채널 메시지로 보내고, `"webhook"`은 구성된 webhook으로 게시합니다. -- `accountId`: 알림 전달 범위를 지정하는 선택적 계정 또는 채널 ID입니다. +- `cooldownMs`: 동일 작업에 대해 반복 알림 사이의 최소 시간(밀리초)입니다(음수가 아닌 정수). +- `mode`: 전달 모드 — `"announce"`는 채널 메시지로 전송하고, `"webhook"`은 구성된 webhook으로 POST합니다. +- `accountId`: 알림 전달 범위를 제한하는 선택적 계정 또는 채널 id입니다. ### `cron.failureDestination` @@ -3597,51 +3674,51 @@ CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 } ``` -- 모든 작업에 대한 cron 실패 알림의 기본 대상입니다. -- `mode`: `"announce"` 또는 `"webhook"`이며, 충분한 대상 데이터가 있으면 기본값은 `"announce"`입니다. +- 모든 작업에 걸친 cron 실패 알림의 기본 대상입니다. +- `mode`: `"announce"` 또는 `"webhook"`입니다. 충분한 대상 정보가 있으면 기본값은 `"announce"`입니다. - `channel`: announce 전달용 채널 재정의입니다. `"last"`는 마지막으로 알려진 전달 채널을 재사용합니다. - `to`: 명시적 announce 대상 또는 webhook URL입니다. webhook 모드에서는 필수입니다. - `accountId`: 전달용 선택적 계정 재정의입니다. -- 작업별 `delivery.failureDestination`은 이 전역 기본값을 재정의합니다. +- 작업별 `delivery.failureDestination`이 이 전역 기본값을 재정의합니다. - 전역 또는 작업별 실패 대상이 모두 설정되지 않은 경우, 이미 `announce`로 전달되는 작업은 실패 시 해당 기본 announce 대상으로 대체됩니다. - `delivery.failureDestination`은 작업의 기본 `delivery.mode`가 `"webhook"`인 경우를 제외하면 `sessionTarget="isolated"` 작업에서만 지원됩니다. -[cron 작업](/ko/automation/cron-jobs)을 참조하세요. 격리된 cron 실행은 [백그라운드 작업](/ko/automation/tasks)으로 추적됩니다. +[Cron Jobs](/ko/automation/cron-jobs)를 참고하세요. 격리된 cron 실행은 [background tasks](/ko/automation/tasks)로 추적됩니다. --- ## 미디어 모델 템플릿 변수 -`tools.media.models[].args`에서 확장되는 템플릿 placeholder: +`tools.media.models[].args`에서 확장되는 템플릿 placeholder입니다: -| 변수 | 설명 | -| ------------------ | ------------------------------------- | -| `{{Body}}` | 전체 수신 메시지 본문 | -| `{{RawBody}}` | 원시 본문(기록/발신자 래퍼 없음) | -| `{{BodyStripped}}` | 그룹 멘션이 제거된 본문 | -| `{{From}}` | 발신자 식별자 | -| `{{To}}` | 대상 식별자 | -| `{{MessageSid}}` | 채널 메시지 ID | -| `{{SessionId}}` | 현재 세션 UUID | -| `{{IsNewSession}}` | 새 세션이 생성되었을 때 `"true"` | -| `{{MediaUrl}}` | 수신 미디어 pseudo-URL | -| `{{MediaPath}}` | 로컬 미디어 경로 | -| `{{MediaType}}` | 미디어 유형(image/audio/document/…) | -| `{{Transcript}}` | 오디오 transcript | -| `{{Prompt}}` | CLI 항목에 대해 해석된 미디어 프롬프트 | -| `{{MaxChars}}` | CLI 항목에 대해 해석된 최대 출력 문자 수 | -| `{{ChatType}}` | `"direct"` 또는 `"group"` | -| `{{GroupSubject}}` | 그룹 제목(best effort) | -| `{{GroupMembers}}` | 그룹 멤버 미리보기(best effort) | -| `{{SenderName}}` | 발신자 표시 이름(best effort) | -| `{{SenderE164}}` | 발신자 전화번호(best effort) | -| `{{Provider}}` | provider 힌트(whatsapp, telegram, discord 등) | +| Variable | 설명 | +| ------------------ | ----------------------------------------------- | +| `{{Body}}` | 전체 수신 메시지 본문 | +| `{{RawBody}}` | 원시 본문(기록/발신자 래퍼 없음) | +| `{{BodyStripped}}` | 그룹 멘션이 제거된 본문 | +| `{{From}}` | 발신자 식별자 | +| `{{To}}` | 대상 식별자 | +| `{{MessageSid}}` | 채널 메시지 id | +| `{{SessionId}}` | 현재 세션 UUID | +| `{{IsNewSession}}` | 새 세션이 생성되었을 때 `"true"` | +| `{{MediaUrl}}` | 수신 미디어 의사 URL | +| `{{MediaPath}}` | 로컬 미디어 경로 | +| `{{MediaType}}` | 미디어 유형(image/audio/document/…) | +| `{{Transcript}}` | 오디오 transcript | +| `{{Prompt}}` | CLI 항목에 대해 확인된 미디어 프롬프트 | +| `{{MaxChars}}` | CLI 항목에 대해 확인된 최대 출력 문자 수 | +| `{{ChatType}}` | `"direct"` 또는 `"group"` | +| `{{GroupSubject}}` | 그룹 제목(가능한 범위 내에서) | +| `{{GroupMembers}}` | 그룹 구성원 미리보기(가능한 범위 내에서) | +| `{{SenderName}}` | 발신자 표시 이름(가능한 범위 내에서) | +| `{{SenderE164}}` | 발신자 전화번호(가능한 범위 내에서) | +| `{{Provider}}` | provider 힌트(whatsapp, telegram, discord 등) | --- -## 구성 포함(`$include`) +## 구성 include (`$include`) -구성을 여러 파일로 분리합니다. +구성을 여러 파일로 분할합니다: ```json5 // ~/.openclaw/openclaw.json @@ -3657,12 +3734,12 @@ CLI 안내 설정 흐름(`onboard`, `configure`, `doctor`)에서 기록하는 **병합 동작:** - 단일 파일: 포함하는 객체를 대체합니다. -- 파일 배열: 순서대로 깊은 병합됩니다(나중 항목이 이전 항목을 재정의). -- 형제 키: include 이후 병합됩니다(포함된 값을 재정의). -- 중첩 include: 최대 10단계까지 허용됩니다. -- 경로: 포함하는 파일을 기준으로 해석되지만 최상위 구성 디렉터리(`openclaw.json`의 `dirname`) 내부에 머물러야 합니다. 절대 경로/`../` 형식도 최종적으로 그 경계 안에서 해석되면 허용됩니다. +- 파일 배열: 순서대로 deep-merge됩니다(나중 항목이 이전 항목을 재정의). +- 형제 키: include 후에 병합됩니다(include된 값을 재정의). +- 중첩 include: 최대 10단계 깊이까지. +- 경로: 포함하는 파일을 기준으로 해석되지만 최상위 구성 디렉터리(`openclaw.json`의 `dirname`) 내부에 머물러야 합니다. 절대 경로/`../` 형식도 그 경계 내부로 해석되는 경우에만 허용됩니다. - 오류: 누락된 파일, 파싱 오류, 순환 include에 대해 명확한 메시지를 제공합니다. --- -_관련 문서: [구성](/ko/gateway/configuration) · [구성 예시](/ko/gateway/configuration-examples) · [Doctor](/ko/gateway/doctor)_ +_관련: [Configuration](/ko/gateway/configuration) · [Configuration Examples](/ko/gateway/configuration-examples) · [Doctor](/ko/gateway/doctor)_ diff --git a/docs/ko/gateway/configuration.md b/docs/ko/gateway/configuration.md index e9cc68ff4..41620ac3d 100644 --- a/docs/ko/gateway/configuration.md +++ b/docs/ko/gateway/configuration.md @@ -1,15 +1,15 @@ --- read_when: - 처음으로 OpenClaw 설정하기 - - 일반적인 구성 패턴 찾기 + - 일반적인 구성 패턴을 찾고 있습니다. - 특정 구성 섹션으로 이동하기 -summary: '구성 개요: 일반적인 작업, 빠른 설정, 전체 참조 링크' +summary: '구성 개요: 일반적인 작업, 빠른 설정, 그리고 전체 참조 링크' title: 구성 x-i18n: - generated_at: "2026-04-08T05:56:44Z" + generated_at: "2026-04-11T02:44:46Z" model: gpt-5.4 provider: openai - source_hash: 199a1e515bd4003319e71593a2659bb883299a76ff67e273d92583df03c96604 + source_hash: e874be80d11b9123cac6ce597ec02667fbc798f622a076f68535a1af1f0e399c source_path: gateway/configuration.md workflow: 15 --- @@ -24,10 +24,10 @@ OpenClaw는 `~/.openclaw/openclaw.json`에서 선택적인 [http://127.0.0.1:18789](http://127.0.0.1:18789)을 열고 **Config** 탭을 사용하세요. - Control UI는 라이브 config 스키마로부터 폼을 렌더링하며, 사용 가능한 경우 - 필드 `title` / `description` 문서 메타데이터와 plugin 및 channel 스키마를 포함하고, - 탈출구로 사용할 수 있는 **Raw JSON** 편집기도 제공합니다. 드릴다운 UI와 - 기타 도구를 위해 gateway는 `config.schema.lookup`도 제공하며, - 경로 범위가 지정된 스키마 노드 하나와 즉시 하위 요약을 가져올 수 있습니다. + Control UI는 라이브 구성 스키마로부터 폼을 렌더링하며, 가능한 경우 + 필드 `title` / `description` 문서 메타데이터와 플러그인 및 채널 스키마를 + 포함하고, 탈출구로 **Raw JSON** 편집기도 제공합니다. 드릴다운 UI와 + 기타 도구를 위해 gateway는 `config.schema.lookup`도 노출하여 + 하나의 경로 범위 스키마 노드와 즉시 하위 요약을 가져올 수 있게 합니다. - `~/.openclaw/openclaw.json`을 직접 편집하세요. Gateway는 파일을 감시하고 변경 사항을 자동으로 적용합니다([핫 리로드](#config-hot-reload) 참조). + `~/.openclaw/openclaw.json`을 직접 편집하세요. Gateway가 파일을 감시하고 변경 사항을 자동으로 적용합니다([핫 리로드](#config-hot-reload) 참조). ## 엄격한 검증 -OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 수 없는 키, 잘못된 타입, 유효하지 않은 값이 있으면 Gateway는 **시작을 거부합니다**. 루트 수준의 유일한 예외는 편집기가 JSON Schema 메타데이터를 연결할 수 있도록 하는 `$schema`(문자열)입니다. +OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 수 없는 키, 잘못된 형식의 타입, 또는 유효하지 않은 값이 있으면 Gateway는 **시작을 거부합니다**. 유일한 루트 수준 예외는 `$schema`(문자열)이며, 이를 통해 편집기가 JSON Schema 메타데이터를 연결할 수 있습니다. -스키마 도구 참고 사항: +스키마 도구 관련 참고 사항: -- `openclaw config schema`는 Control UI와 config 검증에서 사용하는 것과 동일한 JSON Schema 계열을 출력합니다. -- 해당 스키마 출력은 `openclaw.json`의 표준 기계 판독 계약으로 취급하세요. 이 개요와 구성 참조는 이를 요약한 것입니다. +- `openclaw config schema`는 Control UI와 구성 검증에서 사용하는 것과 동일한 JSON Schema 계열을 출력합니다. +- 이 스키마 출력을 `openclaw.json`에 대한 표준 기계 판독 계약으로 취급하세요. 이 개요와 구성 참조는 이를 요약한 것입니다. - 필드 `title` 및 `description` 값은 편집기와 폼 도구를 위해 스키마 출력에 포함됩니다. -- 중첩 객체, 와일드카드(`*`), 배열 항목(`[]`) 항목은 일치하는 필드 문서가 존재하는 경우 동일한 문서 메타데이터를 상속합니다. -- `anyOf` / `oneOf` / `allOf` 구성 분기 역시 동일한 문서 메타데이터를 상속하므로, union/intersection 변형도 같은 필드 도움말을 유지합니다. -- `config.schema.lookup`은 정규화된 config 경로 하나와 얕은 스키마 노드(`title`, `description`, `type`, `enum`, `const`, 일반적인 경계값 및 유사한 검증 필드), 일치하는 UI 힌트 메타데이터, 그리고 드릴다운 도구를 위한 즉시 하위 요약을 반환합니다. -- runtime plugin/channel 스키마는 gateway가 현재 manifest 레지스트리를 로드할 수 있을 때 병합됩니다. -- `pnpm config:docs:check`는 문서용 config 기준 아티팩트와 현재 스키마 표면 간의 드리프트를 감지합니다. +- 중첩 객체, 와일드카드(`*`), 배열 항목(`[]`) 엔트리는 일치하는 필드 문서가 있는 경우 동일한 문서 메타데이터를 상속합니다. +- `anyOf` / `oneOf` / `allOf` 구성 분기도 동일한 문서 메타데이터를 상속하므로, union/intersection 변형에서도 같은 필드 도움말이 유지됩니다. +- `config.schema.lookup`는 하나의 정규화된 구성 경로와 얕은 스키마 노드(`title`, `description`, `type`, `enum`, `const`, 일반적인 범위 제한 및 유사한 검증 필드), 일치한 UI 힌트 메타데이터, 그리고 드릴다운 도구용 즉시 하위 요약을 반환합니다. +- gateway가 현재 매니페스트 레지스트리를 로드할 수 있을 때 런타임 플러그인/채널 스키마가 병합됩니다. +- `pnpm config:docs:check`는 docs용 구성 기준 아티팩트와 현재 스키마 표면 사이의 드리프트를 감지합니다. 검증에 실패하면: -- Gateway가 부팅되지 않음 -- 진단 명령만 작동함(`openclaw doctor`, `openclaw logs`, `openclaw health`, `openclaw status`) -- 정확한 문제를 확인하려면 `openclaw doctor` 실행 -- 수정을 적용하려면 `openclaw doctor --fix`(또는 `--yes`) 실행 +- Gateway가 부팅되지 않습니다 +- 진단 명령만 작동합니다 (`openclaw doctor`, `openclaw logs`, `openclaw health`, `openclaw status`) +- 정확한 문제를 보려면 `openclaw doctor`를 실행하세요 +- 수정을 적용하려면 `openclaw doctor --fix`(또는 `--yes`)를 실행하세요 ## 일반적인 작업 - 각 채널은 `channels.` 아래에 자체 구성 섹션을 가집니다. 설정 단계는 전용 채널 페이지를 참조하세요. + 각 채널에는 `channels.` 아래에 자체 구성 섹션이 있습니다. 설정 단계는 전용 채널 페이지를 확인하세요. - [WhatsApp](/ko/channels/whatsapp) — `channels.whatsapp` - [Telegram](/ko/channels/telegram) — `channels.telegram` @@ -128,7 +128,7 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 - 기본 모델과 선택적 폴백을 설정합니다. + 기본 모델과 선택적 대체 모델을 설정합니다. ```json5 { @@ -147,25 +147,25 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - - `agents.defaults.models`는 모델 카탈로그를 정의하며 `/model`의 허용 목록 역할도 합니다. + - `agents.defaults.models`는 모델 카탈로그를 정의하며 `/model`에 대한 allowlist 역할도 합니다. - 모델 참조는 `provider/model` 형식을 사용합니다(예: `anthropic/claude-opus-4-6`). - - `agents.defaults.imageMaxDimensionPx`는 transcript/tool 이미지 축소 크기 조정을 제어합니다(기본값 `1200`). 값을 낮추면 스크린샷이 많은 실행에서 일반적으로 비전 토큰 사용량이 줄어듭니다. - - 채팅에서 모델 전환은 [Models CLI](/ko/concepts/models), 인증 순환 및 폴백 동작은 [Model Failover](/ko/concepts/model-failover)를 참조하세요. - - 사용자 지정/자체 호스팅 provider는 참조 문서의 [사용자 지정 provider](/ko/gateway/configuration-reference#custom-providers-and-base-urls)를 참조하세요. + - `agents.defaults.imageMaxDimensionPx`는 대화 기록/도구 이미지 축소 크기 조정을 제어합니다(기본값 `1200`). 값을 낮추면 스크린샷이 많은 실행에서 일반적으로 비전 토큰 사용량이 줄어듭니다. + - 채팅에서 모델을 전환하려면 [Models CLI](/ko/concepts/models)를, 인증 회전 및 대체 동작은 [Model Failover](/ko/concepts/model-failover)를 참조하세요. + - 커스텀/self-hosted provider는 참조 문서의 [Custom providers](/ko/gateway/configuration-reference#custom-providers-and-base-urls)를 확인하세요. - DM 접근은 채널별로 `dmPolicy`를 통해 제어됩니다. + DM 액세스는 채널별로 `dmPolicy`를 통해 제어됩니다. - - `"pairing"` (기본값): 알 수 없는 발신자는 승인을 위한 일회성 페어링 코드를 받음 + - `"pairing"` (기본값): 알 수 없는 발신자는 승인을 위한 일회용 페어링 코드를 받습니다 - `"allowlist"`: `allowFrom`(또는 페어링된 허용 저장소)에 있는 발신자만 허용 - `"open"`: 모든 수신 DM 허용(`allowFrom: ["*"]` 필요) - `"disabled"`: 모든 DM 무시 - 그룹의 경우 `groupPolicy` + `groupAllowFrom` 또는 채널별 허용 목록을 사용하세요. + 그룹의 경우 `groupPolicy` + `groupAllowFrom` 또는 채널별 allowlist를 사용하세요. - 채널별 세부 사항은 [전체 참조](/ko/gateway/configuration-reference#dm-and-group-access)를 참조하세요. + 채널별 자세한 내용은 [전체 참조](/ko/gateway/configuration-reference#dm-and-group-access)를 확인하세요. @@ -192,14 +192,15 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - - **메타데이터 멘션**: 네이티브 @멘션(WhatsApp 탭하여 멘션, Telegram @bot 등) + - **메타데이터 멘션**: 네이티브 @멘션(WhatsApp 탭-투-멘션, Telegram @bot 등) - **텍스트 패턴**: `mentionPatterns`의 안전한 정규식 패턴 - - 채널별 재정의와 self-chat 모드는 [전체 참조](/ko/gateway/configuration-reference#group-chat-mention-gating)를 참조하세요. + - 채널별 재정의 및 self-chat 모드는 [전체 참조](/ko/gateway/configuration-reference#group-chat-mention-gating)를 확인하세요. - 공유 기준선에는 `agents.defaults.skills`를 사용하고, 특정 에이전트는 `agents.list[].skills`로 재정의하세요. + 공통 기준선에는 `agents.defaults.skills`를 사용하고, 특정 + 에이전트는 `agents.list[].skills`로 재정의하세요. ```json5 { @@ -218,8 +219,9 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 - 기본적으로 제한 없는 Skills를 원하면 `agents.defaults.skills`를 생략하세요. - 기본값을 상속하려면 `agents.list[].skills`를 생략하세요. - - Skills가 없도록 하려면 `agents.list[].skills: []`를 설정하세요. - - [Skills](/ko/tools/skills), [Skills config](/ko/tools/skills-config), 그리고 [구성 참조](/ko/gateway/configuration-reference#agentsdefaultsskills)를 참조하세요. + - Skills가 없게 하려면 `agents.list[].skills: []`로 설정하세요. + - [Skills](/ko/tools/skills), [Skills config](/ko/tools/skills-config), 그리고 + [Configuration Reference](/ko/gateway/configuration-reference#agents-defaults-skills)를 참조하세요. @@ -246,14 +248,14 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - - 전역적으로 상태 모니터 재시작을 비활성화하려면 `gateway.channelHealthCheckMinutes: 0`을 설정하세요. + - 전역적으로 상태 모니터 재시작을 비활성화하려면 `gateway.channelHealthCheckMinutes: 0`으로 설정하세요. - `channelStaleEventThresholdMinutes`는 검사 간격보다 크거나 같아야 합니다. - - 전역 모니터를 끄지 않고 특정 채널 또는 계정의 자동 재시작만 끄려면 `channels..healthMonitor.enabled` 또는 `channels..accounts..healthMonitor.enabled`를 사용하세요. - - 운영 디버깅은 [상태 검사](/ko/gateway/health), 모든 필드는 [전체 참조](/ko/gateway/configuration-reference#gateway)를 참조하세요. + - 전역 모니터를 끄지 않고 특정 채널 또는 계정에 대한 자동 재시작만 끄려면 `channels..healthMonitor.enabled` 또는 `channels..accounts..healthMonitor.enabled`를 사용하세요. + - 운영 디버깅은 [Health Checks](/ko/gateway/health)를, 모든 필드는 [전체 참조](/ko/gateway/configuration-reference#gateway)를 확인하세요. - + 세션은 대화의 연속성과 격리를 제어합니다. ```json5 @@ -275,9 +277,9 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 ``` - `dmScope`: `main` (공유) | `per-peer` | `per-channel-peer` | `per-account-channel-peer` - - `threadBindings`: 스레드 바인딩 세션 라우팅의 전역 기본값(Discord는 `/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age` 지원). - - 범위, identity 링크, send 정책은 [세션 관리](/ko/concepts/session)를 참조하세요. - - 모든 필드는 [전체 참조](/ko/gateway/configuration-reference#session)를 참조하세요. + - `threadBindings`: 스레드 바인딩 세션 라우팅을 위한 전역 기본값(Discord는 `/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age`를 지원) + - 범위 지정, ID 링크, 전송 정책은 [Session Management](/ko/concepts/session)를 참조하세요. + - 모든 필드는 [전체 참조](/ko/gateway/configuration-reference#session)를 확인하세요. @@ -299,14 +301,14 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 먼저 이미지를 빌드하세요: `scripts/sandbox-setup.sh` - 전체 가이드는 [샌드박싱](/ko/gateway/sandboxing), 모든 옵션은 [전체 참조](/ko/gateway/configuration-reference#agentsdefaultssandbox)를 참조하세요. + 전체 가이드는 [Sandboxing](/ko/gateway/sandboxing), 모든 옵션은 [전체 참조](/ko/gateway/configuration-reference#agentsdefaultssandbox)를 확인하세요. - - relay 기반 푸시는 `openclaw.json`에서 구성합니다. + + relay 기반 push는 `openclaw.json`에서 구성합니다. - gateway config에 다음을 설정하세요. + gateway 구성에서 다음을 설정하세요. ```json5 { @@ -324,39 +326,39 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - 동등한 CLI: + CLI 대응 명령: ```bash openclaw config set gateway.push.apns.relay.baseUrl https://relay.example.com ``` - 이 설정의 역할: + 이것이 수행하는 작업: - - gateway가 외부 relay를 통해 `push.test`, wake nudges, reconnect wakes를 보낼 수 있게 합니다. - - 페어링된 iOS 앱이 전달한 등록 범위 send grant를 사용합니다. gateway에는 배포 전체 범위의 relay 토큰이 필요하지 않습니다. - - 각 relay 기반 등록을 iOS 앱이 페어링한 gateway identity에 바인딩하므로, 다른 gateway는 저장된 등록을 재사용할 수 없습니다. - - 로컬/수동 iOS 빌드는 direct APNs를 유지합니다. relay 기반 전송은 relay를 통해 등록된 공식 배포 빌드에만 적용됩니다. - - 등록 및 전송 트래픽이 동일한 relay 배포에 도달하도록, 공식/TestFlight iOS 빌드에 내장된 relay base URL과 일치해야 합니다. + - gateway가 외부 relay를 통해 `push.test`, wake nudges, 재연결 wake를 보낼 수 있게 합니다. +- 페어링된 iOS 앱이 전달한 registration 범위 send grant를 사용합니다. gateway에는 배포 전체 범위 relay 토큰이 필요하지 않습니다. +- 각 relay 기반 registration은 iOS 앱이 페어링한 gateway ID에 바인딩되므로, 다른 gateway가 저장된 registration을 재사용할 수 없습니다. +- 로컬/수동 iOS 빌드는 direct APNs를 계속 사용합니다. relay 기반 전송은 relay를 통해 등록한 공식 배포 빌드에만 적용됩니다. +- registration 및 전송 트래픽이 동일한 relay 배포에 도달하도록, 공식/TestFlight iOS 빌드에 내장된 relay base URL과 일치해야 합니다. - 종단 간 흐름: +엔드투엔드 흐름: - 1. 동일한 relay base URL로 컴파일된 공식/TestFlight iOS 빌드를 설치합니다. - 2. gateway에서 `gateway.push.apns.relay.baseUrl`을 구성합니다. - 3. iOS 앱을 gateway에 페어링하고 node 세션과 operator 세션이 모두 연결되도록 합니다. - 4. iOS 앱은 gateway identity를 가져오고, App Attest와 앱 영수증을 사용해 relay에 등록한 다음, relay 기반 `push.apns.register` 페이로드를 페어링된 gateway에 게시합니다. - 5. gateway는 relay 핸들과 send grant를 저장하고, 이를 `push.test`, wake nudges, reconnect wakes에 사용합니다. +1. 동일한 relay base URL로 컴파일된 공식/TestFlight iOS 빌드를 설치합니다. +2. gateway에서 `gateway.push.apns.relay.baseUrl`을 구성합니다. +3. iOS 앱을 gateway와 페어링하고 node 세션과 operator 세션이 모두 연결되도록 합니다. +4. iOS 앱이 gateway ID를 가져오고, App Attest와 앱 영수증을 사용해 relay에 등록한 뒤, relay 기반 `push.apns.register` payload를 페어링된 gateway에 게시합니다. +5. gateway가 relay handle과 send grant를 저장한 다음, 이를 `push.test`, wake nudges, 재연결 wake에 사용합니다. - 운영 참고 사항: +운영 참고 사항: - - iOS 앱을 다른 gateway로 전환하는 경우, 앱이 해당 gateway에 바인딩된 새 relay 등록을 게시할 수 있도록 다시 연결하세요. - - 다른 relay 배포를 가리키는 새 iOS 빌드를 배포하는 경우, 앱은 이전 relay origin을 재사용하는 대신 캐시된 relay 등록을 갱신합니다. +- iOS 앱을 다른 gateway로 전환하면, 해당 gateway에 바인딩된 새 relay registration을 게시할 수 있도록 앱을 다시 연결하세요. +- 다른 relay 배포를 가리키는 새 iOS 빌드를 배포하면, 앱은 이전 relay origin을 재사용하는 대신 캐시된 relay registration을 새로 고칩니다. - 호환성 참고: +호환성 참고 사항: - - `OPENCLAW_APNS_RELAY_BASE_URL` 및 `OPENCLAW_APNS_RELAY_TIMEOUT_MS`는 여전히 임시 env 재정의로 동작합니다. - - `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true`는 계속 loopback 전용 개발용 탈출구로 남아 있으며, config에 HTTP relay URL을 영구 저장해서는 안 됩니다. +- `OPENCLAW_APNS_RELAY_BASE_URL` 및 `OPENCLAW_APNS_RELAY_TIMEOUT_MS`는 임시 env 재정의로 여전히 작동합니다. +- `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true`는 여전히 loopback 전용 개발용 예외 수단입니다. HTTP relay URL을 config에 영구 저장하지 마세요. - 종단 간 흐름은 [iOS 앱](/ko/platforms/ios#relay-backed-push-for-official-builds), relay 보안 모델은 [인증 및 신뢰 흐름](/ko/platforms/ios#authentication-and-trust-flow)을 참조하세요. +엔드투엔드 흐름은 [iOS App](/ko/platforms/ios#relay-backed-push-for-official-builds), relay 보안 모델은 [Authentication and trust flow](/ko/platforms/ios#authentication-and-trust-flow)를 참조하세요. @@ -374,7 +376,7 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - - `every`: 기간 문자열(`30m`, `2h`). 비활성화하려면 `0m` 설정. + - `every`: 기간 문자열(`30m`, `2h`). 비활성화하려면 `0m`으로 설정하세요. - `target`: `last` | `none` | `` (예: `discord`, `matrix`, `telegram`, `whatsapp`) - `directPolicy`: DM 스타일 heartbeat 대상에 대해 `allow`(기본값) 또는 `block` - 전체 가이드는 [Heartbeat](/ko/gateway/heartbeat)를 참조하세요. @@ -396,14 +398,14 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - - `sessionRetention`: 완료된 격리 실행 세션을 `sessions.json`에서 정리합니다(기본값 `24h`; 비활성화하려면 `false` 설정). - - `runLog`: 크기와 유지할 줄 수 기준으로 `cron/runs/.jsonl`을 정리합니다. - - 기능 개요와 CLI 예시는 [Cron 작업](/ko/automation/cron-jobs)을 참조하세요. + - `sessionRetention`: 완료된 격리 실행 세션을 `sessions.json`에서 정리합니다(기본값 `24h`; 비활성화하려면 `false`로 설정). + - `runLog`: `cron/runs/.jsonl`을 크기와 보존 라인 수 기준으로 정리합니다. + - 기능 개요와 CLI 예시는 [Cron jobs](/ko/automation/cron-jobs)를 참조하세요. - - Gateway에서 HTTP webhook 엔드포인트를 활성화합니다. + + Gateway에서 HTTP 웹훅 엔드포인트를 활성화합니다. ```json5 { @@ -427,20 +429,20 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 ``` 보안 참고: - - 모든 hook/webhook 페이로드 콘텐츠는 신뢰할 수 없는 입력으로 취급하세요. + - 모든 hook/webhook payload 내용은 신뢰할 수 없는 입력으로 취급하세요. - 전용 `hooks.token`을 사용하세요. 공유 Gateway 토큰을 재사용하지 마세요. - - Hook 인증은 헤더 전용입니다(`Authorization: Bearer ...` 또는 `x-openclaw-token`). 쿼리 문자열 토큰은 거부됩니다. - - `hooks.path`는 `/`가 될 수 없습니다. webhook 수신은 `/hooks` 같은 전용 하위 경로에 유지하세요. - - 엄격히 범위가 제한된 디버깅이 아닌 한, 안전하지 않은 콘텐츠 우회 플래그(`hooks.gmail.allowUnsafeExternalContent`, `hooks.mappings[].allowUnsafeExternalContent`)는 비활성화된 상태로 유지하세요. - - `hooks.allowRequestSessionKey`를 활성화하는 경우, 호출자가 선택하는 세션 키의 범위를 제한하도록 `hooks.allowedSessionKeyPrefixes`도 설정하세요. - - hook 기반 에이전트에는 가능한 경우 강력한 최신 모델 등급과 엄격한 도구 정책(예: 메시징 전용 + 샌드박싱)을 권장합니다. + - hook 인증은 헤더 전용입니다(`Authorization: Bearer ...` 또는 `x-openclaw-token`). 쿼리 문자열 토큰은 거부됩니다. + - `hooks.path`는 `/`일 수 없습니다. 웹훅 ingress는 `/hooks`와 같은 전용 하위 경로에 두세요. + - 엄격하게 제한된 디버깅을 하지 않는 한, 안전하지 않은 콘텐츠 우회 플래그(`hooks.gmail.allowUnsafeExternalContent`, `hooks.mappings[].allowUnsafeExternalContent`)는 비활성화 상태로 유지하세요. + - `hooks.allowRequestSessionKey`를 활성화하는 경우, 호출자가 선택하는 세션 키를 제한하기 위해 `hooks.allowedSessionKeyPrefixes`도 설정하세요. + - hook 기반 에이전트의 경우, 강력한 최신 모델 티어와 엄격한 도구 정책(예: 가능하다면 메시징 전용 + 샌드박싱)을 사용하는 것이 좋습니다. 모든 매핑 옵션과 Gmail 통합은 [전체 참조](/ko/gateway/configuration-reference#hooks)를 참조하세요. - 별도의 워크스페이스와 세션을 사용하는 여러 격리된 에이전트를 실행합니다. + 별도의 workspace와 세션으로 여러 개의 격리된 에이전트를 실행합니다. ```json5 { @@ -457,12 +459,12 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - 바인딩 규칙과 에이전트별 액세스 프로필은 [다중 에이전트](/ko/concepts/multi-agent)와 [전체 참조](/ko/gateway/configuration-reference#multi-agent-routing)를 참조하세요. + 바인딩 규칙과 에이전트별 액세스 프로필은 [Multi-Agent](/ko/concepts/multi-agent) 및 [전체 참조](/ko/gateway/configuration-reference#multi-agent-routing)를 참조하세요. - 큰 구성을 정리하려면 `$include`를 사용하세요. + `$include`를 사용해 큰 구성을 정리하세요. ```json5 // ~/.openclaw/openclaw.json @@ -475,28 +477,28 @@ OpenClaw는 스키마와 완전히 일치하는 구성만 허용합니다. 알 } ``` - - **단일 파일**: 포함하는 객체를 대체 - - **파일 배열**: 순서대로 깊은 병합(나중 것이 우선) - - **형제 키**: include 이후 병합됨(포함된 값 재정의) - - **중첩 include**: 최대 10단계까지 지원 - - **상대 경로**: 포함하는 파일을 기준으로 해석 - - **오류 처리**: 누락된 파일, 구문 분석 오류, 순환 include에 대해 명확한 오류 제공 + - **단일 파일**: 포함하는 객체를 대체합니다 + - **파일 배열**: 순서대로 deep merge됩니다(나중 것이 우선) + - **형제 키**: include 후 병합됩니다(포함된 값 재정의) + - **중첩 include**: 최대 10단계 깊이까지 지원 + - **상대 경로**: 포함하는 파일 기준으로 해석 + - **오류 처리**: 누락된 파일, 파싱 오류, 순환 include에 대해 명확한 오류 제공 -## config 핫 리로드 +## 구성 핫 리로드 Gateway는 `~/.openclaw/openclaw.json`을 감시하고 변경 사항을 자동으로 적용합니다 — 대부분의 설정에는 수동 재시작이 필요하지 않습니다. ### 리로드 모드 -| 모드 | 동작 | -| ---------------------- | --------------------------------------------------------------------------------------- | -| **`hybrid`** (기본값) | 안전한 변경은 즉시 핫 적용합니다. 중요한 변경은 자동으로 재시작합니다. | -| **`hot`** | 안전한 변경만 핫 적용합니다. 재시작이 필요하면 경고를 기록하며, 처리는 사용자가 해야 합니다. | -| **`restart`** | 안전 여부와 관계없이 모든 config 변경 시 Gateway를 재시작합니다. | -| **`off`** | 파일 감시를 비활성화합니다. 변경 사항은 다음 수동 재시작 시 적용됩니다. | +| 모드 | 동작 | +| ---------------------- | ----------------------------------------------------------------------------------- | +| **`hybrid`** (기본값) | 안전한 변경은 즉시 핫 적용합니다. 중요한 변경은 자동으로 재시작합니다. | +| **`hot`** | 안전한 변경만 핫 적용합니다. 재시작이 필요하면 경고를 기록하며, 처리는 사용자가 합니다. | +| **`restart`** | 안전하든 아니든 모든 구성 변경 시 Gateway를 재시작합니다. | +| **`off`** | 파일 감시를 비활성화합니다. 변경 사항은 다음 수동 재시작 시 적용됩니다. | ```json5 { @@ -508,56 +510,57 @@ Gateway는 `~/.openclaw/openclaw.json`을 감시하고 변경 사항을 자동 ### 핫 적용되는 항목과 재시작이 필요한 항목 -대부분의 필드는 다운타임 없이 핫 적용됩니다. `hybrid` 모드에서는 재시작이 필요한 변경이 자동으로 처리됩니다. +대부분의 필드는 다운타임 없이 핫 적용됩니다. `hybrid` 모드에서는 재시작이 필요한 변경도 자동으로 처리됩니다. -| 범주 | 필드 | 재시작 필요? | -| ------------------- | -------------------------------------------------------------------- | --------------- | -| 채널 | `channels.*`, `web` (WhatsApp) — 모든 내장 및 extension 채널 | 아니요 | -| 에이전트 및 모델 | `agent`, `agents`, `models`, `routing` | 아니요 | -| 자동화 | `hooks`, `cron`, `agent.heartbeat` | 아니요 | -| 세션 및 메시지 | `session`, `messages` | 아니요 | -| 도구 및 미디어 | `tools`, `browser`, `skills`, `audio`, `talk` | 아니요 | -| UI 및 기타 | `ui`, `logging`, `identity`, `bindings` | 아니요 | -| Gateway 서버 | `gateway.*` (port, bind, auth, tailscale, TLS, HTTP) | **예** | -| 인프라 | `discovery`, `canvasHost`, `plugins` | **예** | +| 범주 | 필드 | 재시작 필요? | +| ------------------- | -------------------------------------------------------------------- | ------------ | +| 채널 | `channels.*`, `web` (WhatsApp) — 모든 내장 및 확장 채널 | 아니요 | +| 에이전트 및 모델 | `agent`, `agents`, `models`, `routing` | 아니요 | +| 자동화 | `hooks`, `cron`, `agent.heartbeat` | 아니요 | +| 세션 및 메시지 | `session`, `messages` | 아니요 | +| 도구 및 미디어 | `tools`, `browser`, `skills`, `audio`, `talk` | 아니요 | +| UI 및 기타 | `ui`, `logging`, `identity`, `bindings` | 아니요 | +| Gateway 서버 | `gateway.*` (port, bind, auth, tailscale, TLS, HTTP) | **예** | +| 인프라 | `discovery`, `canvasHost`, `plugins` | **예** | -`gateway.reload`와 `gateway.remote`는 예외입니다 — 이를 변경해도 재시작이 트리거되지 않습니다. +`gateway.reload`와 `gateway.remote`는 예외입니다 — 이를 변경해도 **재시작이 트리거되지 않습니다**. -## config RPC (프로그래밍 방식 업데이트) +## 구성 RPC (프로그래밍 방식 업데이트) -control-plane 쓰기 RPC(`config.apply`, `config.patch`, `update.run`)는 `deviceId+clientIp`당 **60초마다 3회 요청**으로 속도 제한됩니다. 제한되면 RPC는 `retryAfterMs`와 함께 `UNAVAILABLE`을 반환합니다. +control-plane 쓰기 RPC(`config.apply`, `config.patch`, `update.run`)는 `deviceId+clientIp`당 **60초에 3회 요청**으로 속도 제한됩니다. 제한되면 RPC는 `retryAfterMs`와 함께 `UNAVAILABLE`을 반환합니다. -안전한 기본 흐름: +안전한/기본 흐름: -- `config.schema.lookup`: 얕은 스키마 노드, 일치하는 힌트 메타데이터, 즉시 하위 요약이 포함된 경로 범위 config 하위 트리 하나 검사 +- `config.schema.lookup`: 얕은 스키마 노드, 일치한 힌트 메타데이터, 즉시 하위 요약과 함께 하나의 경로 범위 구성 하위 트리를 검사 - `config.get`: 현재 스냅샷 + 해시 가져오기 - `config.patch`: 권장되는 부분 업데이트 경로 -- `config.apply`: 전체 config 교체 시에만 사용 +- `config.apply`: 전체 구성 교체 전용 - `update.run`: 명시적 자체 업데이트 + 재시작 -전체 config를 교체하는 것이 아니라면 `config.schema.lookup` 후 `config.patch`를 우선 사용하세요. +전체 구성을 교체하는 것이 아니라면 `config.schema.lookup` +다음 `config.patch`를 사용하는 것이 좋습니다. - 전체 config를 검증 + 기록하고 Gateway를 한 단계로 재시작합니다. + 전체 구성을 검증하고 기록한 뒤 한 번에 Gateway를 재시작합니다. - `config.apply`는 **전체 config**를 교체합니다. 부분 업데이트에는 `config.patch`, 단일 키에는 `openclaw config set`을 사용하세요. + `config.apply`는 **전체 구성**을 교체합니다. 부분 업데이트에는 `config.patch`를, 단일 키에는 `openclaw config set`을 사용하세요. 매개변수: - - `raw` (string) — 전체 config에 대한 JSON5 페이로드 - - `baseHash` (선택 사항) — `config.get`의 config 해시(config가 존재하면 필수) - - `sessionKey` (선택 사항) — 재시작 후 wake-up ping을 위한 세션 키 - - `note` (선택 사항) — 재시작 센티널용 메모 - - `restartDelayMs` (선택 사항) — 재시작 전 지연 시간(기본값 2000) + - `raw` (string) — 전체 구성에 대한 JSON5 payload + - `baseHash` (optional) — `config.get`의 구성 해시(구성이 이미 있으면 필수) + - `sessionKey` (optional) — 재시작 후 wake-up ping을 위한 세션 키 + - `note` (optional) — restart sentinel용 메모 + - `restartDelayMs` (optional) — 재시작 전 지연 시간(기본값 2000) - 재시작 요청은 이미 보류 중/진행 중인 요청이 있으면 합쳐지며, 재시작 주기 사이에는 30초 쿨다운이 적용됩니다. + 재시작 요청은 이미 대기 중/진행 중인 요청이 있는 동안 병합되며, 재시작 사이클 간에는 30초 쿨다운이 적용됩니다. ```bash openclaw gateway call config.get --params '{}' # payload.hash 캡처 @@ -571,7 +574,7 @@ control-plane 쓰기 RPC(`config.apply`, `config.patch`, `update.run`)는 `devic - 기존 config에 부분 업데이트를 병합합니다(JSON merge patch 의미 체계). + 부분 업데이트를 기존 구성에 병합합니다(JSON merge patch 의미론): - 객체는 재귀적으로 병합 - `null`은 키를 삭제 @@ -580,10 +583,10 @@ control-plane 쓰기 RPC(`config.apply`, `config.patch`, `update.run`)는 `devic 매개변수: - `raw` (string) — 변경할 키만 포함한 JSON5 - - `baseHash` (필수) — `config.get`의 config 해시 + - `baseHash` (required) — `config.get`의 구성 해시 - `sessionKey`, `note`, `restartDelayMs` — `config.apply`와 동일 - 재시작 동작은 `config.apply`와 동일합니다. 보류 중인 재시작은 합쳐지며 재시작 주기 사이에는 30초 쿨다운이 적용됩니다. + 재시작 동작은 `config.apply`와 동일합니다: 대기 중인 재시작 병합 + 재시작 사이클 간 30초 쿨다운. ```bash openclaw gateway call config.patch --params '{ @@ -597,12 +600,12 @@ control-plane 쓰기 RPC(`config.apply`, `config.patch`, `update.run`)는 `devic ## 환경 변수 -OpenClaw는 상위 프로세스의 env vars와 함께 다음도 읽습니다. +OpenClaw는 부모 프로세스의 env vars와 다음 위치를 함께 읽습니다. -- 현재 작업 디렉터리의 `.env`(존재하는 경우) -- `~/.openclaw/.env`(전역 폴백) +- 현재 작업 디렉터리의 `.env` (존재하는 경우) +- `~/.openclaw/.env` (전역 fallback) -두 파일 모두 기존 env vars를 재정의하지 않습니다. config에서 인라인 env vars도 설정할 수 있습니다. +어느 파일도 기존 env vars를 덮어쓰지 않습니다. config에 인라인 env vars를 설정할 수도 있습니다. ```json5 { @@ -624,11 +627,11 @@ OpenClaw는 상위 프로세스의 env vars와 함께 다음도 읽습니다. } ``` -Env var 동등값: `OPENCLAW_LOAD_SHELL_ENV=1` +환경 변수 대응 항목: `OPENCLAW_LOAD_SHELL_ENV=1` - - `${VAR_NAME}`으로 모든 config 문자열 값에서 env vars를 참조할 수 있습니다. + + `${VAR_NAME}`를 사용해 모든 구성 문자열 값에서 env vars를 참조할 수 있습니다. ```json5 { @@ -640,15 +643,15 @@ Env var 동등값: `OPENCLAW_LOAD_SHELL_ENV=1` 규칙: - 대문자 이름만 일치: `[A-Z_][A-Z0-9_]*` -- 누락되었거나 비어 있는 vars는 로드 시 오류를 발생시킴 -- 리터럴 출력은 `$${VAR}`로 이스케이프 -- `$include` 파일 내부에서도 동작 +- 누락되었거나 비어 있는 vars는 로드 시 오류를 발생시킵니다 +- 리터럴 출력은 `$${VAR}`로 이스케이프하세요 +- `$include` 파일 내부에서도 작동합니다 - 인라인 치환: `"${BASE}/v1"` → `"https://api.example.com/v1"` - SecretRef 객체를 지원하는 필드에서는 다음을 사용할 수 있습니다. + SecretRef 객체를 지원하는 필드에서는 다음과 같이 사용할 수 있습니다. ```json5 { @@ -680,16 +683,16 @@ Env var 동등값: `OPENCLAW_LOAD_SHELL_ENV=1` } ``` -SecretRef 세부 사항(`env`/`file`/`exec`용 `secrets.providers` 포함)은 [Secrets Management](/ko/gateway/secrets)에 있습니다. -지원되는 자격 증명 경로는 [SecretRef Credential Surface](/ko/reference/secretref-credential-surface)에 나열되어 있습니다. +SecretRef 자세한 내용(`env`/`file`/`exec`용 `secrets.providers` 포함)은 [Secrets Management](/ko/gateway/secrets)를 참조하세요. +지원되는 자격 증명 경로는 [SecretRef Credential Surface](/ko/reference/secretref-credential-surface)에 나와 있습니다. -전체 우선순위와 소스는 [환경](/ko/help/environment)를 참조하세요. +전체 우선순위와 소스는 [Environment](/ko/help/environment)를 참조하세요. ## 전체 참조 -완전한 필드별 참조는 **[구성 참조](/ko/gateway/configuration-reference)**를 확인하세요. +필드별 전체 참조는 **[Configuration Reference](/ko/gateway/configuration-reference)**를 참조하세요. --- -_관련 항목: [구성 예시](/ko/gateway/configuration-examples) · [구성 참조](/ko/gateway/configuration-reference) · [Doctor](/ko/gateway/doctor)_ +_관련 항목: [Configuration Examples](/ko/gateway/configuration-examples) · [Configuration Reference](/ko/gateway/configuration-reference) · [Doctor](/ko/gateway/doctor)_ diff --git a/docs/ko/gateway/heartbeat.md b/docs/ko/gateway/heartbeat.md index 3b9b38c26..64a99edf9 100644 --- a/docs/ko/gateway/heartbeat.md +++ b/docs/ko/gateway/heartbeat.md @@ -1,41 +1,41 @@ --- read_when: - - 하트비트 주기 또는 메시징을 조정하는 경우 - - 예약 작업에 하트비트와 cron 중 무엇을 사용할지 결정하는 경우 -summary: 하트비트 폴링 메시지와 알림 규칙 + - 하트비트 주기 또는 메시지 조정 + - 예약 작업에 대해 하트비트와 cron 중 무엇을 사용할지 결정하기 +summary: 하트비트 폴링 메시지 및 알림 규칙 title: 하트비트 x-i18n: - generated_at: "2026-04-08T02:15:38Z" + generated_at: "2026-04-11T02:44:53Z" model: gpt-5.4 provider: openai - source_hash: a8021d747637060eacb91ec5f75904368a08790c19f4fca32acda8c8c0a25e41 + source_hash: e4485072148753076d909867a623696829bf4a82dcd0479b95d5d0cae43100b0 source_path: gateway/heartbeat.md workflow: 15 --- # 하트비트 (Gateway) -> **하트비트 vs Cron?** 각각을 언제 사용해야 하는지에 대한 안내는 [자동화 및 작업](/ko/automation)을 참조하세요. +> **하트비트와 Cron 중 무엇을 써야 하나요?** 언제 무엇을 사용할지에 대한 안내는 [Automation & Tasks](/ko/automation)를 참고하세요. -하트비트는 **주기적인 에이전트 턴**을 메인 세션에서 실행하여 모델이 -사용자를 스팸하지 않으면서도 주의가 필요한 사항을 알려줄 수 있게 합니다. +하트비트는 **주기적인 에이전트 턴**을 메인 세션에서 실행하여, +모델이 사용자에게 과도한 메시지를 보내지 않으면서 주의가 필요한 사항을 알려줄 수 있게 합니다. -하트비트는 예약된 메인 세션 턴입니다 — [백그라운드 작업](/ko/automation/tasks) 레코드를 생성하지 **않습니다**. +하트비트는 예약된 메인 세션 턴이며, [background task](/ko/automation/tasks) 레코드를 생성하지 **않습니다**. 작업 레코드는 분리된 작업(ACP 실행, 서브에이전트, 격리된 cron 작업)을 위한 것입니다. -문제 해결: [예약 작업](/ko/automation/cron-jobs#troubleshooting) +문제 해결: [Scheduled Tasks](/ko/automation/cron-jobs#troubleshooting) -## 빠른 시작(초보자용) +## 빠른 시작 (초보자) -1. 하트비트를 활성화된 상태로 둡니다(기본값은 `30m`, Anthropic OAuth/토큰 인증의 경우 `1h`, Claude CLI 재사용 포함). 또는 원하는 주기를 직접 설정합니다. -2. 에이전트 workspace에 작은 `HEARTBEAT.md` 체크리스트나 `tasks:` 블록을 만듭니다(선택 사항이지만 권장). -3. 하트비트 메시지가 어디로 가야 하는지 결정합니다(기본값은 `target: "none"`이며, 마지막 연락처로 라우팅하려면 `target: "last"`로 설정). -4. 선택 사항: 투명성을 위해 하트비트 추론 전달을 활성화합니다. -5. 선택 사항: 하트비트 실행에 `HEARTBEAT.md`만 필요하다면 경량 bootstrap 컨텍스트를 사용합니다. -6. 선택 사항: 하트비트마다 전체 대화 기록을 보내지 않도록 격리된 세션을 활성화합니다. +1. 하트비트를 활성화된 상태로 둡니다(기본값은 `30m`, Anthropic OAuth/token 인증(Claude CLI 재사용 포함)일 때는 `1h`) 또는 원하는 주기를 설정합니다. +2. 에이전트 워크스페이스에 작은 `HEARTBEAT.md` 체크리스트 또는 `tasks:` 블록을 만듭니다(선택 사항이지만 권장). +3. 하트비트 메시지를 어디로 보낼지 결정합니다(`target: "none"`이 기본값이며, 마지막 연락처로 라우팅하려면 `target: "last"`로 설정). +4. 선택 사항: 투명성을 위해 하트비트 reasoning 전달을 활성화합니다. +5. 선택 사항: 하트비트 실행에 `HEARTBEAT.md`만 필요하다면 가벼운 bootstrap 컨텍스트를 사용합니다. +6. 선택 사항: 매 하트비트마다 전체 대화 기록을 보내지 않도록 격리 세션을 활성화합니다. 7. 선택 사항: 하트비트를 활성 시간대로 제한합니다(로컬 시간). -예시 config: +예시 구성: ```json5 { @@ -43,10 +43,10 @@ x-i18n: defaults: { heartbeat: { every: "30m", - target: "last", // 마지막 연락처로 명시적으로 전달(기본값은 "none") - directPolicy: "allow", // 기본값: 직접/DM 대상 허용, 억제하려면 "block"으로 설정 + target: "last", // 마지막 연락처로 명시적으로 전달 (기본값은 "none") + directPolicy: "allow", // 기본값: direct/DM 대상 허용; 억제하려면 "block"으로 설정 lightContext: true, // 선택 사항: bootstrap 파일에서 HEARTBEAT.md만 주입 - isolatedSession: true, // 선택 사항: 실행마다 새 세션 사용(대화 기록 없음) + isolatedSession: true, // 선택 사항: 매 실행마다 새 세션 사용(대화 기록 없음) // activeHours: { start: "08:00", end: "24:00" }, // includeReasoning: true, // 선택 사항: 별도의 `Reasoning:` 메시지도 전송 }, @@ -57,46 +57,47 @@ x-i18n: ## 기본값 -- 간격: `30m`(또는 감지된 인증 모드가 Anthropic OAuth/토큰 인증일 때는 `1h`, Claude CLI 재사용 포함). `agents.defaults.heartbeat.every` 또는 에이전트별 `agents.list[].heartbeat.every`를 설정하세요. 비활성화하려면 `0m`을 사용합니다. +- 간격: `30m` (또는 감지된 인증 모드가 Anthropic OAuth/token 인증인 경우 `1h`, Claude CLI 재사용 포함). `agents.defaults.heartbeat.every` 또는 에이전트별 `agents.list[].heartbeat.every`를 설정하세요. 비활성화하려면 `0m`을 사용합니다. - 프롬프트 본문(`agents.defaults.heartbeat.prompt`로 구성 가능): `Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.` -- 하트비트 프롬프트는 사용자 메시지로 **있는 그대로** 전송됩니다. 시스템 +- 하트비트 프롬프트는 사용자 메시지로 **그대로** 전송됩니다. 시스템 프롬프트에는 기본 에이전트에 대해 하트비트가 활성화되어 있고 - 실행이 내부적으로 표시된 경우에만 “Heartbeat” 섹션이 포함됩니다. -- 하트비트를 `0m`으로 비활성화하면 일반 실행에서도 bootstrap 컨텍스트에서 `HEARTBEAT.md`가 - 제외되어 모델이 하트비트 전용 지침을 보지 않게 됩니다. -- 활성 시간(`heartbeat.activeHours`)은 구성된 시간대에서 확인됩니다. - 해당 시간대 밖에서는 창 안의 다음 틱까지 하트비트가 건너뛰어집니다. + 실행이 내부적으로 하트비트로 표시된 경우에만 “Heartbeat” 섹션이 포함됩니다. +- `0m`으로 하트비트를 비활성화하면 일반 실행도 bootstrap 컨텍스트에서 + `HEARTBEAT.md`를 제외하므로 모델이 하트비트 전용 지침을 보지 않습니다. +- 활성 시간(`heartbeat.activeHours`)은 구성된 시간대에서 검사됩니다. + 시간대 밖에서는 다음 유효 시간대의 틱까지 하트비트를 건너뜁니다. -## 하트비트 프롬프트의 용도 +## 하트비트 프롬프트의 목적 -기본 프롬프트는 의도적으로 넓은 범위를 다룹니다: +기본 프롬프트는 의도적으로 폭넓게 설계되어 있습니다: - **백그라운드 작업**: “Consider outstanding tasks”는 에이전트가 - 후속 작업(받은편지함, 달력, 미리 알림, 대기 중인 작업)을 검토하고 긴급한 사항을 알리도록 유도합니다. + 후속 작업(받은편지함, 캘린더, 리마인더, 대기 중인 작업)을 검토하고 긴급한 사항을 알리도록 유도합니다. - **사람 확인**: “Checkup sometimes on your human during day time”는 - 가벼운 “필요한 것 있어?” 메시지를 가끔 보내도록 유도하지만, 사용자가 구성한 로컬 시간대를 사용해 - 야간 스팸은 피합니다([/concepts/timezone](/ko/concepts/timezone) 참조). + 가벼운 “필요한 것 있나요?” 메시지를 가끔 보내도록 유도하지만, 설정된 로컬 시간대를 사용해 + 야간 스팸은 피합니다([/concepts/timezone](/ko/concepts/timezone) 참고). -하트비트는 완료된 [백그라운드 작업](/ko/automation/tasks)에 반응할 수 있지만, 하트비트 실행 자체는 작업 레코드를 생성하지 않습니다. +하트비트는 완료된 [background tasks](/ko/automation/tasks)에 반응할 수 있지만, 하트비트 실행 자체는 작업 레코드를 생성하지 않습니다. -하트비트가 매우 구체적인 작업을 수행하길 원한다면(예: “Gmail PubSub -통계 확인” 또는 “gateway 상태 확인”), `agents.defaults.heartbeat.prompt`(또는 -`agents.list[].heartbeat.prompt`)를 사용자 지정 본문으로 설정하세요(있는 그대로 전송됨). +하트비트가 매우 구체적인 작업(예: “Gmail PubSub +통계 확인” 또는 “gateway 상태 검증”)을 하도록 하려면 `agents.defaults.heartbeat.prompt`(또는 +`agents.list[].heartbeat.prompt`)를 사용자 정의 본문으로 설정하세요(그대로 전송됨). ## 응답 계약 -- 주의가 필요한 사항이 없으면 **`HEARTBEAT_OK`**로 응답합니다. -- 하트비트 실행 중 OpenClaw는 `HEARTBEAT_OK`가 응답의 **시작 또는 끝**에 - 나타나면 이를 ack로 처리합니다. 남은 내용이 **`ackMaxChars` 이하**(기본값: 300)면 - 해당 토큰은 제거되고 응답은 버려집니다. -- `HEARTBEAT_OK`가 응답의 **중간**에 나타나면 특별하게 처리되지 않습니다. +- 주의가 필요한 것이 없으면 **`HEARTBEAT_OK`**로 응답합니다. +- 하트비트 실행 중 OpenClaw는 응답의 **시작 또는 끝**에 `HEARTBEAT_OK`가 있으면 + 이를 ack로 처리합니다. 이 토큰은 제거되며, 남은 내용이 + **`ackMaxChars` 이하**(기본값: 300)면 응답은 폐기됩니다. +- `HEARTBEAT_OK`가 응답의 **중간**에 있으면 특별하게 처리되지 + 않습니다. - 경고의 경우 **`HEARTBEAT_OK`를 포함하지 말고** 경고 텍스트만 반환하세요. -하트비트 외부에서는 메시지의 시작/끝에 우연히 포함된 `HEARTBEAT_OK`가 제거되고 -로그에 기록됩니다. 메시지가 `HEARTBEAT_OK`뿐이면 해당 메시지는 버려집니다. +하트비트 외 실행에서는 메시지 시작/끝의 의도치 않은 `HEARTBEAT_OK`가 제거되고 +로그에 기록됩니다. 메시지가 `HEARTBEAT_OK`만으로 이루어져 있으면 폐기됩니다. -## Config +## 구성 ```json5 { @@ -105,12 +106,12 @@ x-i18n: heartbeat: { every: "30m", // 기본값: 30m (0m이면 비활성화) model: "anthropic/claude-opus-4-6", - includeReasoning: false, // 기본값: false (가능한 경우 별도의 Reasoning: 메시지 전달) - lightContext: false, // 기본값: false; true이면 workspace bootstrap 파일에서 HEARTBEAT.md만 유지 - isolatedSession: false, // 기본값: false; true이면 각 하트비트를 새 세션에서 실행(대화 기록 없음) - target: "last", // 기본값: none | 옵션: last | none | (코어 또는 plugin, 예: "bluebubbles") + includeReasoning: false, // 기본값: false (가능할 때 별도의 Reasoning: 메시지 전달) + lightContext: false, // 기본값: false; true이면 워크스페이스 bootstrap 파일에서 HEARTBEAT.md만 유지 + isolatedSession: false, // 기본값: false; true이면 매 하트비트를 새 세션에서 실행(대화 기록 없음) + target: "last", // 기본값: none | 옵션: last | none | (core 또는 plugin, 예: "bluebubbles") to: "+15551234567", // 선택적 채널별 override - accountId: "ops-bot", // 선택적 다중 계정 channel id + accountId: "ops-bot", // 선택적 멀티 계정 채널 id prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.", ackMaxChars: 300, // HEARTBEAT_OK 뒤에 허용되는 최대 문자 수 }, @@ -119,21 +120,21 @@ x-i18n: } ``` -### 범위와 우선순위 +### 범위 및 우선순위 - `agents.defaults.heartbeat`는 전역 하트비트 동작을 설정합니다. -- `agents.list[].heartbeat`는 그 위에 병합됩니다. 어떤 에이전트든 `heartbeat` 블록이 있으면 **그 에이전트들만** 하트비트를 실행합니다. -- `channels.defaults.heartbeat`는 모든 채널의 기본 가시성을 설정합니다. +- `agents.list[].heartbeat`는 그 위에 병합되며, 어떤 에이전트든 `heartbeat` 블록이 있으면 **그 에이전트들만** 하트비트를 실행합니다. +- `channels.defaults.heartbeat`는 모든 채널의 가시성 기본값을 설정합니다. - `channels..heartbeat`는 채널 기본값을 override합니다. -- `channels..accounts..heartbeat`(다중 계정 채널)는 채널별 설정보다 override합니다. +- `channels..accounts..heartbeat`(멀티 계정 채널)는 채널별 설정을 override합니다. ### 에이전트별 하트비트 -`agents.list[]` 항목 중 하나라도 `heartbeat` 블록을 포함하면 **그 에이전트들만** -하트비트를 실행합니다. 에이전트별 블록은 `agents.defaults.heartbeat` 위에 병합되므로 -공유 기본값을 한 번만 설정하고 에이전트별로 override할 수 있습니다. +어떤 `agents.list[]` 항목이든 `heartbeat` 블록을 포함하면 **그 에이전트들만** +하트비트를 실행합니다. 에이전트별 블록은 `agents.defaults.heartbeat` +위에 병합되므로 공통 기본값을 한 번만 설정하고 에이전트별로 override할 수 있습니다. -예: 에이전트 두 개 중 두 번째 에이전트만 하트비트를 실행합니다. +예시: 에이전트가 두 개이고, 두 번째 에이전트만 하트비트를 실행합니다. ```json5 { @@ -141,7 +142,7 @@ x-i18n: defaults: { heartbeat: { every: "30m", - target: "last", // 마지막 연락처로 명시적으로 전달(기본값은 "none") + target: "last", // 마지막 연락처로 명시적으로 전달 (기본값은 "none") }, }, list: [ @@ -152,6 +153,7 @@ x-i18n: every: "1h", target: "whatsapp", to: "+15551234567", + timeoutSeconds: 45, prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.", }, }, @@ -162,7 +164,7 @@ x-i18n: ### 활성 시간 예시 -특정 시간대의 업무 시간에만 하트비트를 제한합니다: +특정 시간대의 업무 시간으로 하트비트를 제한합니다: ```json5 { @@ -170,11 +172,11 @@ x-i18n: defaults: { heartbeat: { every: "30m", - target: "last", // 마지막 연락처로 명시적으로 전달(기본값은 "none") + target: "last", // 마지막 연락처로 명시적으로 전달 (기본값은 "none") activeHours: { start: "09:00", end: "22:00", - timezone: "America/New_York", // 선택 사항; 설정된 userTimezone이 있으면 그것을 사용하고, 없으면 호스트 시간대 사용 + timezone: "America/New_York", // 선택 사항; userTimezone이 설정되어 있으면 그것을 사용하고, 아니면 호스트 시간대 사용 }, }, }, @@ -182,21 +184,21 @@ x-i18n: } ``` -이 시간대(미 동부 시간 기준 오전 9시 이전 또는 오후 10시 이후) 밖에서는 하트비트가 건너뛰어집니다. 창 안의 다음 예약 틱은 정상적으로 실행됩니다. +이 시간대(동부 시간 기준 오전 9시 이전 또는 오후 10시 이후) 밖에서는 하트비트를 건너뜁니다. 창 안의 다음 예약 틱은 정상적으로 실행됩니다. -### 24시간 연중무휴 설정 +### 24/7 설정 하트비트를 하루 종일 실행하려면 다음 패턴 중 하나를 사용하세요: -- `activeHours`를 완전히 생략합니다(시간 창 제한 없음, 이것이 기본 동작입니다). +- `activeHours`를 아예 생략합니다(시간대 제한 없음, 기본 동작). - 하루 전체 창을 설정합니다: `activeHours: { start: "00:00", end: "24:00" }`. -같은 `start`와 `end` 시간(예: `08:00`에서 `08:00`)을 설정하지 마세요. -이 경우 폭이 0인 창으로 처리되어 하트비트가 항상 건너뛰어집니다. +같은 `start`와 `end` 시간을 설정하지 마세요(예: `08:00`에서 `08:00`). +이 경우 너비가 0인 창으로 처리되어 하트비트가 항상 건너뛰어집니다. -### 다중 계정 예시 +### 멀티 계정 예시 -Telegram 같은 다중 계정 채널에서 특정 계정을 대상으로 지정하려면 `accountId`를 사용합니다: +Telegram과 같은 멀티 계정 채널에서 특정 계정을 대상으로 하려면 `accountId`를 사용합니다: ```json5 { @@ -226,80 +228,82 @@ Telegram 같은 다중 계정 채널에서 특정 계정을 대상으로 지정 ### 필드 참고 - `every`: 하트비트 간격(duration 문자열, 기본 단위 = 분). -- `model`: 하트비트 실행용 선택적 모델 override(`provider/model`). -- `includeReasoning`: 활성화하면 가능한 경우 별도의 `Reasoning:` 메시지도 전달합니다(`/reasoning on`과 동일한 형태). -- `lightContext`: true이면 하트비트 실행 시 경량 bootstrap 컨텍스트를 사용하고 workspace bootstrap 파일에서는 `HEARTBEAT.md`만 유지합니다. -- `isolatedSession`: true이면 각 하트비트가 이전 대화 기록 없이 새 세션에서 실행됩니다. cron의 `sessionTarget: "isolated"`와 동일한 격리 패턴을 사용합니다. 하트비트당 토큰 비용을 크게 줄입니다. 최대 절감을 위해 `lightContext: true`와 함께 사용하세요. 전달 라우팅은 여전히 메인 세션 컨텍스트를 사용합니다. -- `session`: 하트비트 실행용 선택적 세션 키입니다. - - `main`(기본값): 에이전트 메인 세션. +- `model`: 하트비트 실행용 선택적 모델 override (`provider/model`). +- `includeReasoning`: 활성화하면 가능할 때 별도의 `Reasoning:` 메시지도 전달합니다(`/reasoning on`과 동일한 형태). +- `lightContext`: true이면 하트비트 실행은 가벼운 bootstrap 컨텍스트를 사용하고 워크스페이스 bootstrap 파일에서 `HEARTBEAT.md`만 유지합니다. +- `isolatedSession`: true이면 각 하트비트는 이전 대화 기록이 없는 새 세션에서 실행됩니다. cron의 `sessionTarget: "isolated"`와 동일한 격리 패턴을 사용합니다. 하트비트당 토큰 비용을 크게 줄여줍니다. 최대 절감을 위해 `lightContext: true`와 함께 사용하세요. 전달 라우팅은 여전히 메인 세션 컨텍스트를 사용합니다. +- `session`: 하트비트 실행용 선택적 세션 키. + - `main` (기본값): 에이전트 메인 세션. - 명시적 세션 키(`openclaw sessions --json` 또는 [sessions CLI](/cli/sessions)에서 복사). - - 세션 키 형식: [세션](/ko/concepts/session) 및 [그룹](/ko/channels/groups) 참조. + - 세션 키 형식은 [Sessions](/ko/concepts/session) 및 [Groups](/ko/channels/groups)를 참고하세요. - `target`: - - `last`: 마지막으로 사용한 외부 채널로 전달합니다. - - 명시적 채널: 구성된 아무 채널 또는 plugin id나 가능하며, 예를 들어 `discord`, `matrix`, `telegram`, `whatsapp`가 있습니다. - - `none`(기본값): 하트비트를 실행하되 외부로는 **전달하지 않습니다**. -- `directPolicy`: 직접/DM 전달 동작을 제어합니다. - - `allow`(기본값): 직접/DM 하트비트 전달을 허용합니다. - - `block`: 직접/DM 전달을 억제합니다(`reason=dm-blocked`). -- `to`: 선택적 수신자 override(채널별 id, 예: WhatsApp의 E.164 또는 Telegram chat id). Telegram topic/thread의 경우 `:topic:`를 사용하세요. -- `accountId`: 다중 계정 채널용 선택적 계정 id입니다. `target: "last"`일 때 해결된 마지막 채널이 계정을 지원하면 해당 account id가 적용되고, 그렇지 않으면 무시됩니다. account id가 해결된 채널의 구성된 계정과 일치하지 않으면 전달이 건너뛰어집니다. + - `last`: 마지막으로 사용한 외부 채널로 전달. + - 명시적 채널: 구성된 모든 채널 또는 plugin id(예: `discord`, `matrix`, `telegram`, `whatsapp`). + - `none` (기본값): 하트비트를 실행하지만 외부로는 **전달하지 않음**. +- `directPolicy`: direct/DM 전달 동작을 제어합니다: + - `allow` (기본값): direct/DM 하트비트 전달 허용. + - `block`: direct/DM 전달 억제(`reason=dm-blocked`). +- `to`: 선택적 수신자 override(채널별 id, 예: WhatsApp의 E.164 또는 Telegram chat id). Telegram topic/thread에는 `:topic:`를 사용하세요. +- `accountId`: 멀티 계정 채널용 선택적 계정 id. `target: "last"`일 때, 마지막으로 확인된 채널이 계정을 지원하면 그 채널에 적용되고, 그렇지 않으면 무시됩니다. 계정 id가 확인된 채널에 구성된 계정과 일치하지 않으면 전달은 건너뜁니다. - `prompt`: 기본 프롬프트 본문을 override합니다(병합되지 않음). -- `ackMaxChars`: `HEARTBEAT_OK` 뒤에 전달 허용되는 최대 문자 수입니다. +- `ackMaxChars`: `HEARTBEAT_OK` 뒤에 허용되는 최대 문자 수. - `suppressToolErrorWarnings`: true이면 하트비트 실행 중 도구 오류 경고 payload를 억제합니다. -- `activeHours`: 하트비트 실행을 시간 창으로 제한합니다. `start`(HH:MM, 포함, 하루 시작은 `00:00`), `end`(HH:MM, 제외, 하루 끝은 `24:00` 허용), 선택적 `timezone`을 포함하는 객체입니다. - - 생략되거나 `"user"`이면 `agents.defaults.userTimezone`이 설정된 경우 그것을 사용하고, 아니면 호스트 시스템 시간대로 폴백합니다. - - `"local"`이면 항상 호스트 시스템 시간대를 사용합니다. - - 임의의 IANA 식별자(예: `America/New_York`)는 직접 사용하며, 유효하지 않으면 위의 `"user"` 동작으로 폴백합니다. - - 활성 창이 되려면 `start`와 `end`가 같아서는 안 됩니다. 같으면 폭이 0인 창으로 처리되어 항상 창 밖으로 간주됩니다. - - 활성 창 밖에서는 창 안의 다음 틱까지 하트비트가 건너뛰어집니다. +- `activeHours`: 하트비트 실행을 특정 시간 창으로 제한합니다. `start`(HH:MM, 포함, 하루 시작은 `00:00` 사용), `end`(HH:MM, 제외, 하루 끝은 `24:00` 허용), 선택적 `timezone`이 있는 객체입니다. + - 생략 또는 `"user"`: `agents.defaults.userTimezone`이 설정되어 있으면 그것을 사용하고, 아니면 호스트 시스템 시간대로 대체합니다. + - `"local"`: 항상 호스트 시스템 시간대를 사용합니다. + - 모든 IANA 식별자(예: `America/New_York`): 직접 사용하며, 유효하지 않으면 위 `"user"` 동작으로 대체됩니다. + - 활성 창에서는 `start`와 `end`가 같아서는 안 됩니다. 같으면 너비가 0인 창(항상 창 밖)으로 처리됩니다. + - 활성 시간 창 밖에서는 창 안의 다음 틱까지 하트비트를 건너뜁니다. ## 전달 동작 - 하트비트는 기본적으로 에이전트의 메인 세션(`agent::`)에서 실행되며, - `session.scope = "global"`이면 `global`에서 실행됩니다. 특정 채널 세션(Discord/WhatsApp 등)으로 override하려면 `session`을 설정하세요. -- `session`은 실행 컨텍스트에만 영향을 주며, 전달은 `target`과 `to`에 의해 제어됩니다. + `session.scope = "global"`일 때는 `global`에서 실행됩니다. 특정 채널 세션(Discord/WhatsApp 등)으로 + override하려면 `session`을 설정하세요. +- `session`은 실행 컨텍스트에만 영향을 주며, 전달은 `target`과 `to`로 제어됩니다. - 특정 채널/수신자에게 전달하려면 `target` + `to`를 설정하세요. - `target: "last"`이면 해당 세션의 마지막 외부 채널로 전달됩니다. -- 하트비트 전달은 기본적으로 직접/DM 대상을 허용합니다. 직접 대상 전송은 억제하면서 하트비트 턴은 계속 실행하려면 `directPolicy: "block"`을 설정하세요. + `target: "last"`를 사용하면 전달은 해당 세션의 마지막 외부 채널을 사용합니다. +- 하트비트 전달은 기본적으로 direct/DM 대상을 허용합니다. direct 대상 전송은 억제하면서 하트비트 턴은 계속 실행하려면 `directPolicy: "block"`을 설정하세요. - 메인 큐가 바쁘면 하트비트는 건너뛰고 나중에 다시 시도합니다. -- `target`이 외부 대상이 없는 것으로 해석되면 실행은 계속되지만 - outbound 메시지는 전송되지 않습니다. -- `showOk`, `showAlerts`, `useIndicator`가 모두 비활성화되면 실행은 사전에 `reason=alerts-disabled`로 건너뛰어집니다. -- 경고 전달만 비활성화된 경우에도 OpenClaw는 하트비트를 실행하고, 기한이 된 작업 타임스탬프를 업데이트하고, 세션 유휴 타임스탬프를 복원하며, 외부 경고 payload는 억제할 수 있습니다. -- 하트비트 전용 응답은 세션을 활성 상태로 유지하지 않습니다. 마지막 `updatedAt`가 복원되어 유휴 만료가 정상적으로 동작합니다. -- 분리된 [백그라운드 작업](/ko/automation/tasks)은 시스템 이벤트를 큐에 넣고 메인 세션이 무언가를 빨리 알아차려야 할 때 하트비트를 깨울 수 있습니다. 이 깨우기는 하트비트 실행을 백그라운드 작업으로 만들지 않습니다. +- `target`이 외부 대상이 없는 것으로 확인되면 실행은 계속되지만 + 발신 메시지는 전송되지 않습니다. +- `showOk`, `showAlerts`, `useIndicator`가 모두 비활성화되면 실행은 사전에 `reason=alerts-disabled`로 건너뜁니다. +- 경고 전달만 비활성화된 경우에도 OpenClaw는 하트비트를 실행하고, 기한이 된 작업 타임스탬프를 갱신하고, 세션 idle 타임스탬프를 복원하고, 외부 경고 payload는 억제할 수 있습니다. +- 하트비트 전용 응답은 세션을 활성 상태로 유지하지 않습니다. 마지막 `updatedAt` + 값이 복원되므로 idle 만료는 정상적으로 동작합니다. +- 분리된 [background tasks](/ko/automation/tasks)는 시스템 이벤트를 큐에 넣고 메인 세션이 무언가를 빨리 인지해야 할 때 하트비트를 깨울 수 있습니다. 이 깨우기 동작이 하트비트 실행을 background task로 만들지는 않습니다. ## 가시성 제어 -기본적으로 `HEARTBEAT_OK` 확인 응답은 숨겨지고 경고 콘텐츠만 +기본적으로 `HEARTBEAT_OK` 확인 응답은 숨겨지고 경고 콘텐츠는 전달됩니다. 채널별 또는 계정별로 이를 조정할 수 있습니다: ```yaml channels: defaults: heartbeat: - showOk: false # HEARTBEAT_OK 숨기기(기본값) - showAlerts: true # 경고 메시지 표시(기본값) - useIndicator: true # indicator 이벤트 발생(기본값) + showOk: false # HEARTBEAT_OK 숨기기 (기본값) + showAlerts: true # 경고 메시지 표시 (기본값) + useIndicator: true # 인디케이터 이벤트 내보내기 (기본값) telegram: heartbeat: - showOk: true # Telegram에서는 OK 확인 응답 표시 + showOk: true # Telegram에서 OK 확인 응답 표시 whatsapp: accounts: work: heartbeat: - showAlerts: false # 이 계정의 경고 전달 억제 + showAlerts: false # 이 계정에 대한 경고 전달 억제 ``` 우선순위: 계정별 → 채널별 → 채널 기본값 → 내장 기본값. -### 각 플래그의 의미 +### 각 플래그의 역할 -- `showOk`: 모델이 OK 전용 응답을 반환할 때 `HEARTBEAT_OK` 확인 응답을 보냅니다. -- `showAlerts`: 모델이 비-OK 응답을 반환할 때 경고 콘텐츠를 보냅니다. -- `useIndicator`: UI 상태 화면을 위한 indicator 이벤트를 발생시킵니다. +- `showOk`: 모델이 OK 전용 응답을 반환할 때 `HEARTBEAT_OK` 확인 응답을 전송합니다. +- `showAlerts`: 모델이 OK가 아닌 응답을 반환할 때 경고 콘텐츠를 전송합니다. +- `useIndicator`: UI 상태 화면용 인디케이터 이벤트를 내보냅니다. -**세 항목이 모두** false이면 OpenClaw는 하트비트 실행 전체를 건너뜁니다(모델 호출 없음). +**세 값이 모두** false이면 OpenClaw는 하트비트 실행 자체를 건너뜁니다(모델 호출 없음). ### 채널별 vs 계정별 예시 @@ -324,30 +328,30 @@ channels: ### 일반적인 패턴 -| 목표 | Config | -| ---------------------------------------- | ---------------------------------------------------------------------------------------- | -| 기본 동작(조용한 OK, 경고는 표시) | _(구성 불필요)_ | -| 완전 무음(메시지 없음, indicator 없음) | `channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: false }` | -| indicator만 사용(메시지 없음) | `channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: true }` | -| 특정 채널에서만 OK 표시 | `channels.telegram.heartbeat: { showOk: true }` | +| 목표 | 구성 | +| --- | --- | +| 기본 동작 (OK는 숨김, 경고는 표시) | _(구성 불필요)_ | +| 완전히 무음 (메시지 없음, 인디케이터 없음) | `channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: false }` | +| 인디케이터만 사용 (메시지 없음) | `channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: true }` | +| 한 채널에서만 OK 표시 | `channels.telegram.heartbeat: { showOk: true }` | ## HEARTBEAT.md (선택 사항) -workspace에 `HEARTBEAT.md` 파일이 있으면 기본 프롬프트가 -에이전트에게 그 파일을 읽으라고 지시합니다. 이것을 “하트비트 체크리스트”로 생각하세요: -작고, 안정적이며, 30분마다 포함해도 안전해야 합니다. +워크스페이스에 `HEARTBEAT.md` 파일이 있으면 기본 프롬프트는 +에이전트가 이를 읽도록 지시합니다. 이를 “하트비트 체크리스트”라고 생각하면 됩니다: 작고, 안정적이며, +30분마다 포함해도 안전한 내용입니다. 일반 실행에서는 기본 에이전트에 대해 하트비트 지침이 활성화된 경우에만 `HEARTBEAT.md`가 주입됩니다. `0m`으로 하트비트 주기를 비활성화하거나 -`includeSystemPromptSection: false`로 설정하면 일반 bootstrap +`includeSystemPromptSection: false`를 설정하면 일반 bootstrap 컨텍스트에서 제외됩니다. -`HEARTBEAT.md`가 존재하지만 사실상 비어 있는 경우(빈 줄과 -`# Heading` 같은 markdown 헤더만 있는 경우), OpenClaw는 API 호출을 아끼기 위해 하트비트 실행을 건너뜁니다. +`HEARTBEAT.md`가 존재하지만 사실상 비어 있는 경우(빈 줄과 `# Heading` 같은 markdown +헤더만 있는 경우), OpenClaw는 API 호출을 절약하기 위해 하트비트 실행을 건너뜁니다. 이 건너뜀은 `reason=empty-heartbeat-file`로 보고됩니다. -파일이 없으면 하트비트는 여전히 실행되고 모델이 무엇을 할지 결정합니다. +파일이 없으면 하트비트는 계속 실행되며 모델이 무엇을 할지 결정합니다. -프롬프트 팽창을 피하려면 작게 유지하세요(짧은 체크리스트 또는 미리 알림). +프롬프트 팽창을 피하려면 작게 유지하세요(짧은 체크리스트 또는 리마인더). 예시 `HEARTBEAT.md`: @@ -361,8 +365,7 @@ workspace에 `HEARTBEAT.md` 파일이 있으면 기본 프롬프트가 ### `tasks:` 블록 -`HEARTBEAT.md`는 하트비트 자체 내부의 간격 기반 점검을 위한 작은 구조화된 -`tasks:` 블록도 지원합니다. +`HEARTBEAT.md`는 하트비트 내부에서 간격 기반 점검을 수행하기 위한 작은 구조화된 `tasks:` 블록도 지원합니다. 예시: @@ -384,33 +387,32 @@ tasks: 동작: -- OpenClaw는 `tasks:` 블록을 파싱하고 각 작업을 자체 `interval`에 따라 확인합니다. +- OpenClaw는 `tasks:` 블록을 파싱하고 각 작업을 자체 `interval`에 따라 검사합니다. - 해당 틱에서 **기한이 된** 작업만 하트비트 프롬프트에 포함됩니다. -- 기한이 된 작업이 없으면 낭비되는 모델 호출을 피하기 위해 하트비트는 전체가 건너뛰어집니다(`reason=no-tasks-due`). -- `HEARTBEAT.md`의 비작업 콘텐츠는 보존되며, 기한이 된 작업 목록 뒤에 추가 컨텍스트로 덧붙여집니다. -- 작업의 마지막 실행 타임스탬프는 세션 상태(`heartbeatTaskState`)에 저장되므로 간격은 일반적인 재시작 후에도 유지됩니다. -- 작업 타임스탬프는 하트비트 실행이 정상 응답 경로를 완료한 뒤에만 갱신됩니다. `empty-heartbeat-file` / `no-tasks-due`로 건너뛴 실행은 작업을 완료로 표시하지 않습니다. +- 기한이 된 작업이 없으면 하트비트는 낭비되는 모델 호출을 피하기 위해 완전히 건너뜁니다(`reason=no-tasks-due`). +- `HEARTBEAT.md`의 작업 외 콘텐츠는 유지되며 기한이 된 작업 목록 뒤에 추가 컨텍스트로 덧붙여집니다. +- 작업 마지막 실행 타임스탬프는 세션 상태(`heartbeatTaskState`)에 저장되므로 일반적인 재시작 후에도 간격이 유지됩니다. +- 작업 타임스탬프는 하트비트 실행이 정상 응답 경로를 완료한 뒤에만 갱신됩니다. 건너뛴 `empty-heartbeat-file` / `no-tasks-due` 실행은 작업을 완료된 것으로 표시하지 않습니다. -작업 모드는 하나의 하트비트 파일에 여러 주기 점검을 담고 싶지만 매 틱마다 모두의 비용을 지불하고 싶지 않을 때 유용합니다. +작업 모드는 모든 틱에서 비용을 지불하지 않으면서 하나의 하트비트 파일에 여러 주기적 점검을 담고 싶을 때 유용합니다. ### 에이전트가 HEARTBEAT.md를 업데이트할 수 있나요? -예 — 그렇게 하라고 요청하면 됩니다. +네 — 그렇게 하라고 요청하면 가능합니다. -`HEARTBEAT.md`는 에이전트 workspace 안의 일반 파일일 뿐이므로, 일반 채팅에서 -에이전트에게 다음과 같이 말할 수 있습니다: +`HEARTBEAT.md`는 에이전트 워크스페이스에 있는 일반 파일일 뿐이므로, +일반 채팅에서 에이전트에게 다음과 같이 말할 수 있습니다: -- “일일 캘린더 확인을 추가하도록 `HEARTBEAT.md`를 업데이트해.” -- “`HEARTBEAT.md`를 더 짧고 받은편지함 후속 조치 중심으로 다시 써줘.” +- “매일 캘린더 확인을 추가하도록 `HEARTBEAT.md`를 업데이트해.” +- “더 짧고 받은편지함 후속 작업에 집중되도록 `HEARTBEAT.md`를 다시 작성해.” -이 작업이 선제적으로 일어나길 원한다면 하트비트 프롬프트에 -“체크리스트가 오래되면 더 나은 것으로 HEARTBEAT.md를 업데이트해.” 같은 -명시적인 문장을 포함할 수도 있습니다. +이를 더 능동적으로 수행하게 하려면 하트비트 프롬프트에 다음과 같은 명시적 문장을 포함할 수도 있습니다: +“체크리스트가 오래되면 더 나은 것으로 HEARTBEAT.md를 업데이트해.” -안전 참고: 비밀 정보(API 키, 전화번호, 개인 토큰)는 -`HEARTBEAT.md`에 넣지 마세요 — 프롬프트 컨텍스트의 일부가 됩니다. +안전 참고: `HEARTBEAT.md`에는 비밀 정보(API 키, 전화번호, 개인 토큰)를 넣지 마세요. +이 파일은 프롬프트 컨텍스트의 일부가 됩니다. -## 수동 깨우기(온디맨드) +## 수동 깨우기 (온디맨드) 다음 명령으로 시스템 이벤트를 큐에 넣고 즉시 하트비트를 트리거할 수 있습니다: @@ -418,38 +420,38 @@ tasks: openclaw system event --text "Check for urgent follow-ups" --mode now ``` -여러 에이전트에 `heartbeat`가 구성되어 있으면 수동 깨우기는 그 각 에이전트의 -하트비트를 즉시 실행합니다. +여러 에이전트에 `heartbeat`가 구성되어 있으면 수동 깨우기는 그 에이전트들의 +하트비트를 즉시 각각 실행합니다. 다음 예약 틱까지 기다리려면 `--mode next-heartbeat`를 사용하세요. -## 추론 전달(선택 사항) +## reasoning 전달 (선택 사항) -기본적으로 하트비트는 최종 “answer” payload만 전달합니다. +기본적으로 하트비트는 최종 “응답” payload만 전달합니다. 투명성을 원한다면 다음을 활성화하세요: - `agents.defaults.heartbeat.includeReasoning: true` -활성화되면 하트비트는 `Reasoning:` 접두사가 붙은 별도의 메시지도 -전달합니다(`/reasoning on`과 동일한 형태). 이는 에이전트가 여러 세션/codex를 관리하고 있을 때 -왜 나에게 핑을 보내기로 했는지 보고 싶을 때 유용할 수 있습니다. -하지만 원치 않는 더 많은 내부 세부 사항이 노출될 수도 있습니다. 그룹 채팅에서는 -비활성화 상태를 유지하는 것이 좋습니다. +활성화하면 하트비트는 `Reasoning:` 접두사가 붙은 별도 메시지도 전달합니다 +(`reasoning on`과 동일한 형태). 이는 에이전트가 여러 세션/codex를 관리하고 있을 때 +왜 사용자에게 알림을 보내기로 결정했는지 보고 싶을 때 유용할 수 있습니다. +하지만 원하지 않는 더 많은 내부 세부 정보가 드러날 수도 있습니다. 그룹 채팅에서는 +끄는 편이 좋습니다. ## 비용 고려 -하트비트는 전체 에이전트 턴을 실행합니다. 간격이 짧을수록 더 많은 토큰을 소비합니다. 비용을 줄이려면: +하트비트는 전체 에이전트 턴을 실행합니다. 간격이 짧을수록 토큰을 더 많이 사용합니다. 비용을 줄이려면: -- `isolatedSession: true`를 사용해 전체 대화 기록 전송을 피하세요(실행당 약 100K 토큰에서 약 2-5K로 감소). -- `lightContext: true`를 사용해 bootstrap 파일을 `HEARTBEAT.md`로만 제한하세요. +- 전체 대화 기록 전송을 피하기 위해 `isolatedSession: true`를 사용하세요(실행당 약 100K 토큰에서 약 2~5K로 감소). +- bootstrap 파일을 `HEARTBEAT.md`로만 제한하려면 `lightContext: true`를 사용하세요. - 더 저렴한 `model`을 설정하세요(예: `ollama/llama3.2:1b`). - `HEARTBEAT.md`를 작게 유지하세요. - 내부 상태 업데이트만 원한다면 `target: "none"`을 사용하세요. ## 관련 항목 -- [자동화 및 작업](/ko/automation) — 모든 자동화 메커니즘 한눈에 보기 -- [백그라운드 작업](/ko/automation/tasks) — 분리된 작업이 추적되는 방식 -- [시간대](/ko/concepts/timezone) — 시간대가 하트비트 일정에 미치는 영향 -- [문제 해결](/ko/automation/cron-jobs#troubleshooting) — 자동화 문제 디버깅 +- [Automation & Tasks](/ko/automation) — 모든 자동화 메커니즘 한눈에 보기 +- [Background Tasks](/ko/automation/tasks) — 분리된 작업이 추적되는 방식 +- [Timezone](/ko/concepts/timezone) — 시간대가 하트비트 예약에 미치는 영향 +- [Troubleshooting](/ko/automation/cron-jobs#troubleshooting) — 자동화 문제 디버깅 diff --git a/docs/ko/gateway/protocol.md b/docs/ko/gateway/protocol.md index 03f8d0306..225840257 100644 --- a/docs/ko/gateway/protocol.md +++ b/docs/ko/gateway/protocol.md @@ -1,34 +1,31 @@ --- read_when: - - gateway WS 클라이언트를 구현하거나 업데이트할 때 - - 프로토콜 불일치나 연결 실패를 디버깅할 때 - - 프로토콜 스키마/모델을 다시 생성할 때 + - 게이트웨이 WS 클라이언트 구현 또는 업데이트하기 + - 프로토콜 불일치 또는 연결 실패 디버깅하기 + - 프로토콜 스키마/모델 다시 생성하기 summary: 'Gateway WebSocket 프로토콜: 핸드셰이크, 프레임, 버전 관리' title: Gateway 프로토콜 x-i18n: - generated_at: "2026-04-08T02:16:06Z" + generated_at: "2026-04-11T02:44:57Z" model: gpt-5.4 provider: openai - source_hash: 8635e3ac1dd311dbd3a770b088868aa1495a8d53b3ebc1eae0dfda3b2bf4694a + source_hash: 83c820c46d4803d571c770468fd6782619eaa1dca253e156e8087dec735c127f source_path: gateway/protocol.md workflow: 15 --- # Gateway 프로토콜 (WebSocket) -Gateway WS 프로토콜은 OpenClaw의 **단일 제어 평면 + 노드 전송 계층**입니다. -모든 클라이언트(CLI, 웹 UI, macOS 앱, iOS/Android 노드, 헤드리스 -노드)는 WebSocket을 통해 연결하고 핸드셰이크 시점에 자신의 **역할** + **범위**를 -선언합니다. +Gateway WS 프로토콜은 OpenClaw를 위한 **단일 제어 플레인 + 노드 전송 계층**입니다. 모든 클라이언트(CLI, 웹 UI, macOS 앱, iOS/Android 노드, 헤드리스 노드)는 WebSocket을 통해 연결하고 핸드셰이크 시점에 자신의 **역할**과 **범위**를 선언합니다. -## 전송 +## 전송 계층 -- WebSocket, JSON 페이로드를 담는 텍스트 프레임 -- 첫 번째 프레임은 **반드시** `connect` 요청이어야 합니다 +- WebSocket, JSON 페이로드를 사용하는 텍스트 프레임 +- 첫 번째 프레임은 반드시 `connect` 요청이어야 합니다. ## 핸드셰이크(connect) -Gateway → 클라이언트(사전 연결 챌린지): +Gateway → 클라이언트(연결 전 챌린지): ```json { @@ -96,8 +93,7 @@ Gateway → 클라이언트: } ``` -신뢰된 bootstrap handoff 중에는 `hello-ok.auth`에 `deviceTokens` 아래로 -추가적인 제한된 역할 항목이 포함될 수도 있습니다: +신뢰된 부트스트랩 핸드오프 중에는 `hello-ok.auth`에 `deviceTokens` 내 추가적인 범위 제한 역할 항목이 포함될 수도 있습니다: ```json { @@ -116,12 +112,7 @@ Gateway → 클라이언트: } ``` -내장된 node/operator bootstrap 흐름에서는 기본 node 토큰이 계속 -`scopes: []`로 유지되고, handoff된 operator 토큰은 bootstrap -operator 허용 목록(`operator.approvals`, `operator.read`, -`operator.talk.secrets`, `operator.write`)으로 제한됩니다. Bootstrap 범위 검사는 -역할 접두사를 계속 유지합니다. operator 항목은 operator 요청만 충족하며, operator가 아닌 -역할은 여전히 자체 역할 접두사 아래의 범위를 필요로 합니다. +내장된 node/operator 부트스트랩 흐름에서는 기본 노드 토큰이 `scopes: []`로 유지되고, 핸드오프된 모든 operator 토큰은 부트스트랩 operator 허용 목록(`operator.approvals`, `operator.read`, `operator.talk.secrets`, `operator.write`)으로 제한됩니다. 부트스트랩 범위 검사는 계속해서 역할 접두사 기반으로 유지됩니다. operator 항목은 operator 요청만 충족하며, operator가 아닌 역할은 여전히 자신의 역할 접두사 아래 범위가 필요합니다. ### 노드 예시 @@ -170,7 +161,7 @@ operator 허용 목록(`operator.approvals`, `operator.read`, ### 역할 -- `operator` = 제어 평면 클라이언트(CLI/UI/자동화) +- `operator` = 제어 플레인 클라이언트(CLI/UI/자동화) - `node` = 기능 호스트(camera/screen/canvas/system.run) ### 범위(operator) @@ -184,29 +175,24 @@ operator 허용 목록(`operator.approvals`, `operator.read`, - `operator.pairing` - `operator.talk.secrets` -`includeSecrets: true`와 함께 사용하는 `talk.config`는 `operator.talk.secrets` -(또는 `operator.admin`)를 필요로 합니다. +`includeSecrets: true`가 있는 `talk.config`에는 `operator.talk.secrets`(또는 `operator.admin`)가 필요합니다. -plugin이 등록한 gateway RPC 메서드는 자체 operator 범위를 요구할 수 있지만, -예약된 코어 admin 접두사(`config.*`, `exec.approvals.*`, `wizard.*`, -`update.*`)는 항상 `operator.admin`으로 해석됩니다. +plugin 등록 Gateway RPC 메서드는 자체 operator 범위를 요구할 수 있지만, 예약된 핵심 관리자 접두사(`config.*`, `exec.approvals.*`, `wizard.*`, `update.*`)는 항상 `operator.admin`으로 해석됩니다. -메서드 범위는 첫 번째 게이트일 뿐입니다. `chat.send`를 통해 도달하는 일부 -슬래시 명령은 그 위에 더 엄격한 명령 수준 검사를 적용합니다. 예를 들어 지속적인 -`/config set` 및 `/config unset` 쓰기는 `operator.admin`이 필요합니다. +메서드 범위는 첫 번째 게이트일 뿐입니다. `chat.send`를 통해 도달하는 일부 슬래시 명령은 그 위에 더 엄격한 명령 수준 검사를 적용합니다. 예를 들어 영구적인 `/config set` 및 `/config unset` 쓰기 작업에는 `operator.admin`이 필요합니다. -`node.pair.approve`도 기본 메서드 범위 외에 추가 승인 시점 범위 검사가 있습니다: +`node.pair.approve`도 기본 메서드 범위 외에 추가적인 승인 시점 범위 검사가 있습니다: - 명령 없는 요청: `operator.pairing` -- non-exec node 명령이 있는 요청: `operator.pairing` + `operator.write` -- `system.run`, `system.run.prepare`, `system.which`를 포함하는 요청: +- exec가 아닌 노드 명령이 포함된 요청: `operator.pairing` + `operator.write` +- `system.run`, `system.run.prepare`, 또는 `system.which`가 포함된 요청: `operator.pairing` + `operator.admin` ### caps/commands/permissions(node) -노드는 연결 시점에 기능 클레임을 선언합니다: +노드는 연결 시 기능 클레임을 선언합니다: -- `caps`: 상위 수준 기능 범주 +- `caps`: 상위 수준 기능 카테고리 - `commands`: invoke용 명령 허용 목록 - `permissions`: 세부 토글(예: `screen.record`, `camera.capture`) @@ -214,277 +200,210 @@ Gateway는 이를 **클레임**으로 취급하고 서버 측 허용 목록을 ## 프레즌스 -- `system-presence`는 디바이스 식별성을 키로 하는 항목을 반환합니다. -- 프레즌스 항목에는 `deviceId`, `roles`, `scopes`가 포함되므로 UI는 디바이스가 **operator**와 **node**로 - 모두 연결된 경우에도 디바이스당 한 줄만 표시할 수 있습니다. +- `system-presence`는 디바이스 정체성을 키로 하는 항목을 반환합니다. +- 프레즌스 항목에는 `deviceId`, `roles`, `scopes`가 포함되므로 UI는 디바이스가 **operator**와 **node**로 모두 연결되어 있더라도 디바이스당 한 행만 표시할 수 있습니다. ## 일반적인 RPC 메서드 계열 -이 페이지는 생성된 전체 덤프가 아니지만, 공개 WS 표면은 위의 -핸드셰이크/인증 예시보다 더 넓습니다. 다음은 현재 Gateway가 노출하는 주요 메서드 계열입니다. +이 페이지는 생성된 전체 덤프가 아니지만, 공개 WS 표면은 위의 핸드셰이크/인증 예시보다 더 넓습니다. 현재 Gateway가 노출하는 주요 메서드 계열은 다음과 같습니다. -`hello-ok.features.methods`는 -`src/gateway/server-methods-list.ts`와 로드된 plugin/channel 메서드 export로부터 구성된 보수적인 검색 목록입니다. -이를 기능 검색으로 취급하고, `src/gateway/server-methods/*.ts`에 구현된 -모든 호출 가능 헬퍼의 생성된 덤프로 취급하지 마세요. +`hello-ok.features.methods`는 `src/gateway/server-methods-list.ts`와 로드된 plugin/channel 메서드 export를 바탕으로 구성된 보수적인 디스커버리 목록입니다. 이를 기능 디스커버리로 취급하고, `src/gateway/server-methods/*.ts`에 구현된 모든 호출 가능한 헬퍼의 생성된 덤프로 취급하지 마세요. ### 시스템 및 정체성 -- `health`는 캐시된 또는 새로 프로브한 gateway 상태 스냅샷을 반환합니다. -- `status`는 `/status` 스타일 gateway 요약을 반환하며, 민감한 필드는 - admin 범위의 operator 클라이언트에만 포함됩니다. -- `gateway.identity.get`은 relay 및 - pairing 흐름에서 사용되는 gateway 디바이스 정체성을 반환합니다. -- `system-presence`는 연결된 - operator/node 디바이스의 현재 프레즌스 스냅샷을 반환합니다. -- `system-event`는 시스템 이벤트를 추가하고 프레즌스 - 컨텍스트를 업데이트/브로드캐스트할 수 있습니다. -- `last-heartbeat`는 최근에 저장된 heartbeat 이벤트를 반환합니다. -- `set-heartbeats`는 gateway의 heartbeat 처리를 전환합니다. +- `health`는 캐시된 또는 새로 프로브된 Gateway 상태 스냅샷을 반환합니다. +- `status`는 `/status` 스타일의 Gateway 요약을 반환합니다. 민감한 필드는 관리자 범위가 있는 operator 클라이언트에게만 포함됩니다. +- `gateway.identity.get`은 릴레이 및 페어링 흐름에 사용되는 Gateway 디바이스 정체성을 반환합니다. +- `system-presence`는 연결된 operator/node 디바이스의 현재 프레즌스 스냅샷을 반환합니다. +- `system-event`는 시스템 이벤트를 추가하고 프레즌스 컨텍스트를 업데이트/브로드캐스트할 수 있습니다. +- `last-heartbeat`는 가장 최근에 저장된 heartbeat 이벤트를 반환합니다. +- `set-heartbeats`는 Gateway에서 heartbeat 처리를 전환합니다. ### 모델 및 사용량 - `models.list`는 런타임에서 허용된 모델 카탈로그를 반환합니다. -- `usage.status`는 제공자 사용량 창/남은 할당량 요약을 반환합니다. +- `usage.status`는 provider 사용량 윈도우/잔여 할당량 요약을 반환합니다. - `usage.cost`는 날짜 범위에 대한 집계된 비용 사용량 요약을 반환합니다. -- `doctor.memory.status`는 활성 기본 agent 워크스페이스의 - vector-memory / embedding 준비 상태를 반환합니다. +- `doctor.memory.status`는 활성 기본 에이전트 워크스페이스의 벡터 메모리/임베딩 준비 상태를 반환합니다. - `sessions.usage`는 세션별 사용량 요약을 반환합니다. -- `sessions.usage.timeseries`는 한 세션의 시계열 사용량을 반환합니다. -- `sessions.usage.logs`는 한 세션의 사용량 로그 항목을 반환합니다. +- `sessions.usage.timeseries`는 하나의 세션에 대한 시계열 사용량을 반환합니다. +- `sessions.usage.logs`는 하나의 세션에 대한 사용량 로그 항목을 반환합니다. ### 채널 및 로그인 헬퍼 -- `channels.status`는 내장 + 번들 channel/plugin 상태 요약을 반환합니다. -- `channels.logout`은 해당 channel이 logout을 지원할 때 특정 channel/account에서 로그아웃합니다. -- `web.login.start`는 현재 QR 지원 웹 - channel provider에 대한 QR/웹 로그인 흐름을 시작합니다. -- `web.login.wait`는 해당 QR/웹 로그인 흐름이 완료될 때까지 대기하고 성공 시 - channel을 시작합니다. -- `push.test`는 등록된 iOS node로 테스트 APNs 푸시를 보냅니다. +- `channels.status`는 내장 + 번들 채널/plugin 상태 요약을 반환합니다. +- `channels.logout`은 해당 채널이 로그아웃을 지원하는 경우 특정 채널/계정에서 로그아웃합니다. +- `web.login.start`는 현재 QR 지원 웹 채널 provider에 대한 QR/웹 로그인 흐름을 시작합니다. +- `web.login.wait`는 해당 QR/웹 로그인 흐름이 완료될 때까지 기다리고 성공 시 채널을 시작합니다. +- `push.test`는 등록된 iOS 노드에 테스트 APNs 푸시를 전송합니다. - `voicewake.get`은 저장된 웨이크 워드 트리거를 반환합니다. - `voicewake.set`은 웨이크 워드 트리거를 업데이트하고 변경 사항을 브로드캐스트합니다. ### 메시징 및 로그 -- `send`는 chat runner 외부에서 - channel/account/thread 대상을 지정해 전송하는 직접 outbound-delivery RPC입니다. -- `logs.tail`은 cursor/limit 및 - max-byte 제어와 함께 설정된 gateway 파일 로그 tail을 반환합니다. +- `send`는 채팅 러너 외부에서 채널/계정/스레드 대상 전송을 위한 직접 아웃바운드 전달 RPC입니다. +- `logs.tail`은 커서/제한 및 최대 바이트 제어와 함께 구성된 Gateway 파일 로그 tail을 반환합니다. ### Talk 및 TTS -- `talk.config`는 유효한 Talk 설정 페이로드를 반환하며, `includeSecrets`는 - `operator.talk.secrets`(또는 `operator.admin`)를 필요로 합니다. -- `talk.mode`는 WebChat/Control UI - 클라이언트를 위한 현재 Talk 모드 상태를 설정/브로드캐스트합니다. -- `talk.speak`는 활성 Talk speech provider를 통해 음성을 합성합니다. -- `tts.status`는 TTS 활성 상태, 활성 provider, 대체 provider, - 그리고 provider 설정 상태를 반환합니다. +- `talk.config`는 유효한 Talk 설정 페이로드를 반환합니다. `includeSecrets`에는 `operator.talk.secrets`(또는 `operator.admin`)가 필요합니다. +- `talk.mode`는 WebChat/Control UI 클라이언트를 위한 현재 Talk 모드 상태를 설정/브로드캐스트합니다. +- `talk.speak`는 활성 Talk 음성 provider를 통해 음성을 합성합니다. +- `tts.status`는 TTS 활성화 상태, 활성 provider, 폴백 provider, provider 설정 상태를 반환합니다. - `tts.providers`는 표시 가능한 TTS provider 인벤토리를 반환합니다. - `tts.enable` 및 `tts.disable`은 TTS 기본 설정 상태를 전환합니다. - `tts.setProvider`는 선호 TTS provider를 업데이트합니다. -- `tts.convert`는 일회성 텍스트 음성 변환을 실행합니다. +- `tts.convert`는 일회성 텍스트-음성 변환을 실행합니다. -### 시크릿, 설정, 업데이트, wizard +### 시크릿, 설정, 업데이트, 그리고 wizard -- `secrets.reload`는 활성 SecretRef를 다시 해석하고 완전히 성공한 경우에만 - 런타임 시크릿 상태를 교체합니다. -- `secrets.resolve`는 특정 명령/대상 집합에 대한 - 명령 대상 시크릿 할당을 해석합니다. +- `secrets.reload`는 활성 SecretRef를 다시 해석하고 전체 성공 시에만 런타임 시크릿 상태를 교체합니다. +- `secrets.resolve`는 특정 명령/대상 집합에 대한 명령 대상 시크릿 할당을 해석합니다. - `config.get`은 현재 설정 스냅샷과 해시를 반환합니다. - `config.set`은 검증된 설정 페이로드를 기록합니다. - `config.patch`는 부분 설정 업데이트를 병합합니다. - `config.apply`는 전체 설정 페이로드를 검증하고 교체합니다. -- `config.schema`는 Control UI 및 - CLI 도구에서 사용하는 라이브 설정 스키마 페이로드를 반환합니다. 즉, 스키마, - `uiHints`, 버전, 생성 메타데이터이며, 런타임이 로드할 수 있을 때 - plugin + channel 스키마 메타데이터도 포함합니다. 스키마에는 동일한 라벨과 - UI가 사용하는 도움말 텍스트에서 파생된 필드 `title` / `description` 메타데이터가 포함되며, - 일치하는 필드 문서가 존재할 경우 중첩 객체, 와일드카드, 배열 항목, - `anyOf` / `oneOf` / `allOf` 구성 분기도 포함됩니다. -- `config.schema.lookup`은 하나의 설정 - 경로에 대해 경로 범위 조회 페이로드를 반환합니다. 즉 정규화된 경로, 얕은 스키마 노드, - 일치한 힌트 + `hintPath`, 그리고 UI/CLI 드릴다운용 즉시 하위 요약입니다. +- `config.schema`는 Control UI와 CLI 도구에서 사용하는 라이브 설정 스키마 페이로드를 반환합니다: 스키마, `uiHints`, 버전, 생성 메타데이터, 그리고 런타임이 로드할 수 있는 경우 plugin + channel 스키마 메타데이터를 포함합니다. 스키마에는 중첩 객체, 와일드카드, 배열 항목, 그리고 일치하는 필드 문서가 존재하는 경우 `anyOf` / `oneOf` / `allOf` 구성 분기까지 포함해, UI가 사용하는 동일한 레이블 및 도움말 텍스트에서 파생된 필드 `title` / `description` 메타데이터가 포함됩니다. +- `config.schema.lookup`은 하나의 설정 경로에 대한 경로 범위 조회 페이로드를 반환합니다: 정규화된 경로, 얕은 스키마 노드, 일치한 힌트 + `hintPath`, 그리고 UI/CLI 드릴다운을 위한 즉시 하위 항목 요약입니다. - 조회 스키마 노드는 사용자 대상 문서와 일반적인 검증 필드를 유지합니다: `title`, `description`, `type`, `enum`, `const`, `format`, `pattern`, - 숫자/문자열/배열/객체 경계, 그리고 - `additionalProperties`, `deprecated`, `readOnly`, `writeOnly` 같은 불리언 플래그 - - 하위 요약은 `key`, 정규화된 `path`, `type`, `required`, - `hasChildren`, 그리고 일치한 `hint` / `hintPath`를 노출합니다 -- `update.run`은 gateway 업데이트 흐름을 실행하고 - 업데이트 자체가 성공했을 때만 재시작을 예약합니다. -- `wizard.start`, `wizard.next`, `wizard.status`, `wizard.cancel`은 - 온보딩 wizard를 WS RPC를 통해 노출합니다. + 숫자/문자열/배열/객체 경계, 그리고 `additionalProperties`, `deprecated`, `readOnly`, `writeOnly` 같은 불리언 플래그 + - 하위 항목 요약은 `key`, 정규화된 `path`, `type`, `required`, + `hasChildren`, 그리고 일치한 `hint` / `hintPath`를 노출합니다. +- `update.run`은 Gateway 업데이트 흐름을 실행하고 업데이트 자체가 성공한 경우에만 재시작을 예약합니다. +- `wizard.start`, `wizard.next`, `wizard.status`, `wizard.cancel`은 WS RPC를 통해 온보딩 wizard를 노출합니다. ### 기존 주요 계열 -#### Agent 및 워크스페이스 헬퍼 +#### 에이전트 및 워크스페이스 헬퍼 -- `agents.list`는 설정된 agent 항목을 반환합니다. -- `agents.create`, `agents.update`, `agents.delete`는 agent 레코드 및 - 워크스페이스 연결을 관리합니다. -- `agents.files.list`, `agents.files.get`, `agents.files.set`은 - agent에 대해 노출된 bootstrap 워크스페이스 파일을 관리합니다. -- `agent.identity.get`은 agent 또는 - 세션에 대한 유효 assistant 정체성을 반환합니다. -- `agent.wait`는 실행이 끝날 때까지 기다리고 가능한 경우 - 종료 스냅샷을 반환합니다. +- `agents.list`는 구성된 에이전트 항목을 반환합니다. +- `agents.create`, `agents.update`, `agents.delete`는 에이전트 레코드와 워크스페이스 연결을 관리합니다. +- `agents.files.list`, `agents.files.get`, `agents.files.set`은 에이전트에 대해 노출되는 부트스트랩 워크스페이스 파일을 관리합니다. +- `agent.identity.get`은 에이전트 또는 세션에 대한 유효한 어시스턴트 정체성을 반환합니다. +- `agent.wait`는 실행이 끝날 때까지 기다리고, 가능하면 종료 스냅샷을 반환합니다. #### 세션 제어 - `sessions.list`는 현재 세션 인덱스를 반환합니다. -- `sessions.subscribe` 및 `sessions.unsubscribe`는 - 현재 WS 클라이언트에 대한 세션 변경 이벤트 구독을 전환합니다. -- `sessions.messages.subscribe` 및 `sessions.messages.unsubscribe`는 - 한 세션에 대한 트랜스크립트/메시지 이벤트 구독을 전환합니다. -- `sessions.preview`는 특정 세션 - 키에 대한 제한된 트랜스크립트 미리보기를 반환합니다. +- `sessions.subscribe`와 `sessions.unsubscribe`는 현재 WS 클라이언트에 대한 세션 변경 이벤트 구독을 전환합니다. +- `sessions.messages.subscribe`와 `sessions.messages.unsubscribe`는 하나의 세션에 대한 대화 내용/메시지 이벤트 구독을 전환합니다. +- `sessions.preview`는 특정 세션 키에 대해 범위가 제한된 대화 내용 미리보기를 반환합니다. - `sessions.resolve`는 세션 대상을 해석하거나 정규화합니다. - `sessions.create`는 새 세션 항목을 생성합니다. - `sessions.send`는 기존 세션에 메시지를 보냅니다. - `sessions.steer`는 활성 세션을 위한 인터럽트 후 조정 변형입니다. - `sessions.abort`는 세션의 활성 작업을 중단합니다. -- `sessions.patch`는 세션 메타데이터/오버라이드를 업데이트합니다. -- `sessions.reset`, `sessions.delete`, `sessions.compact`는 세션 - 유지 관리를 수행합니다. -- `sessions.get`은 저장된 전체 세션 행을 반환합니다. -- chat 실행은 여전히 `chat.history`, `chat.send`, `chat.abort`, - `chat.inject`를 사용합니다. -- `chat.history`는 UI 클라이언트용으로 표시 정규화됩니다. 인라인 directive 태그는 - 보이는 텍스트에서 제거되고, 일반 텍스트 tool-call XML 페이로드(예: - `...`, `...`, - `...`, `...`, 그리고 - 잘린 tool-call 블록) 및 유출된 ASCII/전각 모델 제어 토큰이 제거되며, - 정확히 `NO_REPLY` / `no_reply`인 순수 silent-token assistant 행은 생략되고, - 과도하게 큰 행은 플레이스홀더로 대체될 수 있습니다. +- `sessions.patch`는 세션 메타데이터/재정의를 업데이트합니다. +- `sessions.reset`, `sessions.delete`, `sessions.compact`는 세션 유지 관리 작업을 수행합니다. +- `sessions.get`은 전체 저장된 세션 행을 반환합니다. +- 채팅 실행은 여전히 `chat.history`, `chat.send`, `chat.abort`, `chat.inject`를 사용합니다. +- `chat.history`는 UI 클라이언트를 위해 표시 기준으로 정규화됩니다. 인라인 directive 태그는 보이는 텍스트에서 제거되고, 일반 텍스트 tool-call XML 페이로드(`"..."`, `"..."`, `"..."`, `"..."`, 그리고 잘린 tool-call 블록 포함)와 유출된 ASCII/전각 모델 제어 토큰은 제거되며, 정확히 `NO_REPLY` / `no_reply`인 순수 silent-token assistant 행은 생략되고, 과도하게 큰 행은 플레이스홀더로 대체될 수 있습니다. #### 디바이스 페어링 및 디바이스 토큰 - `device.pair.list`는 대기 중 및 승인된 페어링 디바이스를 반환합니다. -- `device.pair.approve`, `device.pair.reject`, `device.pair.remove`는 - 디바이스 페어링 레코드를 관리합니다. -- `device.token.rotate`는 승인된 역할 - 및 범위 경계 내에서 페어링된 디바이스 토큰을 회전합니다. -- `device.token.revoke`는 페어링된 디바이스 토큰을 취소합니다. +- `device.pair.approve`, `device.pair.reject`, `device.pair.remove`는 디바이스 페어링 레코드를 관리합니다. +- `device.token.rotate`는 승인된 역할 및 범위 한도 내에서 페어링된 디바이스 토큰을 교체합니다. +- `device.token.revoke`는 페어링된 디바이스 토큰을 폐기합니다. #### 노드 페어링, invoke, 대기 중 작업 -- `node.pair.request`, `node.pair.list`, `node.pair.approve`, - `node.pair.reject`, `node.pair.verify`는 노드 페어링 및 bootstrap - 검증을 다룹니다. -- `node.list` 및 `node.describe`는 알려진/연결된 노드 상태를 반환합니다. +- `node.pair.request`, `node.pair.list`, `node.pair.approve`, `node.pair.reject`, `node.pair.verify`는 노드 페어링과 부트스트랩 검증을 다룹니다. +- `node.list`와 `node.describe`는 알려진/연결된 노드 상태를 반환합니다. - `node.rename`은 페어링된 노드 레이블을 업데이트합니다. -- `node.invoke`는 명령을 연결된 노드로 전달합니다. -- `node.invoke.result`는 invoke 요청에 대한 결과를 반환합니다. -- `node.event`는 노드에서 시작된 이벤트를 다시 gateway로 전달합니다. -- `node.canvas.capability.refresh`는 범위가 지정된 canvas 기능 토큰을 새로 고칩니다. -- `node.pending.pull` 및 `node.pending.ack`는 연결된 노드 큐 API입니다. -- `node.pending.enqueue` 및 `node.pending.drain`은 오프라인/연결 해제된 노드용 - 지속형 대기 작업을 관리합니다. +- `node.invoke`는 연결된 노드로 명령을 전달합니다. +- `node.invoke.result`는 invoke 요청의 결과를 반환합니다. +- `node.event`는 노드 발생 이벤트를 다시 게이트웨이로 전달합니다. +- `node.canvas.capability.refresh`는 범위가 지정된 canvas capability 토큰을 새로 고칩니다. +- `node.pending.pull`과 `node.pending.ack`는 연결된 노드 큐 API입니다. +- `node.pending.enqueue`와 `node.pending.drain`은 오프라인/연결 해제된 노드를 위한 지속형 대기 작업을 관리합니다. #### 승인 계열 -- `exec.approval.request`, `exec.approval.get`, `exec.approval.list`, - `exec.approval.resolve`는 일회성 exec 승인 요청과 대기 중인 - 승인 조회/재생을 다룹니다. -- `exec.approval.waitDecision`은 하나의 대기 중인 exec 승인을 기다리고 - 최종 결정(또는 타임아웃 시 `null`)을 반환합니다. -- `exec.approvals.get` 및 `exec.approvals.set`은 gateway exec 승인 - 정책 스냅샷을 관리합니다. -- `exec.approvals.node.get` 및 `exec.approvals.node.set`은 노드 relay 명령을 통해 - node-local exec 승인 정책을 관리합니다. -- `plugin.approval.request`, `plugin.approval.list`, - `plugin.approval.waitDecision`, `plugin.approval.resolve`는 - plugin이 정의한 승인 흐름을 다룹니다. +- `exec.approval.request`, `exec.approval.get`, `exec.approval.list`, `exec.approval.resolve`는 일회성 exec 승인 요청과 대기 중 승인 조회/재실행을 다룹니다. +- `exec.approval.waitDecision`은 하나의 대기 중 exec 승인을 기다리고 최종 결정(또는 타임아웃 시 `null`)을 반환합니다. +- `exec.approvals.get`과 `exec.approvals.set`은 게이트웨이 exec 승인 정책 스냅샷을 관리합니다. +- `exec.approvals.node.get`과 `exec.approvals.node.set`은 노드 릴레이 명령을 통해 노드 로컬 exec 승인 정책을 관리합니다. +- `plugin.approval.request`, `plugin.approval.list`, `plugin.approval.waitDecision`, `plugin.approval.resolve`는 plugin 정의 승인 흐름을 다룹니다. #### 기타 주요 계열 -- automation: - - `wake`는 즉시 또는 다음 heartbeat 시점의 wake 텍스트 주입을 예약합니다 - - `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`, - `cron.run`, `cron.runs` -- skills/tools: `skills.*`, `tools.catalog`, `tools.effective` +- 자동화: + - `wake`는 즉시 또는 다음 heartbeat에 wake 텍스트 주입을 예약합니다 + - `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`, `cron.run`, `cron.runs` +- Skills/tools: `commands.list`, `skills.*`, `tools.catalog`, `tools.effective` ### 일반적인 이벤트 계열 -- `chat`: `chat.inject` 및 기타 트랜스크립트 전용 chat - 이벤트 같은 UI chat 업데이트 -- `session.message` 및 `session.tool`: 구독한 세션에 대한 트랜스크립트/이벤트 스트림 업데이트 +- `chat`: `chat.inject` 및 기타 대화 내용 전용 채팅 이벤트 같은 UI 채팅 업데이트 +- `session.message`와 `session.tool`: 구독된 세션에 대한 대화 내용/이벤트 스트림 업데이트 - `sessions.changed`: 세션 인덱스 또는 메타데이터가 변경됨 - `presence`: 시스템 프레즌스 스냅샷 업데이트 -- `tick`: 주기적 keepalive / 생존 이벤트 -- `health`: gateway 상태 스냅샷 업데이트 +- `tick`: 주기적인 keepalive / liveness 이벤트 +- `health`: 게이트웨이 상태 스냅샷 업데이트 - `heartbeat`: heartbeat 이벤트 스트림 업데이트 - `cron`: cron 실행/작업 변경 이벤트 -- `shutdown`: gateway 종료 알림 +- `shutdown`: 게이트웨이 종료 알림 - `node.pair.requested` / `node.pair.resolved`: 노드 페어링 수명 주기 - `node.invoke.request`: 노드 invoke 요청 브로드캐스트 - `device.pair.requested` / `device.pair.resolved`: 페어링 디바이스 수명 주기 - `voicewake.changed`: 웨이크 워드 트리거 설정이 변경됨 -- `exec.approval.requested` / `exec.approval.resolved`: exec 승인 - 수명 주기 +- `exec.approval.requested` / `exec.approval.resolved`: exec 승인 수명 주기 - `plugin.approval.requested` / `plugin.approval.resolved`: plugin 승인 수명 주기 ### 노드 헬퍼 메서드 - 노드는 자동 허용 검사에 사용할 현재 skill 실행 파일 목록을 가져오기 위해 `skills.bins`를 호출할 수 있습니다. -### Operator 헬퍼 메서드 +### operator 헬퍼 메서드 -- Operator는 agent의 런타임 도구 카탈로그를 가져오기 위해 `tools.catalog` (`operator.read`)을 호출할 수 있습니다. - 응답에는 그룹화된 도구와 출처 메타데이터가 포함됩니다: +- operator는 에이전트의 런타임 명령 인벤토리를 가져오기 위해 `commands.list`(`operator.read`)를 호출할 수 있습니다. + - `agentId`는 선택 사항이며, 생략하면 기본 에이전트 워크스페이스를 읽습니다. + - `scope`는 기본 `name`이 어떤 표면을 대상으로 하는지 제어합니다: + - `text`는 앞의 `/`가 없는 기본 텍스트 명령 토큰을 반환합니다 + - `native`와 기본값인 `both` 경로는 가능할 때 provider 인식 native 이름을 반환합니다 + - `textAliases`는 `/model` 및 `/m` 같은 정확한 슬래시 별칭을 담습니다. + - `nativeName`은 존재할 경우 provider 인식 native 명령 이름을 담습니다. + - `provider`는 선택 사항이며 native 이름 지정과 native plugin 명령 가용성에만 영향을 줍니다. + - `includeArgs=false`는 응답에서 직렬화된 인자 메타데이터를 제외합니다. +- operator는 에이전트의 런타임 tool 카탈로그를 가져오기 위해 `tools.catalog`(`operator.read`)를 호출할 수 있습니다. 응답에는 그룹화된 tool과 출처 메타데이터가 포함됩니다: - `source`: `core` 또는 `plugin` - - `pluginId`: `source="plugin"`일 때의 plugin 소유자 - - `optional`: plugin 도구가 선택 사항인지 여부 -- Operator는 세션의 런타임 유효 도구 - 인벤토리를 가져오기 위해 `tools.effective` (`operator.read`)를 호출할 수 있습니다. + - `pluginId`: `source="plugin"`일 때 plugin 소유자 + - `optional`: plugin tool이 선택 사항인지 여부 +- operator는 세션의 런타임 유효 tool 인벤토리를 가져오기 위해 `tools.effective`(`operator.read`)를 호출할 수 있습니다. - `sessionKey`는 필수입니다. - - gateway는 호출자가 제공한 인증 또는 전달 컨텍스트를 받아들이는 대신, - 서버 측에서 세션으로부터 신뢰된 런타임 컨텍스트를 도출합니다. - - 응답은 세션 범위이며 현재 활성 대화가 지금 사용할 수 있는 항목을 반영합니다. - 여기에는 core, plugin, channel 도구가 포함됩니다. -- Operator는 agent에 표시 가능한 - skill 인벤토리를 가져오기 위해 `skills.status` (`operator.read`)를 호출할 수 있습니다. - - `agentId`는 선택 사항이며, 생략하면 기본 agent 워크스페이스를 읽습니다. - - 응답에는 원시 시크릿 값을 노출하지 않고도 - 적격성, 누락된 요구 사항, 설정 검사, 정리된 설치 옵션이 포함됩니다. -- Operator는 ClawHub 검색 메타데이터를 위해 - `skills.search` 및 `skills.detail` (`operator.read`)를 호출할 수 있습니다. -- Operator는 `skills.install` (`operator.admin`)을 두 가지 모드로 호출할 수 있습니다: - - ClawHub 모드: `{ source: "clawhub", slug, version?, force? }`는 - 기본 agent 워크스페이스 `skills/` 디렉터리에 skill 폴더를 설치합니다. - - Gateway installer 모드: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` - 는 gateway 호스트에서 선언된 `metadata.openclaw.install` 작업을 실행합니다. -- Operator는 `skills.update` (`operator.admin`)를 두 가지 모드로 호출할 수 있습니다: - - ClawHub 모드는 기본 agent 워크스페이스에서 - 추적되는 하나의 slug 또는 모든 추적된 ClawHub 설치를 업데이트합니다. - - Config 모드는 `enabled`, - `apiKey`, `env` 같은 `skills.entries.` 값을 패치합니다. + - 게이트웨이는 호출자가 제공한 인증 또는 전달 컨텍스트를 받지 않고 세션으로부터 신뢰된 런타임 컨텍스트를 서버 측에서 도출합니다. + - 응답은 세션 범위이며, core, plugin, channel tool을 포함해 현재 활성 대화가 지금 사용할 수 있는 내용을 반영합니다. +- operator는 에이전트의 표시 가능한 skill 인벤토리를 가져오기 위해 `skills.status`(`operator.read`)를 호출할 수 있습니다. + - `agentId`는 선택 사항이며, 생략하면 기본 에이전트 워크스페이스를 읽습니다. + - 응답에는 원시 시크릿 값을 노출하지 않고 적격성, 누락된 요구 사항, 설정 검사, 정리된 설치 옵션이 포함됩니다. +- operator는 ClawHub 디스커버리 메타데이터를 위해 `skills.search`와 `skills.detail`(`operator.read`)를 호출할 수 있습니다. +- operator는 두 가지 모드로 `skills.install`(`operator.admin`)을 호출할 수 있습니다: + - ClawHub 모드: `{ source: "clawhub", slug, version?, force? }`는 기본 에이전트 워크스페이스 `skills/` 디렉터리에 skill 폴더를 설치합니다. + - 게이트웨이 설치 프로그램 모드: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }`는 게이트웨이 호스트에서 선언된 `metadata.openclaw.install` 작업을 실행합니다. +- operator는 두 가지 모드로 `skills.update`(`operator.admin`)를 호출할 수 있습니다: + - ClawHub 모드는 추적된 slug 하나 또는 기본 에이전트 워크스페이스의 모든 추적된 ClawHub 설치를 업데이트합니다. + - 설정 모드는 `enabled`, `apiKey`, `env` 같은 `skills.entries.` 값을 패치합니다. ## Exec 승인 -- exec 요청에 승인이 필요하면 gateway는 `exec.approval.requested`를 브로드캐스트합니다. -- Operator 클라이언트는 `exec.approval.resolve`를 호출하여 이를 해결합니다(`operator.approvals` 범위 필요). -- `host=node`의 경우, `exec.approval.request`는 `systemRunPlan`(정규화된 `argv`/`cwd`/`rawCommand`/세션 메타데이터)을 포함해야 합니다. - `systemRunPlan`이 없는 요청은 거부됩니다. -- 승인 후 전달되는 `node.invoke system.run` 호출은 - 해당 정규화된 `systemRunPlan`을 권위 있는 명령/cwd/세션 컨텍스트로 재사용합니다. -- 호출자가 prepare와 최종 승인된 `system.run` 전달 사이에서 - `command`, `rawCommand`, `cwd`, `agentId`, `sessionKey`를 변경하면, - gateway는 변경된 페이로드를 신뢰하는 대신 실행을 거부합니다. +- exec 요청에 승인이 필요하면, 게이트웨이는 `exec.approval.requested`를 브로드캐스트합니다. +- operator 클라이언트는 `exec.approval.resolve`를 호출해 이를 처리합니다(`operator.approvals` 범위 필요). +- `host=node`인 경우 `exec.approval.request`에는 `systemRunPlan`(정규화된 `argv`/`cwd`/`rawCommand`/세션 메타데이터)이 포함되어야 합니다. `systemRunPlan`이 없는 요청은 거부됩니다. +- 승인 후 전달되는 `node.invoke system.run` 호출은 해당 정규 `systemRunPlan`을 권위 있는 명령/cwd/세션 컨텍스트로 재사용합니다. +- 호출자가 prepare와 최종 승인된 `system.run` 전달 사이에서 `command`, `rawCommand`, `cwd`, `agentId`, `sessionKey`를 변경하면, 게이트웨이는 변경된 페이로드를 신뢰하는 대신 실행을 거부합니다. -## Agent 전달 대체 +## 에이전트 전달 폴백 -- `agent` 요청은 outbound 전달을 요청하기 위해 `deliver=true`를 포함할 수 있습니다. -- `bestEffortDeliver=false`는 엄격한 동작을 유지합니다. 해석할 수 없거나 내부 전용 전달 대상은 `INVALID_REQUEST`를 반환합니다. -- `bestEffortDeliver=true`는 외부로 전달 가능한 경로를 해석할 수 없을 때 세션 전용 실행으로 대체할 수 있습니다 - (예: internal/webchat 세션 또는 모호한 다중 채널 설정). +- `agent` 요청에는 아웃바운드 전달을 요청하기 위해 `deliver=true`를 포함할 수 있습니다. +- `bestEffortDeliver=false`는 엄격한 동작을 유지합니다. 해결되지 않거나 내부 전용 전달 대상은 `INVALID_REQUEST`를 반환합니다. +- `bestEffortDeliver=true`는 외부로 전달 가능한 경로를 해석할 수 없을 때(예: internal/webchat 세션 또는 모호한 다중 채널 설정) 세션 전용 실행으로의 폴백을 허용합니다. ## 버전 관리 - `PROTOCOL_VERSION`은 `src/gateway/protocol/schema.ts`에 있습니다. -- 클라이언트는 `minProtocol` + `maxProtocol`을 보내며, 서버는 불일치를 거부합니다. +- 클라이언트는 `minProtocol` + `maxProtocol`을 전송하며, 서버는 불일치를 거부합니다. - 스키마 + 모델은 TypeBox 정의에서 생성됩니다: - `pnpm protocol:gen` - `pnpm protocol:gen:swift` @@ -492,99 +411,69 @@ Gateway는 이를 **클레임**으로 취급하고 서버 측 허용 목록을 ## 인증 -- 공유 시크릿 gateway 인증은 설정된 인증 모드에 따라 - `connect.params.auth.token` 또는 `connect.params.auth.password`를 사용합니다. -- Tailscale Serve(`gateway.auth.allowTailscale: true`) 또는 non-loopback - `gateway.auth.mode: "trusted-proxy"` 같은 정체성 기반 모드는 - `connect.params.auth.*` 대신 요청 헤더에서 연결 인증 검사를 충족합니다. -- private-ingress `gateway.auth.mode: "none"`은 공유 시크릿 연결 인증을 - 완전히 건너뜁니다. 이 모드를 공개/비신뢰 인그레스에 노출하지 마세요. -- 페어링 후 Gateway는 연결 - 역할 + 범위에 범위가 지정된 **디바이스 토큰**을 발급합니다. 이는 `hello-ok.auth.deviceToken`에 반환되며, - 클라이언트는 이후 연결을 위해 이를 저장해야 합니다. +- 공유 시크릿 게이트웨이 인증은 구성된 인증 모드에 따라 `connect.params.auth.token` 또는 `connect.params.auth.password`를 사용합니다. +- Tailscale Serve(`gateway.auth.allowTailscale: true`) 또는 루프백이 아닌 `gateway.auth.mode: "trusted-proxy"` 같은 identity 포함 모드는 `connect.params.auth.*` 대신 요청 헤더에서 연결 인증 검사를 충족합니다. +- 비공개 인그레스 `gateway.auth.mode: "none"`은 공유 시크릿 연결 인증을 완전히 건너뜁니다. 해당 모드를 공개/신뢰할 수 없는 인그레스에 노출하지 마세요. +- 페어링 후 Gateway는 연결 역할 + 범위로 범위가 제한된 **디바이스 토큰**을 발급합니다. 이 토큰은 `hello-ok.auth.deviceToken`으로 반환되며, 클라이언트는 이후 연결을 위해 이를 저장해야 합니다. - 클라이언트는 성공적으로 연결한 후 기본 `hello-ok.auth.deviceToken`을 저장해야 합니다. -- 저장된 해당 **디바이스 토큰**으로 다시 연결할 때도 - 해당 토큰에 대해 저장된 승인 범위 집합을 재사용해야 합니다. 이렇게 하면 이미 부여된 - 읽기/프로브/상태 접근을 보존하고, 재연결이 더 좁은 암묵적 admin 전용 범위로 - 조용히 축소되는 일을 방지할 수 있습니다. -- 일반적인 연결 인증 우선순위는 명시적 공유 토큰/비밀번호가 먼저이고, - 그다음 명시적 `deviceToken`, 그다음 저장된 디바이스별 토큰, 그다음 bootstrap 토큰입니다. -- 추가적인 `hello-ok.auth.deviceTokens` 항목은 bootstrap handoff 토큰입니다. - `wss://` 또는 루프백/로컬 페어링 같은 신뢰된 전송에서 bootstrap 인증을 사용해 연결한 경우에만 - 이를 저장하세요. -- 클라이언트가 **명시적** `deviceToken` 또는 명시적 `scopes`를 제공하는 경우, - 호출자가 요청한 해당 범위 집합이 권위 있는 값으로 유지됩니다. 캐시된 범위는 클라이언트가 - 저장된 디바이스별 토큰을 재사용할 때만 다시 사용됩니다. -- 디바이스 토큰은 `device.token.rotate` 및 - `device.token.revoke`를 통해 회전/취소할 수 있습니다(`operator.pairing` 범위 필요). -- 토큰 발급/회전은 해당 디바이스의 페어링 항목에 기록된 승인된 역할 집합 내로 제한됩니다. - 토큰을 회전한다고 해서 페어링 승인이 한 번도 부여하지 않은 역할로 디바이스를 확장할 수는 없습니다. -- 페어링된 디바이스 토큰 세션의 경우, 호출자에게 `operator.admin`도 없는 한 - 디바이스 관리는 자기 범위로 제한됩니다. admin이 아닌 호출자는 자신의 **자체** - 디바이스 항목만 제거/취소/회전할 수 있습니다. -- `device.token.rotate`는 요청된 operator 범위 집합도 - 호출자의 현재 세션 범위에 대해 검사합니다. admin이 아닌 호출자는 자신이 이미 보유한 것보다 - 더 넓은 operator 범위 집합으로 토큰을 회전할 수 없습니다. -- 인증 실패에는 `error.details.code`와 복구 힌트가 포함됩니다: - - `error.details.canRetryWithDeviceToken` (boolean) +- 저장된 디바이스 토큰으로 다시 연결할 때는 그 토큰에 대해 저장된 승인 범위 집합도 함께 재사용해야 합니다. 이렇게 하면 이미 부여된 읽기/프로브/상태 액세스를 유지하고, 재연결이 더 좁은 암묵적 관리자 전용 범위로 조용히 축소되는 일을 방지할 수 있습니다. +- 일반적인 연결 인증 우선순위는 명시적 공유 토큰/비밀번호 우선, 그다음 명시적 `deviceToken`, 그다음 저장된 디바이스별 토큰, 마지막으로 부트스트랩 토큰입니다. +- 추가 `hello-ok.auth.deviceTokens` 항목은 부트스트랩 핸드오프 토큰입니다. `wss://` 또는 루프백/로컬 페어링 같은 신뢰된 전송 계층에서 부트스트랩 인증을 사용해 연결한 경우에만 이를 저장하세요. +- 클라이언트가 명시적 `deviceToken` 또는 명시적 `scopes`를 제공하면, 호출자가 요청한 그 범위 집합이 계속 권위 있는 값으로 유지됩니다. 캐시된 범위는 클라이언트가 저장된 디바이스별 토큰을 재사용하는 경우에만 재사용됩니다. +- 디바이스 토큰은 `device.token.rotate`와 `device.token.revoke`를 통해 교체/폐기할 수 있습니다(`operator.pairing` 범위 필요). +- 토큰 발급/교체는 해당 디바이스의 페어링 항목에 기록된 승인 역할 집합 범위 내로 제한됩니다. 토큰을 교체해도 페어링 승인에서 한 번도 허용하지 않은 역할로 디바이스를 확장할 수는 없습니다. +- 페어링된 디바이스 토큰 세션에서, 호출자에게 `operator.admin`도 있지 않은 한 디바이스 관리는 자체 범위로 제한됩니다. 관리자가 아닌 호출자는 **자신의** 디바이스 항목만 제거/폐기/교체할 수 있습니다. +- `device.token.rotate`는 요청된 operator 범위 집합을 호출자의 현재 세션 범위와도 비교합니다. 관리자가 아닌 호출자는 현재 자신이 가진 것보다 더 넓은 operator 범위 집합으로 토큰을 교체할 수 없습니다. +- 인증 실패에는 `error.details.code`와 함께 복구 힌트가 포함됩니다: + - `error.details.canRetryWithDeviceToken` (불리언) - `error.details.recommendedNextStep` (`retry_with_device_token`, `update_auth_configuration`, `update_auth_credentials`, `wait_then_retry`, `review_auth_configuration`) - `AUTH_TOKEN_MISMATCH`에 대한 클라이언트 동작: - - 신뢰된 클라이언트는 캐시된 디바이스별 토큰으로 제한된 한 번의 재시도를 시도할 수 있습니다. - - 해당 재시도도 실패하면 클라이언트는 자동 재연결 루프를 중단하고 operator 작업 지침을 표시해야 합니다. + - 신뢰된 클라이언트는 캐시된 디바이스별 토큰으로 한 번의 제한된 재시도를 시도할 수 있습니다. + - 그 재시도가 실패하면, 클라이언트는 자동 재연결 루프를 중단하고 운영자 조치 안내를 표시해야 합니다. ## 디바이스 정체성 + 페어링 -- 노드는 키 쌍 fingerprint에서 파생된 안정적인 디바이스 정체성(`device.id`)을 포함해야 합니다. -- Gateway는 디바이스 + 역할별로 토큰을 발급합니다. -- 새 디바이스 ID에는 로컬 자동 승인이 활성화되어 있지 않은 한 - 페어링 승인이 필요합니다. -- 페어링 자동 승인은 직접적인 로컬 루프백 연결을 중심으로 합니다. -- OpenClaw에는 신뢰된 공유 시크릿 헬퍼 흐름을 위한 좁은 백엔드/컨테이너-로컬 - self-connect 경로도 있습니다. -- 같은 호스트 tailnet 또는 LAN 연결은 여전히 원격으로 취급되며 - 페어링 승인이 필요합니다. +- 노드는 키 쌍 지문에서 파생된 안정적인 디바이스 정체성(`device.id`)을 포함해야 합니다. +- 게이트웨이는 디바이스 + 역할별로 토큰을 발급합니다. +- 로컬 자동 승인이 활성화되어 있지 않다면, 새 디바이스 ID에는 페어링 승인이 필요합니다. +- 페어링 자동 승인은 직접적인 local loopback 연결을 중심으로 동작합니다. +- OpenClaw에는 신뢰된 공유 시크릿 헬퍼 흐름을 위한, 범위가 좁은 백엔드/컨테이너 로컬 self-connect 경로도 있습니다. +- 동일 호스트의 tailnet 또는 LAN 연결은 여전히 페어링 관점에서 원격으로 취급되며 승인이 필요합니다. - 모든 WS 클라이언트는 `connect` 중에 `device` 정체성을 포함해야 합니다(operator + node). Control UI는 다음 모드에서만 이를 생략할 수 있습니다: - localhost 전용 비보안 HTTP 호환성을 위한 `gateway.controlUi.allowInsecureAuth=true` - - 성공한 `gateway.auth.mode: "trusted-proxy"` operator Control UI 인증 - - `gateway.controlUi.dangerouslyDisableDeviceAuth=true`(비상용, 심각한 보안 저하) + - 성공적인 `gateway.auth.mode: "trusted-proxy"` operator Control UI 인증 + - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (비상용, 심각한 보안 저하) - 모든 연결은 서버가 제공한 `connect.challenge` nonce에 서명해야 합니다. ### 디바이스 인증 마이그레이션 진단 -여전히 사전 챌린지 서명 동작을 사용하는 레거시 클라이언트의 경우, -이제 `connect`는 안정적인 `error.details.reason`과 함께 `error.details.code` 아래에 -`DEVICE_AUTH_*` 상세 코드를 반환합니다. +여전히 사전 챌린지 서명 동작을 사용하는 레거시 클라이언트를 위해, 이제 `connect`는 `error.details.reason`과 함께 안정적인 `error.details.code` 아래 `DEVICE_AUTH_*` 상세 코드를 반환합니다. 일반적인 마이그레이션 실패: | 메시지 | details.code | details.reason | 의미 | -| --------------------------- | -------------------------------- | ------------------------ | -------------------------------------------------- | -| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | 클라이언트가 `device.nonce`를 생략했거나(또는 빈 값 전송) 함 | -| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | 클라이언트가 오래되었거나 잘못된 nonce로 서명함 | -| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | 서명 페이로드가 v2 페이로드와 일치하지 않음 | -| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | 서명된 타임스탬프가 허용된 스큐 범위를 벗어남 | -| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id`가 공개 키 fingerprint와 일치하지 않음 | -| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | 공개 키 형식/정규화에 실패함 | +| ------ | ------------ | -------------- | ---- | +| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | 클라이언트가 `device.nonce`를 생략했거나 빈 값을 보냈습니다. | +| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | 클라이언트가 오래되었거나 잘못된 nonce로 서명했습니다. | +| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | 서명 페이로드가 v2 페이로드와 일치하지 않습니다. | +| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | 서명된 타임스탬프가 허용된 시간 오차 범위를 벗어났습니다. | +| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id`가 공개 키 지문과 일치하지 않습니다. | +| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | 공개 키 형식 또는 정규화에 실패했습니다. | 마이그레이션 목표: -- 항상 `connect.challenge`를 기다리세요 -- 서버 nonce를 포함하는 v2 페이로드에 서명하세요 -- 동일한 nonce를 `connect.params.device.nonce`에 보내세요 -- 선호되는 서명 페이로드는 디바이스/클라이언트/역할/범위/토큰/nonce 필드에 더해 - `platform`과 `deviceFamily`를 바인딩하는 `v3`입니다 -- 레거시 `v2` 서명도 호환성을 위해 계속 허용되지만, 페어링된 디바이스 - 메타데이터 고정은 여전히 재연결 시 명령 정책을 제어합니다 +- 항상 `connect.challenge`를 기다리세요. +- 서버 nonce가 포함된 v2 페이로드에 서명하세요. +- 동일한 nonce를 `connect.params.device.nonce`에 보내세요. +- 권장 서명 페이로드는 `v3`이며, 이는 device/client/role/scopes/token/nonce 필드에 더해 `platform`과 `deviceFamily`를 바인딩합니다. +- 레거시 `v2` 서명은 호환성을 위해 계속 허용되지만, 페어링된 디바이스 메타데이터 고정은 재연결 시에도 계속 명령 정책을 제어합니다. -## TLS + 핀닝 +## TLS + 핀 고정 - WS 연결에 TLS를 지원합니다. -- 클라이언트는 선택적으로 gateway 인증서 fingerprint를 핀할 수 있습니다(`gateway.tls` - 설정과 `gateway.remote.tlsFingerprint` 또는 CLI `--tls-fingerprint` 참조). +- 클라이언트는 선택적으로 게이트웨이 인증서 지문을 핀 고정할 수 있습니다(`gateway.tls` 설정과 `gateway.remote.tlsFingerprint` 또는 CLI `--tls-fingerprint` 참조). ## 범위 -이 프로토콜은 **전체 gateway API**(status, channels, models, chat, -agent, sessions, nodes, approvals 등)를 노출합니다. 정확한 표면은 -`src/gateway/protocol/schema.ts`의 TypeBox 스키마로 정의됩니다. +이 프로토콜은 **전체 게이트웨이 API**(status, channels, models, chat, agent, sessions, nodes, approvals 등)를 노출합니다. 정확한 표면은 `src/gateway/protocol/schema.ts`의 TypeBox 스키마로 정의됩니다. diff --git a/docs/ko/gateway/security/index.md b/docs/ko/gateway/security/index.md index 6064c08c7..3d21d1dcd 100644 --- a/docs/ko/gateway/security/index.md +++ b/docs/ko/gateway/security/index.md @@ -1,13 +1,13 @@ --- read_when: - - 접근 범위나 자동화를 넓히는 기능을 추가할 때 -summary: 셸 접근 권한이 있는 AI gateway 실행을 위한 보안 고려 사항 및 위협 모델 + - 접근 권한이나 자동화를 확장하는 기능 추가 +summary: 셸 접근 권한이 있는 AI gateway를 실행할 때의 보안 고려 사항 및 위협 모델 title: 보안 x-i18n: - generated_at: "2026-04-05T12:47:06Z" + generated_at: "2026-04-11T02:44:58Z" model: gpt-5.4 provider: openai - source_hash: 223deb798774952f8d0208e761e163708a322045cf4ca3df181689442ef6fcfb + source_hash: 770407f64b2ce27221ebd9756b2f8490a249c416064186e64edb663526f9d6b5 source_path: gateway/security/index.md workflow: 15 --- @@ -16,28 +16,28 @@ x-i18n: **개인 비서 신뢰 모델:** 이 가이드는 gateway당 하나의 신뢰된 운영자 경계(단일 사용자/개인 비서 모델)를 가정합니다. -OpenClaw는 하나의 에이전트/gateway를 여러 적대적 사용자가 공유하는 환경에서 적대적인 멀티테넌트 보안 경계가 **아닙니다**. -혼합 신뢰 또는 적대적 사용자 운영이 필요하다면 신뢰 경계를 분리하세요(별도의 gateway + 자격 증명, 가능하면 별도의 OS 사용자/호스트도 권장). +OpenClaw는 하나의 에이전트/gateway를 여러 적대적 사용자가 공유하는 환경에서의 적대적 멀티테넌트 보안 경계가 **아닙니다**. +혼합 신뢰 또는 적대적 사용자 환경이 필요하다면 신뢰 경계를 분리하세요(별도의 gateway + 자격 증명, 가능하면 별도의 OS 사용자/호스트). -**이 페이지에서 다루는 내용:** [신뢰 모델](#scope-first-personal-assistant-security-model) | [빠른 감사](#quick-check-openclaw-security-audit) | [강화된 기본 설정](#hardened-baseline-in-60-seconds) | [DM 접근 모델](#dm-access-model-pairing--allowlist--open--disabled) | [구성 강화](#configuration-hardening-examples) | [사고 대응](#incident-response) +**이 페이지에서 다루는 내용:** [신뢰 모델](#scope-first-personal-assistant-security-model) | [빠른 감사](#quick-check-openclaw-security-audit) | [강화된 기본 구성](#hardened-baseline-in-60-seconds) | [DM 접근 모델](#dm-access-model-pairing-allowlist-open-disabled) | [설정 강화](#configuration-hardening-examples) | [사고 대응](#incident-response) -## 먼저 범위를 정하기: 개인 비서 보안 모델 +## 먼저 범위를 정하세요: 개인 비서 보안 모델 -OpenClaw 보안 가이드는 **개인 비서** 배포를 가정합니다. 즉, 잠재적으로 여러 에이전트가 있더라도 하나의 신뢰된 운영자 경계만 있습니다. +OpenClaw의 보안 가이드는 **개인 비서** 배포를 가정합니다. 즉, 잠재적으로 여러 에이전트가 있더라도 신뢰된 운영자 경계는 하나입니다. -- 지원되는 보안 상태: gateway당 하나의 사용자/신뢰 경계(각 경계마다 별도 OS 사용자/호스트/VPS 권장) -- 지원되지 않는 보안 경계: 상호 신뢰하지 않거나 적대적인 사용자가 하나의 공유 gateway/에이전트를 함께 사용하는 경우 -- 적대적 사용자 격리가 필요하다면 신뢰 경계별로 분리하세요(별도의 gateway + 자격 증명, 이상적으로는 별도의 OS 사용자/호스트) -- 여러 신뢰하지 않는 사용자가 하나의 도구 활성화 에이전트에 메시지를 보낼 수 있다면, 그 사용자들은 해당 에이전트에 대해 동일한 위임된 도구 권한을 공유하는 것으로 간주해야 합니다. +- 지원되는 보안 상태: gateway당 하나의 사용자/신뢰 경계(기본적으로 경계당 하나의 OS 사용자/호스트/VPS 권장) +- 지원되지 않는 보안 경계: 상호 신뢰하지 않거나 적대적인 사용자가 하나의 gateway/agent를 공유하는 경우 +- 적대적 사용자 격리가 필요하다면 신뢰 경계별로 분리하세요(별도의 gateway + 자격 증명, 가능하면 별도의 OS 사용자/호스트까지 분리). +- 여러 비신뢰 사용자가 하나의 도구 사용 가능 에이전트에 메시지를 보낼 수 있다면, 그들은 해당 에이전트에 대해 동일한 위임된 도구 권한을 공유하는 것으로 간주해야 합니다. -이 페이지는 **그 모델 내부에서**의 강화를 설명합니다. 하나의 공유 gateway에서 적대적인 멀티테넌트 격리를 주장하지는 않습니다. +이 페이지는 **이 모델 내에서** 하드닝하는 방법을 설명합니다. 하나의 공유 gateway에서 적대적 멀티테넌트 격리를 보장한다고 주장하지 않습니다. -## 빠른 확인: `openclaw security audit` +## 빠른 점검: `openclaw security audit` -참고: [정형 검증(보안 모델)](/security/formal-verification) +참고: [Formal Verification (Security Models)](/ko/security/formal-verification) -특히 구성을 변경하거나 네트워크 표면을 노출한 후에는 정기적으로 실행하세요: +정기적으로 실행하세요(특히 설정을 변경했거나 네트워크 노출 범위를 넓힌 후): ```bash openclaw security audit @@ -46,106 +46,103 @@ openclaw security audit --fix openclaw security audit --json ``` -`security audit --fix`는 의도적으로 범위가 좁습니다. 일반적인 개방형 그룹 -정책을 allowlist로 바꾸고, `logging.redactSensitive: "tools"`를 복원하며, -상태/구성/include 파일 권한을 강화하고, Windows에서는 POSIX `chmod` 대신 -Windows ACL 재설정을 사용합니다. +`security audit --fix`는 의도적으로 범위를 좁게 유지합니다. 일반적으로 열려 있는 그룹 정책을 allowlist로 전환하고, `logging.redactSensitive: "tools"`를 복원하며, 상태/설정/include 파일 권한을 강화하고, Windows에서는 POSIX `chmod` 대신 Windows ACL 재설정을 사용합니다. -일반적인 실수 항목(Gateway 인증 노출, 브라우저 제어 노출, elevated allowlist, 파일시스템 권한, 느슨한 exec 승인, 개방 채널 도구 노출)을 표시합니다. +이 감사는 흔한 실수들(Gateway 인증 노출, 브라우저 제어 노출, 과도한 allowlist, 파일시스템 권한, 느슨한 exec 승인, 개방된 채널 도구 노출)을 표시합니다. -OpenClaw는 제품이자 실험이기도 합니다. 실제 메시징 표면과 실제 도구에 최전선 모델 동작을 연결하고 있기 때문입니다. **“완벽하게 안전한” 설정은 없습니다.** 목표는 다음을 의식적으로 설계하는 것입니다: +OpenClaw는 제품이면서 실험이기도 합니다. 실제 메시징 표면과 실제 도구에 최전선 모델 동작을 연결하고 있기 때문입니다. **“완벽하게 안전한” 설정은 없습니다.** 목표는 다음을 의도적으로 결정하는 것입니다. - 누가 봇과 대화할 수 있는가 -- 봇이 어디에서 행동할 수 있는가 +- 봇이 어디에서 동작할 수 있는가 - 봇이 무엇에 접근할 수 있는가 -작동하는 가장 작은 접근 권한으로 시작하고, 확신이 생길수록 점진적으로 넓히세요. +작동하는 가장 작은 접근 권한에서 시작하고, 확신이 생길수록 점진적으로 넓히세요. ### 배포 및 호스트 신뢰 -OpenClaw는 호스트와 구성 경계가 신뢰된다고 가정합니다: +OpenClaw는 호스트와 설정 경계가 신뢰된다고 가정합니다. -- 누군가가 Gateway 호스트 상태/구성(`~/.openclaw`와 `openclaw.json` 포함)을 수정할 수 있다면, 그 사람은 신뢰된 운영자로 간주해야 합니다. -- 하나의 Gateway를 여러 상호 신뢰하지 않거나 적대적인 운영자가 함께 실행하는 것은 **권장되는 설정이 아닙니다**. -- 혼합 신뢰 팀의 경우 별도의 gateway로 신뢰 경계를 나누세요(최소한 별도의 OS 사용자/호스트 권장). -- 권장 기본값: 머신/호스트(또는 VPS)당 한 명의 사용자, 그 사용자용 gateway 하나, 그리고 그 gateway 안의 하나 이상의 에이전트. +- 누군가가 Gateway 호스트 상태/설정(`openclaw.json`을 포함한 `~/.openclaw`)을 수정할 수 있다면, 그 사람은 신뢰된 운영자로 간주해야 합니다. +- 상호 신뢰하지 않거나 적대적인 여러 운영자를 위해 하나의 Gateway를 실행하는 것은 **권장되는 설정이 아닙니다**. +- 혼합 신뢰 팀의 경우, 별도의 gateways(또는 최소한 별도의 OS 사용자/호스트)로 신뢰 경계를 분리하세요. +- 권장 기본값: 머신/호스트(또는 VPS)당 한 명의 사용자, 그 사용자를 위한 하나의 gateway, 그리고 그 gateway 안의 하나 이상의 에이전트. - 하나의 Gateway 인스턴스 안에서 인증된 운영자 접근은 사용자별 테넌트 역할이 아니라 신뢰된 제어 평면 역할입니다. -- 세션 식별자(`sessionKey`, 세션 ID, 라벨)는 권한 토큰이 아니라 라우팅 선택자입니다. -- 여러 사람이 하나의 도구 활성화 에이전트에 메시지를 보낼 수 있다면, 그들 각각은 동일한 권한 집합을 조작할 수 있습니다. 사용자별 세션/메모리 격리는 프라이버시에 도움이 되지만, 공유 에이전트를 사용자별 호스트 권한 경계로 바꾸지는 못합니다. +- 세션 식별자(`sessionKey`, 세션 ID, 라벨)는 인증 토큰이 아니라 라우팅 선택자입니다. +- 여러 사람이 하나의 도구 사용 가능 에이전트에 메시지를 보낼 수 있다면, 그들 각자는 동일한 권한 집합을 유도할 수 있습니다. 사용자별 세션/메모리 격리는 프라이버시에는 도움이 되지만, 공유 에이전트를 사용자별 호스트 권한 모델로 바꾸지는 않습니다. ### 공유 Slack 워크스페이스: 실제 위험 -“Slack의 الجميع가 봇에 메시지를 보낼 수 있다”면, 핵심 위험은 위임된 도구 권한입니다: +“Slack의 모두가 봇에게 메시지를 보낼 수 있다”면, 핵심 위험은 위임된 도구 권한입니다. -- 허용된 모든 발신자는 에이전트 정책 범위 내에서 도구 호출(`exec`, 브라우저, 네트워크/파일 도구)을 유도할 수 있습니다. -- 한 발신자의 프롬프트/콘텐츠 인젝션이 공유 상태, 장치 또는 출력에 영향을 미치는 작업을 유발할 수 있습니다. -- 하나의 공유 에이전트가 민감한 자격 증명/파일을 가지고 있다면, 허용된 모든 발신자가 도구 사용을 통해 유출을 유도할 가능성이 있습니다. +- 허용된 발신자는 누구나 에이전트 정책 범위 안에서 도구 호출(`exec`, 브라우저, 네트워크/파일 도구)을 유도할 수 있습니다. +- 한 발신자의 프롬프트/콘텐츠 주입으로 공유 상태, 디바이스 또는 출력에 영향을 주는 작업이 실행될 수 있습니다. +- 하나의 공유 에이전트에 민감한 자격 증명/파일이 있다면, 허용된 발신자는 누구나 도구 사용을 통해 잠재적으로 이를 유출시킬 수 있습니다. -팀 워크플로에는 최소 도구만 가진 별도의 에이전트/gateway를 사용하고, 개인 데이터 에이전트는 비공개로 유지하세요. +팀 워크플로에는 최소한의 도구만 가진 별도의 에이전트/gateway를 사용하고, 개인 데이터 에이전트는 비공개로 유지하세요. ### 회사 공유 에이전트: 허용 가능한 패턴 -해당 에이전트를 사용하는 모든 사람이 같은 신뢰 경계(예: 하나의 회사 팀)에 있고, 에이전트가 엄격하게 업무 범위로 제한되어 있다면 허용 가능합니다. +이 패턴은 해당 에이전트를 사용하는 모두가 같은 신뢰 경계 안에 있고(예: 하나의 회사 팀), 에이전트가 엄격히 업무 범위로 제한되어 있을 때 허용 가능합니다. - 전용 머신/VM/컨테이너에서 실행하세요. -- 전용 OS 사용자 + 전용 브라우저/프로필/계정을 해당 런타임에 사용하세요. -- 그 런타임을 개인 Apple/Google 계정이나 개인 비밀번호 관리자/브라우저 프로필에 로그인시키지 마세요. +- 해당 런타임을 위해 전용 OS 사용자 + 전용 브라우저/프로필/계정을 사용하세요. +- 그 런타임에 개인 Apple/Google 계정이나 개인 비밀번호 관리자/브라우저 프로필로 로그인하지 마세요. -개인 신원과 회사 신원을 같은 런타임에서 혼합하면 분리가 무너지고 개인 데이터 노출 위험이 증가합니다. +동일한 런타임에서 개인 신원과 회사 신원을 섞으면 분리가 무너지고 개인 데이터 노출 위험이 커집니다. ## Gateway와 node 신뢰 개념 -Gateway와 node는 서로 다른 역할을 가진 하나의 운영자 신뢰 도메인으로 취급하세요: +Gateway와 node를 역할이 다른 하나의 운영자 신뢰 도메인으로 취급하세요. -- **Gateway**는 제어 평면 및 정책 표면입니다(`gateway.auth`, 도구 정책, 라우팅). -- **Node**는 해당 Gateway에 페어링된 원격 실행 표면입니다(명령, 장치 동작, 호스트 로컬 기능). +- **Gateway**는 제어 평면이자 정책 표면입니다(`gateway.auth`, 도구 정책, 라우팅). +- **Node**는 해당 Gateway와 페어링된 원격 실행 표면입니다(명령, 디바이스 작업, 호스트 로컬 기능). - Gateway에 인증된 호출자는 Gateway 범위에서 신뢰됩니다. 페어링 후 node 작업은 해당 node에서의 신뢰된 운영자 작업입니다. -- `sessionKey`는 라우팅/컨텍스트 선택용이지 사용자별 인증이 아닙니다. -- Exec 승인(allowlist + ask)은 운영자 의도에 대한 가드레일이지 적대적 멀티테넌트 격리가 아닙니다. -- 신뢰된 단일 운영자 설정을 위한 OpenClaw의 제품 기본값은 `gateway`/`node`에서 호스트 exec를 승인 프롬프트 없이 허용하는 것입니다(`security="full"`, `ask="off"`, 별도로 강화하지 않는 한). 이는 의도된 UX 기본값이며, 그 자체로 취약점이 아닙니다. -- Exec 승인은 정확한 요청 컨텍스트와 best-effort 직접 로컬 파일 피연산자에 바인딩됩니다. 모든 런타임/인터프리터 로더 경로를 의미론적으로 모델링하지는 않습니다. 강한 경계가 필요하면 샌드박싱과 호스트 격리를 사용하세요. +- `sessionKey`는 사용자별 인증이 아니라 라우팅/컨텍스트 선택입니다. +- Exec 승인(allowlist + ask)은 적대적 멀티테넌트 격리가 아니라 운영자 의도를 위한 가드레일입니다. +- 신뢰된 단일 운영자 설정에서 OpenClaw의 제품 기본값은 `gateway`/`node`의 호스트 exec를 승인 프롬프트 없이 허용하는 것입니다(`security="full"`, 별도로 강화하지 않으면 `ask="off"`). 이 기본값은 의도된 UX이며, 그 자체로 취약점은 아닙니다. +- Exec 승인은 정확한 요청 컨텍스트와 가능한 범위의 직접 로컬 파일 피연산자에 바인딩되며, 모든 런타임/인터프리터 로더 경로를 의미적으로 모델링하지는 않습니다. 강한 경계가 필요하면 샌드박싱과 호스트 격리를 사용하세요. -적대적 사용자 격리가 필요하면 OS 사용자/호스트 단위로 신뢰 경계를 분리하고 별도의 gateway를 실행하세요. +적대적 사용자 격리가 필요하다면 OS 사용자/호스트 단위로 신뢰 경계를 분리하고 별도의 gateways를 실행하세요. ## 신뢰 경계 매트릭스 -위험을 분류할 때 빠르게 참고할 수 있는 모델입니다: +위험을 분류할 때 사용할 빠른 모델입니다. -| 경계 또는 제어 | 의미 | 흔한 오해 | +| 경계 또는 제어 | 의미 | 흔한 오해 | | --------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------- | -| `gateway.auth` (token/password/trusted-proxy/device auth) | gateway API에 대한 호출자 인증 | “보안이 되려면 모든 프레임에 사용자별 메시지 서명이 필요하다” | -| `sessionKey` | 컨텍스트/세션 선택용 라우팅 키 | “세션 키는 사용자 인증 경계다” | -| 프롬프트/콘텐츠 가드레일 | 모델 악용 위험 감소 | “프롬프트 인젝션만으로 인증 우회가 증명된다” | -| `canvas.eval` / browser evaluate | 활성화 시 의도된 운영자 기능 | “모든 JS eval primitive는 이 신뢰 모델에서 자동으로 취약점이다” | -| 로컬 TUI `!` 셸 | 명시적인 운영자 트리거 로컬 실행 | “로컬 셸 편의 명령은 원격 인젝션이다” | -| Node 페어링 및 node 명령 | 페어링된 장치에 대한 운영자 수준 원격 실행 | “원격 장치 제어는 기본적으로 신뢰되지 않는 사용자 접근으로 취급해야 한다” | +| `gateway.auth` (token/password/trusted-proxy/device auth) | gateway API 호출자를 인증함 | "안전하려면 모든 프레임에 대해 메시지별 서명이 필요하다" | +| `sessionKey` | 컨텍스트/세션 선택을 위한 라우팅 키 | "세션 키는 사용자 인증 경계다" | +| 프롬프트/콘텐츠 가드레일 | 모델 오용 위험을 줄임 | "프롬프트 주입만으로도 인증 우회가 증명된다" | +| `canvas.eval` / browser evaluate | 활성화 시 의도된 운영자 기능 | "모든 JS eval 원시 기능은 이 신뢰 모델에서 자동으로 취약점이다" | +| 로컬 TUI `!` shell | 명시적으로 운영자가 트리거하는 로컬 실행 | "로컬 셸 편의 명령은 원격 주입이다" | +| Node 페어링 및 node 명령 | 페어링된 디바이스에서의 운영자 수준 원격 실행 | "원격 디바이스 제어는 기본적으로 비신뢰 사용자 접근으로 간주해야 한다" | ## 설계상 취약점이 아닌 것들 -다음 패턴은 자주 보고되지만, 실제 경계 우회가 입증되지 않으면 보통 조치 없음으로 종료됩니다: +다음 패턴은 자주 보고되지만, 실제 경계 우회가 입증되지 않으면 보통 조치 없이 종료됩니다. -- 정책/auth/sandbox 우회 없이 프롬프트 인젝션만으로 이루어진 체인 -- 하나의 공유 호스트/구성에서 적대적 멀티테넌트 운영을 가정하는 주장 -- 공유 gateway 설정에서 정상적인 운영자 읽기 경로(예: `sessions.list`/`sessions.preview`/`chat.history`)를 IDOR로 분류하는 주장 -- localhost 전용 배포에서의 지적(예: loopback 전용 gateway에 대한 HSTS) -- 이 저장소에 존재하지 않는 인바운드 경로에 대한 Discord inbound webhook 서명 관련 보고 -- node pairing 메타데이터를 `system.run`에 대한 숨겨진 두 번째 per-command 승인 계층으로 보는 보고. 실제 실행 경계는 gateway의 전역 node 명령 정책 + node 자체의 exec 승인입니다. -- `sessionKey`를 인증 토큰으로 간주하는 “per-user authorization 누락” 지적 +- 정책/인증/샌드박스 우회 없이 프롬프트 주입만으로 이어지는 체인 +- 하나의 공유 호스트/설정에서 적대적 멀티테넌트 운영을 가정하는 주장 +- 공유 gateway 설정에서 일반적인 운영자 읽기 경로 접근(예: `sessions.list`/`sessions.preview`/`chat.history`)을 IDOR로 분류하는 주장 +- localhost 전용 배포 관련 지적(예: loopback 전용 gateway에서의 HSTS) +- 이 저장소에 존재하지 않는 수신 경로에 대한 Discord 인바운드 webhook 서명 관련 지적 +- `system.run`에 대해 node 페어링 메타데이터를 숨겨진 두 번째 명령별 승인 계층으로 간주하는 보고. 실제 실행 경계는 여전히 gateway의 전역 node 명령 정책과 node 자체의 exec 승인입니다. +- `sessionKey`를 인증 토큰으로 간주하는 “사용자별 권한 부재” 지적 ## 연구자 사전 점검 체크리스트 -GHSA를 열기 전에 다음을 모두 확인하세요: +GHSA를 열기 전에 다음을 모두 확인하세요. 1. 재현이 최신 `main` 또는 최신 릴리스에서 여전히 동작한다. -2. 보고서에 정확한 코드 경로(`file`, 함수, 라인 범위)와 테스트한 버전/커밋이 포함되어 있다. -3. 영향이 문서화된 신뢰 경계를 넘는다(프롬프트 인젝션만이 아님). +2. 보고서에 정확한 코드 경로(`file`, 함수, 줄 범위)와 테스트한 버전/커밋이 포함되어 있다. +3. 영향이 문서화된 신뢰 경계를 넘는다(단순 프롬프트 주입만이 아님). 4. 주장이 [Out of Scope](https://github.com/openclaw/openclaw/blob/main/SECURITY.md#out-of-scope)에 포함되어 있지 않다. -5. 기존 advisory에 중복이 없는지 확인했다(해당 시 정식 GHSA 재사용). -6. 배포 가정이 명확하다(loopback/local vs 노출, 신뢰된 vs 신뢰되지 않는 운영자). +5. 기존 권고문에서 중복 여부를 확인했다(해당되는 경우 정식 GHSA 재사용). +6. 배포 가정이 명시되어 있다(loopback/local vs exposed, trusted vs untrusted operators). -## 60초 만에 강화된 기본 설정 +## 60초 안에 적용하는 강화된 기본 구성 -먼저 이 기본 설정을 사용하고, 이후 신뢰된 에이전트별로 도구를 선택적으로 다시 활성화하세요: +먼저 이 기본 구성을 사용하고, 이후 신뢰된 에이전트별로 필요한 도구만 선택적으로 다시 활성화하세요. ```json5 { @@ -170,207 +167,209 @@ GHSA를 열기 전에 다음을 모두 확인하세요: } ``` -이렇게 하면 Gateway를 local 전용으로 유지하고, DM을 격리하며, 기본적으로 제어 평면/런타임 도구를 비활성화합니다. +이 설정은 Gateway를 로컬 전용으로 유지하고, DM을 격리하며, 제어 평면/런타임 도구를 기본적으로 비활성화합니다. -## 공유 inbox 빠른 규칙 +## 공유 받은편지함 빠른 규칙 -둘 이상의 사람이 봇에 DM을 보낼 수 있다면: +한 명보다 많은 사람이 봇에게 DM을 보낼 수 있다면: -- `session.dmScope: "per-channel-peer"`로 설정하세요(멀티 계정 채널이라면 `"per-account-channel-peer"`). +- `session.dmScope: "per-channel-peer"`(또는 다중 계정 채널의 경우 `"per-account-channel-peer"`)를 설정하세요. - `dmPolicy: "pairing"` 또는 엄격한 allowlist를 유지하세요. -- 공유 DM과 광범위한 도구 접근을 절대 결합하지 마세요. -- 이는 협업/공유 inbox를 강화해 주지만, 사용자가 호스트/구성 쓰기 접근을 공유하는 경우 적대적 공동 테넌트 격리를 위해 설계된 것은 아닙니다. +- 공유 DM과 광범위한 도구 접근을 절대 함께 사용하지 마세요. +- 이는 협업/공유 받은편지함을 강화하지만, 사용자가 호스트/설정 쓰기 권한을 공유하는 경우 적대적 공동 테넌트 격리를 위한 설계는 아닙니다. ## 컨텍스트 가시성 모델 -OpenClaw는 두 가지 개념을 분리합니다: +OpenClaw는 두 가지 개념을 분리합니다. -- **트리거 권한**: 누가 에이전트를 트리거할 수 있는가(`dmPolicy`, `groupPolicy`, allowlist, mention gate) -- **컨텍스트 가시성**: 어떤 보조 컨텍스트가 모델 입력에 주입되는가(답장 본문, 인용 텍스트, 스레드 기록, 전달 메타데이터) +- **트리거 권한 부여**: 누가 에이전트를 트리거할 수 있는가(`dmPolicy`, `groupPolicy`, allowlist, 멘션 게이트) +- **컨텍스트 가시성**: 어떤 보조 컨텍스트가 모델 입력에 주입되는가(답장 본문, 인용 텍스트, 스레드 기록, 전달된 메타데이터) -Allowlists는 트리거와 명령 권한을 제어합니다. `contextVisibility` 설정은 보조 컨텍스트(인용 답장, 스레드 루트, 가져온 기록)를 활성 allowlist 검사에 따라 어떻게 필터링할지 제어합니다: +Allowlist는 트리거와 명령 권한을 제어합니다. `contextVisibility` 설정은 보조 컨텍스트(인용된 답장, 스레드 루트, 가져온 기록)가 어떻게 필터링되는지를 제어합니다. -- `contextVisibility: "all"`(기본값): 보조 컨텍스트를 받은 그대로 유지 -- `contextVisibility: "allowlist"`: 활성 allowlist 검사로 허용된 발신자만 보조 컨텍스트에 포함 -- `contextVisibility: "allowlist_quote"`: `allowlist`처럼 동작하지만 하나의 명시적 인용 답장은 유지 +- `contextVisibility: "all"`(기본값)은 수신된 보조 컨텍스트를 그대로 유지합니다. +- `contextVisibility: "allowlist"`는 활성 allowlist 검사로 허용된 발신자로 보조 컨텍스트를 필터링합니다. +- `contextVisibility: "allowlist_quote"`는 `allowlist`처럼 동작하지만, 명시적으로 인용된 답장 하나는 계속 유지합니다. -`contextVisibility`는 채널별 또는 룸/대화별로 설정하세요. 설정 세부 사항은 [Group Chats](/channels/groups#context-visibility)를 참조하세요. +`contextVisibility`는 채널별 또는 방/대화별로 설정할 수 있습니다. 설정 방법은 [Group Chats](/ko/channels/groups#context-visibility-and-allowlists)를 참고하세요. -Advisory 분류 가이드: +권고문 분류 가이드: -- “모델이 allowlist에 없는 발신자의 인용 또는 기록 텍스트를 볼 수 있다”는 주장만으로는 인증 또는 sandbox 경계 우회가 아니라 `contextVisibility`로 다룰 수 있는 강화 이슈입니다. -- 보안 영향이 있다고 보려면, 보고서는 여전히 인증, 정책, sandbox, 승인 또는 다른 문서화된 경계 우회를 입증해야 합니다. +- “모델이 allowlist에 없는 발신자의 인용 또는 과거 텍스트를 볼 수 있다”는 것만 보여주는 주장은 하드닝 이슈이며, `contextVisibility`로 대응할 수 있습니다. 그 자체만으로 인증 또는 샌드박스 경계 우회는 아닙니다. +- 보안 영향이 있다고 보려면, 보고서는 여전히 신뢰 경계 우회(인증, 정책, 샌드박스, 승인 또는 다른 문서화된 경계)를 입증해야 합니다. -## 감사가 확인하는 항목(상위 수준) +## 감사가 확인하는 항목(개요) - **인바운드 접근**(DM 정책, 그룹 정책, allowlist): 낯선 사람이 봇을 트리거할 수 있는가? -- **도구 폭발 반경**(elevated 도구 + 개방된 방): 프롬프트 인젝션이 셸/파일/네트워크 작업으로 이어질 수 있는가? -- **Exec 승인 드리프트**(`security=full`, `autoAllowSkills`, `strictInlineEval` 없는 인터프리터 allowlist): 호스트 exec 가드레일이 여전히 의도대로 작동하는가? - - `security="full"`은 광범위한 상태 경고이지 버그의 증거가 아닙니다. 이는 신뢰된 개인 비서 설정을 위한 선택된 기본값이며, 위협 모델에서 승인 또는 allowlist 가드레일이 필요할 때만 강화하세요. -- **네트워크 노출**(Gateway bind/auth, Tailscale Serve/Funnel, 약하거나 짧은 인증 토큰) -- **브라우저 제어 노출**(원격 node, relay 포트, 원격 CDP 엔드포인트) -- **로컬 디스크 위생**(권한, 심볼릭 링크, config include, “동기화 폴더” 경로) -- **Plugins**(명시적 allowlist 없이 확장이 존재) -- **정책 드리프트/오구성**(sandbox Docker 설정이 있지만 sandbox mode가 꺼져 있음; 일치가 정확한 명령 이름에만 적용되고 셸 텍스트는 보지 않기 때문에 `gateway.nodes.denyCommands` 패턴이 효과가 없음(예: `system.run`); 위험한 `gateway.nodes.allowCommands` 항목; 전역 `tools.profile="minimal"`이 에이전트별 profile로 재정의됨; 확장 plugin 도구가 느슨한 도구 정책 아래 도달 가능) -- **런타임 기대 드리프트**(예: 암묵적 exec가 여전히 `sandbox`라고 가정하지만 `tools.exec.host` 기본값이 이제 `auto`인 경우, 또는 sandbox mode가 꺼진 상태에서 `tools.exec.host="sandbox"`를 명시적으로 설정한 경우) -- **모델 위생**(구성된 모델이 레거시처럼 보일 경우 경고, 강제 차단은 아님) +- **도구 영향 반경**(권한 상승 도구 + 개방된 방): 프롬프트 주입이 셸/파일/네트워크 작업으로 이어질 수 있는가? +- **Exec 승인 드리프트**(`security=full`, `autoAllowSkills`, `strictInlineEval` 없는 인터프리터 allowlist): 호스트 exec 가드레일이 여전히 의도한 대로 동작하고 있는가? + - `security="full"`은 광범위한 보안 상태 경고이지, 버그의 증거는 아닙니다. 이는 신뢰된 개인 비서 설정을 위해 선택된 기본값이며, 위협 모델에 승인 또는 allowlist 가드레일이 필요할 때만 강화하세요. +- **네트워크 노출**(Gateway bind/auth, Tailscale Serve/Funnel, 약하거나 짧은 인증 토큰). +- **브라우저 제어 노출**(원격 nodes, relay 포트, 원격 CDP 엔드포인트). +- **로컬 디스크 위생**(권한, 심볼릭 링크, config include, “동기화된 폴더” 경로). +- **Plugins**(명시적인 allowlist 없이 확장이 존재함). +- **정책 드리프트/오설정**(sandbox docker 설정은 되어 있지만 sandbox 모드는 꺼져 있음, `gateway.nodes.denyCommands` 패턴이 명령 이름만 정확히 매칭하기 때문에 효과가 없음(예: `system.run`) 그리고 셸 텍스트는 검사하지 않음, 위험한 `gateway.nodes.allowCommands` 항목, 전역 `tools.profile="minimal"`이 에이전트별 프로필로 재정의됨, 느슨한 도구 정책 아래에서 extension plugin 도구에 접근 가능함). +- **런타임 기대 드리프트**(예: `tools.exec.host` 기본값이 이제 `auto`인데도 암시적 exec가 여전히 `sandbox`를 의미한다고 가정하거나, sandbox 모드가 꺼져 있는데도 `tools.exec.host="sandbox"`를 명시적으로 설정함). +- **모델 위생**(설정된 모델이 레거시처럼 보일 때 경고, 강제 차단은 아님). -`--deep`를 사용하면 OpenClaw는 best-effort 실시간 Gateway 프로브도 시도합니다. +`--deep`으로 실행하면 OpenClaw는 최선의 범위에서 실시간 Gateway probe도 시도합니다. ## 자격 증명 저장소 맵 -접근 감사를 하거나 무엇을 백업할지 결정할 때 참고하세요: +접근 권한을 감사하거나 무엇을 백업할지 결정할 때 이 목록을 사용하세요. - **WhatsApp**: `~/.openclaw/credentials/whatsapp//creds.json` -- **Telegram bot token**: config/env 또는 `channels.telegram.tokenFile`(일반 파일만 허용, 심볼릭 링크 거부) +- **Telegram bot token**: config/env 또는 `channels.telegram.tokenFile`(일반 파일만 허용, 심볼릭 링크는 거부됨) - **Discord bot token**: config/env 또는 SecretRef(env/file/exec provider) -- **Slack 토큰**: config/env (`channels.slack.*`) +- **Slack tokens**: config/env (`channels.slack.*`) - **페어링 allowlist**: - `~/.openclaw/credentials/-allowFrom.json`(기본 계정) - - `~/.openclaw/credentials/--allowFrom.json`(비기본 계정) + - `~/.openclaw/credentials/--allowFrom.json`(기본이 아닌 계정) - **모델 인증 프로필**: `~/.openclaw/agents//agent/auth-profiles.json` -- **파일 기반 비밀 페이로드(선택 사항)**: `~/.openclaw/secrets.json` +- **파일 기반 시크릿 payload(선택 사항)**: `~/.openclaw/secrets.json` - **레거시 OAuth 가져오기**: `~/.openclaw/credentials/oauth.json` ## 보안 감사 체크리스트 -감사 결과에 항목이 표시되면 다음 우선순위로 처리하세요: +감사에서 결과가 출력되면, 다음 우선순위대로 처리하세요. -1. **“open” + 도구 활성화 조합**: 먼저 DM/그룹을 잠그고(페어링/allowlist), 그다음 도구 정책/sandboxing을 강화하세요. -2. **공용 네트워크 노출**(LAN bind, Funnel, 인증 없음): 즉시 수정하세요. -3. **브라우저 제어 원격 노출**: 운영자 접근처럼 취급하세요(tailnet 전용, 의도적 node 페어링, 공용 노출 회피). -4. **권한**: 상태/구성/자격 증명/인증 파일이 그룹/전체 읽기 가능하지 않도록 하세요. -5. **Plugins/확장**: 명시적으로 신뢰하는 것만 로드하세요. -6. **모델 선택**: 도구가 있는 봇에는 최신, 지시 강화형 모델을 우선하세요. +1. **“open” 상태이면서 도구가 활성화된 모든 항목**: 먼저 DM/그룹을 잠그고(페어링/allowlist), 그다음 도구 정책/샌드박싱을 강화하세요. +2. **공용 네트워크 노출**(LAN bind, Funnel, 인증 누락): 즉시 수정하세요. +3. **브라우저 제어의 원격 노출**: 운영자 접근처럼 취급하세요(tailnet 전용, node는 신중히 페어링, 공개 노출 피하기). +4. **권한**: 상태/설정/자격 증명/인증 파일이 그룹/전체 사용자에게 읽히지 않도록 하세요. +5. **Plugins/extensions**: 명시적으로 신뢰하는 것만 로드하세요. +6. **모델 선택**: 도구를 사용하는 봇에는 최신의 instruction-hardened 모델을 우선 사용하세요. ## 보안 감사 용어집 -실제 배포에서 가장 자주 보게 되는 고신호 `checkId` 값들입니다(전체 목록은 아님): +실제 배포에서 가장 자주 보게 될 가능성이 높은 고신호 `checkId` 값들입니다(전체 목록은 아님): -| `checkId` | 심각도 | 중요한 이유 | 주요 수정 키/경로 | 자동 수정 | +| `checkId` | 심각도 | 중요한 이유 | 주요 수정 키/경로 | 자동 수정 | | ------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | -------- | -| `fs.state_dir.perms_world_writable` | critical | 다른 사용자/프로세스가 전체 OpenClaw 상태를 수정할 수 있음 | `~/.openclaw`의 파일시스템 권한 | yes | -| `fs.state_dir.perms_group_writable` | warn | 그룹 사용자가 전체 OpenClaw 상태를 수정할 수 있음 | `~/.openclaw`의 파일시스템 권한 | yes | -| `fs.state_dir.perms_readable` | warn | 상태 디렉터리를 다른 사람이 읽을 수 있음 | `~/.openclaw`의 파일시스템 권한 | yes | -| `fs.state_dir.symlink` | warn | 상태 디렉터리 대상이 다른 신뢰 경계가 됨 | 상태 디렉터리 파일시스템 레이아웃 | no | -| `fs.config.perms_writable` | critical | 다른 사람이 인증/도구 정책/구성을 변경할 수 있음 | `~/.openclaw/openclaw.json`의 파일시스템 권한 | yes | -| `fs.config.symlink` | warn | 구성 대상이 다른 신뢰 경계가 됨 | 구성 파일 파일시스템 레이아웃 | no | -| `fs.config.perms_group_readable` | warn | 그룹 사용자가 구성 토큰/설정을 읽을 수 있음 | 구성 파일 파일시스템 권한 | yes | -| `fs.config.perms_world_readable` | critical | 구성에서 토큰/설정이 노출될 수 있음 | 구성 파일 파일시스템 권한 | yes | -| `fs.config_include.perms_writable` | critical | 구성 include 파일을 다른 사람이 수정할 수 있음 | `openclaw.json`에서 참조하는 include 파일 권한 | yes | -| `fs.config_include.perms_group_readable` | warn | 그룹 사용자가 포함된 비밀/설정을 읽을 수 있음 | `openclaw.json`에서 참조하는 include 파일 권한 | yes | -| `fs.config_include.perms_world_readable` | critical | 포함된 비밀/설정이 전체 읽기 가능함 | `openclaw.json`에서 참조하는 include 파일 권한 | yes | -| `fs.auth_profiles.perms_writable` | critical | 다른 사람이 저장된 모델 자격 증명을 주입 또는 교체할 수 있음 | `agents//agent/auth-profiles.json` 권한 | yes | -| `fs.auth_profiles.perms_readable` | warn | 다른 사람이 API 키와 OAuth 토큰을 읽을 수 있음 | `agents//agent/auth-profiles.json` 권한 | yes | -| `fs.credentials_dir.perms_writable` | critical | 다른 사람이 채널 페어링/자격 증명 상태를 수정할 수 있음 | `~/.openclaw/credentials`의 파일시스템 권한 | yes | -| `fs.credentials_dir.perms_readable` | warn | 다른 사람이 채널 자격 증명 상태를 읽을 수 있음 | `~/.openclaw/credentials`의 파일시스템 권한 | yes | -| `fs.sessions_store.perms_readable` | warn | 다른 사람이 세션 transcript/메타데이터를 읽을 수 있음 | 세션 저장소 권한 | yes | -| `fs.log_file.perms_readable` | warn | 다른 사람이 redaction되었지만 여전히 민감한 로그를 읽을 수 있음 | gateway 로그 파일 권한 | yes | -| `fs.synced_dir` | warn | iCloud/Dropbox/Drive의 상태/구성은 토큰/transcript 노출 범위를 넓힘 | config/state를 동기화 폴더 밖으로 이동 | no | -| `gateway.bind_no_auth` | critical | 인증 없이 원격 bind | `gateway.bind`, `gateway.auth.*` | no | -| `gateway.loopback_no_auth` | critical | reverse-proxied loopback이 인증되지 않게 될 수 있음 | `gateway.auth.*`, 프록시 설정 | no | -| `gateway.trusted_proxies_missing` | warn | reverse-proxy 헤더가 있지만 신뢰되지 않음 | `gateway.trustedProxies` | no | -| `gateway.http.no_auth` | warn/critical | `auth.mode="none"`인 상태에서 Gateway HTTP API 접근 가능 | `gateway.auth.mode`, `gateway.http.endpoints.*` | no | -| `gateway.http.session_key_override_enabled` | info | HTTP API 호출자가 `sessionKey`를 재정의할 수 있음 | `gateway.http.allowSessionKeyOverride` | no | -| `gateway.tools_invoke_http.dangerous_allow` | warn/critical | HTTP API를 통해 위험한 도구를 다시 활성화 | `gateway.tools.allow` | no | -| `gateway.nodes.allow_commands_dangerous` | warn/critical | 고영향 node 명령 활성화(카메라/화면/연락처/캘린더/SMS) | `gateway.nodes.allowCommands` | no | -| `gateway.nodes.deny_commands_ineffective` | warn | 패턴형 deny 항목이 셸 텍스트나 그룹과 일치하지 않음 | `gateway.nodes.denyCommands` | no | -| `gateway.tailscale_funnel` | critical | 공용 인터넷 노출 | `gateway.tailscale.mode` | no | -| `gateway.tailscale_serve` | info | Tailscale Serve를 통한 tailnet 노출이 활성화됨 | `gateway.tailscale.mode` | no | -| `gateway.control_ui.allowed_origins_required` | critical | non-loopback Control UI에 명시적 브라우저 origin allowlist가 없음 | `gateway.controlUi.allowedOrigins` | no | -| `gateway.control_ui.allowed_origins_wildcard` | warn/critical | `allowedOrigins=["*"]`는 브라우저 origin allowlist를 비활성화함 | `gateway.controlUi.allowedOrigins` | no | -| `gateway.control_ui.host_header_origin_fallback` | warn/critical | Host-header origin fallback 활성화(DNS rebinding 강화 저하) | `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback` | no | -| `gateway.control_ui.insecure_auth` | warn | insecure-auth 호환 토글이 활성화됨 | `gateway.controlUi.allowInsecureAuth` | no | -| `gateway.control_ui.device_auth_disabled` | critical | 장치 신원 확인이 비활성화됨 | `gateway.controlUi.dangerouslyDisableDeviceAuth` | no | -| `gateway.real_ip_fallback_enabled` | warn/critical | `X-Real-IP` 대체를 신뢰하면 프록시 오구성 시 source-IP spoofing 가능 | `gateway.allowRealIpFallback`, `gateway.trustedProxies` | no | -| `gateway.token_too_short` | warn | 짧은 공유 토큰은 brute force가 쉬움 | `gateway.auth.token` | no | -| `gateway.auth_no_rate_limit` | warn | 인증이 노출되었지만 rate limiting이 없으면 brute-force 위험 증가 | `gateway.auth.rateLimit` | no | -| `gateway.trusted_proxy_auth` | critical | proxy 신원이 이제 인증 경계가 됨 | `gateway.auth.mode="trusted-proxy"` | no | -| `gateway.trusted_proxy_no_proxies` | critical | trusted-proxy auth인데 trusted proxy IP가 없음 | `gateway.trustedProxies` | no | -| `gateway.trusted_proxy_no_user_header` | critical | trusted-proxy auth가 사용자 신원을 안전하게 해석할 수 없음 | `gateway.auth.trustedProxy.userHeader` | no | -| `gateway.trusted_proxy_no_allowlist` | warn | trusted-proxy auth가 인증된 모든 업스트림 사용자를 허용함 | `gateway.auth.trustedProxy.allowUsers` | no | -| `gateway.probe_auth_secretref_unavailable` | warn | deep probe가 이 명령 경로에서 auth SecretRef를 해석하지 못함 | deep-probe auth source / SecretRef availability | no | -| `gateway.probe_failed` | warn/critical | live Gateway probe 실패 | gateway reachability/auth | no | -| `discovery.mdns_full_mode` | warn/critical | mDNS full mode가 로컬 네트워크에 `cliPath`/`sshPort` 메타데이터를 광고함 | `discovery.mdns.mode`, `gateway.bind` | no | -| `config.insecure_or_dangerous_flags` | warn | insecure/dangerous 디버그 플래그가 활성화됨 | 여러 키(세부 내용 참조) | no | -| `config.secrets.gateway_password_in_config` | warn | gateway 비밀번호가 config에 직접 저장됨 | `gateway.auth.password` | no | -| `config.secrets.hooks_token_in_config` | warn | hook bearer token이 config에 직접 저장됨 | `hooks.token` | no | -| `hooks.token_reuse_gateway_token` | critical | hook ingress token이 Gateway auth도 해제함 | `hooks.token`, `gateway.auth.token` | no | -| `hooks.token_too_short` | warn | hook ingress brute force가 쉬움 | `hooks.token` | no | -| `hooks.default_session_key_unset` | warn | hook agent run이 생성된 per-request 세션으로 퍼져 나감 | `hooks.defaultSessionKey` | no | -| `hooks.allowed_agent_ids_unrestricted` | warn/critical | 인증된 hook 호출자가 모든 구성된 에이전트로 라우팅 가능 | `hooks.allowedAgentIds` | no | -| `hooks.request_session_key_enabled` | warn/critical | 외부 호출자가 sessionKey를 선택할 수 있음 | `hooks.allowRequestSessionKey` | no | -| `hooks.request_session_key_prefixes_missing` | warn/critical | 외부 session key 형태에 제한이 없음 | `hooks.allowedSessionKeyPrefixes` | no | -| `hooks.path_root` | critical | hook path가 `/`여서 ingress 충돌/오라우팅이 쉬움 | `hooks.path` | no | -| `hooks.installs_unpinned_npm_specs` | warn | hook 설치 기록이 불변 npm spec에 고정되지 않음 | hook install metadata | no | -| `hooks.installs_missing_integrity` | warn | hook 설치 기록에 integrity 메타데이터가 없음 | hook install metadata | no | -| `hooks.installs_version_drift` | warn | hook 설치 기록이 설치된 패키지와 어긋남 | hook install metadata | no | -| `logging.redact_off` | warn | 민감한 값이 로그/상태에 노출됨 | `logging.redactSensitive` | yes | -| `browser.control_invalid_config` | warn | 브라우저 제어 구성이 런타임 전에 유효하지 않음 | `browser.*` | no | -| `browser.control_no_auth` | critical | 인증 없이 브라우저 제어 노출 | `gateway.auth.*` | no | -| `browser.remote_cdp_http` | warn | plain HTTP 원격 CDP는 전송 암호화가 없음 | 브라우저 프로필 `cdpUrl` | no | -| `browser.remote_cdp_private_host` | warn | 원격 CDP가 private/internal 호스트를 대상으로 함 | 브라우저 프로필 `cdpUrl`, `browser.ssrfPolicy.*` | no | -| `sandbox.docker_config_mode_off` | warn | sandbox Docker 구성이 있지만 비활성 상태 | `agents.*.sandbox.mode` | no | -| `sandbox.bind_mount_non_absolute` | warn | 상대 bind mount는 예측 불가능하게 해석될 수 있음 | `agents.*.sandbox.docker.binds[]` | no | -| `sandbox.dangerous_bind_mount` | critical | sandbox bind mount가 차단된 시스템, 자격 증명, Docker socket 경로를 대상으로 함 | `agents.*.sandbox.docker.binds[]` | no | -| `sandbox.dangerous_network_mode` | critical | sandbox Docker network가 `host` 또는 `container:*` namespace join 모드를 사용함 | `agents.*.sandbox.docker.network` | no | -| `sandbox.dangerous_seccomp_profile` | critical | sandbox seccomp profile이 컨테이너 격리를 약화함 | `agents.*.sandbox.docker.securityOpt` | no | -| `sandbox.dangerous_apparmor_profile` | critical | sandbox AppArmor profile이 컨테이너 격리를 약화함 | `agents.*.sandbox.docker.securityOpt` | no | -| `sandbox.browser_cdp_bridge_unrestricted` | warn | sandbox browser bridge가 source-range 제한 없이 노출됨 | `sandbox.browser.cdpSourceRange` | no | -| `sandbox.browser_container.non_loopback_publish` | critical | 기존 browser 컨테이너가 non-loopback 인터페이스에 CDP를 publish함 | browser sandbox container publish config | no | -| `sandbox.browser_container.hash_label_missing` | warn | 기존 browser 컨테이너가 현재 config-hash label보다 이전 것임 | `openclaw sandbox recreate --browser --all` | no | -| `sandbox.browser_container.hash_epoch_stale` | warn | 기존 browser 컨테이너가 현재 browser config epoch보다 이전 것임 | `openclaw sandbox recreate --browser --all` | no | -| `tools.exec.host_sandbox_no_sandbox_defaults` | warn | `exec host=sandbox`는 sandbox가 꺼져 있으면 fail closed함 | `tools.exec.host`, `agents.defaults.sandbox.mode` | no | -| `tools.exec.host_sandbox_no_sandbox_agents` | warn | 에이전트별 `exec host=sandbox`는 sandbox가 꺼져 있으면 fail closed함 | `agents.list[].tools.exec.host`, `agents.list[].sandbox.mode` | no | -| `tools.exec.security_full_configured` | warn/critical | 호스트 exec가 `security="full"`로 실행 중 | `tools.exec.security`, `agents.list[].tools.exec.security` | no | -| `tools.exec.auto_allow_skills_enabled` | warn | exec 승인이 Skill bin을 암묵적으로 신뢰함 | `~/.openclaw/exec-approvals.json` | no | -| `tools.exec.allowlist_interpreter_without_strict_inline_eval` | warn | 인터프리터 allowlist가 강제 재승인 없이 inline eval을 허용함 | `tools.exec.strictInlineEval`, `agents.list[].tools.exec.strictInlineEval`, exec approvals allowlist | no | -| `tools.exec.safe_bins_interpreter_unprofiled` | warn | `safeBins`의 인터프리터/런타임 bin이 명시적 profile 없이 exec 위험을 넓힘 | `tools.exec.safeBins`, `tools.exec.safeBinProfiles`, `agents.list[].tools.exec.*` | no | -| `tools.exec.safe_bins_broad_behavior` | warn | `safeBins`의 넓은 동작 도구가 저위험 stdin-filter 신뢰 모델을 약화함 | `tools.exec.safeBins`, `agents.list[].tools.exec.safeBins` | no | -| `tools.exec.safe_bin_trusted_dirs_risky` | warn | `safeBinTrustedDirs`에 변경 가능하거나 위험한 디렉터리가 포함됨 | `tools.exec.safeBinTrustedDirs`, `agents.list[].tools.exec.safeBinTrustedDirs` | no | -| `skills.workspace.symlink_escape` | warn | 워크스페이스 `skills/**/SKILL.md`가 워크스페이스 루트 밖으로 해석됨(심볼릭 링크 체인 드리프트) | 워크스페이스 `skills/**` 파일시스템 상태 | no | -| `plugins.extensions_no_allowlist` | warn | 명시적 plugin allowlist 없이 확장이 설치됨 | `plugins.allowlist` | no | -| `plugins.installs_unpinned_npm_specs` | warn | plugin 설치 기록이 불변 npm spec에 고정되지 않음 | plugin install metadata | no | -| `plugins.installs_missing_integrity` | warn | plugin 설치 기록에 integrity 메타데이터가 없음 | plugin install metadata | no | -| `plugins.installs_version_drift` | warn | plugin 설치 기록이 설치된 패키지와 어긋남 | plugin install metadata | no | -| `plugins.code_safety` | warn/critical | plugin 코드 스캔에서 의심스럽거나 위험한 패턴 발견 | plugin 코드 / 설치 소스 | no | -| `plugins.code_safety.entry_path` | warn | plugin entry path가 숨김 또는 `node_modules` 위치를 가리킴 | plugin manifest `entry` | no | -| `plugins.code_safety.entry_escape` | critical | plugin entry가 plugin 디렉터리 밖으로 벗어남 | plugin manifest `entry` | no | -| `plugins.code_safety.scan_failed` | warn | plugin 코드 스캔을 완료할 수 없음 | plugin extension path / scan environment | no | -| `skills.code_safety` | warn/critical | Skill 설치 메타데이터/코드에 의심스럽거나 위험한 패턴이 있음 | Skill 설치 소스 | no | -| `skills.code_safety.scan_failed` | warn | Skill 코드 스캔을 완료할 수 없음 | Skill scan environment | no | -| `security.exposure.open_channels_with_exec` | warn/critical | 공유/공개 룸이 exec 활성화 에이전트에 접근 가능 | `channels.*.dmPolicy`, `channels.*.groupPolicy`, `tools.exec.*`, `agents.list[].tools.exec.*` | no | -| `security.exposure.open_groups_with_elevated` | critical | open group + elevated 도구는 고영향 프롬프트 인젝션 경로를 만듦 | `channels.*.groupPolicy`, `tools.elevated.*` | no | -| `security.exposure.open_groups_with_runtime_or_fs` | critical/warn | open group이 sandbox/workspace 가드 없이 명령/파일 도구에 접근 가능 | `channels.*.groupPolicy`, `tools.profile/deny`, `tools.fs.workspaceOnly`, `agents.*.sandbox.mode` | no | -| `security.trust_model.multi_user_heuristic` | warn | 구성이 multi-user처럼 보이지만 gateway 신뢰 모델은 개인 비서임 | 신뢰 경계 분리, 또는 공유 사용자 강화(`sandbox.mode`, tool deny/workspace scoping) | no | -| `tools.profile_minimal_overridden` | warn | 에이전트 재정의가 전역 minimal profile을 우회함 | `agents.list[].tools.profile` | no | -| `plugins.tools_reachable_permissive_policy` | warn | 느슨한 정책에서 확장 도구에 도달 가능 | `tools.profile` + tool allow/deny | no | -| `models.legacy` | warn | 레거시 모델 패밀리가 여전히 구성됨 | 모델 선택 | no | -| `models.weak_tier` | warn | 구성된 모델이 현재 권장 티어보다 낮음 | 모델 선택 | no | -| `models.small_params` | critical/info | 작은 모델 + 안전하지 않은 도구 표면은 인젝션 위험을 높임 | 모델 선택 + sandbox/tool policy | no | -| `summary.attack_surface` | info | 인증, 채널, 도구, 노출 상태의 롤업 요약 | 여러 키(세부 내용 참조) | no | +| `fs.state_dir.perms_world_writable` | critical | 다른 사용자/프로세스가 전체 OpenClaw 상태를 수정할 수 있음 | `~/.openclaw`의 파일시스템 권한 | 예 | +| `fs.state_dir.perms_group_writable` | warn | 같은 그룹의 사용자가 전체 OpenClaw 상태를 수정할 수 있음 | `~/.openclaw`의 파일시스템 권한 | 예 | +| `fs.state_dir.perms_readable` | warn | 상태 디렉터리를 다른 사용자가 읽을 수 있음 | `~/.openclaw`의 파일시스템 권한 | 예 | +| `fs.state_dir.symlink` | warn | 상태 디렉터리 대상이 다른 신뢰 경계가 됨 | 상태 디렉터리 파일시스템 레이아웃 | 아니요 | +| `fs.config.perms_writable` | critical | 다른 사용자가 인증/도구 정책/설정을 변경할 수 있음 | `~/.openclaw/openclaw.json`의 파일시스템 권한 | 예 | +| `fs.config.symlink` | warn | 설정 대상이 다른 신뢰 경계가 됨 | 설정 파일 파일시스템 레이아웃 | 아니요 | +| `fs.config.perms_group_readable` | warn | 같은 그룹의 사용자가 설정 토큰/값을 읽을 수 있음 | 설정 파일의 파일시스템 권한 | 예 | +| `fs.config.perms_world_readable` | critical | 설정에서 토큰/설정이 노출될 수 있음 | 설정 파일의 파일시스템 권한 | 예 | +| `fs.config_include.perms_writable` | critical | 설정 include 파일을 다른 사용자가 수정할 수 있음 | `openclaw.json`에서 참조되는 include 파일 권한 | 예 | +| `fs.config_include.perms_group_readable` | warn | 같은 그룹의 사용자가 포함된 시크릿/설정을 읽을 수 있음 | `openclaw.json`에서 참조되는 include 파일 권한 | 예 | +| `fs.config_include.perms_world_readable` | critical | 포함된 시크릿/설정이 모든 사용자에게 읽기 가능함 | `openclaw.json`에서 참조되는 include 파일 권한 | 예 | +| `fs.auth_profiles.perms_writable` | critical | 다른 사용자가 저장된 모델 자격 증명을 주입하거나 바꿔치기할 수 있음 | `agents//agent/auth-profiles.json` 권한 | 예 | +| `fs.auth_profiles.perms_readable` | warn | 다른 사용자가 API 키와 OAuth 토큰을 읽을 수 있음 | `agents//agent/auth-profiles.json` 권한 | 예 | +| `fs.credentials_dir.perms_writable` | critical | 다른 사용자가 채널 페어링/자격 증명 상태를 수정할 수 있음 | `~/.openclaw/credentials`의 파일시스템 권한 | 예 | +| `fs.credentials_dir.perms_readable` | warn | 다른 사용자가 채널 자격 증명 상태를 읽을 수 있음 | `~/.openclaw/credentials`의 파일시스템 권한 | 예 | +| `fs.sessions_store.perms_readable` | warn | 다른 사용자가 세션 기록/메타데이터를 읽을 수 있음 | 세션 저장소 권한 | 예 | +| `fs.log_file.perms_readable` | warn | 다른 사용자가 민감 정보가 일부 가려졌지만 여전히 민감할 수 있는 로그를 읽을 수 있음 | gateway 로그 파일 권한 | 예 | +| `fs.synced_dir` | warn | iCloud/Dropbox/Drive에 있는 상태/설정은 토큰/기록 노출 범위를 넓힘 | 설정/상태를 동기화 폴더 밖으로 이동 | 아니요 | +| `gateway.bind_no_auth` | critical | 공유 시크릿 없이 원격 바인드됨 | `gateway.bind`, `gateway.auth.*` | 아니요 | +| `gateway.loopback_no_auth` | critical | reverse proxy된 loopback이 인증되지 않은 상태가 될 수 있음 | `gateway.auth.*`, 프록시 설정 | 아니요 | +| `gateway.trusted_proxies_missing` | warn | reverse proxy 헤더가 존재하지만 신뢰되지 않음 | `gateway.trustedProxies` | 아니요 | +| `gateway.http.no_auth` | warn/critical | `auth.mode="none"` 상태로 Gateway HTTP API에 접근 가능 | `gateway.auth.mode`, `gateway.http.endpoints.*` | 아니요 | +| `gateway.http.session_key_override_enabled` | info | HTTP API 호출자가 `sessionKey`를 재정의할 수 있음 | `gateway.http.allowSessionKeyOverride` | 아니요 | +| `gateway.tools_invoke_http.dangerous_allow` | warn/critical | HTTP API를 통해 위험한 도구를 다시 활성화함 | `gateway.tools.allow` | 아니요 | +| `gateway.nodes.allow_commands_dangerous` | warn/critical | 영향도가 큰 node 명령(camera/screen/contacts/calendar/SMS)을 활성화함 | `gateway.nodes.allowCommands` | 아니요 | +| `gateway.nodes.deny_commands_ineffective` | warn | 패턴처럼 보이는 deny 항목이 셸 텍스트나 그룹과 매치되지 않음 | `gateway.nodes.denyCommands` | 아니요 | +| `gateway.tailscale_funnel` | critical | 공용 인터넷에 노출됨 | `gateway.tailscale.mode` | 아니요 | +| `gateway.tailscale_serve` | info | Serve를 통해 Tailnet 노출이 활성화됨 | `gateway.tailscale.mode` | 아니요 | +| `gateway.control_ui.allowed_origins_required` | critical | loopback이 아닌 Control UI에 명시적인 브라우저 origin allowlist가 없음 | `gateway.controlUi.allowedOrigins` | 아니요 | +| `gateway.control_ui.allowed_origins_wildcard` | warn/critical | `allowedOrigins=["*"]`가 브라우저 origin allowlisting을 비활성화함 | `gateway.controlUi.allowedOrigins` | 아니요 | +| `gateway.control_ui.host_header_origin_fallback` | warn/critical | Host 헤더 origin fallback을 활성화함(DNS rebinding 하드닝 저하) | `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback` | 아니요 | +| `gateway.control_ui.insecure_auth` | warn | 호환성을 위한 비보안 인증 토글이 활성화됨 | `gateway.controlUi.allowInsecureAuth` | 아니요 | +| `gateway.control_ui.device_auth_disabled` | critical | 디바이스 신원 확인을 비활성화함 | `gateway.controlUi.dangerouslyDisableDeviceAuth` | 아니요 | +| `gateway.real_ip_fallback_enabled` | warn/critical | `X-Real-IP` fallback을 신뢰하면 프록시 오설정 시 소스 IP 스푸핑이 가능해질 수 있음 | `gateway.allowRealIpFallback`, `gateway.trustedProxies` | 아니요 | +| `gateway.token_too_short` | warn | 짧은 공유 토큰은 무차별 대입 공격에 더 취약함 | `gateway.auth.token` | 아니요 | +| `gateway.auth_no_rate_limit` | warn | 노출된 인증에 rate limiting이 없으면 무차별 대입 위험이 증가함 | `gateway.auth.rateLimit` | 아니요 | +| `gateway.trusted_proxy_auth` | critical | 이제 프록시 신원이 인증 경계가 됨 | `gateway.auth.mode="trusted-proxy"` | 아니요 | +| `gateway.trusted_proxy_no_proxies` | critical | 신뢰할 프록시 IP 없이 trusted-proxy 인증을 사용하면 안전하지 않음 | `gateway.trustedProxies` | 아니요 | +| `gateway.trusted_proxy_no_user_header` | critical | trusted-proxy 인증이 사용자 신원을 안전하게 확인할 수 없음 | `gateway.auth.trustedProxy.userHeader` | 아니요 | +| `gateway.trusted_proxy_no_allowlist` | warn | trusted-proxy 인증이 인증된 모든 업스트림 사용자를 허용함 | `gateway.auth.trustedProxy.allowUsers` | 아니요 | +| `checkId` | 심각도 | 중요한 이유 | 주요 수정 키/경로 | 자동 수정 | +| ------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | -------- | +| `gateway.probe_auth_secretref_unavailable` | warn | 이 명령 경로에서 심층 probe가 인증 SecretRef를 확인할 수 없었음 | 심층 probe 인증 소스 / SecretRef 사용 가능성 | 아니요 | +| `gateway.probe_failed` | warn/critical | 실시간 Gateway probe 실패 | gateway 도달 가능 여부/인증 | 아니요 | +| `discovery.mdns_full_mode` | warn/critical | mDNS 전체 모드가 로컬 네트워크에 `cliPath`/`sshPort` 메타데이터를 광고함 | `discovery.mdns.mode`, `gateway.bind` | 아니요 | +| `config.insecure_or_dangerous_flags` | warn | 비보안/위험한 디버그 플래그가 하나라도 활성화됨 | 여러 키(결과 세부 정보 참조) | 아니요 | +| `config.secrets.gateway_password_in_config` | warn | Gateway 비밀번호가 설정 파일에 직접 저장되어 있음 | `gateway.auth.password` | 아니요 | +| `config.secrets.hooks_token_in_config` | warn | hook bearer 토큰이 설정 파일에 직접 저장되어 있음 | `hooks.token` | 아니요 | +| `hooks.token_reuse_gateway_token` | critical | hook ingress 토큰이 Gateway 인증 해제에도 사용됨 | `hooks.token`, `gateway.auth.token` | 아니요 | +| `hooks.token_too_short` | warn | hook ingress에 대한 무차별 대입이 더 쉬워짐 | `hooks.token` | 아니요 | +| `hooks.default_session_key_unset` | warn | hook 에이전트 실행이 요청별로 생성되는 세션들로 fan out됨 | `hooks.defaultSessionKey` | 아니요 | +| `hooks.allowed_agent_ids_unrestricted` | warn/critical | 인증된 hook 호출자가 설정된 모든 에이전트로 라우팅할 수 있음 | `hooks.allowedAgentIds` | 아니요 | +| `hooks.request_session_key_enabled` | warn/critical | 외부 호출자가 `sessionKey`를 선택할 수 있음 | `hooks.allowRequestSessionKey` | 아니요 | +| `hooks.request_session_key_prefixes_missing` | warn/critical | 외부 세션 키 형식에 대한 제한이 없음 | `hooks.allowedSessionKeyPrefixes` | 아니요 | +| `hooks.path_root` | critical | hook 경로가 `/`여서 ingress 충돌 또는 오라우팅이 쉬워짐 | `hooks.path` | 아니요 | +| `hooks.installs_unpinned_npm_specs` | warn | hook 설치 기록이 불변 npm spec으로 고정되어 있지 않음 | hook 설치 메타데이터 | 아니요 | +| `hooks.installs_missing_integrity` | warn | hook 설치 기록에 integrity 메타데이터가 없음 | hook 설치 메타데이터 | 아니요 | +| `hooks.installs_version_drift` | warn | hook 설치 기록과 설치된 패키지 사이에 드리프트가 있음 | hook 설치 메타데이터 | 아니요 | +| `logging.redact_off` | warn | 민감한 값이 로그/상태 출력에 노출됨 | `logging.redactSensitive` | 예 | +| `browser.control_invalid_config` | warn | 브라우저 제어 설정이 런타임 이전에 이미 유효하지 않음 | `browser.*` | 아니요 | +| `browser.control_no_auth` | critical | 브라우저 제어가 토큰/비밀번호 인증 없이 노출됨 | `gateway.auth.*` | 아니요 | +| `browser.remote_cdp_http` | warn | 일반 HTTP를 통한 원격 CDP는 전송 계층 암호화가 없음 | 브라우저 프로필 `cdpUrl` | 아니요 | +| `browser.remote_cdp_private_host` | warn | 원격 CDP가 사설/내부 호스트를 대상으로 함 | 브라우저 프로필 `cdpUrl`, `browser.ssrfPolicy.*` | 아니요 | +| `sandbox.docker_config_mode_off` | warn | Sandbox Docker 설정이 존재하지만 비활성 상태임 | `agents.*.sandbox.mode` | 아니요 | +| `sandbox.bind_mount_non_absolute` | warn | 상대 경로 bind mount는 예측하기 어렵게 해석될 수 있음 | `agents.*.sandbox.docker.binds[]` | 아니요 | +| `sandbox.dangerous_bind_mount` | critical | Sandbox bind mount 대상이 차단된 시스템, 자격 증명 또는 Docker socket 경로임 | `agents.*.sandbox.docker.binds[]` | 아니요 | +| `sandbox.dangerous_network_mode` | critical | Sandbox Docker 네트워크가 `host` 또는 `container:*` 네임스페이스 조인 모드를 사용함 | `agents.*.sandbox.docker.network` | 아니요 | +| `sandbox.dangerous_seccomp_profile` | critical | Sandbox seccomp 프로필이 컨테이너 격리를 약화시킴 | `agents.*.sandbox.docker.securityOpt` | 아니요 | +| `sandbox.dangerous_apparmor_profile` | critical | Sandbox AppArmor 프로필이 컨테이너 격리를 약화시킴 | `agents.*.sandbox.docker.securityOpt` | 아니요 | +| `sandbox.browser_cdp_bridge_unrestricted` | warn | Sandbox 브라우저 브리지가 소스 범위 제한 없이 노출됨 | `sandbox.browser.cdpSourceRange` | 아니요 | +| `sandbox.browser_container.non_loopback_publish` | critical | 기존 브라우저 컨테이너가 loopback이 아닌 인터페이스에 CDP를 게시함 | 브라우저 sandbox 컨테이너 게시 설정 | 아니요 | +| `sandbox.browser_container.hash_label_missing` | warn | 기존 브라우저 컨테이너가 현재 config-hash 라벨 이전에 생성됨 | `openclaw sandbox recreate --browser --all` | 아니요 | +| `sandbox.browser_container.hash_epoch_stale` | warn | 기존 브라우저 컨테이너가 현재 브라우저 설정 epoch 이전에 생성됨 | `openclaw sandbox recreate --browser --all` | 아니요 | +| `tools.exec.host_sandbox_no_sandbox_defaults` | warn | sandbox가 꺼져 있으면 `exec host=sandbox`는 닫힌 상태로 실패함 | `tools.exec.host`, `agents.defaults.sandbox.mode` | 아니요 | +| `tools.exec.host_sandbox_no_sandbox_agents` | warn | 에이전트별 `exec host=sandbox`는 sandbox가 꺼져 있으면 닫힌 상태로 실패함 | `agents.list[].tools.exec.host`, `agents.list[].sandbox.mode` | 아니요 | +| `tools.exec.security_full_configured` | warn/critical | 호스트 exec가 `security="full"`로 실행 중임 | `tools.exec.security`, `agents.list[].tools.exec.security` | 아니요 | +| `tools.exec.auto_allow_skills_enabled` | warn | exec 승인이 skill 바이너리를 암묵적으로 신뢰함 | `~/.openclaw/exec-approvals.json` | 아니요 | +| `tools.exec.allowlist_interpreter_without_strict_inline_eval` | warn | 인터프리터 allowlist가 강제 재승인 없이 인라인 eval을 허용함 | `tools.exec.strictInlineEval`, `agents.list[].tools.exec.strictInlineEval`, exec approvals allowlist | 아니요 | +| `tools.exec.safe_bins_interpreter_unprofiled` | warn | `safeBins`의 인터프리터/런타임 바이너리가 명시적 프로필 없이 exec 위험을 넓힘 | `tools.exec.safeBins`, `tools.exec.safeBinProfiles`, `agents.list[].tools.exec.*` | 아니요 | +| `tools.exec.safe_bins_broad_behavior` | warn | `safeBins`의 광범위 동작 도구가 저위험 stdin 필터 신뢰 모델을 약화시킴 | `tools.exec.safeBins`, `agents.list[].tools.exec.safeBins` | 아니요 | +| `tools.exec.safe_bin_trusted_dirs_risky` | warn | `safeBinTrustedDirs`에 변경 가능하거나 위험한 디렉터리가 포함됨 | `tools.exec.safeBinTrustedDirs`, `agents.list[].tools.exec.safeBinTrustedDirs` | 아니요 | +| `skills.workspace.symlink_escape` | warn | 워크스페이스 `skills/**/SKILL.md`가 워크스페이스 루트 밖으로 해석됨(심볼릭 링크 체인 드리프트) | 워크스페이스 `skills/**` 파일시스템 상태 | 아니요 | +| `plugins.extensions_no_allowlist` | warn | 명시적인 plugin allowlist 없이 extensions가 설치됨 | `plugins.allowlist` | 아니요 | +| `plugins.installs_unpinned_npm_specs` | warn | plugin 설치 기록이 불변 npm spec으로 고정되어 있지 않음 | plugin 설치 메타데이터 | 아니요 | +| `checkId` | 심각도 | 중요한 이유 | 주요 수정 키/경로 | 자동 수정 | +| ------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | -------- | +| `plugins.installs_missing_integrity` | warn | Plugin 설치 기록에 integrity 메타데이터가 없음 | plugin 설치 메타데이터 | 아니요 | +| `plugins.installs_version_drift` | warn | Plugin 설치 기록과 설치된 패키지 사이에 드리프트가 있음 | plugin 설치 메타데이터 | 아니요 | +| `plugins.code_safety` | warn/critical | Plugin 코드 스캔에서 의심스럽거나 위험한 패턴이 발견됨 | plugin 코드 / 설치 소스 | 아니요 | +| `plugins.code_safety.entry_path` | warn | Plugin 엔트리 경로가 숨김 위치 또는 `node_modules`를 가리킴 | plugin manifest `entry` | 아니요 | +| `plugins.code_safety.entry_escape` | critical | Plugin 엔트리가 plugin 디렉터리를 벗어남 | plugin manifest `entry` | 아니요 | +| `plugins.code_safety.scan_failed` | warn | Plugin 코드 스캔을 완료할 수 없었음 | plugin extension 경로 / 스캔 환경 | 아니요 | +| `skills.code_safety` | warn/critical | Skill 설치 메타데이터/코드에 의심스럽거나 위험한 패턴이 포함됨 | skill 설치 소스 | 아니요 | +| `skills.code_safety.scan_failed` | warn | Skill 코드 스캔을 완료할 수 없었음 | skill 스캔 환경 | 아니요 | +| `security.exposure.open_channels_with_exec` | warn/critical | 공유/공개 방이 exec가 활성화된 에이전트에 접근할 수 있음 | `channels.*.dmPolicy`, `channels.*.groupPolicy`, `tools.exec.*`, `agents.list[].tools.exec.*` | 아니요 | +| `security.exposure.open_groups_with_elevated` | critical | 개방된 그룹 + 권한 상승 도구는 영향이 큰 프롬프트 주입 경로를 만듦 | `channels.*.groupPolicy`, `tools.elevated.*` | 아니요 | +| `security.exposure.open_groups_with_runtime_or_fs` | critical/warn | 개방된 그룹이 sandbox/워크스페이스 가드 없이 명령/파일 도구에 접근할 수 있음 | `channels.*.groupPolicy`, `tools.profile/deny`, `tools.fs.workspaceOnly`, `agents.*.sandbox.mode` | 아니요 | +| `security.trust_model.multi_user_heuristic` | warn | 설정이 multi-user처럼 보이지만 gateway 신뢰 모델은 개인 비서 모델임 | 신뢰 경계를 분리하거나 공유 사용자 하드닝 적용(`sandbox.mode`, tool deny/workspace 범위 지정) | 아니요 | +| `tools.profile_minimal_overridden` | warn | 에이전트 재정의가 전역 minimal 프로필을 우회함 | `agents.list[].tools.profile` | 아니요 | +| `plugins.tools_reachable_permissive_policy` | warn | 느슨한 정책 환경에서 extension 도구에 접근 가능함 | `tools.profile` + tool allow/deny | 아니요 | +| `models.legacy` | warn | 레거시 모델 계열이 여전히 설정되어 있음 | 모델 선택 | 아니요 | +| `models.weak_tier` | warn | 설정된 모델이 현재 권장 티어보다 낮음 | 모델 선택 | 아니요 | +| `models.small_params` | critical/info | 작은 모델 + 안전하지 않은 도구 표면은 주입 위험을 높임 | 모델 선택 + sandbox/도구 정책 | 아니요 | +| `summary.attack_surface` | info | 인증, 채널, 도구, 노출 상태에 대한 종합 요약 | 여러 키(결과 세부 정보 참조) | 아니요 | ## HTTP를 통한 Control UI -Control UI는 장치 신원을 생성하기 위해 **보안 컨텍스트**(HTTPS 또는 localhost)가 필요합니다. -`gateway.controlUi.allowInsecureAuth`는 로컬 호환 토글입니다: +Control UI는 디바이스 신원을 생성하려면 **보안 컨텍스트**(HTTPS 또는 localhost)가 필요합니다. `gateway.controlUi.allowInsecureAuth`는 로컬 호환성 토글입니다. -- localhost에서는 페이지가 비보안 HTTP로 로드될 때 장치 신원 없이도 Control UI 인증을 허용합니다. -- 페어링 검사를 우회하지는 않습니다. -- 원격(non-localhost) 장치 신원 요구 사항을 완화하지도 않습니다. +- localhost에서는 페이지가 보안되지 않은 HTTP로 로드될 때 디바이스 신원 없이도 Control UI 인증을 허용합니다. +- 이는 페어링 검사를 우회하지 않습니다. +- 원격(비 localhost) 디바이스 신원 요구 사항을 완화하지도 않습니다. -HTTPS(Tailscale Serve) 또는 `127.0.0.1`에서 UI를 여는 것을 권장합니다. +가능하면 HTTPS(Tailscale Serve)를 사용하거나 `127.0.0.1`에서 UI를 여세요. -비상 상황에서만 `gateway.controlUi.dangerouslyDisableDeviceAuth`를 사용해 장치 신원 검사를 완전히 비활성화할 수 있습니다. 이는 심각한 보안 저하이므로, 적극적으로 디버깅 중이고 빠르게 되돌릴 수 있을 때만 사용하세요. +비상 상황에서만 `gateway.controlUi.dangerouslyDisableDeviceAuth`를 사용해 디바이스 신원 검사를 완전히 비활성화할 수 있습니다. 이는 심각한 보안 저하이므로, 적극적으로 디버깅 중이고 빠르게 되돌릴 수 있을 때만 사용하세요. -이러한 dangerous 플래그와 별도로, 성공적인 `gateway.auth.mode: "trusted-proxy"`는 장치 신원 없이도 **운영자** Control UI 세션을 허용할 수 있습니다. 이는 의도된 auth-mode 동작이지 `allowInsecureAuth` 지름길이 아니며, node-role Control UI 세션으로 확장되지도 않습니다. +이러한 위험한 플래그와는 별개로, 성공적인 `gateway.auth.mode: "trusted-proxy"`는 디바이스 신원 없이도 **운영자** Control UI 세션을 허용할 수 있습니다. 이는 의도된 인증 모드 동작이지 `allowInsecureAuth` 우회가 아니며, node 역할의 Control UI 세션에는 여전히 적용되지 않습니다. -`openclaw security audit`는 이 설정이 활성화되면 경고합니다. +`openclaw security audit`는 이 설정이 활성화되어 있으면 경고합니다. -## insecure 또는 dangerous 플래그 요약 +## 비보안 또는 위험한 플래그 요약 -`openclaw security audit`는 알려진 insecure/dangerous 디버그 스위치가 활성화되면 -`config.insecure_or_dangerous_flags`를 포함합니다. 현재 이 검사는 다음을 집계합니다: +`openclaw security audit`는 알려진 비보안/위험 디버그 스위치가 활성화되면 `config.insecure_or_dangerous_flags`를 포함합니다. 현재 이 검사는 다음 항목을 집계합니다. - `gateway.controlUi.allowInsecureAuth=true` - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` @@ -380,7 +379,7 @@ HTTPS(Tailscale Serve) 또는 `127.0.0.1`에서 UI를 여는 것을 권장합니 - `tools.exec.applyPatch.workspaceOnly=false` - `plugins.entries.acpx.config.permissionMode=approve-all` -OpenClaw config schema에 정의된 전체 `dangerous*` / `dangerously*` 구성 키: +OpenClaw config schema에 정의된 전체 `dangerous*` / `dangerously*` config 키: - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback` - `gateway.controlUi.dangerouslyDisableDeviceAuth` @@ -392,15 +391,15 @@ OpenClaw config schema에 정의된 전체 `dangerous*` / `dangerously*` 구성 - `channels.googlechat.dangerouslyAllowNameMatching` - `channels.googlechat.accounts..dangerouslyAllowNameMatching` - `channels.msteams.dangerouslyAllowNameMatching` -- `channels.synology-chat.dangerouslyAllowNameMatching` (extension channel) -- `channels.synology-chat.accounts..dangerouslyAllowNameMatching` (extension channel) -- `channels.synology-chat.dangerouslyAllowInheritedWebhookPath` (extension channel) -- `channels.zalouser.dangerouslyAllowNameMatching` (extension channel) -- `channels.zalouser.accounts..dangerouslyAllowNameMatching` (extension channel) -- `channels.irc.dangerouslyAllowNameMatching` (extension channel) -- `channels.irc.accounts..dangerouslyAllowNameMatching` (extension channel) -- `channels.mattermost.dangerouslyAllowNameMatching` (extension channel) -- `channels.mattermost.accounts..dangerouslyAllowNameMatching` (extension channel) +- `channels.synology-chat.dangerouslyAllowNameMatching` (extension 채널) +- `channels.synology-chat.accounts..dangerouslyAllowNameMatching` (extension 채널) +- `channels.synology-chat.dangerouslyAllowInheritedWebhookPath` (extension 채널) +- `channels.zalouser.dangerouslyAllowNameMatching` (extension 채널) +- `channels.zalouser.accounts..dangerouslyAllowNameMatching` (extension 채널) +- `channels.irc.dangerouslyAllowNameMatching` (extension 채널) +- `channels.irc.accounts..dangerouslyAllowNameMatching` (extension 채널) +- `channels.mattermost.dangerouslyAllowNameMatching` (extension 채널) +- `channels.mattermost.accounts..dangerouslyAllowNameMatching` (extension 채널) - `channels.telegram.network.dangerouslyAllowPrivateNetwork` - `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork` - `agents.defaults.sandbox.docker.dangerouslyAllowReservedContainerTargets` @@ -410,141 +409,131 @@ OpenClaw config schema에 정의된 전체 `dangerous*` / `dangerously*` 구성 - `agents.list[].sandbox.docker.dangerouslyAllowExternalBindSources` - `agents.list[].sandbox.docker.dangerouslyAllowContainerNamespaceJoin` -## Reverse Proxy 구성 +## Reverse Proxy 설정 -Gateway를 reverse proxy(nginx, Caddy, Traefik 등) 뒤에서 실행한다면, -올바른 forwarded-client IP 처리를 위해 `gateway.trustedProxies`를 구성하세요. +Gateway를 reverse proxy(nginx, Caddy, Traefik 등) 뒤에서 실행한다면, 전달된 클라이언트 IP를 올바르게 처리하도록 `gateway.trustedProxies`를 설정하세요. -Gateway는 **trustedProxies에 없는** 주소로부터 프록시 헤더를 감지하면 해당 연결을 로컬 클라이언트로 취급하지 않습니다. gateway auth가 비활성화되어 있다면 그 연결은 거부됩니다. 이는 프록시된 연결이 localhost에서 온 것처럼 보이면서 자동 신뢰를 받는 인증 우회를 방지합니다. +Gateway가 `trustedProxies`에 **포함되지 않은** 주소에서 proxy 헤더를 감지하면, 해당 연결을 로컬 클라이언트로 취급하지 **않습니다**. gateway 인증이 비활성화된 경우, 그 연결은 거부됩니다. 이는 proxy된 연결이 localhost에서 온 것처럼 보여 자동 신뢰를 받게 되는 인증 우회를 방지합니다. -`gateway.trustedProxies`는 `gateway.auth.mode: "trusted-proxy"`에도 사용되지만, 그 인증 모드는 더 엄격합니다: +`gateway.trustedProxies`는 `gateway.auth.mode: "trusted-proxy"`에도 사용되지만, 이 인증 모드는 더 엄격합니다. -- trusted-proxy auth는 **loopback-source proxy에서 fail closed**합니다 -- 같은 호스트의 loopback reverse proxy는 여전히 `gateway.trustedProxies`를 사용해 local client 감지 및 forwarded IP 처리를 할 수 있습니다 -- 같은 호스트의 loopback reverse proxy에는 `gateway.auth.mode: "trusted-proxy"` 대신 token/password auth를 사용하세요 +- trusted-proxy 인증은 **loopback 출처 프록시에 대해 닫힌 상태로 실패합니다** +- 동일 호스트의 loopback reverse proxy는 여전히 로컬 클라이언트 판별과 전달 IP 처리를 위해 `gateway.trustedProxies`를 사용할 수 있습니다 +- 동일 호스트의 loopback reverse proxy에서는 `gateway.auth.mode: "trusted-proxy"` 대신 token/password 인증을 사용하세요 ```yaml gateway: trustedProxies: - "10.0.0.1" # reverse proxy IP - # Optional. Default false. - # Only enable if your proxy cannot provide X-Forwarded-For. + # 선택 사항. 기본값은 false. + # 프록시가 X-Forwarded-For를 제공할 수 없는 경우에만 활성화하세요. allowRealIpFallback: false auth: mode: password password: ${OPENCLAW_GATEWAY_PASSWORD} ``` -`trustedProxies`가 구성되면 Gateway는 `X-Forwarded-For`를 사용해 클라이언트 IP를 결정합니다. `gateway.allowRealIpFallback: true`를 명시적으로 설정하지 않는 한 `X-Real-IP`는 기본적으로 무시됩니다. +`trustedProxies`가 설정되면 Gateway는 클라이언트 IP를 결정하기 위해 `X-Forwarded-For`를 사용합니다. `X-Real-IP`는 기본적으로 무시되며, `gateway.allowRealIpFallback: true`를 명시적으로 설정한 경우에만 사용됩니다. -좋은 reverse proxy 동작(들어오는 전달 헤더 덮어쓰기): +좋은 reverse proxy 동작(들어오는 전달 헤더를 덮어씀): ```nginx proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Real-IP $remote_addr; ``` -나쁜 reverse proxy 동작(신뢰되지 않은 전달 헤더 추가/보존): +나쁜 reverse proxy 동작(신뢰되지 않은 전달 헤더를 추가/보존함): ```nginx proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ``` -## HSTS 및 origin 참고 +## HSTS 및 origin 참고 사항 -- OpenClaw gateway는 local/loopback 우선입니다. reverse proxy에서 TLS를 종료한다면, 해당 프록시 앞 HTTPS 도메인에서 HSTS를 설정하세요. -- gateway 자체가 HTTPS를 종료한다면 `gateway.http.securityHeaders.strictTransportSecurity`를 설정해 OpenClaw 응답에서 HSTS 헤더를 보낼 수 있습니다. -- 자세한 배포 가이드는 [Trusted Proxy Auth](/gateway/trusted-proxy-auth#tls-termination-and-hsts)에 있습니다. -- non-loopback Control UI 배포에는 기본적으로 `gateway.controlUi.allowedOrigins`가 필요합니다. -- `gateway.controlUi.allowedOrigins: ["*"]`는 강화된 기본값이 아니라 명시적 전체 허용 브라우저 origin 정책입니다. 엄격히 통제된 로컬 테스트가 아니라면 피하세요. -- loopback에서의 브라우저 origin 인증 실패도 일반 loopback 예외가 활성화되어 있더라도 여전히 rate limit가 적용되지만, lockout 키는 하나의 공유 localhost 버킷이 아니라 정규화된 `Origin` 값별로 범위가 지정됩니다. -- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true`는 Host-header origin fallback 모드를 활성화합니다. 운영자가 선택한 위험한 정책으로 취급하세요. -- DNS rebinding과 proxy-host header 동작은 배포 강화 이슈로 취급하세요. `trustedProxies`를 엄격하게 유지하고 gateway를 공용 인터넷에 직접 노출하지 마세요. +- OpenClaw gateway는 로컬/loopback 우선입니다. reverse proxy에서 TLS를 종료한다면, proxy가 바라보는 HTTPS 도메인에서 HSTS를 설정하세요. +- gateway 자체가 HTTPS를 종료한다면, `gateway.http.securityHeaders.strictTransportSecurity`를 설정해 OpenClaw 응답에서 HSTS 헤더를 보낼 수 있습니다. +- 자세한 배포 가이드는 [Trusted Proxy Auth](/ko/gateway/trusted-proxy-auth#tls-termination-and-hsts)에 있습니다. +- loopback이 아닌 Control UI 배포에서는 기본적으로 `gateway.controlUi.allowedOrigins`가 필요합니다. +- `gateway.controlUi.allowedOrigins: ["*"]`는 명시적인 전체 허용 브라우저 origin 정책이며, 강화된 기본값이 아닙니다. 엄격히 통제된 로컬 테스트가 아니라면 피하세요. +- 일반적인 loopback 예외가 활성화되어 있어도, loopback에서의 브라우저 origin 인증 실패는 여전히 rate limiting이 적용되지만, 잠금 키는 하나의 공유 localhost 버킷이 아니라 정규화된 `Origin` 값별로 범위가 정해집니다. +- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true`는 Host 헤더 origin fallback 모드를 활성화합니다. 위험성을 인지한 운영자 선택 정책으로 취급하세요. +- DNS rebinding과 proxy Host 헤더 동작은 배포 하드닝 문제로 취급하세요. `trustedProxies`는 엄격하게 제한하고, gateway를 공용 인터넷에 직접 노출하지 마세요. ## 로컬 세션 로그는 디스크에 저장됩니다 -OpenClaw는 세션 transcript를 디스크의 `~/.openclaw/agents//sessions/*.jsonl` 아래에 저장합니다. -이것은 세션 연속성과(선택적으로) 세션 메모리 인덱싱을 위해 필요하지만, -동시에 **파일시스템 접근 권한이 있는 모든 프로세스/사용자가 해당 로그를 읽을 수 있다**는 뜻이기도 합니다. -디스크 접근을 신뢰 경계로 취급하고 `~/.openclaw` 권한을 엄격히 제한하세요(아래 감사 섹션 참조). 에이전트 간 더 강한 격리가 필요하면 별도의 OS 사용자 또는 별도의 호스트에서 실행하세요. +OpenClaw는 세션 연속성과(선택적으로) 세션 메모리 인덱싱을 위해 세션 기록을 `~/.openclaw/agents//sessions/*.jsonl` 아래 디스크에 저장합니다. +이는 필요하지만, 동시에 **파일시스템에 접근할 수 있는 모든 프로세스/사용자가 이 로그를 읽을 수 있다는 뜻이기도 합니다**. 디스크 접근을 신뢰 경계로 간주하고 `~/.openclaw` 권한을 엄격히 제한하세요(아래 감사 섹션 참고). 에이전트 간 더 강한 격리가 필요하다면 별도의 OS 사용자 또는 별도의 호스트에서 실행하세요. ## Node 실행 (`system.run`) -macOS node가 페어링되어 있으면 Gateway는 해당 node에서 `system.run`을 호출할 수 있습니다. 이는 Mac에 대한 **원격 코드 실행**입니다: +macOS node가 페어링되어 있으면 Gateway는 해당 node에서 `system.run`을 호출할 수 있습니다. 이는 Mac에서의 **원격 코드 실행**입니다. - node 페어링(승인 + 토큰)이 필요합니다. -- Gateway node 페어링은 per-command 승인 표면이 아닙니다. 이는 node 신원/신뢰 및 토큰 발급을 설정합니다. -- Gateway는 `gateway.nodes.allowCommands` / `denyCommands`를 통해 거친 전역 node 명령 정책을 적용합니다. -- Mac에서는 **Settings → Exec approvals**(security + ask + allowlist)로 제어합니다. -- node별 `system.run` 정책은 node 자체의 exec approval 파일(`exec.approvals.node.*`)이며, 이는 gateway의 전역 명령 ID 정책보다 더 엄격하거나 더 느슨할 수 있습니다. -- `security="full"` 및 `ask="off"`로 실행되는 node는 기본 신뢰 운영자 모델을 따르고 있는 것입니다. 배포에서 더 엄격한 승인 또는 allowlist가 명시적으로 필요하지 않다면 이는 예상된 동작으로 취급하세요. -- 승인 모드는 정확한 요청 컨텍스트와, 가능할 경우 하나의 구체적인 로컬 스크립트/파일 피연산자에 바인딩됩니다. OpenClaw가 인터프리터/런타임 명령에 대해 정확히 하나의 직접 로컬 파일을 식별할 수 없으면, 전체 의미론적 범위를 약속하는 대신 승인 기반 실행은 거부됩니다. -- `host=node`의 경우 승인 기반 실행은 canonical prepared - `systemRunPlan`도 저장합니다. 이후 승인된 전달은 그 저장된 plan을 재사용하며, - gateway 검증은 승인 요청 생성 후 호출자가 command/cwd/session 컨텍스트를 수정하는 것을 거부합니다. +- Gateway node 페어링은 명령별 승인 표면이 아닙니다. 이는 node 신뢰/신원과 토큰 발급을 설정합니다. +- Gateway는 `gateway.nodes.allowCommands` / `denyCommands`를 통해 대략적인 전역 node 명령 정책을 적용합니다. +- Mac에서는 **Settings → Exec approvals**로 제어합니다(security + ask + allowlist). +- node별 `system.run` 정책은 node 자체의 exec approvals 파일(`exec.approvals.node.*`)이며, gateway의 전역 명령 ID 정책보다 더 엄격하거나 느슨할 수 있습니다. +- `security="full"` 및 `ask="off"`로 실행되는 node는 기본 신뢰 운영자 모델을 따르는 것입니다. 배포에서 명시적으로 더 엄격한 승인 또는 allowlist 정책을 요구하지 않는 한 이는 예상된 동작으로 간주하세요. +- 승인 모드는 정확한 요청 컨텍스트와, 가능하다면 하나의 구체적인 로컬 스크립트/파일 피연산자에 바인딩됩니다. OpenClaw가 인터프리터/런타임 명령에 대해 정확히 하나의 직접 로컬 파일을 식별할 수 없으면, 완전한 의미적 범위를 약속하는 대신 승인 기반 실행을 거부합니다. +- `host=node`의 경우, 승인 기반 실행은 정규화된 준비 `systemRunPlan`도 저장하며, 이후 승인된 전달은 저장된 그 plan을 재사용합니다. 그리고 gateway 검증은 승인 요청 생성 이후 호출자가 명령/cwd/세션 컨텍스트를 수정하는 것을 거부합니다. - 원격 실행을 원하지 않는다면 security를 **deny**로 설정하고 해당 Mac의 node 페어링을 제거하세요. -분류 시 이 구분이 중요합니다: +이 구분은 분류에 중요합니다. -- 다시 연결된 페어링 node가 다른 명령 목록을 광고하는 것만으로는, Gateway 전역 정책과 node의 로컬 exec approval이 실제 실행 경계를 계속 강제한다면 그 자체로 취약점이 아닙니다. -- node pairing 메타데이터를 두 번째 숨겨진 per-command 승인 계층으로 보는 보고는 보통 보안 경계 우회가 아니라 정책/UX 혼동입니다. +- 다시 연결되는 페어링된 node가 다른 명령 목록을 광고한다고 해서, Gateway 전역 정책과 node의 로컬 exec 승인이 실제 실행 경계를 계속 강제하고 있다면 그것만으로는 취약점이 아닙니다. +- node 페어링 메타데이터를 숨겨진 두 번째 명령별 승인 계층으로 간주하는 보고는 보통 정책/UX 혼동이지, 보안 경계 우회가 아닙니다. ## 동적 Skills (watcher / 원격 nodes) -OpenClaw는 세션 도중 Skills 목록을 새로고침할 수 있습니다: +OpenClaw는 세션 중간에도 Skills 목록을 새로 고칠 수 있습니다. -- **Skills watcher**: `SKILL.md` 변경 사항이 다음 에이전트 턴에서 Skills 스냅샷을 업데이트할 수 있습니다. -- **원격 nodes**: macOS node 연결 시 macOS 전용 Skills가 사용 가능해질 수 있습니다(bin probing 기준). +- **Skills watcher**: `SKILL.md`가 변경되면 다음 에이전트 턴에서 Skills 스냅샷이 업데이트될 수 있습니다. +- **원격 nodes**: macOS node가 연결되면 macOS 전용 Skills가 적격 상태가 될 수 있습니다(바이너리 probe 기준). -Skill 폴더는 **신뢰된 코드**로 취급하고 누가 이를 수정할 수 있는지 제한하세요. +Skill 폴더는 **신뢰된 코드**로 취급하고, 누가 수정할 수 있는지 엄격히 제한하세요. ## 위협 모델 -AI 비서는 다음을 할 수 있습니다: +AI 비서는 다음을 수행할 수 있습니다. -- 임의 셸 명령 실행 +- 임의의 셸 명령 실행 - 파일 읽기/쓰기 - 네트워크 서비스 접근 -- WhatsApp 접근 권한이 있다면 누구에게나 메시지 전송 +- 누구에게나 메시지 전송(WhatsApp 접근 권한을 준 경우) -사용자에게 메시지를 보내는 사람들은 다음을 시도할 수 있습니다: +당신에게 메시지를 보내는 사람은 다음을 시도할 수 있습니다. -- AI를 속여 나쁜 일을 하게 만들기 -- 사용자 데이터를 얻기 위한 사회공학 -- 인프라 세부 정보 탐색 +- AI를 속여 나쁜 행동을 하게 만들기 +- 당신의 데이터에 접근하도록 사회공학 시도하기 +- 인프라 세부 정보를 탐색하기 ## 핵심 개념: 지능보다 먼저 접근 제어 -여기서 대부분의 실패는 정교한 익스플로잇이 아닙니다. “누군가 봇에 메시지를 보냈고, 봇이 그 요청을 수행했다”에 가깝습니다. +여기서 발생하는 대부분의 실패는 정교한 익스플로잇이 아닙니다. 단지 “누군가가 봇에 메시지를 보냈고, 봇이 시키는 대로 했다”는 문제입니다. -OpenClaw의 입장: +OpenClaw의 입장은 다음과 같습니다. -- **정체성 우선:** 누가 봇과 대화할 수 있는지 결정(DM 페어링 / allowlist / 명시적 “open”) -- **범위 다음:** 봇이 어디에서 행동할 수 있는지 결정(그룹 allowlist + mention gating, 도구, sandboxing, 장치 권한) -- **모델은 마지막:** 모델은 조작될 수 있다고 가정하고, 조작의 폭발 반경이 제한되도록 설계 +- **먼저 신원:** 누가 봇과 대화할 수 있는지 결정하세요(DM 페어링 / allowlist / 명시적 “open”). +- **그다음 범위:** 봇이 어디에서 동작할 수 있는지 결정하세요(그룹 allowlist + 멘션 게이팅, 도구, 샌드박싱, 디바이스 권한). +- **마지막으로 모델:** 모델은 조작될 수 있다고 가정하고, 조작되더라도 영향 반경이 제한되도록 설계하세요. ## 명령 권한 모델 -슬래시 명령과 지시문은 **권한 있는 발신자**에게만 적용됩니다. 권한은 -채널 allowlist/페어링과 `commands.useAccessGroups`에서 파생됩니다([Configuration](/gateway/configuration) -및 [Slash commands](/tools/slash-commands) 참조). 채널 allowlist가 비어 있거나 `"*"`를 포함하면, -해당 채널의 명령은 사실상 개방됩니다. +슬래시 명령과 directive는 **권한이 있는 발신자**에게만 적용됩니다. 권한은 채널 allowlist/페어링과 `commands.useAccessGroups`에서 파생됩니다([Configuration](/ko/gateway/configuration) 및 [Slash commands](/ko/tools/slash-commands) 참고). 채널 allowlist가 비어 있거나 `"*"`를 포함하면, 해당 채널의 명령은 사실상 공개됩니다. -`/exec`는 권한 있는 운영자를 위한 세션 전용 편의 기능입니다. 구성 파일을 쓰거나 -다른 세션을 변경하지는 않습니다. +`/exec`는 권한이 있는 운영자를 위한 세션 전용 편의 기능입니다. 이는 설정을 기록하거나 다른 세션을 변경하지 않습니다. ## 제어 평면 도구 위험 -두 개의 내장 도구는 영구적인 제어 평면 변경을 만들 수 있습니다: +두 개의 내장 도구는 지속적인 제어 평면 변경을 만들 수 있습니다. -- `gateway`는 `config.schema.lookup` / `config.get`으로 구성을 검사할 수 있고, `config.apply`, `config.patch`, `update.run`으로 영구 변경을 만들 수 있습니다. +- `gateway`는 `config.schema.lookup` / `config.get`으로 설정을 조회할 수 있고, `config.apply`, `config.patch`, `update.run`으로 지속적인 변경을 적용할 수 있습니다. - `cron`은 원래 채팅/작업이 끝난 뒤에도 계속 실행되는 예약 작업을 만들 수 있습니다. 소유자 전용 `gateway` 런타임 도구는 여전히 -`tools.exec.ask` 또는 `tools.exec.security`를 다시 쓰는 것을 거부합니다. 레거시 `tools.bash.*` 별칭도 -쓰기 전에 같은 보호된 exec 경로로 정규화됩니다. +`tools.exec.ask` 또는 `tools.exec.security`를 다시 쓰는 것을 거부합니다. 레거시 `tools.bash.*` 별칭은 쓰기 전에 동일한 보호된 exec 경로로 정규화됩니다. -신뢰되지 않는 콘텐츠를 처리하는 에이전트/표면에서는 기본적으로 다음을 거부하세요: +비신뢰 콘텐츠를 처리하는 에이전트/표면에서는 기본적으로 다음 도구를 거부하세요. ```json5 { @@ -554,47 +543,49 @@ OpenClaw의 입장: } ``` -`commands.restart=false`는 재시작 동작만 막습니다. `gateway` config/update 동작은 비활성화하지 않습니다. +`commands.restart=false`는 재시작 작업만 차단합니다. `gateway`의 config/update 작업을 비활성화하지는 않습니다. -## Plugins/확장 +## Plugins/extensions -Plugins는 Gateway와 **같은 프로세스 안에서** 실행됩니다. 신뢰된 코드로 취급하세요: +Plugins는 Gateway **프로세스 내부에서** 실행됩니다. 신뢰된 코드로 취급하세요. -- 신뢰하는 소스의 plugin만 설치하세요. -- 명시적인 `plugins.allow` allowlist를 선호하세요. -- 활성화 전에 plugin 구성을 검토하세요. -- plugin 변경 후 Gateway를 재시작하세요. -- plugins를 설치하거나 업데이트하는 경우(`openclaw plugins install `, `openclaw plugins update `), 신뢰되지 않는 코드를 실행하는 것처럼 취급하세요: +- 신뢰하는 소스에서만 plugins를 설치하세요. +- 명시적인 `plugins.allow` allowlist를 우선 사용하세요. +- 활성화하기 전에 plugin 설정을 검토하세요. +- plugin 변경 후에는 Gateway를 재시작하세요. +- plugins를 설치하거나 업데이트할 때(`openclaw plugins install `, `openclaw plugins update `), 이를 비신뢰 코드 실행처럼 취급하세요. - 설치 경로는 활성 plugin 설치 루트 아래의 plugin별 디렉터리입니다. - - OpenClaw는 설치/업데이트 전에 내장 dangerous-code 스캔을 실행합니다. `critical` 결과는 기본적으로 차단합니다. - - OpenClaw는 `npm pack`을 사용한 뒤 해당 디렉터리에서 `npm install --omit=dev`를 실행합니다(npm lifecycle script는 설치 중 코드를 실행할 수 있음). - - 버전 고정 exact 버전(`@scope/pkg@1.2.3`)을 선호하고, 활성화 전에 디스크에 압축 해제된 코드를 검사하세요. - - `--dangerously-force-unsafe-install`은 plugin 설치/업데이트 흐름에서 내장 스캔 오탐에 대한 비상 탈출용입니다. plugin `before_install` hook 정책 차단이나 scan failure를 우회하지는 않습니다. - - Gateway 기반 Skill 의존성 설치도 동일한 dangerous/suspicious 구분을 따릅니다. 내장 `critical` 결과는 호출자가 명시적으로 `dangerouslyForceUnsafeInstall`을 설정하지 않는 한 차단되며, suspicious 결과는 경고만 합니다. `openclaw skills install`은 여전히 별도의 ClawHub Skill 다운로드/설치 흐름입니다. + - OpenClaw는 설치/업데이트 전에 내장된 위험 코드 스캔을 실행합니다. `critical` 결과는 기본적으로 차단됩니다. + - OpenClaw는 `npm pack`을 사용한 뒤 해당 디렉터리에서 `npm install --omit=dev`를 실행합니다(`npm` lifecycle 스크립트는 설치 중 코드를 실행할 수 있습니다). + - 정확히 고정된 버전(`@scope/pkg@1.2.3`)을 선호하고, 활성화 전에 디스크에 풀린 코드를 검사하세요. + - `--dangerously-force-unsafe-install`은 plugin 설치/업데이트 흐름에서 내장 스캔의 false positive가 발생했을 때만 사용하는 비상 옵션입니다. 이는 plugin `before_install` hook 정책 차단을 우회하지 않으며, 스캔 실패도 우회하지 않습니다. + - Gateway 기반 skill 의존성 설치도 동일한 위험/의심 분리를 따릅니다. 내장 `critical` 결과는 호출자가 명시적으로 `dangerouslyForceUnsafeInstall`을 설정하지 않는 한 차단되며, 의심 결과는 여전히 경고만 표시합니다. `openclaw skills install`은 별도의 ClawHub skill 다운로드/설치 흐름으로 유지됩니다. -자세한 내용: [Plugins](/tools/plugin) +자세한 내용: [Plugins](/ko/tools/plugin) + + ## DM 접근 모델 (pairing / allowlist / open / disabled) -현재 DM을 지원하는 모든 채널은 메시지가 처리되기 **전에** 인바운드 DM을 제어하는 DM 정책(`dmPolicy` 또는 `*.dm.policy`)을 지원합니다: +현재 DM을 지원하는 모든 채널은 메시지가 처리되기 **전**에 인바운드 DM을 제어하는 DM 정책(`dmPolicy` 또는 `*.dm.policy`)을 지원합니다. -- `pairing`(기본값): 알 수 없는 발신자는 짧은 페어링 코드를 받고, 승인되기 전까지 봇은 그 메시지를 무시합니다. 코드는 1시간 후 만료되며, 반복되는 DM은 새 요청이 생성되기 전까지 코드를 다시 보내지 않습니다. 대기 요청은 기본적으로 **채널당 3개**로 제한됩니다. -- `allowlist`: 알 수 없는 발신자는 차단됩니다(페어링 핸드셰이크 없음). -- `open`: 누구나 DM 가능(공개). 채널 allowlist에 `"*"`가 포함되어야 합니다(**명시적 opt-in 필요**). +- `pairing`(기본값): 알 수 없는 발신자는 짧은 pairing 코드를 받고, 승인될 때까지 봇은 해당 메시지를 무시합니다. 코드는 1시간 후 만료되며, 새 요청이 생성되기 전까지는 반복된 DM에도 코드를 다시 보내지 않습니다. 기본적으로 대기 중 요청은 **채널당 3개**로 제한됩니다. +- `allowlist`: 알 수 없는 발신자는 차단됩니다(pairing 핸드셰이크 없음). +- `open`: 누구나 DM을 보낼 수 있습니다(공개). 채널 allowlist에 `"*"`가 포함되어 있어야 합니다(**명시적 opt-in 필요**). - `disabled`: 인바운드 DM을 완전히 무시합니다. -CLI를 통한 승인: +CLI로 승인: ```bash openclaw pairing list openclaw pairing approve ``` -세부 사항 + 디스크 파일: [Pairing](/channels/pairing) +자세한 내용 및 디스크 파일 위치: [Pairing](/ko/channels/pairing) ## DM 세션 격리 (multi-user 모드) -기본적으로 OpenClaw는 **모든 DM을 메인 세션으로 라우팅**하므로 비서가 장치와 채널 전반에서 연속성을 가집니다. 그러나 **여러 사람**이 봇에 DM할 수 있다면(open DMs 또는 다중 인원 allowlist), DM 세션을 격리하는 것을 고려하세요: +기본적으로 OpenClaw는 사용자의 비서가 디바이스와 채널 전반에서 연속성을 유지할 수 있도록 **모든 DM을 메인 세션으로 라우팅**합니다. **여러 사람**이 봇에 DM을 보낼 수 있다면(open DM 또는 다중 인원 allowlist), DM 세션을 격리하는 것을 고려하세요. ```json5 { @@ -602,185 +593,175 @@ openclaw pairing approve } ``` -이렇게 하면 그룹 채팅은 계속 격리하면서도 사용자 간 컨텍스트 유출을 막을 수 있습니다. +이렇게 하면 그룹 채팅은 계속 격리된 상태를 유지하면서 사용자 간 컨텍스트 누출을 방지할 수 있습니다. -이것은 메시징 컨텍스트 경계이지 호스트 관리자 경계가 아닙니다. 사용자가 상호 적대적이고 같은 Gateway 호스트/구성을 공유한다면, 신뢰 경계별로 별도의 gateway를 실행하세요. +이것은 메시징 컨텍스트 경계이지, 호스트 관리자 경계는 아닙니다. 사용자들이 서로 적대적이고 같은 Gateway 호스트/설정을 공유한다면, 신뢰 경계별로 별도의 gateways를 실행하세요. -### Secure DM 모드 (권장) +### 보안 DM 모드(권장) -위 스니펫을 **Secure DM 모드**로 취급하세요: +위 스니펫을 **보안 DM 모드**로 간주하세요. - 기본값: `session.dmScope: "main"`(모든 DM이 연속성을 위해 하나의 세션을 공유) -- 로컬 CLI 온보딩 기본값: 설정되지 않은 경우 `session.dmScope: "per-channel-peer"`를 기록함(기존 명시적 값은 유지) -- Secure DM 모드: `session.dmScope: "per-channel-peer"`(각 채널+발신자 쌍이 격리된 DM 컨텍스트를 가짐) -- 크로스 채널 피어 격리: `session.dmScope: "per-peer"`(각 발신자가 같은 유형의 모든 채널에서 하나의 세션을 가짐) +- 로컬 CLI 온보딩 기본값: 값이 설정되지 않았을 때 `session.dmScope: "per-channel-peer"`를 기록함(기존의 명시적 값은 유지) +- 보안 DM 모드: `session.dmScope: "per-channel-peer"`(각 채널+발신자 쌍이 격리된 DM 컨텍스트를 가짐) +- 교차 채널 피어 격리: `session.dmScope: "per-peer"`(같은 유형의 모든 채널에서 각 발신자가 하나의 세션을 가짐) -같은 채널에서 여러 계정을 실행한다면 `per-account-channel-peer`를 사용하세요. 같은 사람이 여러 채널에서 연락한다면 `session.identityLinks`를 사용해 تلك DM 세션을 하나의 정규 신원으로 합치세요. [Session Management](/concepts/session) 및 [Configuration](/gateway/configuration)을 참조하세요. +같은 채널에서 여러 계정을 실행한다면 `per-account-channel-peer`를 대신 사용하세요. 같은 사람이 여러 채널로 연락하는 경우에는 `session.identityLinks`를 사용해 그 DM 세션들을 하나의 정식 신원으로 통합할 수 있습니다. [Session Management](/ko/concepts/session)와 [Configuration](/ko/gateway/configuration)을 참고하세요. -## Allowlists (DM + 그룹) - 용어 +## Allowlist (DM + 그룹) - 용어 -OpenClaw에는 “누가 나를 트리거할 수 있는가?”에 대한 두 개의 별도 계층이 있습니다: +OpenClaw에는 “누가 나를 트리거할 수 있는가?”를 결정하는 두 개의 별도 계층이 있습니다. -- **DM allowlist** (`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`; 레거시: `channels.discord.dm.allowFrom`, `channels.slack.dm.allowFrom`): 누가 직접 메시지에서 봇과 대화할 수 있는가. - - `dmPolicy="pairing"`이면 승인은 `~/.openclaw/credentials/` 아래의 계정 범위 pairing allowlist 저장소에 기록되며(기본 계정은 `-allowFrom.json`, 비기본 계정은 `--allowFrom.json`), config allowlist와 병합됩니다. -- **그룹 allowlist** (채널별): 봇이 어떤 그룹/채널/guild에서 메시지를 아예 받을지. +- **DM allowlist** (`allowFrom` / `channels.discord.allowFrom` / `channels.slack.allowFrom`; 레거시: `channels.discord.dm.allowFrom`, `channels.slack.dm.allowFrom`): 직접 메시지에서 누가 봇과 대화할 수 있는가 + - `dmPolicy="pairing"`일 때 승인 결과는 계정 범위의 pairing allowlist 저장소인 `~/.openclaw/credentials/` 아래에 기록되며(`기본 계정은 -allowFrom.json`, 비기본 계정은 `--allowFrom.json`), config allowlist와 병합됩니다. +- **그룹 allowlist**(채널별): 어떤 그룹/채널/guild에서 봇이 메시지를 아예 받을지 - 일반적인 패턴: - - `channels.whatsapp.groups`, `channels.telegram.groups`, `channels.imessage.groups`: `requireMention` 같은 그룹별 기본값; 설정되면 그룹 allowlist 역할도 함(전체 허용 동작을 유지하려면 `"*"` 포함) - - `groupPolicy="allowlist"` + `groupAllowFrom`: 그룹 세션 **내부에서** 누가 봇을 트리거할 수 있는지 제한(WhatsApp/Telegram/Signal/iMessage/Microsoft Teams) - - `channels.discord.guilds` / `channels.slack.channels`: 표면별 allowlist + 멘션 기본값 - - 그룹 검사는 이 순서로 실행됩니다: 먼저 `groupPolicy`/그룹 allowlist, 그다음 mention/reply activation. - - 봇 메시지에 답장하는 것(암묵적 멘션)은 `groupAllowFrom` 같은 발신자 allowlist를 우회하지 않습니다. - - **보안 참고:** `dmPolicy="open"`과 `groupPolicy="open"`은 최후의 수단 설정으로 취급하세요. 모든 방 멤버를 완전히 신뢰하지 않는 한 거의 사용하지 말고, pairing + allowlist를 우선하세요. + - `channels.whatsapp.groups`, `channels.telegram.groups`, `channels.imessage.groups`: `requireMention` 같은 그룹별 기본값이며, 설정되면 그룹 allowlist 역할도 합니다(전체 허용 동작을 유지하려면 `"*"` 포함). + - `groupPolicy="allowlist"` + `groupAllowFrom`: 그룹 세션 **내부에서** 누가 봇을 트리거할 수 있는지 제한(WhatsApp/Telegram/Signal/iMessage/Microsoft Teams). + - `channels.discord.guilds` / `channels.slack.channels`: 표면별 allowlist + 멘션 기본값. + - 그룹 검사는 다음 순서로 실행됩니다. 먼저 `groupPolicy`/그룹 allowlist, 그다음 멘션/답장 활성화. + - 봇 메시지에 답장하는 것(암시적 멘션)은 `groupAllowFrom` 같은 발신자 allowlist를 우회하지 않습니다. + - **보안 참고:** `dmPolicy="open"` 및 `groupPolicy="open"`은 최후의 수단으로 취급하세요. 거의 사용하지 않아야 하며, 방의 모든 구성원을 완전히 신뢰하지 않는 한 pairing + allowlist를 선호하세요. -자세한 내용: [Configuration](/gateway/configuration) 및 [Groups](/channels/groups) +자세한 내용: [Configuration](/ko/gateway/configuration) 및 [Groups](/ko/channels/groups) -## 프롬프트 인젝션(무엇이고, 왜 중요한가) +## 프롬프트 주입(무엇이며 왜 중요한가) -프롬프트 인젝션은 공격자가 모델을 조작해 안전하지 않은 일을 하게 만드는 메시지를 만드는 것입니다(“지시를 무시하라”, “파일시스템을 덤프하라”, “이 링크를 따라가서 명령을 실행하라” 등). +프롬프트 주입은 공격자가 모델을 조작해 안전하지 않은 일을 하도록 만드는 메시지를 만드는 것입니다(“지침을 무시해”, “파일시스템을 덤프해”, “이 링크를 열고 명령을 실행해” 등). -강한 시스템 프롬프트가 있더라도 **프롬프트 인젝션은 해결되지 않았습니다**. 시스템 프롬프트 가드레일은 소프트 가이드일 뿐이며, 실제 강제력은 도구 정책, exec 승인, sandboxing, 채널 allowlist에서 나옵니다(그리고 운영자는 설계상 이를 비활성화할 수 있습니다). 실제로 도움이 되는 것은: +강력한 시스템 프롬프트가 있어도 **프롬프트 주입은 해결되지 않았습니다**. 시스템 프롬프트 가드레일은 약한 지침일 뿐이며, 강제력은 도구 정책, exec 승인, 샌드박싱, 채널 allowlist에서 나옵니다(그리고 운영자는 설계상 이를 비활성화할 수 있습니다). 실제로 도움이 되는 것은 다음과 같습니다. -- 인바운드 DM을 잠그기(pairing/allowlist) -- 그룹에서는 mention gating을 선호하고, 공개 방에서 “항상 켜져 있는” 봇을 피하기 -- 링크, 첨부 파일, 붙여넣은 지시문을 기본적으로 적대적인 것으로 취급하기 -- 민감한 도구 실행은 sandbox에서 수행하고, 비밀은 에이전트가 접근 가능한 파일시스템 밖에 두기 -- 참고: sandboxing은 opt-in입니다. sandbox 모드가 꺼져 있으면 암묵적 `host=auto`는 gateway 호스트로 해석됩니다. 명시적 `host=sandbox`는 sandbox 런타임이 없기 때문에 여전히 fail closed합니다. 이 동작을 config에서 명시하려면 `host=gateway`를 설정하세요. -- 고위험 도구(`exec`, `browser`, `web_fetch`, `web_search`)는 신뢰된 에이전트 또는 명시적 allowlist에만 제한하기 -- 인터프리터(`python`, `node`, `ruby`, `perl`, `php`, `lua`, `osascript`)를 allowlist에 넣는 경우 `tools.exec.strictInlineEval`을 활성화하여 inline eval 형식도 명시적 승인을 요구하게 하기 -- **모델 선택이 중요:** 오래되거나 작은 레거시 모델은 프롬프트 인젝션과 도구 오용에 훨씬 덜 강합니다. 도구 활성화 에이전트에는 가장 강력한 최신 세대 instruction-hardened 모델을 사용하세요. +- 인바운드 DM을 잠그세요(pairing/allowlist). +- 그룹에서는 멘션 게이팅을 선호하고, 공개 방에서 “항상 켜져 있는” 봇은 피하세요. +- 링크, 첨부파일, 붙여넣은 지시는 기본적으로 적대적이라고 가정하세요. +- 민감한 도구 실행은 샌드박스에서 수행하고, 시크릿은 에이전트가 접근 가능한 파일시스템 밖에 두세요. +- 참고: 샌드박싱은 opt-in입니다. sandbox 모드가 꺼져 있으면 암시적 `host=auto`는 gateway 호스트로 해석됩니다. 명시적인 `host=sandbox`는 사용 가능한 sandbox 런타임이 없으므로 여전히 닫힌 상태로 실패합니다. 이 동작을 config에서 명시적으로 표현하고 싶다면 `host=gateway`를 설정하세요. +- 고위험 도구(`exec`, `browser`, `web_fetch`, `web_search`)는 신뢰된 에이전트 또는 명시적 allowlist로 제한하세요. +- 인터프리터(`python`, `node`, `ruby`, `perl`, `php`, `lua`, `osascript`)를 allowlist에 넣는다면, 인라인 eval 형식도 여전히 명시적 승인이 필요하도록 `tools.exec.strictInlineEval`을 활성화하세요. +- **모델 선택이 중요합니다:** 더 오래되거나 더 작거나 레거시인 모델은 프롬프트 주입과 도구 오용에 훨씬 덜 견고합니다. 도구 사용 가능 에이전트에는 가장 강력한 최신 세대의 instruction-hardened 모델을 사용하세요. -다음과 같은 신호는 신뢰하지 마세요: +비신뢰로 취급해야 할 위험 신호: -- “이 파일/URL을 읽고 적힌 대로 정확히 수행해.” +- “이 파일/URL을 읽고 그 내용대로 정확히 수행해.” - “시스템 프롬프트나 안전 규칙을 무시해.” - “숨겨진 지침이나 도구 출력을 공개해.” -- “`~/.openclaw`나 로그 전체 내용을 붙여넣어.” +- “`~/.openclaw`나 로그의 전체 내용을 붙여넣어.” -## unsafe external content 우회 플래그 +## 안전하지 않은 외부 콘텐츠 우회 플래그 -OpenClaw에는 외부 콘텐츠 안전 래핑을 비활성화하는 명시적 우회 플래그가 있습니다: +OpenClaw에는 외부 콘텐츠 안전 래핑을 비활성화하는 명시적 우회 플래그가 있습니다. - `hooks.mappings[].allowUnsafeExternalContent` - `hooks.gmail.allowUnsafeExternalContent` -- Cron 페이로드 필드 `allowUnsafeExternalContent` +- Cron payload 필드 `allowUnsafeExternalContent` 가이드: -- 프로덕션에서는 설정하지 않거나 false로 유지하세요. -- 매우 제한된 디버깅 용도로만 일시적으로 활성화하세요. -- 활성화한다면 해당 에이전트를 격리하세요(sandbox + minimal 도구 + 전용 세션 네임스페이스). +- 프로덕션에서는 이를 설정하지 않거나 false로 유지하세요. +- 엄격히 제한된 디버깅에만 일시적으로 활성화하세요. +- 활성화한다면 해당 에이전트를 격리하세요(sandbox + 최소 도구 + 전용 세션 네임스페이스). Hooks 위험 참고: -- Hook 페이로드는 사용자가 제어하는 시스템에서 전달되더라도 신뢰되지 않는 콘텐츠입니다(메일/문서/웹 콘텐츠는 프롬프트 인젝션을 담을 수 있음). -- 약한 모델 티어는 이 위험을 증가시킵니다. hook 기반 자동화에는 강력한 최신 모델 티어를 선호하고, `tools.profile: "messaging"` 또는 그보다 더 엄격한 도구 정책을 유지하며, 가능하면 sandboxing도 사용하세요. +- hook payload는 전송이 통제된 시스템에서 오더라도 비신뢰 콘텐츠입니다(메일/문서/웹 콘텐츠는 프롬프트 주입을 포함할 수 있습니다). +- 약한 모델 티어는 이 위험을 증가시킵니다. hook 기반 자동화에는 강력한 최신 모델 티어를 선호하고, 가능한 경우 `tools.profile: "messaging"` 또는 그보다 더 엄격한 정책과 함께 샌드박싱을 사용하세요. -### 프롬프트 인젝션은 공개 DM이 없어도 발생할 수 있습니다 +### 프롬프트 주입은 공개 DM이 아니어도 발생할 수 있습니다 -봇에 메시지를 보낼 수 있는 사람이 **오직 본인뿐**이라 해도, 봇이 읽는 **신뢰되지 않는 콘텐츠**(웹 검색/가져오기 결과, 브라우저 페이지, 이메일, 문서, 첨부 파일, 붙여넣은 로그/코드)를 통해 프롬프트 인젝션은 여전히 발생할 수 있습니다. 즉, 발신자만이 위협 표면이 아니라 **콘텐츠 자체**가 적대적 지시를 담고 있을 수 있습니다. +봇에 메시지를 보낼 수 있는 사람이 **오직 당신뿐**이어도, 봇이 읽는 **비신뢰 콘텐츠**(웹 검색/가져오기 결과, 브라우저 페이지, 이메일, 문서, 첨부파일, 붙여넣은 로그/코드)를 통해 프롬프트 주입이 발생할 수 있습니다. 즉, 발신자만이 유일한 위협 표면이 아니라 **콘텐츠 자체**가 적대적 지시를 담을 수 있습니다. -도구가 활성화된 경우 일반적인 위험은 컨텍스트 유출 또는 도구 호출 트리거입니다. 폭발 반경을 줄이려면: +도구가 활성화되어 있을 때의 일반적인 위험은 컨텍스트 유출 또는 도구 호출 트리거입니다. 영향 반경을 줄이려면 다음을 고려하세요. -- 신뢰되지 않는 콘텐츠를 요약하는 읽기 전용 또는 도구 비활성화 **reader agent**를 사용하고, 그 요약만 메인 에이전트에 전달하세요. -- 필요하지 않다면 도구 활성화 에이전트에서 `web_search` / `web_fetch` / `browser`를 꺼두세요. -- OpenResponses URL 입력(`input_file` / `input_image`)의 경우 - `gateway.http.endpoints.responses.files.urlAllowlist`와 - `gateway.http.endpoints.responses.images.urlAllowlist`를 엄격하게 설정하고 - `maxUrlParts`를 낮게 유지하세요. 빈 allowlist는 설정되지 않은 것으로 간주되므로, - URL 가져오기를 완전히 비활성화하려면 `files.allowUrl: false` / `images.allowUrl: false`를 사용하세요. -- OpenResponses 파일 입력의 경우 디코드된 `input_file` 텍스트도 여전히 - **신뢰되지 않는 외부 콘텐츠**로 주입됩니다. Gateway가 로컬에서 디코드했다는 이유만으로 - 파일 텍스트를 신뢰할 수 있다고 생각하지 마세요. 이 주입 블록은 여전히 - 긴 `SECURITY NOTICE:` 배너는 생략하더라도 명시적인 - `<<>>` 경계 마커와 `Source: External` - 메타데이터를 포함합니다. -- 첨부 문서에서 텍스트를 추출하여 미디어 프롬프트에 추가하기 전에 - media-understanding이 텍스트를 추출하는 경우에도 동일한 marker 기반 래핑이 적용됩니다. -- 신뢰되지 않는 입력을 다루는 모든 에이전트에는 sandboxing과 엄격한 도구 allowlist를 활성화하세요. -- 비밀은 프롬프트에 넣지 말고 gateway 호스트의 env/config를 통해 전달하세요. +- 비신뢰 콘텐츠를 요약하는 읽기 전용 또는 도구 비활성화 **reader agent**를 사용한 뒤, 그 요약만 메인 에이전트에 전달하세요. +- 필요하지 않다면 도구 사용 가능 에이전트에서는 `web_search` / `web_fetch` / `browser`를 꺼두세요. +- OpenResponses URL 입력(`input_file` / `input_image`)의 경우, `gateway.http.endpoints.responses.files.urlAllowlist`와 `gateway.http.endpoints.responses.images.urlAllowlist`를 엄격하게 설정하고 `maxUrlParts`는 낮게 유지하세요. 빈 allowlist는 미설정으로 취급되므로, URL 가져오기를 완전히 비활성화하려면 `files.allowUrl: false` / `images.allowUrl: false`를 사용하세요. +- OpenResponses 파일 입력의 경우, 디코드된 `input_file` 텍스트도 여전히 **비신뢰 외부 콘텐츠**로 주입됩니다. Gateway가 로컬에서 디코드했다는 이유만으로 파일 텍스트를 신뢰하지 마세요. 이 주입 블록은 더 긴 `SECURITY NOTICE:` 배너는 생략하지만, 여전히 명시적인 `<<>>` 경계 마커와 `Source: External` 메타데이터를 포함합니다. +- 첨부 문서에서 media-understanding이 텍스트를 추출해 미디어 프롬프트에 추가할 때도 동일한 마커 기반 래핑이 적용됩니다. +- 비신뢰 입력을 다루는 모든 에이전트에 샌드박싱과 엄격한 도구 allowlist를 활성화하세요. +- 시크릿은 프롬프트에 넣지 말고 gateway 호스트의 env/config를 통해 전달하세요. ### 모델 강도(보안 참고) -프롬프트 인젝션 저항성은 모델 티어마다 **균일하지 않습니다**. 더 작고 저렴한 모델일수록, 특히 적대적 프롬프트 아래에서 도구 오용과 지시 탈취에 더 취약한 경향이 있습니다. +프롬프트 주입 저항성은 모델 티어마다 **균일하지 않습니다**. 더 작고 저렴한 모델은 일반적으로, 특히 적대적 프롬프트 상황에서 도구 오용과 지시 탈취에 더 취약합니다. -도구 활성화 에이전트나 신뢰되지 않는 콘텐츠를 읽는 에이전트에서는 오래되거나 작은 모델의 프롬프트 인젝션 위험이 지나치게 높을 수 있습니다. 그런 작업에는 약한 모델 티어를 사용하지 마세요. +도구 사용 가능 에이전트 또는 비신뢰 콘텐츠를 읽는 에이전트의 경우, 더 오래되거나 더 작은 모델에서의 프롬프트 주입 위험은 대체로 너무 높습니다. 그런 작업 부하를 약한 모델 티어에서 실행하지 마세요. 권장 사항: - 도구를 실행하거나 파일/네트워크에 접근할 수 있는 모든 봇에는 **최신 세대의 최고 티어 모델**을 사용하세요. -- 도구 활성화 에이전트나 신뢰되지 않는 inbox에는 **오래되거나 약하거나 작은 티어**를 사용하지 마세요. 프롬프트 인젝션 위험이 너무 큽니다. -- 작은 모델을 반드시 사용해야 한다면 **폭발 반경을 줄이세요**(읽기 전용 도구, 강한 sandboxing, 최소 파일시스템 접근, 엄격한 allowlist). -- 작은 모델을 사용할 때는 **모든 세션에 sandboxing을 활성화**하고, 입력이 엄격히 통제되지 않는 한 **web_search/web_fetch/browser를 비활성화**하세요. -- 신뢰된 입력과 도구가 없는 채팅 전용 개인 비서라면 작은 모델도 보통 괜찮습니다. +- 도구 사용 가능 에이전트나 비신뢰 받은편지함에는 **더 오래되거나 더 약하거나 더 작은 티어를 사용하지 마세요**. 프롬프트 주입 위험이 너무 높습니다. +- 더 작은 모델을 반드시 사용해야 한다면, **영향 반경을 줄이세요**(읽기 전용 도구, 강력한 샌드박싱, 최소한의 파일시스템 접근, 엄격한 allowlist). +- 작은 모델을 실행할 때는 **모든 세션에 샌드박싱을 활성화**하고, 입력이 엄격히 통제되지 않는 한 **web_search/web_fetch/browser를 비활성화**하세요. +- 신뢰된 입력만 다루고 도구가 없는 채팅 전용 개인 비서라면, 더 작은 모델도 보통 괜찮습니다. -## 그룹에서의 Reasoning 및 verbose 출력 +## 그룹에서의 Reasoning 및 상세 출력 -`/reasoning`과 `/verbose`는 공개 채널에 의도되지 않은 내부 reasoning 또는 도구 출력을 노출할 수 있습니다. 그룹 환경에서는 이를 **디버그 전용**으로 취급하고 명시적으로 필요하지 않다면 꺼두세요. +`/reasoning`과 `/verbose`는 공개 채널에 노출되어서는 안 되는 내부 추론 또는 도구 출력을 드러낼 수 있습니다. 그룹 환경에서는 이를 **디버그 전용**으로 취급하고, 명시적으로 필요하지 않다면 꺼두세요. 가이드: -- 공개 방에서는 `/reasoning`과 `/verbose`를 꺼두세요. -- 활성화한다면 신뢰된 DM 또는 엄격히 통제된 방에서만 하세요. -- 기억하세요: verbose 출력에는 도구 인수, URL, 모델이 본 데이터가 포함될 수 있습니다. +- 공개 방에서는 `/reasoning`과 `/verbose`를 비활성화하세요. +- 활성화한다면 신뢰된 DM 또는 엄격히 통제된 방에서만 사용하세요. +- 상세 출력에는 도구 인자, URL, 모델이 본 데이터가 포함될 수 있다는 점을 기억하세요. -## 구성 강화(예시) +## 설정 강화(예시) ### 0) 파일 권한 -Gateway 호스트에서 config + state를 비공개로 유지하세요: +gateway 호스트에서 설정과 상태를 비공개로 유지하세요. - `~/.openclaw/openclaw.json`: `600`(사용자 읽기/쓰기만) - `~/.openclaw`: `700`(사용자만) -`openclaw doctor`는 이러한 권한 문제를 경고하고 강화 제안을 할 수 있습니다. +`openclaw doctor`는 이러한 권한을 경고하고 더 엄격하게 조정하도록 제안할 수 있습니다. ### 0.4) 네트워크 노출(bind + port + firewall) -Gateway는 하나의 포트에서 **WebSocket + HTTP**를 다중화합니다: +Gateway는 하나의 포트에서 **WebSocket + HTTP**를 멀티플렉싱합니다. - 기본값: `18789` -- Config/플래그/env: `gateway.port`, `--port`, `OPENCLAW_GATEWAY_PORT` +- 설정/플래그/env: `gateway.port`, `--port`, `OPENCLAW_GATEWAY_PORT` -이 HTTP 표면에는 Control UI와 canvas host도 포함됩니다: +이 HTTP 표면에는 Control UI와 canvas host가 포함됩니다. -- Control UI(SPA assets) (기본 base path `/`) -- Canvas host: `/__openclaw__/canvas/` 및 `/__openclaw__/a2ui/` (임의 HTML/JS, 신뢰되지 않는 콘텐츠로 취급) +- Control UI (SPA assets) (기본 base path `/`) +- Canvas host: `/__openclaw__/canvas/` 및 `/__openclaw__/a2ui/` (임의의 HTML/JS, 비신뢰 콘텐츠로 취급) -일반 브라우저에서 canvas 콘텐츠를 로드한다면, 다른 신뢰되지 않는 웹 페이지처럼 취급하세요: +일반 브라우저에서 canvas 콘텐츠를 로드한다면, 다른 비신뢰 웹 페이지와 동일하게 취급하세요. -- canvas host를 신뢰되지 않는 네트워크/사용자에게 노출하지 마세요. -- 의미를 완전히 이해하지 못하는 한, canvas 콘텐츠가 권한 있는 웹 표면과 같은 origin을 공유하도록 하지 마세요. +- canvas host를 비신뢰 네트워크/사용자에게 노출하지 마세요. +- 그 영향을 완전히 이해하지 못한다면, canvas 콘텐츠가 권한 있는 웹 표면과 동일한 origin을 공유하게 하지 마세요. -Bind 모드는 Gateway가 어디서 리스닝할지 제어합니다: +bind 모드는 Gateway가 어디에서 수신 대기하는지를 제어합니다. -- `gateway.bind: "loopback"`(기본값): 로컬 클라이언트만 연결 가능 -- non-loopback bind(`"lan"`, `"tailnet"`, `"custom"`)는 공격 표면을 확장합니다. gateway auth(공유 token/password 또는 올바르게 구성된 non-loopback trusted proxy) 및 실제 firewall과 함께만 사용하세요. +- `gateway.bind: "loopback"`(기본값): 로컬 클라이언트만 연결할 수 있습니다. +- loopback이 아닌 bind(`"lan"`, `"tailnet"`, `"custom"`)는 공격 표면을 넓힙니다. gateway auth(공유 token/password 또는 올바르게 설정된 비-loopback trusted proxy)와 실제 방화벽이 있는 경우에만 사용하세요. -실전 규칙: +경험칙: -- LAN bind보다 Tailscale Serve를 선호하세요(Serve는 Gateway를 loopback에 유지하고, 접근은 Tailscale이 처리). -- LAN에 bind해야 한다면 포트를 엄격한 source IP allowlist로 firewall하세요. 광범위하게 port-forward하지 마세요. -- `0.0.0.0`에 인증 없이 Gateway를 노출하지 마세요. +- LAN bind보다 Tailscale Serve를 선호하세요(Serve는 Gateway를 loopback에 유지하고, Tailscale이 접근을 처리합니다). +- 반드시 LAN에 bind해야 한다면, 포트를 엄격한 소스 IP allowlist로 방화벽 처리하세요. 광범위한 포트 포워딩은 하지 마세요. +- 인증 없이 `0.0.0.0`에 Gateway를 절대 노출하지 마세요. -### 0.4.1) Docker 포트 publish + UFW (`DOCKER-USER`) +### 0.4.1) Docker 포트 게시 + UFW (`DOCKER-USER`) -VPS에서 Docker로 OpenClaw를 실행한다면, publish된 컨테이너 포트 -(`-p HOST:CONTAINER` 또는 Compose `ports:`)는 호스트 `INPUT` 규칙만이 아니라 -Docker forwarding chain을 통해 라우팅된다는 점을 기억하세요. +VPS에서 Docker로 OpenClaw를 실행한다면, 게시된 컨테이너 포트 +(`-p HOST:CONTAINER` 또는 Compose `ports:`)는 호스트의 `INPUT` 규칙만이 아니라 +Docker의 포워딩 체인을 통해 라우팅된다는 점을 기억하세요. -Docker 트래픽을 firewall 정책과 일치시키려면 -`DOCKER-USER`에서 규칙을 강제하세요(이 체인은 Docker 자체 accept 규칙보다 먼저 평가됨). +Docker 트래픽을 방화벽 정책과 일치시키려면 +`DOCKER-USER`에서 규칙을 강제하세요(이 체인은 Docker 자체의 accept 규칙보다 먼저 평가됩니다). 많은 최신 배포판에서 `iptables`/`ip6tables`는 `iptables-nft` 프런트엔드를 사용하며, -여전히 nftables 백엔드에 이러한 규칙을 적용합니다. +이 규칙은 여전히 nftables 백엔드에 적용됩니다. 최소 allowlist 예시(IPv4): ```bash -# /etc/ufw/after.rules (append as its own *filter section) +# /etc/ufw/after.rules (독립된 *filter 섹션으로 추가) *filter :DOCKER-USER - [0:0] -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN @@ -796,11 +777,12 @@ Docker 트래픽을 firewall 정책과 일치시키려면 COMMIT ``` -IPv6에는 별도의 테이블이 있습니다. Docker IPv6가 활성화되어 있다면 -`/etc/ufw/after6.rules`에 일치하는 정책도 추가하세요. +IPv6는 별도의 테이블을 사용합니다. Docker IPv6가 활성화되어 있다면 +`/etc/ufw/after6.rules`에도 동일한 정책을 추가하세요. -문서 스니펫에 `eth0` 같은 인터페이스 이름을 하드코딩하지 마세요. 인터페이스 이름은 -VPS 이미지마다 다르며(`ens3`, `enp*` 등), 불일치하면 deny 규칙이 의도치 않게 건너뛰어질 수 있습니다. +문서 예시에서 `eth0` 같은 인터페이스 이름을 하드코딩하지 마세요. 인터페이스 이름은 +VPS 이미지마다 다르며(`ens3`, `enp*` 등), 일치하지 않으면 차단 규칙이 +실수로 적용되지 않을 수 있습니다. 리로드 후 빠른 검증: @@ -811,22 +793,22 @@ ip6tables -S DOCKER-USER nmap -sT -p 1-65535 --open ``` -외부에서 보이는 포트는 의도적으로 노출한 것만이어야 합니다(대부분의 설정에서는 -SSH + reverse proxy 포트). +외부에서 보이는 예상 포트는 의도적으로 노출한 것만이어야 합니다(대부분의 +설정에서는 SSH + reverse proxy 포트). -### 0.4.2) mDNS/Bonjour discovery (정보 노출) +### 0.4.2) mDNS/Bonjour 검색(정보 노출) -Gateway는 로컬 장치 discovery를 위해 mDNS(`_openclaw-gw._tcp`, 포트 5353)로 자신의 존재를 브로드캐스트합니다. full 모드에서는 운영 세부 정보를 노출할 수 있는 TXT 레코드도 포함됩니다: +Gateway는 로컬 디바이스 검색을 위해 mDNS(`_openclaw-gw._tcp`, 포트 5353)로 자신의 존재를 브로드캐스트합니다. full 모드에서는 운영 세부 정보를 노출할 수 있는 TXT 레코드가 포함됩니다. -- `cliPath`: CLI 바이너리의 전체 파일시스템 경로(사용자 이름 및 설치 위치 노출) +- `cliPath`: CLI 바이너리의 전체 파일시스템 경로(사용자 이름과 설치 위치 노출) - `sshPort`: 호스트의 SSH 사용 가능 여부 광고 - `displayName`, `lanHost`: 호스트명 정보 -**운영 보안 고려 사항:** 인프라 세부 정보를 브로드캐스트하면 로컬 네트워크의 누구에게나 정찰이 쉬워집니다. 파일시스템 경로나 SSH 사용 가능 여부 같은 “무해해 보이는” 정보도 공격자가 환경을 매핑하는 데 도움을 줍니다. +**운영 보안 고려 사항:** 인프라 세부 정보를 브로드캐스트하면 로컬 네트워크의 누구에게나 정찰이 쉬워집니다. 파일시스템 경로나 SSH 사용 가능 여부 같은 “무해해 보이는” 정보도 공격자가 환경을 파악하는 데 도움이 됩니다. **권장 사항:** -1. **minimal 모드**(기본값, 노출된 gateway에 권장): 민감한 필드를 mDNS 브로드캐스트에서 제외합니다: +1. **minimal 모드**(기본값, 노출된 gateways에 권장): mDNS 브로드캐스트에서 민감한 필드를 제외합니다. ```json5 { @@ -836,7 +818,7 @@ Gateway는 로컬 장치 discovery를 위해 mDNS(`_openclaw-gw._tcp`, 포트 53 } ``` -2. 로컬 장치 discovery가 필요 없다면 **완전히 비활성화**하세요: +2. 로컬 디바이스 검색이 필요하지 않다면 **완전히 비활성화**하세요. ```json5 { @@ -846,7 +828,7 @@ Gateway는 로컬 장치 discovery를 위해 mDNS(`_openclaw-gw._tcp`, 포트 53 } ``` -3. **full 모드**(opt-in): TXT 레코드에 `cliPath` + `sshPort`를 포함합니다: +3. **full 모드**(opt-in): TXT 레코드에 `cliPath` + `sshPort`를 포함합니다. ```json5 { @@ -856,19 +838,19 @@ Gateway는 로컬 장치 discovery를 위해 mDNS(`_openclaw-gw._tcp`, 포트 53 } ``` -4. **환경 변수**(대안): config 변경 없이 mDNS를 비활성화하려면 `OPENCLAW_DISABLE_BONJOUR=1`을 설정하세요. +4. **환경 변수**(대안): 설정 변경 없이 mDNS를 비활성화하려면 `OPENCLAW_DISABLE_BONJOUR=1`을 설정하세요. -minimal 모드에서도 Gateway는 장치 discovery에 충분한 정보(`role`, `gatewayPort`, `transport`)를 계속 브로드캐스트하지만, `cliPath`와 `sshPort`는 제외합니다. CLI 경로 정보가 필요한 앱은 인증된 WebSocket 연결을 통해 이를 가져올 수 있습니다. +minimal 모드에서도 Gateway는 디바이스 검색에 충분한 정보(`role`, `gatewayPort`, `transport`)는 브로드캐스트하지만 `cliPath`와 `sshPort`는 제외합니다. CLI 경로 정보가 필요한 앱은 인증된 WebSocket 연결을 통해 대신 가져올 수 있습니다. -### 0.5) Gateway WebSocket 잠그기 (local auth) +### 0.5) Gateway WebSocket 잠그기(로컬 인증) -Gateway auth는 기본적으로 **필수**입니다. 유효한 gateway auth 경로가 구성되지 않으면 -Gateway는 WebSocket 연결을 거부합니다(fail‑closed). +Gateway 인증은 기본적으로 **필수**입니다. 유효한 gateway 인증 경로가 설정되지 않으면 +Gateway는 WebSocket 연결을 거부합니다(fail-closed). -온보딩은 기본적으로 token을 생성하므로(loopback이라도) +온보딩은 기본적으로 token을 생성하므로(loopback에서도) 로컬 클라이언트도 인증해야 합니다. -**모든** WS 클라이언트가 인증하게 하려면 token을 설정하세요: +**모든** WS 클라이언트가 인증해야 하도록 token을 설정하세요. ```json5 { @@ -878,124 +860,131 @@ Gateway는 WebSocket 연결을 거부합니다(fail‑closed). } ``` -Doctor가 이를 생성해 줄 수 있습니다: `openclaw doctor --generate-gateway-token`. +Doctor가 대신 생성해 줄 수 있습니다: `openclaw doctor --generate-gateway-token`. 참고: `gateway.remote.token` / `.password`는 클라이언트 자격 증명 소스입니다. -이 값만으로는 로컬 WS 접근을 보호하지 **않습니다**. +그 자체만으로 로컬 WS 접근을 보호하지는 **않습니다**. 로컬 호출 경로는 `gateway.auth.*`가 설정되지 않은 경우에만 `gateway.remote.*`를 fallback으로 사용할 수 있습니다. -`gateway.auth.token` / `gateway.auth.password`가 -SecretRef로 명시적으로 구성되어 있고 해석되지 않으면, 해석은 fail closed합니다(원격 fallback이 이를 가리지 않음). -선택 사항: `wss://` 사용 시 `gateway.remote.tlsFingerprint`로 원격 TLS를 pin할 수 있습니다. -plaintext `ws://`는 기본적으로 loopback 전용입니다. 신뢰된 private-network -경로에 대해서만, 비상 수단으로 클라이언트 프로세스에서 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`을 설정하세요. +`gateway.auth.token` / `gateway.auth.password`가 SecretRef로 명시적으로 설정되었는데 해결되지 않으면, 해결은 닫힌 상태로 실패합니다(원격 fallback으로 가려지지 않음). +선택 사항: `wss://`를 사용할 때는 `gateway.remote.tlsFingerprint`로 원격 TLS를 pinning하세요. +일반 텍스트 `ws://`는 기본적으로 loopback 전용입니다. 신뢰된 사설 네트워크 +경로를 위한 비상 옵션으로, 클라이언트 프로세스에 `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`을 설정하세요. -로컬 장치 페어링: +로컬 디바이스 페어링: -- 같은 호스트 클라이언트를 원활하게 하기 위해, 직접 local loopback 연결에 대해서는 장치 페어링이 자동 승인됩니다. -- OpenClaw는 또한 - 신뢰된 shared-secret helper 흐름을 위한 제한적인 backend/container-local self-connect 경로를 가지고 있습니다. -- tailnet 및 LAN 연결은 같은 호스트의 tailnet bind를 포함해 원격으로 간주되며 여전히 승인이 필요합니다. +- 동일 호스트 클라이언트의 사용성을 유지하기 위해 직접 로컬 loopback 연결은 디바이스 페어링이 자동 승인됩니다. +- OpenClaw에는 신뢰된 공유 시크릿 helper 흐름을 위한 제한적인 backend/container-local self-connect 경로도 있습니다. +- Tailnet 및 LAN 연결은, 동일 호스트의 tailnet bind를 포함하더라도, 페어링 측면에서는 원격으로 취급되며 여전히 승인이 필요합니다. 인증 모드: - `gateway.auth.mode: "token"`: 공유 bearer token(대부분의 설정에 권장) -- `gateway.auth.mode: "password"`: 비밀번호 인증(env를 통한 설정 권장: `OPENCLAW_GATEWAY_PASSWORD`) -- `gateway.auth.mode: "trusted-proxy"`: identity-aware reverse proxy가 사용자를 인증하고 헤더로 신원을 전달하도록 신뢰([Trusted Proxy Auth](/gateway/trusted-proxy-auth) 참조) +- `gateway.auth.mode: "password"`: 비밀번호 인증(env로 설정 권장: `OPENCLAW_GATEWAY_PASSWORD`) +- `gateway.auth.mode: "trusted-proxy"`: identity-aware reverse proxy가 사용자를 인증하고 헤더를 통해 신원을 전달하도록 신뢰([Trusted Proxy Auth](/ko/gateway/trusted-proxy-auth) 참고) -교체 체크리스트(token/password): +회전 체크리스트(token/password): -1. 새 비밀 생성/설정(`gateway.auth.token` 또는 `OPENCLAW_GATEWAY_PASSWORD`) -2. Gateway 재시작(또는 macOS 앱이 Gateway를 감독한다면 앱 재시작) -3. Gateway를 호출하는 모든 머신에서 원격 클라이언트 비밀 갱신(`gateway.remote.token` / `.password`) -4. 이전 자격 증명으로 더 이상 연결할 수 없는지 확인 +1. 새 시크릿을 생성/설정합니다(`gateway.auth.token` 또는 `OPENCLAW_GATEWAY_PASSWORD`). +2. Gateway를 재시작합니다(또는 macOS 앱이 Gateway를 감독 중이라면 그 앱을 재시작합니다). +3. 원격 클라이언트를 업데이트합니다(Gateway를 호출하는 머신의 `gateway.remote.token` / `.password`). +4. 이전 자격 증명으로 더 이상 연결할 수 없는지 확인합니다. -### 0.6) Tailscale Serve identity headers +### 0.6) Tailscale Serve 신원 헤더 `gateway.auth.allowTailscale`이 `true`일 때(Serve의 기본값), OpenClaw는 -Control UI/WebSocket 인증을 위해 Tailscale Serve identity header(`tailscale-user-login`)를 허용합니다. OpenClaw는 -로컬 Tailscale daemon(`tailscale whois`)을 통해 `x-forwarded-for` 주소를 해석하고 이를 해당 헤더와 일치시켜 신원을 검증합니다. 이 동작은 loopback에 도달하고 `x-forwarded-for`, `x-forwarded-proto`, `x-forwarded-host`가 Tailscale에 의해 주입된 요청에만 적용됩니다. -이 비동기 identity check 경로에서는 동일한 `{scope, ip}`에 대한 실패한 시도가 limiter가 실패를 기록하기 전에 직렬화됩니다. 따라서 한 Serve 클라이언트의 잘못된 동시 재시도는 두 번의 단순 불일치처럼 경쟁하지 않고 두 번째 시도에서 즉시 잠금이 걸릴 수 있습니다. -HTTP API 엔드포인트(예: `/v1/*`, `/tools/invoke`, `/api/channels/*`)는 Tailscale identity-header auth를 사용하지 않습니다. 이들은 여전히 gateway의 구성된 HTTP auth 모드를 따릅니다. +Control UI/WebSocket 인증을 위해 Tailscale Serve 신원 헤더(`tailscale-user-login`)를 허용합니다. OpenClaw는 +`x-forwarded-for` 주소를 로컬 Tailscale 데몬(`tailscale whois`)을 통해 확인하고 +이를 헤더와 비교해 신원을 검증합니다. 이 경로는 loopback에 도달하고 +Tailscale이 주입한 `x-forwarded-for`, `x-forwarded-proto`, `x-forwarded-host`를 포함한 요청에만 +적용됩니다. +이 비동기 신원 검사 경로에서는 동일한 `{scope, ip}`에 대한 실패 시도가 +limiter가 실패를 기록하기 전에 직렬화됩니다. 따라서 하나의 Serve 클라이언트에서 +동시 발생한 잘못된 재시도는 두 번의 일반 불일치처럼 경합하지 않고, 두 번째 시도가 즉시 잠길 수 있습니다. +HTTP API 엔드포인트(예: `/v1/*`, `/tools/invoke`, `/api/channels/*`)는 +Tailscale 신원 헤더 인증을 사용하지 않습니다. 이들은 여전히 gateway의 +설정된 HTTP 인증 모드를 따릅니다. 중요한 경계 참고: -- Gateway HTTP bearer auth는 사실상 전체 운영자 접근입니다. -- `/v1/chat/completions`, `/v1/responses`, `/api/channels/*`를 호출할 수 있는 자격 증명은 해당 gateway에 대한 전체 접근 운영자 비밀로 취급하세요. -- OpenAI 호환 HTTP 표면에서는 공유 비밀 bearer auth가 전체 기본 운영자 scope(`operator.admin`, `operator.approvals`, `operator.pairing`, `operator.read`, `operator.talk.secrets`, `operator.write`)와 에이전트 턴의 owner 의미를 복원합니다. 더 좁은 `x-openclaw-scopes` 값은 이 shared-secret 경로를 축소하지 못합니다. -- HTTP에서 per-request scope 의미는 요청이 trusted proxy auth나 private ingress의 `gateway.auth.mode="none"` 같은 신원 기반 모드에서 온 경우에만 적용됩니다. -- 그러한 신원 기반 모드에서는 `x-openclaw-scopes`를 생략하면 일반 운영자 기본 scope 집합으로 fallback합니다. 더 좁은 scope 집합이 필요하면 헤더를 명시적으로 보내세요. -- `/tools/invoke`도 동일한 shared-secret 규칙을 따릅니다. token/password bearer auth는 여기서도 전체 운영자 접근으로 취급되며, 신원 기반 모드는 여전히 선언된 scope를 존중합니다. -- 신뢰되지 않는 호출자와 이러한 자격 증명을 공유하지 마세요. 신뢰 경계별로 별도의 gateway를 선호하세요. +- Gateway HTTP bearer 인증은 사실상 전부 아니면 전무의 운영자 접근입니다. +- `/v1/chat/completions`, `/v1/responses`, 또는 `/api/channels/*`를 호출할 수 있는 자격 증명은 해당 gateway의 전체 접근 운영자 시크릿으로 취급하세요. +- OpenAI 호환 HTTP 표면에서 공유 시크릿 bearer 인증은 전체 기본 운영자 범위(`operator.admin`, `operator.approvals`, `operator.pairing`, `operator.read`, `operator.talk.secrets`, `operator.write`)와 에이전트 턴에 대한 owner 의미를 복원합니다. 더 좁은 `x-openclaw-scopes` 값은 이 공유 시크릿 경로를 축소하지 않습니다. +- HTTP에서 요청별 scope 의미는 trusted proxy auth 또는 `gateway.auth.mode="none"`인 사설 ingress처럼 신원 기반 모드에서만 적용됩니다. +- 이러한 신원 기반 모드에서는 `x-openclaw-scopes`를 생략하면 일반적인 기본 운영자 scope 집합으로 fallback됩니다. 더 좁은 scope 집합을 원할 때는 헤더를 명시적으로 보내세요. +- `/tools/invoke`도 동일한 공유 시크릿 규칙을 따릅니다. token/password bearer 인증은 여기서도 전체 운영자 접근으로 취급되며, 신원 기반 모드는 여전히 선언된 scope를 존중합니다. +- 이러한 자격 증명을 비신뢰 호출자와 공유하지 마세요. 신뢰 경계별로 별도의 gateways를 선호하세요. -**신뢰 가정:** tokenless Serve auth는 gateway 호스트가 신뢰된다고 가정합니다. -이를 적대적인 같은 호스트 프로세스에 대한 보호로 취급하지 마세요. gateway 호스트에서 신뢰되지 않는 -로컬 코드가 실행될 수 있다면 `gateway.auth.allowTailscale`을 비활성화하고 +**신뢰 가정:** token 없는 Serve 인증은 gateway 호스트가 신뢰된다고 가정합니다. +이를 적대적인 동일 호스트 프로세스로부터의 보호로 간주하지 마세요. 비신뢰 +로컬 코드가 gateway 호스트에서 실행될 수 있다면, `gateway.auth.allowTailscale`을 비활성화하고 `gateway.auth.mode: "token"` 또는 -`"password"`로 명시적인 shared-secret auth를 요구하세요. +`"password"`로 명시적 공유 시크릿 인증을 요구하세요. -**보안 규칙:** 자신의 reverse proxy에서 이러한 헤더를 전달하지 마세요. Gateway 앞에서 TLS를 종료하거나 프록시를 사용한다면 -`gateway.auth.allowTailscale`을 비활성화하고 -공유 비밀 auth(`gateway.auth.mode: -"token"` 또는 `"password"`) 또는 [Trusted Proxy Auth](/gateway/trusted-proxy-auth)를 사용하세요. +**보안 규칙:** 자체 reverse proxy에서 이 헤더들을 전달하지 마세요. +gateway 앞에서 TLS를 종료하거나 proxy를 둔다면, +`gateway.auth.allowTailscale`을 비활성화하고 공유 시크릿 인증(`gateway.auth.mode: +"token"` 또는 `"password"`) 또는 [Trusted Proxy Auth](/ko/gateway/trusted-proxy-auth)를 +사용하세요. -Trusted proxies: +신뢰된 프록시: -- Gateway 앞에서 TLS를 종료한다면 프록시 IP를 `gateway.trustedProxies`에 설정하세요. -- OpenClaw는 local pairing 검사와 HTTP auth/local 검사를 위한 클라이언트 IP를 결정하기 위해 해당 IP의 `x-forwarded-for`(또는 `x-real-ip`)를 신뢰합니다. +- Gateway 앞에서 TLS를 종료한다면, 프록시 IP를 `gateway.trustedProxies`에 설정하세요. +- OpenClaw는 로컬 페어링 검사와 HTTP 인증/로컬 검사를 위한 클라이언트 IP 결정에 대해 해당 IP에서 오는 `x-forwarded-for`(또는 `x-real-ip`)를 신뢰합니다. - 프록시가 `x-forwarded-for`를 **덮어쓰고**, Gateway 포트에 대한 직접 접근을 차단하도록 하세요. -참고: [Tailscale](/gateway/tailscale) 및 [Web overview](/web) +[Tailscale](/ko/gateway/tailscale) 및 [Web overview](/web)를 참고하세요. ### 0.6.1) node host를 통한 브라우저 제어(권장) -Gateway는 원격에 있지만 브라우저는 다른 머신에서 실행된다면, 브라우저 머신에서 **node host**를 실행하고 Gateway가 브라우저 작업을 프록시하도록 하세요([Browser tool](/tools/browser) 참조). node 페어링은 관리자 접근처럼 취급하세요. +Gateway는 원격에 있지만 브라우저가 다른 머신에서 실행된다면, 브라우저 머신에서 **node host**를 실행하고 Gateway가 브라우저 작업을 프록시하도록 하세요([Browser tool](/ko/tools/browser) 참고). +node 페어링은 관리자 접근처럼 취급하세요. 권장 패턴: -- Gateway와 node host를 같은 tailnet(Tailscale) 안에 두세요. -- node는 의도적으로 페어링하고, 필요하지 않다면 브라우저 프록시 라우팅을 비활성화하세요. +- Gateway와 node host를 같은 tailnet(Tailscale)에 유지하세요. +- node는 의도적으로 페어링하고, 필요 없다면 브라우저 프록시 라우팅은 비활성화하세요. 피해야 할 것: - relay/control 포트를 LAN 또는 공용 인터넷에 노출하기 -- 브라우저 제어 엔드포인트에 Tailscale Funnel 사용하기(공용 노출) +- 브라우저 제어 엔드포인트에 Tailscale Funnel 사용하기(공개 노출) -### 0.7) 디스크의 비밀 정보(민감 데이터) +### 0.7) 디스크의 시크릿(민감한 데이터) -`~/.openclaw/`(또는 `$OPENCLAW_STATE_DIR/`) 아래의 모든 것은 비밀 또는 개인 데이터를 포함할 수 있다고 가정하세요: +`~/.openclaw/`(또는 `$OPENCLAW_STATE_DIR/`) 아래의 모든 항목에는 시크릿 또는 비공개 데이터가 포함될 수 있다고 가정하세요. -- `openclaw.json`: config에 token(gateway, remote gateway), provider 설정, allowlist가 포함될 수 있음 -- `credentials/**`: 채널 자격 증명(예: WhatsApp creds), pairing allowlist, legacy OAuth 가져오기 -- `agents//agent/auth-profiles.json`: API 키, token profile, OAuth 토큰, 선택적인 `keyRef`/`tokenRef` -- `secrets.json`(선택 사항): `file` SecretRef provider에서 사용하는 파일 기반 비밀 페이로드(`secrets.providers`) -- `agents//agent/auth.json`: 레거시 호환 파일. 정적 `api_key` 항목은 발견 시 제거됩니다. -- `agents//sessions/**`: 개인 메시지 및 도구 출력을 포함할 수 있는 세션 transcript(`*.jsonl`) + 라우팅 메타데이터(`sessions.json`) -- 번들 plugin 패키지: 설치된 plugins(및 그 `node_modules/`) -- `sandboxes/**`: 도구 sandbox 워크스페이스; sandbox 안에서 읽고 쓴 파일 복사본이 쌓일 수 있음 +- `openclaw.json`: config에 토큰(gateway, remote gateway), provider 설정, allowlist가 포함될 수 있습니다. +- `credentials/**`: 채널 자격 증명(예: WhatsApp creds), pairing allowlist, 레거시 OAuth 가져오기. +- `agents//agent/auth-profiles.json`: API 키, 토큰 프로필, OAuth 토큰, 선택적 `keyRef`/`tokenRef`. +- `secrets.json`(선택 사항): `file` SecretRef provider(`secrets.providers`)에서 사용하는 파일 기반 시크릿 payload. +- `agents//agent/auth.json`: 레거시 호환성 파일. 정적 `api_key` 항목은 발견 시 제거됩니다. +- `agents//sessions/**`: 비공개 메시지와 도구 출력을 포함할 수 있는 세션 기록(`*.jsonl`) + 라우팅 메타데이터(`sessions.json`). +- 번들 plugin 패키지: 설치된 plugins(및 해당 `node_modules/`). +- `sandboxes/**`: 도구 sandbox 워크스페이스. sandbox 안에서 읽거나 쓴 파일의 복사본이 누적될 수 있습니다. -강화 팁: +하드닝 팁: -- 권한을 엄격히 유지하세요(디렉터리 `700`, 파일 `600`) -- gateway 호스트에 전체 디스크 암호화를 사용하세요 -- 호스트를 공유한다면 Gateway용 전용 OS 사용자 계정을 선호하세요 +- 권한을 엄격히 유지하세요(디렉터리는 `700`, 파일은 `600`). +- gateway 호스트에 전체 디스크 암호화를 사용하세요. +- 호스트를 공유한다면 Gateway 전용 OS 사용자 계정을 사용하는 것을 권장합니다. -### 0.8) 로그 + transcript (redaction + 보존) +### 0.8) 로그 + 기록(redaction + 보존) -접근 제어가 올바르더라도 로그와 transcript는 민감한 정보를 유출할 수 있습니다: +접근 제어가 올바르더라도 로그와 기록은 민감한 정보를 유출할 수 있습니다. - Gateway 로그에는 도구 요약, 오류, URL이 포함될 수 있습니다. -- 세션 transcript에는 붙여넣은 비밀, 파일 내용, 명령 출력, 링크가 포함될 수 있습니다. +- 세션 기록에는 붙여넣은 시크릿, 파일 내용, 명령 출력, 링크가 포함될 수 있습니다. 권장 사항: -- 도구 요약 redaction을 유지하세요(`logging.redactSensitive: "tools"`; 기본값) -- `logging.redactPatterns`를 통해 환경별 사용자 정의 패턴(token, hostnames, 내부 URL)을 추가하세요 -- 진단을 공유할 때는 raw logs보다 `openclaw status --all`(붙여넣기 친화적, 비밀 redaction됨)를 선호하세요 -- 장기 보존이 필요하지 않다면 오래된 세션 transcript와 로그 파일을 정리하세요 +- 도구 요약 redaction을 켜 두세요(`logging.redactSensitive: "tools"`; 기본값). +- `logging.redactPatterns`를 통해 환경별 사용자 지정 패턴(토큰, 호스트명, 내부 URL)을 추가하세요. +- 진단 정보를 공유할 때는 원시 로그보다 `openclaw status --all`을 우선 사용하세요(붙여넣기 가능, 시크릿 redacted). +- 긴 보존이 필요 없다면 오래된 세션 기록과 로그 파일을 정리하세요. -자세한 내용: [Logging](/gateway/logging) +자세한 내용: [Logging](/ko/gateway/logging) -### 1) DM: 기본값은 pairing +### 1) DM: 기본적으로 pairing ```json5 { @@ -1003,7 +992,7 @@ Gateway는 원격에 있지만 브라우저는 다른 머신에서 실행된다 } ``` -### 2) 그룹: 어디서나 멘션 필요 +### 2) 그룹: 어디서나 멘션 필수 ```json { @@ -1025,31 +1014,31 @@ Gateway는 원격에 있지만 브라우저는 다른 머신에서 실행된다 } ``` -그룹 채팅에서는 명시적으로 멘션될 때만 응답하세요. +그룹 채팅에서는 명시적으로 멘션된 경우에만 응답하세요. -### 3) 별도 번호 사용 (WhatsApp, Signal, Telegram) +### 3) 번호 분리(WhatsApp, Signal, Telegram) -전화번호 기반 채널에서는 개인 번호와 AI 번호를 분리하는 것을 고려하세요: +전화번호 기반 채널에서는 AI를 개인 번호와 별도의 전화번호로 운영하는 것을 고려하세요. -- 개인 번호: 개인 대화는 비공개 유지 -- 봇 번호: AI가 처리하며, 적절한 경계를 설정 +- 개인 번호: 대화가 비공개로 유지됨 +- 봇 번호: AI가 적절한 경계 안에서 이를 처리함 -### 4) 읽기 전용 모드 (sandbox + 도구 사용) +### 4) 읽기 전용 모드(sandbox + tools 사용) -다음을 조합해 읽기 전용 profile을 만들 수 있습니다: +다음을 조합해 읽기 전용 프로필을 만들 수 있습니다. - `agents.defaults.sandbox.workspaceAccess: "ro"`(또는 워크스페이스 접근이 전혀 없게 하려면 `"none"`) -- `write`, `edit`, `apply_patch`, `exec`, `process` 등을 차단하는 도구 allow/deny 목록 +- `write`, `edit`, `apply_patch`, `exec`, `process` 등을 차단하는 tool allow/deny 목록 -추가 강화 옵션: +추가 하드닝 옵션: -- `tools.exec.applyPatch.workspaceOnly: true`(기본값): sandboxing이 꺼져 있어도 `apply_patch`가 워크스페이스 디렉터리 밖에 쓰거나 삭제하지 못하게 합니다. `apply_patch`가 워크스페이스 밖 파일을 건드리게 하려는 경우에만 `false`로 설정하세요. -- `tools.fs.workspaceOnly: true`(선택 사항): `read`/`write`/`edit`/`apply_patch` 경로와 네이티브 프롬프트 이미지 자동 로드 경로를 워크스페이스 디렉터리로 제한합니다(현재 절대 경로를 허용하고 있고 하나의 가드레일을 원할 때 유용). -- 파일시스템 루트를 좁게 유지하세요. 에이전트 워크스페이스/샌드박스 워크스페이스에 홈 디렉터리 같은 광범위한 루트를 사용하지 마세요. 넓은 루트는 민감한 로컬 파일(예: `~/.openclaw` 아래의 상태/구성)을 파일시스템 도구에 노출할 수 있습니다. +- `tools.exec.applyPatch.workspaceOnly: true`(기본값): sandboxing이 꺼져 있어도 `apply_patch`가 워크스페이스 디렉터리 밖에 쓰기/삭제하지 못하도록 보장합니다. `apply_patch`가 워크스페이스 밖 파일도 다루게 하려는 의도가 있는 경우에만 `false`로 설정하세요. +- `tools.fs.workspaceOnly: true`(선택 사항): `read`/`write`/`edit`/`apply_patch` 경로와 네이티브 프롬프트 이미지 자동 로드 경로를 워크스페이스 디렉터리로 제한합니다(현재 절대 경로를 허용하고 있다면 하나의 가드레일로 유용합니다). +- 파일시스템 루트는 좁게 유지하세요. 에이전트 워크스페이스/sandbox 워크스페이스에 홈 디렉터리 같은 넓은 루트를 사용하지 마세요. 넓은 루트는 민감한 로컬 파일(예: `~/.openclaw` 아래의 상태/설정)을 파일시스템 도구에 노출할 수 있습니다. -### 5) 안전한 기본 설정 (복사/붙여넣기) +### 5) 보안 기본 구성(복사/붙여넣기) -Gateway를 비공개로 유지하고, DM pairing을 요구하며, 항상 켜진 그룹 봇을 피하는 “안전한 기본” config 예시: +Gateway를 비공개로 유지하고, DM pairing을 요구하며, 항상 켜져 있는 그룹 봇을 피하는 하나의 “안전한 기본값” 설정입니다. ```json5 { @@ -1068,70 +1057,71 @@ Gateway를 비공개로 유지하고, DM pairing을 요구하며, 항상 켜진 } ``` -더 “기본적으로 안전한” 도구 실행도 원한다면 sandbox + 위험한 도구 deny를 non-owner 에이전트에 추가하세요(아래 “에이전트별 접근 프로필” 예시 참조). +도구 실행도 “기본적으로 더 안전하게” 만들고 싶다면, 소유자가 아닌 에이전트에 대해 sandbox + 위험한 도구 deny를 추가하세요(아래 “에이전트별 접근 프로필” 예시 참고). -채팅 기반 에이전트 턴에 대한 내장 기본값: non-owner 발신자는 `cron` 또는 `gateway` 도구를 사용할 수 없습니다. +채팅 기반 에이전트 턴의 내장 기본값: 소유자가 아닌 발신자는 `cron` 또는 `gateway` 도구를 사용할 수 없습니다. -## Sandboxing (권장) +## 샌드박싱(권장) -전용 문서: [Sandboxing](/gateway/sandboxing) +전용 문서: [Sandboxing](/ko/gateway/sandboxing) -서로 보완적인 두 가지 접근 방식이 있습니다: +상호 보완적인 두 가지 접근 방식: -- **전체 Gateway를 Docker에서 실행**(컨테이너 경계): [Docker](/install/docker) -- **도구 sandbox** (`agents.defaults.sandbox`, 호스트 gateway + Docker 격리 도구): [Sandboxing](/gateway/sandboxing) +- **전체 Gateway를 Docker에서 실행**(컨테이너 경계): [Docker](/ko/install/docker) +- **도구 sandbox**(`agents.defaults.sandbox`, 호스트 gateway + Docker 격리 도구): [Sandboxing](/ko/gateway/sandboxing) -참고: 에이전트 간 교차 접근을 막으려면 `agents.defaults.sandbox.scope`를 `"agent"`(기본값) +참고: 에이전트 간 접근을 막으려면 `agents.defaults.sandbox.scope`를 `"agent"`(기본값) 또는 더 엄격한 세션별 격리를 위한 `"session"`으로 유지하세요. `scope: "shared"`는 -하나의 컨테이너/워크스페이스를 공유합니다. +하나의 컨테이너/워크스페이스를 사용합니다. -sandbox 내부의 에이전트 워크스페이스 접근도 고려하세요: +sandbox 내부의 에이전트 워크스페이스 접근도 고려하세요. -- `agents.defaults.sandbox.workspaceAccess: "none"`(기본값)은 에이전트 워크스페이스 접근을 막으며, 도구는 `~/.openclaw/sandboxes` 아래 sandbox 워크스페이스에서 실행됩니다 +- `agents.defaults.sandbox.workspaceAccess: "none"`(기본값)은 에이전트 워크스페이스에 접근하지 못하게 하며, 도구는 `~/.openclaw/sandboxes` 아래 sandbox 워크스페이스를 대상으로 실행됩니다 - `agents.defaults.sandbox.workspaceAccess: "ro"`는 에이전트 워크스페이스를 `/agent`에 읽기 전용으로 마운트합니다(`write`/`edit`/`apply_patch` 비활성화) -- `agents.defaults.sandbox.workspaceAccess: "rw"`는 에이전트 워크스페이스를 `/workspace`에 읽기/쓰기 마운트합니다 -- 추가 `sandbox.docker.binds`는 정규화 및 canonicalization된 source path에 대해 검증됩니다. 부모 심볼릭 링크 트릭과 canonical home alias도 `/etc`, `/var/run`, 또는 OS 홈 아래 자격 증명 디렉터리 같은 차단된 루트로 해석되면 여전히 fail closed합니다. +- `agents.defaults.sandbox.workspaceAccess: "rw"`는 에이전트 워크스페이스를 `/workspace`에 읽기/쓰기로 마운트합니다 +- 추가 `sandbox.docker.binds`는 정규화 및 canonicalized source path를 기준으로 검증됩니다. 상위 심볼릭 링크 트릭과 canonical home alias도 `/etc`, `/var/run`, 또는 OS 홈 아래 자격 증명 디렉터리 같은 차단된 루트로 해석되면 여전히 닫힌 상태로 실패합니다. -중요: `tools.elevated`는 sandbox 밖에서 exec를 실행하는 전역 기본 탈출구입니다. 실제 호스트는 기본적으로 `gateway`, exec 대상이 `node`로 구성된 경우에는 `node`입니다. `tools.elevated.allowFrom`은 엄격하게 유지하고 낯선 사람에게 활성화하지 마세요. 에이전트별 `agents.list[].tools.elevated`로 추가 제한도 가능합니다. [Elevated Mode](/tools/elevated)를 참조하세요. +중요: `tools.elevated`는 sandbox 밖에서 exec를 실행하는 전역 기본 탈출구입니다. 유효 호스트는 기본적으로 `gateway`이며, exec 대상이 `node`로 설정된 경우에는 `node`입니다. `tools.elevated.allowFrom`은 엄격하게 제한하고 낯선 사람에게는 활성화하지 마세요. `agents.list[].tools.elevated`를 통해 에이전트별로 elevated를 더 제한할 수도 있습니다. [Elevated Mode](/ko/tools/elevated)를 참고하세요. ### 하위 에이전트 위임 가드레일 -세션 도구를 허용한다면, 위임된 하위 에이전트 실행도 또 하나의 경계 결정으로 취급하세요: +세션 도구를 허용한다면, 위임된 하위 에이전트 실행도 또 하나의 경계 결정으로 취급하세요. - 에이전트가 실제로 위임이 필요하지 않다면 `sessions_spawn`을 거부하세요. -- `agents.defaults.subagents.allowAgents`와 에이전트별 `agents.list[].subagents.allowAgents` 재정의를 알려진 안전한 대상 에이전트로 제한하세요. -- sandbox를 유지해야 하는 워크플로에서는 `sessions_spawn`을 `sandbox: "require"`로 호출하세요(기본값은 `inherit`). -- `sandbox: "require"`는 대상 자식 런타임이 sandbox되지 않은 경우 빠르게 실패합니다. +- `agents.defaults.subagents.allowAgents`와 에이전트별 `agents.list[].subagents.allowAgents` 재정의는 알려진 안전한 대상 에이전트로 제한하세요. +- 반드시 sandbox 상태를 유지해야 하는 워크플로라면, `sessions_spawn`을 `sandbox: "require"`로 호출하세요(기본값은 `inherit`). +- `sandbox: "require"`는 대상 자식 런타임이 sandbox 상태가 아니면 즉시 실패합니다. ## 브라우저 제어 위험 브라우저 제어를 활성화하면 모델이 실제 브라우저를 조작할 수 있게 됩니다. -그 브라우저 프로필에 이미 로그인된 세션이 있다면, 모델은 해당 계정과 데이터에 -접근할 수 있습니다. 브라우저 프로필은 **민감한 상태**로 취급하세요: +그 브라우저 프로필에 이미 로그인된 세션이 있다면, 모델은 +해당 계정과 데이터에 접근할 수 있습니다. 브라우저 프로필은 **민감한 상태**로 취급하세요. -- 에이전트용 전용 프로필을 선호하세요(기본 `openclaw` 프로필). -- 에이전트를 개인 일상용 프로필에 연결하지 마세요. -- sandbox된 에이전트에는 신뢰하지 않는 한 호스트 브라우저 제어를 비활성화하세요. -- 독립형 loopback 브라우저 제어 API는 shared-secret auth만 허용합니다 - (gateway token bearer auth 또는 gateway password). trusted-proxy 또는 Tailscale Serve identity header는 사용하지 않습니다. -- 브라우저 다운로드는 신뢰되지 않는 입력으로 취급하세요. 격리된 다운로드 디렉터리를 선호하세요. -- 가능하면 에이전트 프로필에서 브라우저 sync/비밀번호 관리자를 비활성화하세요(폭발 반경 감소). -- 원격 gateway의 경우 “브라우저 제어”는 해당 프로필이 접근할 수 있는 모든 것에 대한 “운영자 접근”과 동등하다고 가정하세요. -- Gateway와 node host는 tailnet 전용으로 유지하고, 브라우저 제어 포트를 LAN이나 공용 인터넷에 노출하지 마세요. +- 에이전트 전용 프로필을 사용하세요(기본 `openclaw` 프로필 권장). +- 에이전트를 개인용 메인 브라우저 프로필에 연결하지 마세요. +- sandbox된 에이전트를 신뢰하지 않는다면 호스트 브라우저 제어는 비활성화하세요. +- 독립형 loopback 브라우저 제어 API는 공유 시크릿 인증만 허용합니다 + (gateway token bearer auth 또는 gateway password). 이 API는 + trusted-proxy 또는 Tailscale Serve 신원 헤더를 사용하지 않습니다. +- 브라우저 다운로드는 비신뢰 입력으로 취급하고, 격리된 다운로드 디렉터리를 사용하는 것이 좋습니다. +- 가능하다면 에이전트 프로필에서 브라우저 동기화/비밀번호 관리자를 비활성화하세요(영향 반경 감소). +- 원격 gateways에서는 “브라우저 제어”를 해당 프로필이 접근할 수 있는 것에 대한 “운영자 접근”과 동등하게 간주하세요. +- Gateway와 node host는 tailnet 전용으로 유지하고, 브라우저 제어 포트를 LAN 또는 공용 인터넷에 노출하지 마세요. - 필요하지 않다면 브라우저 프록시 라우팅을 비활성화하세요(`gateway.nodes.browser.mode="off"`). -- Chrome MCP existing-session 모드는 **더 안전하지 않습니다**. 해당 호스트 Chrome 프로필이 접근 가능한 곳에서 사용자처럼 동작할 수 있습니다. +- Chrome MCP의 기존 세션 모드는 **더 안전한 것**이 아닙니다. 해당 호스트 Chrome 프로필이 접근 가능한 모든 것에 대해 당신으로서 동작할 수 있습니다. -### 브라우저 SSRF 정책 (신뢰된 네트워크 기본값) +### 브라우저 SSRF 정책(기본적으로 엄격함) -OpenClaw의 브라우저 네트워크 정책은 기본적으로 신뢰된 운영자 모델을 따릅니다. 명시적으로 비활성화하지 않는 한 private/internal 대상은 허용됩니다. +OpenClaw의 브라우저 내비게이션 정책은 기본적으로 엄격합니다. 명시적으로 opt-in하지 않는 한 사설/내부 대상은 계속 차단됩니다. -- 기본값: `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: true` (설정되지 않았을 때 암묵적 적용) -- 레거시 별칭: `browser.ssrfPolicy.allowPrivateNetwork`도 호환성을 위해 계속 허용됨 -- 엄격 모드: private/internal/special-use 대상을 기본적으로 차단하려면 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: false`로 설정 -- 엄격 모드에서는 `hostnameAllowlist`(예: `*.example.com`)와 `allowedHostnames`(정확한 호스트 예외, `localhost` 같은 차단된 이름 포함)를 명시적 예외로 사용 -- 리디렉션 기반 피벗을 줄이기 위해 네비게이션 전 검사와, 네비게이션 후 최종 `http(s)` URL에 대한 best-effort 재검사가 수행됨 +- 기본값: `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork`가 설정되지 않았으므로 브라우저 내비게이션은 사설/내부/특수 용도 대상을 계속 차단합니다. +- 레거시 별칭: `browser.ssrfPolicy.allowPrivateNetwork`도 호환성을 위해 계속 허용됩니다. +- Opt-in 모드: 사설/내부/특수 용도 대상을 허용하려면 `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: true`를 설정하세요. +- 엄격 모드에서는 `hostnameAllowlist`(예: `*.example.com`)와 `allowedHostnames`(차단된 이름인 `localhost`를 포함한 정확한 호스트 예외)를 사용해 명시적 예외를 설정하세요. +- 리디렉션 기반 pivot을 줄이기 위해 내비게이션은 요청 전에 검사되고, 내비게이션 후 최종 `http(s)` URL에 대해서도 최선의 범위에서 다시 검사됩니다. -엄격 정책 예시: +엄격한 정책 예시: ```json5 { @@ -1145,20 +1135,19 @@ OpenClaw의 브라우저 네트워크 정책은 기본적으로 신뢰된 운영 } ``` -## 에이전트별 접근 프로필 (multi-agent) +## 에이전트별 접근 프로필(multi-agent) -멀티 에이전트 라우팅에서는 각 에이전트가 자체 sandbox + 도구 정책을 가질 수 있습니다. -이를 사용해 에이전트별로 **전체 접근**, **읽기 전용**, **접근 없음**을 설정하세요. -전체 세부 사항과 우선순위 규칙은 [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools)를 -참조하세요. +multi-agent 라우팅에서는 각 에이전트가 자체 sandbox + 도구 정책을 가질 수 있습니다. +이를 사용해 에이전트별로 **전체 접근**, **읽기 전용**, **접근 없음**을 부여하세요. +전체 세부 정보와 우선순위 규칙은 [Multi-Agent Sandbox & Tools](/ko/tools/multi-agent-sandbox-tools)를 참고하세요. 일반적인 사용 사례: -- Personal 에이전트: 전체 접근, sandbox 없음 +- 개인 에이전트: 전체 접근, sandbox 없음 - 가족/업무 에이전트: sandbox + 읽기 전용 도구 - 공개 에이전트: sandbox + 파일시스템/셸 도구 없음 -### 예시: 전체 접근 (sandbox 없음) +### 예시: 전체 접근(sandbox 없음) ```json5 { @@ -1198,7 +1187,7 @@ OpenClaw의 브라우저 네트워크 정책은 기본적으로 신뢰된 운영 } ``` -### 예시: 파일시스템/셸 접근 없음 (provider 메시징 허용) +### 예시: 파일시스템/셸 접근 없음(provider messaging 허용) ```json5 { @@ -1212,9 +1201,9 @@ OpenClaw의 브라우저 네트워크 정책은 기본적으로 신뢰된 운영 scope: "agent", workspaceAccess: "none", }, - // Session tools can reveal sensitive data from transcripts. By default OpenClaw limits these tools - // to the current session + spawned subagent sessions, but you can clamp further if needed. - // See `tools.sessions.visibility` in the configuration reference. + // 세션 도구는 기록에서 민감한 데이터를 드러낼 수 있습니다. 기본적으로 OpenClaw는 이러한 도구를 + // 현재 세션 + 생성된 하위 에이전트 세션으로 제한하지만, 필요하면 더 엄격히 제한할 수 있습니다. + // 설정 참조의 `tools.sessions.visibility`를 참고하세요. tools: { sessions: { visibility: "tree" }, // self | tree | agent | all allow: [ @@ -1249,9 +1238,9 @@ OpenClaw의 브라우저 네트워크 정책은 기본적으로 신뢰된 운영 } ``` -## AI에게 무엇을 알려야 하나 +## AI에 무엇을 알려줘야 하나요 -에이전트의 시스템 프롬프트에 보안 가이드라인을 포함하세요: +에이전트의 시스템 프롬프트에 보안 가이드를 포함하세요. ``` ## Security Rules @@ -1264,70 +1253,71 @@ OpenClaw의 브라우저 네트워크 정책은 기본적으로 신뢰된 운영 ## 사고 대응 -AI가 잘못된 일을 했다면: +AI가 나쁜 행동을 했다면: ### 격리 1. **중지:** macOS 앱이 Gateway를 감독 중이라면 앱을 중지하거나, `openclaw gateway` 프로세스를 종료하세요. 2. **노출 차단:** 무슨 일이 있었는지 이해할 때까지 `gateway.bind: "loopback"`으로 설정하거나 Tailscale Funnel/Serve를 비활성화하세요. -3. **접근 동결:** 위험한 DM/그룹을 `dmPolicy: "disabled"`로 바꾸거나 멘션 필수로 설정하고, `"*"` 전체 허용 항목이 있었다면 제거하세요. +3. **접근 동결:** 위험한 DM/그룹을 `dmPolicy: "disabled"`로 전환하거나 멘션을 요구하도록 바꾸고, `"*"` 전체 허용 항목이 있었다면 제거하세요. -### 교체 (비밀이 유출되었다면 침해로 간주) +### 교체(시크릿이 유출되었다면 침해로 가정) -1. Gateway auth(`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`)를 교체하고 재시작하세요. -2. Gateway를 호출할 수 있는 모든 머신의 원격 클라이언트 비밀(`gateway.remote.token` / `.password`)을 교체하세요. -3. provider/API 자격 증명(WhatsApp creds, Slack/Discord token, `auth-profiles.json`의 모델/API 키, 사용 중인 암호화된 비밀 페이로드 값)을 교체하세요. +1. Gateway 인증을 교체합니다(`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`) 그리고 재시작합니다. +2. Gateway를 호출할 수 있는 모든 머신에서 원격 클라이언트 시크릿(`gateway.remote.token` / `.password`)을 교체합니다. +3. provider/API 자격 증명(WhatsApp creds, Slack/Discord 토큰, `auth-profiles.json`의 모델/API 키, 그리고 사용 중인 경우 암호화된 시크릿 payload 값)을 교체합니다. ### 감사 -1. Gateway 로그 확인: `/tmp/openclaw/openclaw-YYYY-MM-DD.log` (또는 `logging.file`) -2. 관련 transcript 검토: `~/.openclaw/agents//sessions/*.jsonl` -3. 최근 config 변경 검토(접근 범위를 넓혔을 수 있는 모든 것: `gateway.bind`, `gateway.auth`, dm/group 정책, `tools.elevated`, plugin 변경) -4. `openclaw security audit --deep`를 다시 실행하고 critical 결과가 해결되었는지 확인 +1. Gateway 로그를 확인합니다: `/tmp/openclaw/openclaw-YYYY-MM-DD.log`(또는 `logging.file`). +2. 관련 기록을 검토합니다: `~/.openclaw/agents//sessions/*.jsonl`. +3. 최근 설정 변경을 검토합니다(접근을 넓혔을 수 있는 항목: `gateway.bind`, `gateway.auth`, DM/그룹 정책, `tools.elevated`, plugin 변경). +4. `openclaw security audit --deep`를 다시 실행하고 critical 결과가 해결되었는지 확인합니다. -### 보고용 수집 항목 +### 보고용 수집 - 타임스탬프, gateway 호스트 OS + OpenClaw 버전 -- 세션 transcript + 짧은 로그 tail(redaction 후) -- 공격자가 보낸 내용 + 에이전트가 수행한 동작 -- Gateway가 loopback 외부(LAN/Tailscale Funnel/Serve)로 노출되어 있었는지 여부 +- 세션 기록 + 짧은 로그 tail(redaction 후) +- 공격자가 보낸 내용 + 에이전트가 수행한 내용 +- Gateway가 loopback을 넘어 노출되었는지 여부(LAN/Tailscale Funnel/Serve) -## Secret Scanning (`detect-secrets`) +## 시크릿 스캐닝 (`detect-secrets`) CI는 `secrets` 작업에서 `detect-secrets` pre-commit hook을 실행합니다. -`main`에 대한 push는 항상 전체 파일 스캔을 실행합니다. pull request는 -base commit이 있을 때 변경 파일 빠른 경로를 사용하고, 그렇지 않으면 전체 파일 스캔으로 대체합니다. 실패하면 baseline에 아직 없는 새 후보가 있다는 뜻입니다. +`main`에 대한 push는 항상 전체 파일 스캔을 실행합니다. Pull request는 +base 커밋을 사용할 수 있으면 변경된 파일만 빠르게 검사하고, 그렇지 않으면 전체 파일 스캔으로 대체합니다. +실패한다면 아직 baseline에 없는 새 후보가 있다는 뜻입니다. -### CI가 실패할 때 +### CI가 실패한 경우 -1. 로컬에서 재현: +1. 로컬에서 재현하세요. ```bash pre-commit run --all-files detect-secrets ``` -2. 도구 이해: - - pre-commit의 `detect-secrets`는 저장소의 - baseline 및 exclude를 사용해 `detect-secrets-hook`을 실행합니다. - - `detect-secrets audit`는 대화형 검토를 열어 baseline의 각 - 항목을 실제 비밀인지 오탐인지 표시할 수 있게 합니다. -3. 실제 비밀이라면: 교체/제거한 뒤 스캔을 다시 실행해 baseline을 업데이트하세요. -4. 오탐이라면: 대화형 감사를 실행하고 false로 표시하세요: +2. 도구를 이해하세요. + - pre-commit에서의 `detect-secrets`는 저장소의 + baseline과 excludes를 사용해 `detect-secrets-hook`를 실행합니다. + - `detect-secrets audit`는 각 baseline + 항목을 실제 시크릿인지 false positive인지 표시할 수 있는 대화형 검토를 엽니다. +3. 실제 시크릿인 경우: 교체/제거한 다음, baseline을 업데이트하기 위해 스캔을 다시 실행하세요. +4. false positive인 경우: 대화형 audit를 실행하고 false로 표시하세요. ```bash detect-secrets audit .secrets.baseline ``` -5. 새 exclude가 필요하다면 `.detect-secrets.cfg`에 추가하고, 동일한 `--exclude-files` / `--exclude-lines` 플래그로 - baseline을 재생성하세요(config 파일은 참고용일 뿐이며, +5. 새 exclude가 필요하다면 `.detect-secrets.cfg`에 추가하고, 일치하는 `--exclude-files` / `--exclude-lines` 플래그로 + baseline을 다시 생성하세요(config 파일은 참고용일 뿐이며, detect-secrets는 이를 자동으로 읽지 않습니다). -의도한 상태를 반영하도록 업데이트된 `.secrets.baseline`을 커밋하세요. +의도한 상태가 반영되면 업데이트된 `.secrets.baseline`을 커밋하세요. ## 보안 이슈 보고 -OpenClaw에서 취약점을 발견하셨나요? 책임감 있게 보고해 주세요: +OpenClaw에서 취약점을 발견하셨나요? 책임 있는 방식으로 보고해 주세요. 1. 이메일: [security@openclaw.ai](mailto:security@openclaw.ai) -2. 수정되기 전까지는 공개 게시하지 마세요 -3. 원하시면 익명으로, 아니면 크레딧을 드리겠습니다 +2. 수정되기 전에는 공개 게시하지 마세요 +3. 원하시면 익명으로 처리할 수 있으며, 그렇지 않으면 크레딧을 드립니다 diff --git a/docs/ko/gateway/troubleshooting.md b/docs/ko/gateway/troubleshooting.md index 6e619ece5..1edadd1cf 100644 --- a/docs/ko/gateway/troubleshooting.md +++ b/docs/ko/gateway/troubleshooting.md @@ -1,14 +1,14 @@ --- read_when: - - 더 깊은 진단을 위해 문제 해결 허브가 이 페이지를 가리킨 경우 - - 정확한 명령이 포함된 안정적인 증상 기반 런북 섹션이 필요한 경우 -summary: 게이트웨이, 채널, 자동화, 노드, 브라우저에 대한 심층 문제 해결 런북 + - 문제 해결 허브에서 더 심층적인 진단을 위해 이 페이지로 안내했습니다 + - 정확한 명령어가 포함된 안정적인 증상별 런북 섹션이 필요합니다 +summary: 게이트웨이, 채널, 자동화, 노드, 브라우저를 위한 심층 문제 해결 런북 title: 문제 해결 x-i18n: - generated_at: "2026-04-08T02:16:07Z" + generated_at: "2026-04-11T02:45:04Z" model: gpt-5.4 provider: openai - source_hash: 02c9537845248db0c9d315bf581338a93215fe6fe3688ed96c7105cbb19fe6ba + source_hash: 7ef2faccba26ede307861504043a6415bc1f12dc64407771106f63ddc5b107f5 source_path: gateway/troubleshooting.md workflow: 15 --- @@ -16,11 +16,11 @@ x-i18n: # 게이트웨이 문제 해결 이 페이지는 심층 런북입니다. -먼저 빠른 초기 진단 흐름이 필요하다면 [/help/troubleshooting](/ko/help/troubleshooting)부터 시작하세요. +먼저 빠른 초기 분류 흐름이 필요하다면 [/help/troubleshooting](/ko/help/troubleshooting)에서 시작하세요. -## 명령 순서 +## 명령어 단계별 점검 -먼저 아래 명령을 이 순서대로 실행하세요. +먼저 아래 명령어를 이 순서대로 실행하세요. ```bash openclaw status @@ -32,14 +32,14 @@ openclaw channels status --probe 정상 상태에서 기대되는 신호: -- `openclaw gateway status`에 `Runtime: running`과 `RPC probe: ok`가 표시됩니다. -- `openclaw doctor`가 차단하는 구성/서비스 문제를 보고하지 않습니다. -- `openclaw channels status --probe`가 계정별 실시간 전송 상태와, +- `openclaw gateway status`에 `Runtime: running` 및 `RPC probe: ok`가 표시됩니다. +- `openclaw doctor`가 차단성 config/service 문제를 보고하지 않습니다. +- `openclaw channels status --probe`가 계정별 실제 전송 상태와, 지원되는 경우 `works` 또는 `audit ok` 같은 probe/audit 결과를 표시합니다. -## 긴 컨텍스트에 대해 추가 사용량이 필요한 Anthropic 429 +## 긴 컨텍스트에 추가 사용량이 필요한 Anthropic 429 -로그/오류에 다음 내용이 포함될 때 사용하세요: +로그/오류에 다음이 포함될 때 사용하세요. `HTTP 429: rate_limit_error: Extra usage is required for long context requests`. ```bash @@ -48,17 +48,17 @@ openclaw models status openclaw config get agents.defaults.models ``` -확인할 사항: +다음을 확인하세요. -- 선택된 Anthropic Opus/Sonnet 모델에 `params.context1m: true`가 설정되어 있음 -- 현재 Anthropic 자격 증명이 긴 컨텍스트 사용 자격이 없음 -- 1M 베타 경로가 필요한 긴 세션/모델 실행에서만 요청이 실패함 +- 선택된 Anthropic Opus/Sonnet 모델에 `params.context1m: true`가 설정되어 있습니다. +- 현재 Anthropic 자격 증명이 긴 컨텍스트 사용 권한 대상이 아닙니다. +- 1M 베타 경로가 필요한 긴 세션/모델 실행에서만 요청이 실패합니다. 해결 방법: -1. 해당 모델의 `context1m`을 비활성화해 일반 컨텍스트 창으로 되돌립니다. -2. 긴 컨텍스트 요청 자격이 있는 Anthropic 자격 증명을 사용하거나 Anthropic API 키로 전환합니다. -3. Anthropic 긴 컨텍스트 요청이 거부될 때도 실행이 계속되도록 대체 모델을 구성합니다. +1. 해당 모델의 `context1m`을 비활성화하여 일반 컨텍스트 창으로 폴백합니다. +2. 긴 컨텍스트 요청 권한이 있는 Anthropic 자격 증명을 사용하거나 Anthropic API 키로 전환합니다. +3. Anthropic 긴 컨텍스트 요청이 거부될 때도 실행이 계속되도록 폴백 모델을 구성합니다. 관련 문서: @@ -66,13 +66,13 @@ openclaw config get agents.defaults.models - [/reference/token-use](/ko/reference/token-use) - [/help/faq#why-am-i-seeing-http-429-ratelimiterror-from-anthropic](/ko/help/faq#why-am-i-seeing-http-429-ratelimiterror-from-anthropic) -## 로컬 OpenAI 호환 백엔드는 직접 probe에는 통과하지만 에이전트 실행은 실패함 +## 로컬 OpenAI 호환 백엔드는 직접 probe는 통과하지만 에이전트 실행은 실패함 -다음과 같은 경우에 사용하세요: +다음과 같은 경우에 사용하세요. - `curl ... /v1/models`는 동작함 - 작은 직접 `/v1/chat/completions` 호출은 동작함 -- OpenClaw 모델 실행은 일반 에이전트 턴에서만 실패함 +- OpenClaw 모델 실행은 일반적인 에이전트 턴에서만 실패함 ```bash curl http://127.0.0.1:1234/v1/models @@ -83,34 +83,34 @@ openclaw infer model run --model --prompt "hi" --json openclaw logs --follow ``` -확인할 사항: +다음을 확인하세요. -- 직접적인 작은 호출은 성공하지만 OpenClaw 실행은 더 큰 프롬프트에서만 실패함 -- 백엔드 오류가 `messages[].content`가 문자열이어야 한다고 보고함 -- 더 큰 프롬프트 토큰 수 또는 전체 에이전트 런타임 프롬프트에서만 나타나는 백엔드 크래시 +- 작은 직접 호출은 성공하지만, OpenClaw 실행은 더 큰 프롬프트에서만 실패함 +- 백엔드 오류에 `messages[].content`가 문자열이어야 한다는 내용이 있음 +- 더 큰 프롬프트 토큰 수 또는 전체 에이전트 런타임 프롬프트에서만 발생하는 백엔드 크래시 일반적인 징후: -- `messages[...].content: invalid type: sequence, expected a string` → 백엔드가 구조화된 Chat Completions content part를 거부합니다. 해결: `models.providers..models[].compat.requiresStringContent: true` 설정. -- 직접적인 작은 요청은 성공하지만 OpenClaw 에이전트 실행은 백엔드/모델 크래시로 실패함(예: 일부 `inferrs` 빌드에서 Gemma) → OpenClaw 전송 계층은 이미 올바를 가능성이 높으며, 백엔드가 더 큰 에이전트 런타임 프롬프트 형태를 처리하지 못하고 있습니다. -- 도구를 비활성화하면 실패가 줄어들지만 사라지지 않음 → 도구 스키마가 부담의 일부였지만, 남은 문제는 여전히 업스트림 모델/서버 용량 또는 백엔드 버그입니다. +- `messages[...].content: invalid type: sequence, expected a string` → 백엔드가 구조화된 Chat Completions content parts를 거부합니다. 해결: `models.providers..models[].compat.requiresStringContent: true`를 설정하세요. +- 작은 직접 요청은 성공하지만 OpenClaw 에이전트 실행은 백엔드/모델 크래시로 실패함(예: 일부 `inferrs` 빌드의 Gemma) → OpenClaw 전송 자체는 이미 올바를 가능성이 높고, 더 큰 에이전트 런타임 프롬프트 형태에서 백엔드가 실패하고 있는 것입니다. +- 도구를 비활성화하면 실패가 줄어들지만 사라지지는 않음 → 도구 스키마가 부담의 일부였지만, 남아 있는 문제는 여전히 상위 모델/서버 용량 또는 백엔드 버그입니다. 해결 방법: -1. 문자열만 받는 Chat Completions 백엔드에는 `compat.requiresStringContent: true`를 설정합니다. -2. OpenClaw의 도구 스키마 표면을 안정적으로 처리하지 못하는 모델/백엔드에는 `compat.supportsTools: false`를 설정합니다. -3. 가능하면 프롬프트 부담을 줄입니다: 더 작은 워크스페이스 부트스트랩, 더 짧은 세션 기록, 더 가벼운 로컬 모델, 또는 긴 컨텍스트 지원이 더 강한 백엔드 사용. -4. 작은 직접 요청은 계속 성공하는데 OpenClaw 에이전트 턴만 백엔드 내부에서 계속 크래시한다면, 이를 업스트림 서버/모델 한계로 보고 허용되는 페이로드 형태와 함께 그쪽에 재현 사례를 제출하세요. +1. 문자열만 받는 Chat Completions 백엔드에 `compat.requiresStringContent: true`를 설정합니다. +2. OpenClaw의 도구 스키마 표면을 안정적으로 처리할 수 없는 모델/백엔드에는 `compat.supportsTools: false`를 설정합니다. +3. 가능한 경우 프롬프트 부담을 줄입니다: 더 작은 작업공간 bootstrap, 더 짧은 세션 기록, 더 가벼운 로컬 모델, 또는 긴 컨텍스트 지원이 더 강한 백엔드. +4. 작은 직접 요청은 계속 성공하는데 OpenClaw 에이전트 턴은 여전히 백엔드 내부에서 크래시한다면, 이를 상위 서버/모델 한계로 보고 허용되는 payload 형태와 함께 해당 프로젝트에 재현 사례를 제출하세요. 관련 문서: - [/gateway/local-models](/ko/gateway/local-models) -- [/gateway/configuration#models](/ko/gateway/configuration#models) +- [/gateway/configuration](/ko/gateway/configuration) - [/gateway/configuration-reference#openai-compatible-endpoints](/ko/gateway/configuration-reference#openai-compatible-endpoints) ## 응답이 없음 -채널은 살아 있지만 아무 응답도 없으면, 무엇이든 다시 연결하기 전에 라우팅과 정책부터 확인하세요. +채널은 살아 있는데 아무 응답도 없다면, 무엇이든 다시 연결하기 전에 먼저 라우팅과 정책을 확인하세요. ```bash openclaw status @@ -120,17 +120,17 @@ openclaw config get channels openclaw logs --follow ``` -확인할 사항: +다음을 확인하세요. -- DM 발신자에 대한 페어링 대기 중 상태 -- 그룹 멘션 게이트(`requireMention`, `mentionPatterns`) +- DM 발신자에 대해 페어링이 대기 중인지 여부 +- 그룹 멘션 게이팅(`requireMention`, `mentionPatterns`) - 채널/그룹 허용 목록 불일치 일반적인 징후: -- `drop guild message (mention required` → 멘션이 있기 전까지 그룹 메시지가 무시됨 -- `pairing request` → 발신자 승인이 필요함 -- `blocked` / `allowlist` → 정책에 따라 발신자/채널이 필터링됨 +- `drop guild message (mention required` → 멘션되기 전까지 그룹 메시지가 무시됩니다. +- `pairing request` → 발신자 승인 필요 +- `blocked` / `allowlist` → 발신자/채널이 정책에 의해 필터링됨 관련 문서: @@ -138,7 +138,7 @@ openclaw logs --follow - [/channels/pairing](/ko/channels/pairing) - [/channels/groups](/ko/channels/groups) -## 대시보드 control UI 연결 +## 대시보드 control ui 연결 문제 대시보드/control UI가 연결되지 않으면 URL, 인증 모드, 보안 컨텍스트 가정을 검증하세요. @@ -150,40 +150,40 @@ openclaw doctor openclaw gateway status --json ``` -확인할 사항: +다음을 확인하세요. -- 올바른 probe URL과 dashboard URL +- 올바른 probe URL 및 dashboard URL - 클라이언트와 게이트웨이 간 인증 모드/토큰 불일치 -- 장치 신원이 필요한 상황에서의 HTTP 사용 +- 디바이스 ID가 필요한 상황에서의 HTTP 사용 일반적인 징후: -- `device identity required` → 비보안 컨텍스트이거나 장치 인증이 누락됨 +- `device identity required` → 비보안 컨텍스트이거나 디바이스 인증이 누락됨 - `origin not allowed` → 브라우저 `Origin`이 `gateway.controlUi.allowedOrigins`에 없거나 - (또는 명시적 허용 목록 없이 loopback이 아닌 브라우저 origin에서 연결 중임) + (또는 명시적인 허용 목록 없이 루프백이 아닌 브라우저 origin에서 연결 중임) - `device nonce required` / `device nonce mismatch` → 클라이언트가 - 챌린지 기반 장치 인증 흐름(`connect.challenge` + `device.nonce`)을 완료하지 않음 -- `device signature invalid` / `device signature expired` → 클라이언트가 현재 핸드셰이크에 대해 잘못된 페이로드(또는 오래된 타임스탬프)에 서명함 -- `AUTH_TOKEN_MISMATCH`와 함께 `canRetryWithDeviceToken=true` → 클라이언트는 캐시된 장치 토큰으로 한 번의 신뢰된 재시도를 할 수 있음 -- 해당 캐시 토큰 재시도는 페어링된 장치 토큰과 함께 저장된 캐시된 scope 집합을 재사용합니다. 명시적 `deviceToken` / 명시적 `scopes` 호출자는 요청한 scope 집합을 그대로 유지합니다. -- 그 재시도 경로 외에는 연결 인증 우선순위가 명시적 공유 토큰/비밀번호 우선, 그다음 명시적 `deviceToken`, 그다음 저장된 장치 토큰, 마지막으로 bootstrap 토큰입니다. -- 비동기 Tailscale Serve Control UI 경로에서는 동일한 `{scope, ip}`에 대한 실패 시도가 limiter가 실패를 기록하기 전에 직렬화됩니다. 따라서 같은 클라이언트의 잘못된 동시 재시도 두 건은 두 번째 시도에서 단순한 불일치 두 번 대신 `retry later`로 나타날 수 있습니다. -- 브라우저 origin loopback 클라이언트에서 `too many failed authentication attempts (retry later)` → 동일한 정규화된 `Origin`에서의 반복 실패는 일시적으로 잠깁니다. 다른 localhost origin은 별도의 버킷을 사용합니다. -- 그 재시도 이후에도 반복되는 `unauthorized` → 공유 토큰/장치 토큰 드리프트. 토큰 구성을 새로 고치고 필요 시 장치 토큰을 다시 승인/회전하세요. + 챌린지 기반 디바이스 인증 흐름(`connect.challenge` + `device.nonce`)을 완료하지 못함 +- `device signature invalid` / `device signature expired` → 클라이언트가 현재 핸드셰이크에 대해 잘못된 payload(또는 오래된 타임스탬프)에 서명함 +- `AUTH_TOKEN_MISMATCH`와 `canRetryWithDeviceToken=true` → 클라이언트는 캐시된 디바이스 토큰으로 신뢰된 1회 재시도를 할 수 있음 +- 그 캐시된 토큰 재시도는 페어링된 디바이스 토큰과 함께 저장된 캐시된 scope 집합을 재사용합니다. 명시적인 `deviceToken` / 명시적인 `scopes` 호출자는 요청한 scope 집합을 그대로 유지합니다. +- 그 재시도 경로 밖에서는 connect 인증 우선순위가 명시적인 공유 토큰/비밀번호 우선, 그다음 명시적인 `deviceToken`, 그다음 저장된 디바이스 토큰, 마지막으로 bootstrap 토큰입니다. +- 비동기 Tailscale Serve Control UI 경로에서는 동일한 `{scope, ip}`에 대한 실패 시도가 limiter가 실패를 기록하기 전에 직렬화됩니다. 따라서 같은 클라이언트에서 동시에 잘못된 재시도 2회를 하면, 두 번 모두 단순 불일치 대신 두 번째 시도에서 `retry later`가 표시될 수 있습니다. +- 브라우저 origin 루프백 클라이언트에서 `too many failed authentication attempts (retry later)` → 같은 정규화된 `Origin`에서 반복된 실패가 일시적으로 잠깁니다. 다른 localhost origin은 별도 버킷을 사용합니다. +- 그 재시도 후에도 반복적으로 `unauthorized`가 발생함 → 공유 토큰/디바이스 토큰 드리프트입니다. 필요하면 토큰 구성을 새로 고치고 디바이스 토큰을 다시 승인/교체하세요. - `gateway connect failed:` → 잘못된 호스트/포트/url 대상 -### 인증 상세 코드 빠른 매핑 +### 인증 세부 코드 빠른 매핑 -실패한 `connect` 응답의 `error.details.code`를 사용해 다음 조치를 선택하세요. +실패한 `connect` 응답의 `error.details.code`를 사용해 다음 조치를 결정하세요. -| 상세 코드 | 의미 | 권장 조치 | -| ---------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `AUTH_TOKEN_MISSING` | 클라이언트가 필요한 공유 토큰을 보내지 않았습니다. | 클라이언트에 토큰을 붙여넣거나 설정한 뒤 다시 시도하세요. 대시보드 경로의 경우: `openclaw config get gateway.auth.token`을 실행한 다음 Control UI 설정에 붙여넣으세요. | -| `AUTH_TOKEN_MISMATCH` | 공유 토큰이 게이트웨이 인증 토큰과 일치하지 않습니다. | `canRetryWithDeviceToken=true`이면 한 번의 신뢰된 재시도를 허용하세요. 캐시 토큰 재시도는 저장된 승인된 scope를 재사용합니다. 명시적 `deviceToken` / `scopes` 호출자는 요청한 scope를 유지합니다. 그래도 실패하면 [토큰 드리프트 복구 체크리스트](/cli/devices#token-drift-recovery-checklist)를 실행하세요. | -| `AUTH_DEVICE_TOKEN_MISMATCH` | 장치별 캐시 토큰이 오래되었거나 취소되었습니다. | [devices CLI](/cli/devices)를 사용해 장치 토큰을 회전/재승인한 다음 다시 연결하세요. | -| `PAIRING_REQUIRED` | 장치 신원은 알려져 있지만 이 역할에 대해 승인되지 않음 | 대기 중인 요청을 승인하세요: `openclaw devices list` 다음 `openclaw devices approve `. | +| 세부 코드 | 의미 | 권장 조치 | +| ---------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `AUTH_TOKEN_MISSING` | 클라이언트가 필요한 공유 토큰을 보내지 않았습니다. | 클라이언트에 토큰을 붙여넣거나 설정한 후 다시 시도하세요. 대시보드 경로의 경우: `openclaw config get gateway.auth.token`을 실행한 뒤 Control UI 설정에 붙여넣으세요. | +| `AUTH_TOKEN_MISMATCH` | 공유 토큰이 게이트웨이 인증 토큰과 일치하지 않습니다. | `canRetryWithDeviceToken=true`이면 신뢰된 1회 재시도를 허용하세요. 캐시된 토큰 재시도는 저장된 승인 scope를 재사용합니다. 명시적인 `deviceToken` / `scopes` 호출자는 요청한 scope를 유지합니다. 계속 실패하면 [토큰 드리프트 복구 체크리스트](/cli/devices#token-drift-recovery-checklist)를 실행하세요. | +| `AUTH_DEVICE_TOKEN_MISMATCH` | 캐시된 디바이스별 토큰이 오래되었거나 폐기되었습니다. | [devices CLI](/cli/devices)를 사용해 디바이스 토큰을 교체하거나 다시 승인한 뒤 다시 연결하세요. | +| `PAIRING_REQUIRED` | 디바이스 ID는 알려져 있지만 이 역할에 대해 승인되지 않음 | 대기 중인 요청을 승인하세요: `openclaw devices list` 다음 `openclaw devices approve `. | -장치 인증 v2 마이그레이션 확인: +디바이스 인증 v2 마이그레이션 점검: ```bash openclaw --version @@ -191,16 +191,16 @@ openclaw doctor openclaw gateway status ``` -로그에 nonce/서명 오류가 보이면 연결 중인 클라이언트를 업데이트하고 다음을 확인하세요. +로그에 nonce/signature 오류가 보이면 연결 중인 클라이언트를 업데이트하고 다음을 확인하세요. 1. `connect.challenge`를 기다림 -2. 챌린지에 바인딩된 페이로드에 서명함 +2. 챌린지에 바인딩된 payload에 서명함 3. 동일한 챌린지 nonce와 함께 `connect.params.device.nonce`를 전송함 -`openclaw devices rotate` / `revoke` / `remove`가 예상과 다르게 거부되는 경우: +`openclaw devices rotate` / `revoke` / `remove`가 예상치 않게 거부된다면: -- 페어링된 장치 토큰 세션은 호출자에게 `operator.admin`도 있는 경우가 아니면 **자기 자신의** 장치만 관리할 수 있습니다 -- `openclaw devices rotate --scope ...`는 호출자 세션이 이미 보유한 operator scope만 요청할 수 있습니다 +- 페어링된 디바이스 토큰 세션은 호출자에게 `operator.admin`도 없는 한 **자기 자신의** 디바이스만 관리할 수 있습니다. +- `openclaw devices rotate --scope ...`는 호출자 세션이 이미 보유한 operator scope만 요청할 수 있습니다. 관련 문서: @@ -222,20 +222,20 @@ openclaw doctor openclaw gateway status --deep # 시스템 수준 서비스도 스캔 ``` -확인할 사항: +다음을 확인하세요. -- 종료 힌트와 함께 표시되는 `Runtime: stopped` -- 서비스 구성 불일치(`Config (cli)` vs `Config (service)`) +- 종료 힌트와 함께 `Runtime: stopped`가 표시됨 +- 서비스 구성 불일치(`Config (cli)` 대 `Config (service)`) - 포트/리스너 충돌 - `--deep` 사용 시 추가 launchd/systemd/schtasks 설치 - `Other gateway-like services detected (best effort)` 정리 힌트 일반적인 징후: -- `Gateway start blocked: set gateway.mode=local` 또는 `existing config is missing gateway.mode` → 로컬 게이트웨이 모드가 활성화되지 않았거나 구성 파일이 손상되어 `gateway.mode`를 잃었습니다. 해결: 구성에서 `gateway.mode="local"`을 설정하거나 `openclaw onboard --mode local` / `openclaw setup`을 다시 실행해 예상되는 로컬 모드 구성을 다시 기록하세요. Podman으로 OpenClaw를 실행 중이라면 기본 구성 경로는 `~/.openclaw/openclaw.json`입니다. -- `refusing to bind gateway ... without auth` → 유효한 게이트웨이 인증 경로(토큰/비밀번호 또는 구성된 경우 trusted-proxy) 없이 loopback이 아닌 bind를 시도함 +- `Gateway start blocked: set gateway.mode=local` 또는 `existing config is missing gateway.mode` → 로컬 게이트웨이 모드가 활성화되지 않았거나 config 파일이 덮어써지면서 `gateway.mode`를 잃었습니다. 해결: config에서 `gateway.mode="local"`을 설정하거나, `openclaw onboard --mode local` / `openclaw setup`을 다시 실행해 예상되는 로컬 모드 config를 다시 기록하세요. Podman으로 OpenClaw를 실행 중이라면 기본 config 경로는 `~/.openclaw/openclaw.json`입니다. +- `refusing to bind gateway ... without auth` → 유효한 게이트웨이 인증 경로(토큰/비밀번호 또는 구성된 경우 trusted-proxy) 없이 루프백이 아닌 바인딩을 시도함 - `another gateway instance is already listening` / `EADDRINUSE` → 포트 충돌 -- `Other gateway-like services detected (best effort)` → 오래되었거나 병렬인 launchd/systemd/schtasks 유닛이 존재함. 대부분의 설정에서는 머신당 게이트웨이 하나를 유지해야 합니다. 둘 이상이 필요하다면 포트 + config/state/workspace를 분리하세요. [/gateway#multiple-gateways-same-host](/ko/gateway#multiple-gateways-same-host) 참고. +- `Other gateway-like services detected (best effort)` → 오래되었거나 병렬인 launchd/systemd/schtasks 유닛이 존재함. 대부분의 설정에서는 머신당 게이트웨이 하나만 유지하는 것이 좋습니다. 여러 개가 정말 필요하다면 포트 + config/state/workspace를 분리하세요. [/gateway#multiple-gateways-same-host](/ko/gateway#multiple-gateways-same-host)를 참고하세요. 관련 문서: @@ -245,7 +245,7 @@ openclaw gateway status --deep # 시스템 수준 서비스도 스캔 ## 게이트웨이 probe 경고 -`openclaw gateway probe`가 무언가에 도달했지만 여전히 경고 블록을 출력할 때 사용하세요. +`openclaw gateway probe`가 어떤 대상에는 도달하지만 여전히 경고 블록을 출력할 때 사용하세요. ```bash openclaw gateway probe @@ -253,17 +253,17 @@ openclaw gateway probe --json openclaw gateway probe --ssh user@gateway-host ``` -확인할 사항: +다음을 확인하세요. - JSON 출력의 `warnings[].code`와 `primaryTargetId` -- 경고가 SSH 대체 경로, 여러 게이트웨이, 누락된 scope, 해결되지 않은 인증 참조 중 무엇에 관한 것인지 +- 경고가 SSH 폴백, 다중 게이트웨이, 누락된 scope, 또는 해석되지 않은 auth ref에 관한 것인지 여부 일반적인 징후: -- `SSH tunnel failed to start; falling back to direct probes.` → SSH 설정에 실패했지만 명령은 여전히 구성된/loopback 대상에 직접 시도함 -- `multiple reachable gateways detected` → 둘 이상의 대상이 응답함. 보통 의도된 다중 게이트웨이 설정이거나 오래되었거나 중복된 리스너를 의미함 -- `Probe diagnostics are limited by gateway scopes (missing operator.read)` → 연결은 성공했지만 세부 RPC는 scope 제한을 받음. 장치 신원을 페어링하거나 `operator.read`가 있는 자격 증명을 사용하세요. -- 해결되지 않은 `gateway.auth.*` / `gateway.remote.*` SecretRef 경고 텍스트 → 실패한 대상에 대한 이 명령 경로에서 인증 자료를 사용할 수 없었음 +- `SSH tunnel failed to start; falling back to direct probes.` → SSH 설정에 실패했지만, 명령은 여전히 구성된 직접 대상/루프백 대상을 시도했습니다. +- `multiple reachable gateways detected` → 둘 이상의 대상이 응답했습니다. 보통 이는 의도적인 다중 게이트웨이 설정이거나 오래된/중복된 리스너를 의미합니다. +- `Probe diagnostics are limited by gateway scopes (missing operator.read)` → 연결은 성공했지만 세부 RPC는 scope 제한을 받습니다. 디바이스 ID를 페어링하거나 `operator.read`가 있는 자격 증명을 사용하세요. +- 해석되지 않은 `gateway.auth.*` / `gateway.remote.*` SecretRef 경고 텍스트 → 실패한 대상에 대해 이 명령 경로에서 인증 자료를 사용할 수 없었습니다. 관련 문서: @@ -273,7 +273,7 @@ openclaw gateway probe --ssh user@gateway-host ## 채널은 연결되었지만 메시지가 흐르지 않음 -채널 상태는 connected인데 메시지 흐름이 끊겼다면, 정책, 권한, 채널별 전달 규칙에 집중하세요. +채널 상태는 connected인데 메시지 흐름이 멈췄다면, 정책, 권한, 채널별 전달 규칙에 집중하세요. ```bash openclaw channels status --probe @@ -283,7 +283,7 @@ openclaw logs --follow openclaw config get channels ``` -확인할 사항: +다음을 확인하세요. - DM 정책(`pairing`, `allowlist`, `open`, `disabled`) - 그룹 허용 목록 및 멘션 요구 사항 @@ -292,7 +292,7 @@ openclaw config get channels 일반적인 징후: - `mention required` → 그룹 멘션 정책 때문에 메시지가 무시됨 -- `pairing` / 대기 중 승인 추적 → 발신자가 승인되지 않음 +- `pairing` / 승인 대기 추적 → 발신자가 승인되지 않음 - `missing_scope`, `not_in_channel`, `Forbidden`, `401/403` → 채널 인증/권한 문제 관련 문서: @@ -302,9 +302,9 @@ openclaw config get channels - [/channels/telegram](/ko/channels/telegram) - [/channels/discord](/ko/channels/discord) -## Cron 및 하트비트 전달 +## cron 및 heartbeat 전달 -cron 또는 하트비트가 실행되지 않았거나 전달되지 않았다면, 먼저 스케줄러 상태를 확인하고 그다음 전달 대상을 확인하세요. +cron 또는 heartbeat가 실행되지 않았거나 전달되지 않았다면, 먼저 스케줄러 상태를 확인한 다음 전달 대상을 점검하세요. ```bash openclaw cron status @@ -314,21 +314,21 @@ openclaw system heartbeat last openclaw logs --follow ``` -확인할 사항: +다음을 확인하세요. -- Cron이 활성화되어 있고 다음 깨우기가 존재함 +- Cron이 활성화되어 있고 다음 기상이 존재하는지 여부 - 작업 실행 기록 상태(`ok`, `skipped`, `error`) -- 하트비트 건너뜀 사유(`quiet-hours`, `requests-in-flight`, `alerts-disabled`, `empty-heartbeat-file`, `no-tasks-due`) +- Heartbeat 건너뜀 사유(`quiet-hours`, `requests-in-flight`, `alerts-disabled`, `empty-heartbeat-file`, `no-tasks-due`) 일반적인 징후: - `cron: scheduler disabled; jobs will not run automatically` → cron 비활성화됨 -- `cron: timer tick failed` → 스케줄러 틱 실패. 파일/로그/런타임 오류를 확인하세요. -- `heartbeat skipped`와 함께 `reason=quiet-hours` → 활성 시간대 밖임 -- `heartbeat skipped`와 함께 `reason=empty-heartbeat-file` → `HEARTBEAT.md`는 존재하지만 빈 줄/마크다운 헤더만 포함하고 있어 OpenClaw가 모델 호출을 건너뜀 -- `heartbeat skipped`와 함께 `reason=no-tasks-due` → `HEARTBEAT.md`에 `tasks:` 블록이 있지만 이번 틱에서 마감된 작업이 없음 -- `heartbeat: unknown accountId` → 하트비트 전달 대상에 대한 잘못된 account id -- `heartbeat skipped`와 함께 `reason=dm-blocked` → 하트비트 대상이 DM 스타일 목적지로 해석되었지만 `agents.defaults.heartbeat.directPolicy`(또는 에이전트별 override)가 `block`으로 설정됨 +- `cron: timer tick failed` → 스케줄러 tick 실패; 파일/로그/런타임 오류를 확인하세요. +- `heartbeat skipped`와 `reason=quiet-hours` → 활성 시간 창 밖임 +- `heartbeat skipped`와 `reason=empty-heartbeat-file` → `HEARTBEAT.md`는 존재하지만 빈 줄/Markdown 헤더만 포함하고 있어 OpenClaw가 모델 호출을 건너뜁니다. +- `heartbeat skipped`와 `reason=no-tasks-due` → `HEARTBEAT.md`에 `tasks:` 블록이 있지만 이번 tick에 실행 기한이 된 작업이 없습니다. +- `heartbeat: unknown accountId` → heartbeat 전달 대상의 account id가 유효하지 않음 +- `heartbeat skipped`와 `reason=dm-blocked` → heartbeat 대상이 DM 스타일 목적지로 해석되었지만 `agents.defaults.heartbeat.directPolicy`(또는 에이전트별 재정의)가 `block`으로 설정됨 관련 문서: @@ -338,7 +338,7 @@ openclaw logs --follow ## 페어링된 노드 도구 실패 -노드는 페어링되었지만 도구가 실패한다면, foreground, 권한, 승인 상태를 분리해서 확인하세요. +노드는 페어링되어 있지만 도구가 실패한다면, 포그라운드 상태, 권한, 승인 상태를 분리해서 확인하세요. ```bash openclaw nodes status @@ -348,18 +348,18 @@ openclaw logs --follow openclaw status ``` -확인할 사항: +다음을 확인하세요. -- 노드가 예상 기능과 함께 온라인 상태인지 -- 카메라/마이크/위치/화면에 대한 OS 권한 부여 +- 노드가 예상된 기능과 함께 온라인 상태인지 여부 +- 카메라/마이크/위치/화면에 대한 OS 권한 허용 - exec 승인 및 허용 목록 상태 일반적인 징후: -- `NODE_BACKGROUND_UNAVAILABLE` → 노드 앱이 foreground에 있어야 함 +- `NODE_BACKGROUND_UNAVAILABLE` → 노드 앱이 포그라운드에 있어야 함 - `*_PERMISSION_REQUIRED` / `LOCATION_PERMISSION_REQUIRED` → OS 권한 누락 - `SYSTEM_RUN_DENIED: approval required` → exec 승인 대기 중 -- `SYSTEM_RUN_DENIED: allowlist miss` → 허용 목록에 없어 명령 차단됨 +- `SYSTEM_RUN_DENIED: allowlist miss` → 허용 목록에 없어 명령이 차단됨 관련 문서: @@ -379,43 +379,43 @@ openclaw logs --follow openclaw doctor ``` -확인할 사항: +다음을 확인하세요. -- `plugins.allow`가 설정되어 있고 `browser`를 포함하는지 +- `plugins.allow`가 설정되어 있고 `browser`를 포함하는지 여부 - 유효한 브라우저 실행 파일 경로 - CDP 프로필 도달 가능 여부 -- `existing-session` / `user` 프로필에 대한 로컬 Chrome 사용 가능 여부 +- `existing-session` / `user` 프로필에 대해 로컬 Chrome을 사용할 수 있는지 여부 일반적인 징후: -- `unknown command "browser"` 또는 `unknown command 'browser'` → 번들된 browser plugin이 `plugins.allow`에 의해 제외됨 -- `browser.enabled=true`인데 browser 도구가 없거나 사용할 수 없음 → `plugins.allow`가 `browser`를 제외해서 plugin이 로드되지 않음 -- `Failed to start Chrome CDP on port` → 브라우저 프로세스 시작 실패 +- `unknown command "browser"` 또는 `unknown command 'browser'` → 번들된 browser 플러그인이 `plugins.allow`에 의해 제외됨 +- `browser.enabled=true`인데 browser 도구가 없거나 사용할 수 없음 → `plugins.allow`가 `browser`를 제외하여 플러그인이 로드되지 않음 +- `Failed to start Chrome CDP on port` → 브라우저 프로세스 실행 실패 - `browser.executablePath not found` → 구성된 경로가 유효하지 않음 - `browser.cdpUrl must be http(s) or ws(s)` → 구성된 CDP URL이 `file:` 또는 `ftp:` 같은 지원되지 않는 스킴을 사용함 - `browser.cdpUrl has invalid port` → 구성된 CDP URL의 포트가 잘못되었거나 범위를 벗어남 -- `No Chrome tabs found for profile="user"` → Chrome MCP attach 프로필에 열린 로컬 Chrome 탭이 없음 -- `Remote CDP for profile "" is not reachable` → 구성된 원격 CDP 엔드포인트에 게이트웨이 호스트에서 접근할 수 없음 -- `Browser attachOnly is enabled ... not reachable` 또는 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only 프로필에 도달 가능한 대상이 없거나 HTTP 엔드포인트는 응답했지만 CDP WebSocket은 여전히 열 수 없음 -- `Playwright is not available in this gateway build; '' is unsupported.` → 현재 게이트웨이 설치에는 전체 Playwright package가 없음. ARIA 스냅샷과 기본 페이지 스크린샷은 여전히 동작할 수 있지만 내비게이션, AI 스냅샷, CSS 선택자 요소 스크린샷, PDF 내보내기는 계속 사용할 수 없음 -- `fullPage is not supported for element screenshots` → 스크린샷 요청에서 `--full-page`를 `--ref` 또는 `--element`와 함께 사용함 +- `No Chrome tabs found for profile="user"` → Chrome MCP attach 프로필에 열려 있는 로컬 Chrome 탭이 없음 +- `Remote CDP for profile "" is not reachable` → 구성된 원격 CDP 엔드포인트에 게이트웨이 호스트에서 도달할 수 없음 +- `Browser attachOnly is enabled ... not reachable` 또는 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only 프로필에 도달 가능한 대상이 없거나, HTTP 엔드포인트는 응답했지만 CDP WebSocket을 여전히 열 수 없음 +- `Playwright is not available in this gateway build; '' is unsupported.` → 현재 게이트웨이 설치에 전체 Playwright 패키지가 없음; ARIA 스냅샷과 기본 페이지 스크린샷은 여전히 동작할 수 있지만, 탐색, AI 스냅샷, CSS 선택자 요소 스크린샷, PDF 내보내기는 계속 사용할 수 없습니다. +- `fullPage is not supported for element screenshots` → 스크린샷 요청에서 `--full-page`와 `--ref` 또는 `--element`를 함께 사용함 - `element screenshots are not supported for existing-session profiles; use ref from snapshot.` → Chrome MCP / `existing-session` 스크린샷 호출은 CSS `--element`가 아니라 페이지 캡처 또는 스냅샷 `--ref`를 사용해야 함 -- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP 업로드 훅은 CSS 선택자가 아니라 스냅샷 ref를 사용해야 함 -- `existing-session file uploads currently support one file at a time.` → Chrome MCP 프로필에서는 호출당 업로드 하나만 전송 가능 -- `existing-session dialog handling does not support timeoutMs.` → Chrome MCP 프로필의 대화상자 훅은 timeout override를 지원하지 않음 +- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP 업로드 훅은 CSS 선택자가 아니라 스냅샷 ref를 필요로 함 +- `existing-session file uploads currently support one file at a time.` → Chrome MCP 프로필에서는 호출당 업로드 하나만 전송하세요. +- `existing-session dialog handling does not support timeoutMs.` → Chrome MCP 프로필의 대화상자 훅은 timeout 재정의를 지원하지 않음 - `response body is not supported for existing-session profiles yet.` → `responsebody`는 여전히 관리형 브라우저 또는 raw CDP 프로필이 필요함 -- attach-only 또는 원격 CDP 프로필에서 viewport / dark-mode / locale / offline override가 오래 남아 있음 → `openclaw browser stop --browser-profile `을 실행해 전체 게이트웨이를 다시 시작하지 않고도 활성 제어 세션을 닫고 Playwright/CDP 에뮬레이션 상태를 해제하세요. +- attach-only 또는 원격 CDP 프로필에서 viewport / dark-mode / locale / offline 재정의가 오래 남아 있음 → 전체 게이트웨이를 재시작하지 않고 활성 제어 세션을 닫고 Playwright/CDP 에뮬레이션 상태를 해제하려면 `openclaw browser stop --browser-profile `을 실행하세요. 관련 문서: - [/tools/browser-linux-troubleshooting](/ko/tools/browser-linux-troubleshooting) - [/tools/browser](/ko/tools/browser) -## 업그레이드 후 갑자기 무언가가 깨졌다면 +## 업그레이드 후 갑자기 문제가 생겼다면 -대부분의 업그레이드 후 문제는 구성 드리프트이거나 이제 더 엄격한 기본값이 적용되기 때문입니다. +업그레이드 후 발생하는 대부분의 문제는 config 드리프트이거나, 이제 더 엄격한 기본값이 적용되기 때문입니다. -### 1) 인증 및 URL override 동작 변경 +### 1) 인증 및 URL 재정의 동작 변경 ```bash openclaw gateway status @@ -426,15 +426,15 @@ openclaw config get gateway.auth.mode 확인할 사항: -- `gateway.mode=remote`이면, CLI 호출이 원격 대상을 향하고 있어 로컬 서비스는 정상이어도 문제가 될 수 있음 -- 명시적인 `--url` 호출은 저장된 자격 증명으로 대체되지 않음 +- `gateway.mode=remote`이면 로컬 서비스는 정상이더라도 CLI 호출이 원격 대상을 향하고 있을 수 있습니다. +- 명시적인 `--url` 호출은 저장된 자격 증명으로 폴백하지 않습니다. 일반적인 징후: - `gateway connect failed:` → 잘못된 URL 대상 - `unauthorized` → 엔드포인트에는 도달했지만 인증이 잘못됨 -### 2) bind 및 인증 가드레일이 더 엄격해짐 +### 2) bind 및 auth 가드레일이 더 엄격해짐 ```bash openclaw config get gateway.bind @@ -446,15 +446,15 @@ openclaw logs --follow 확인할 사항: -- loopback이 아닌 bind(`lan`, `tailnet`, `custom`)에는 유효한 게이트웨이 인증 경로가 필요함: 공유 토큰/비밀번호 인증 또는 올바르게 구성된 loopback이 아닌 `trusted-proxy` 배포 -- `gateway.token` 같은 이전 키는 `gateway.auth.token`을 대체하지 않음 +- 루프백이 아닌 bind(`lan`, `tailnet`, `custom`)에는 유효한 게이트웨이 인증 경로가 필요합니다: 공유 토큰/비밀번호 인증 또는 올바르게 구성된 비루프백 `trusted-proxy` 배포 +- `gateway.token` 같은 이전 키는 `gateway.auth.token`을 대체하지 않습니다. 일반적인 징후: -- `refusing to bind gateway ... without auth` → 유효한 게이트웨이 인증 경로 없이 loopback이 아닌 bind를 시도함 -- 런타임은 실행 중인데 `RPC probe: failed` → 게이트웨이는 살아 있지만 현재 인증/url로는 접근할 수 없음 +- `refusing to bind gateway ... without auth` → 유효한 게이트웨이 인증 경로 없이 루프백이 아닌 bind를 시도함 +- 런타임은 실행 중인데 `RPC probe: failed` → 게이트웨이는 살아 있지만 현재 auth/url로 접근할 수 없음 -### 3) 페어링 및 장치 신원 상태 변경 +### 3) 페어링 및 디바이스 ID 상태 변경 ```bash openclaw devices list @@ -465,15 +465,15 @@ openclaw doctor 확인할 사항: -- dashboard/nodes에 대한 대기 중 장치 승인 -- 정책 또는 신원 변경 후 대기 중인 DM 페어링 승인 +- dashboard/nodes에 대한 대기 중인 디바이스 승인 +- 정책 또는 ID 변경 후 대기 중인 DM 페어링 승인 일반적인 징후: -- `device identity required` → 장치 인증 요구를 충족하지 못함 -- `pairing required` → 발신자/장치를 승인해야 함 +- `device identity required` → 디바이스 인증이 충족되지 않음 +- `pairing required` → 발신자/디바이스를 승인해야 함 -확인 후에도 서비스 구성과 런타임이 계속 일치하지 않으면, 동일한 프로필/state 디렉터리에서 서비스 메타데이터를 다시 설치하세요. +점검 후에도 서비스 config와 런타임이 계속 불일치한다면, 같은 profile/state 디렉터리에서 서비스 메타데이터를 다시 설치하세요. ```bash openclaw gateway install --force diff --git a/docs/ko/help/testing.md b/docs/ko/help/testing.md index 3b2c9fe5e..c9066a4e9 100644 --- a/docs/ko/help/testing.md +++ b/docs/ko/help/testing.md @@ -1,304 +1,325 @@ --- read_when: - 로컬 또는 CI에서 테스트 실행하기 - - 모델/프로바이더 버그에 대한 회귀 테스트 추가하기 - - 게이트웨이 + 에이전트 동작 디버깅하기 -summary: '테스트 키트: 단위/e2e/라이브 스위트, Docker 실행기, 그리고 각 테스트가 다루는 내용' + - 모델/provider 버그에 대한 회귀 테스트 추가하기 + - gateway + agent 동작 디버깅하기 +summary: '테스트 키트: unit/e2e/live 스위트, Docker 실행기, 그리고 각 테스트가 다루는 범위' title: 테스트 x-i18n: - generated_at: "2026-04-10T05:59:49Z" + generated_at: "2026-04-11T02:45:17Z" model: gpt-5.4 provider: openai - source_hash: 21b78e59a5189f4e8e6e1b490d350f4735c0395da31d21fc5d10b825313026b4 + source_hash: 55e75d056306a77b0d112a3902c08c7771f53533250847fc3d785b1df3e0e9e7 source_path: help/testing.md workflow: 15 --- # 테스트 -OpenClaw에는 세 가지 Vitest 스위트(단위/통합, e2e, 라이브)와 소수의 Docker 실행기가 있습니다. +OpenClaw에는 세 가지 Vitest 스위트(unit/integration, e2e, live)와 소규모 Docker 실행기 세트가 있습니다. -이 문서는 “우리가 테스트하는 방식”에 대한 가이드입니다. +이 문서는 “우리가 테스트하는 방식” 가이드입니다. - 각 스위트가 무엇을 다루는지(그리고 의도적으로 무엇을 다루지 않는지) - 일반적인 워크플로(로컬, 푸시 전, 디버깅)에서 어떤 명령을 실행해야 하는지 -- 라이브 테스트가 자격 증명을 어떻게 탐색하고 모델/프로바이더를 어떻게 선택하는지 -- 실제 모델/프로바이더 이슈에 대한 회귀 테스트를 추가하는 방법 +- live 테스트가 자격 증명을 어떻게 찾고 모델/provider를 어떻게 선택하는지 +- 실제 모델/provider 문제에 대한 회귀 테스트를 추가하는 방법 ## 빠른 시작 -대부분의 날에는: +대부분의 날에는 다음을 사용합니다. -- 전체 게이트(푸시 전에 기대되는 항목): `pnpm build && pnpm check && pnpm test` +- 전체 게이트(보통 푸시 전에 기대됨): `pnpm build && pnpm check && pnpm test` - 여유 있는 머신에서 더 빠른 로컬 전체 스위트 실행: `pnpm test:max` -- 직접 Vitest 감시 루프 실행: `pnpm test:watch` -- 직접 파일 지정은 이제 확장/채널 경로도 라우팅합니다: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- 단일 실패를 반복하고 있다면 먼저 대상 범위를 좁힌 실행을 선호하세요. +- 직접 Vitest watch 루프: `pnpm test:watch` +- 이제 직접 파일 지정도 extension/channel 경로를 라우팅합니다: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- 하나의 실패를 반복 작업 중이라면 먼저 대상 범위를 좁힌 실행을 선호하세요. - Docker 기반 QA 사이트: `pnpm qa:lab:up` - Linux VM 기반 QA 레인: `pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -테스트를 수정했거나 추가 확신이 필요할 때: +테스트를 수정했거나 추가적인 확신이 필요할 때는 다음을 사용합니다. - 커버리지 게이트: `pnpm test:coverage` - E2E 스위트: `pnpm test:e2e` -실제 프로바이더/모델을 디버깅할 때(실제 자격 증명 필요): +실제 provider/model을 디버깅할 때는(실제 자격 증명 필요) 다음을 사용합니다. -- 라이브 스위트(모델 + 게이트웨이 도구/이미지 프로브): `pnpm test:live` -- 하나의 라이브 파일만 조용히 대상으로 지정: `pnpm test:live -- src/agents/models.profiles.live.test.ts` +- live 스위트(models + gateway tool/image 프로브): `pnpm test:live` +- 하나의 live 파일만 조용히 지정: `pnpm test:live -- src/agents/models.profiles.live.test.ts` -팁: 하나의 실패 케이스만 필요하다면, 아래에 설명된 허용 목록 환경 변수를 사용해 라이브 테스트 범위를 좁히는 방식을 선호하세요. +팁: 하나의 실패 사례만 필요하다면, 아래에 설명된 허용 목록 환경 변수를 통해 live 테스트 범위를 좁히는 방법을 우선 사용하세요. ## QA 전용 실행기 -더 현실적인 QA-lab 환경이 필요할 때는 이 명령들을 기본 테스트 스위트와 함께 사용합니다. +이 명령들은 QA-lab 수준의 현실성이 필요할 때 메인 테스트 스위트 옆에서 사용합니다. - `pnpm openclaw qa suite` - - 호스트에서 저장소 기반 QA 시나리오를 직접 실행합니다. + - 호스트에서 repo 기반 QA 시나리오를 직접 실행합니다. + - 기본적으로 여러 선택된 시나리오를 격리된 gateway 워커와 함께 병렬로 실행하며, 최대 64개 워커 또는 선택한 시나리오 수까지 사용합니다. 워커 수를 조정하려면 `--concurrency `를 사용하고, 예전의 직렬 레인을 원하면 `--concurrency 1`을 사용하세요. - `pnpm openclaw qa suite --runner multipass` - - 동일한 QA 스위트를 일회용 Multipass Linux VM 내부에서 실행합니다. + - 동일한 QA 스위트를 일회용 Multipass Linux VM 안에서 실행합니다. - 호스트의 `qa suite`와 동일한 시나리오 선택 동작을 유지합니다. - - `qa suite`와 동일한 프로바이더/모델 선택 플래그를 재사용합니다. - - 라이브 실행은 게스트에서 실용적으로 전달 가능한 지원 QA 인증 입력을 전달합니다: - env 기반 프로바이더 키, QA 라이브 프로바이더 구성 경로, 그리고 존재할 경우 `CODEX_HOME`. - - 게스트가 마운트된 워크스페이스를 통해 다시 쓸 수 있도록 출력 디렉터리는 저장소 루트 아래에 있어야 합니다. - - 일반적인 QA 보고서 + 요약과 함께 Multipass 로그를 `.artifacts/qa-e2e/...` 아래에 기록합니다. + - `qa suite`와 동일한 provider/model 선택 플래그를 재사용합니다. + - live 실행은 게스트에서 실용적으로 전달 가능한 지원 QA 인증 입력을 전달합니다: + 환경 변수 기반 provider 키, QA live provider 구성 경로, 그리고 존재할 경우 `CODEX_HOME`. + - 출력 디렉터리는 게스트가 마운트된 워크스페이스를 통해 다시 쓸 수 있도록 repo 루트 아래에 있어야 합니다. + - 일반 QA 보고서 + 요약과 함께 Multipass 로그를 `.artifacts/qa-e2e/...` 아래에 기록합니다. - `pnpm qa:lab:up` - 운영자 스타일 QA 작업을 위한 Docker 기반 QA 사이트를 시작합니다. +- `pnpm openclaw qa matrix` + - 일회용 Docker 기반 Tuwunel homeserver를 대상으로 Matrix live QA 레인을 실행합니다. + - 임시 Matrix 사용자 세 명(`driver`, `sut`, `observer`)과 비공개 방 하나를 프로비저닝한 뒤, 실제 Matrix plugin을 SUT 전송 수단으로 사용하는 QA gateway 자식을 시작합니다. + - 기본적으로 고정된 안정 Tuwunel 이미지 `ghcr.io/matrix-construct/tuwunel:v1.5.1`를 사용합니다. 다른 이미지를 테스트해야 할 경우 `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE`로 재정의하세요. + - Matrix QA 보고서, 요약, observed-events 아티팩트를 `.artifacts/qa-e2e/...` 아래에 기록합니다. +- `pnpm openclaw qa telegram` + - 환경 변수에 있는 driver 및 SUT 봇 토큰을 사용해 실제 비공개 그룹을 대상으로 Telegram live QA 레인을 실행합니다. + - `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`, `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`이 필요합니다. 그룹 ID는 숫자형 Telegram 채팅 ID여야 합니다. + - 같은 비공개 그룹 안에 있는 서로 다른 두 봇이 필요하며, SUT 봇은 Telegram 사용자 이름을 노출해야 합니다. + - 안정적인 봇 간 관찰을 위해 `@BotFather`에서 두 봇 모두에 대해 Bot-to-Bot Communication Mode를 활성화하고, driver 봇이 그룹의 봇 트래픽을 관찰할 수 있도록 하세요. + - Telegram QA 보고서, 요약, observed-messages 아티팩트를 `.artifacts/qa-e2e/...` 아래에 기록합니다. -## 테스트 스위트(무엇이 어디서 실행되는지) +live transport 레인은 새 transport가 드리프트하지 않도록 하나의 표준 계약을 공유합니다. -스위트는 “현실성이 점점 높아지는 순서”(그리고 불안정성/비용도 증가)로 생각하면 됩니다. +`qa-channel`은 여전히 넓은 범위의 합성 QA 스위트이며 live transport 커버리지 매트릭스의 일부는 아닙니다. -### 단위 / 통합(기본값) +| 레인 | Canary | 멘션 게이팅 | 허용 목록 차단 | 최상위 응답 | 재시작 복구 | 스레드 후속 응답 | 스레드 격리 | 반응 관찰 | 도움말 명령 | +| -------- | ------ | ----------- | -------------- | ----------- | ----------- | ---------------- | ----------- | --------- | ------------ | +| Matrix | x | x | x | x | x | x | x | x | | +| Telegram | x | | | | | | | | x | + +## 테스트 스위트(무엇이 어디서 실행되는가) + +스위트는 “현실성이 증가하는 순서”(그리고 불안정성/비용도 증가하는 순서)로 생각하면 됩니다. + +### Unit / integration(기본값) - 명령: `pnpm test` - 구성: 기존 범위 지정 Vitest 프로젝트에 대한 10개의 순차 샤드 실행(`vitest.full-*.config.ts`) -- 파일: `src/**/*.test.ts`, `packages/**/*.test.ts`, `test/**/*.test.ts` 아래의 코어/단위 인벤토리, 그리고 `vitest.unit.config.ts`가 다루는 허용 목록 `ui` node 테스트 +- 파일: `src/**/*.test.ts`, `packages/**/*.test.ts`, `test/**/*.test.ts` 아래의 core/unit 인벤토리와 `vitest.unit.config.ts`가 다루는 허용 목록 `ui` node 테스트 - 범위: - - 순수 단위 테스트 - - 프로세스 내부 통합 테스트(게이트웨이 인증, 라우팅, 도구, 파싱, 구성) - - 알려진 버그에 대한 결정론적 회귀 테스트 + - 순수 unit 테스트 + - 프로세스 내 integration 테스트(gateway auth, routing, tooling, parsing, config) + - 알려진 버그에 대한 결정적 회귀 테스트 - 기대 사항: - CI에서 실행됨 - 실제 키 불필요 - 빠르고 안정적이어야 함 - 프로젝트 참고: - - 범위를 지정하지 않은 `pnpm test`는 이제 하나의 거대한 네이티브 루트 프로젝트 프로세스 대신 11개의 더 작은 샤드 구성(`core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`)을 실행합니다. 이렇게 하면 부하가 걸린 머신에서 최대 RSS를 줄이고 auto-reply/extension 작업이 관련 없는 스위트를 굶기지 않도록 합니다. - - `pnpm test --watch`는 다중 샤드 감시 루프가 실용적이지 않기 때문에 여전히 네이티브 루트 `vitest.config.ts` 프로젝트 그래프를 사용합니다. - - `pnpm test`, `pnpm test:watch`, `pnpm test:perf:imports`는 명시적 파일/디렉터리 대상을 먼저 범위 지정 레인으로 라우팅하므로, `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts`는 전체 루트 프로젝트 시작 비용을 치르지 않습니다. - - `pnpm test:changed`는 변경된 git 경로가 라우팅 가능한 소스/테스트 파일만 건드릴 때 동일한 범위 지정 레인으로 확장되며, 구성/설정 수정은 여전히 넓은 루트 프로젝트 재실행으로 대체됩니다. - - 일부 `plugin-sdk` 및 `commands` 테스트도 `test/setup-openclaw-runtime.ts`를 건너뛰는 전용 경량 레인을 통해 라우팅되며, 상태 유지/런타임 부담이 큰 파일은 기존 레인에 남습니다. - - 일부 `plugin-sdk` 및 `commands` 헬퍼 소스 파일도 변경 모드 실행을 해당 경량 레인의 명시적 형제 테스트로 매핑하므로, 헬퍼 수정 시 해당 디렉터리의 전체 무거운 스위트를 다시 실행할 필요가 없습니다. - - `auto-reply`는 이제 세 가지 전용 버킷을 가집니다: 최상위 코어 헬퍼, 최상위 `reply.*` 통합 테스트, 그리고 `src/auto-reply/reply/**` 하위 트리. 이렇게 하면 가장 무거운 reply 하네스 작업이 가벼운 status/chunk/token 테스트에 영향을 주지 않습니다. + - 범위를 지정하지 않은 `pnpm test`는 이제 하나의 거대한 네이티브 루트 프로젝트 프로세스 대신 11개의 더 작은 샤드 구성(`core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`)을 실행합니다. 이렇게 하면 부하가 높은 머신에서 피크 RSS를 줄이고 auto-reply/extension 작업이 관련 없는 스위트를 굶기지 않게 합니다. + - `pnpm test --watch`는 다중 샤드 watch 루프가 실용적이지 않기 때문에 여전히 네이티브 루트 `vitest.config.ts` 프로젝트 그래프를 사용합니다. + - `pnpm test`, `pnpm test:watch`, `pnpm test:perf:imports`는 이제 명시적인 파일/디렉터리 대상을 먼저 범위 지정 레인으로 라우팅하므로, `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts`는 전체 루트 프로젝트 시작 비용을 치르지 않습니다. + - `pnpm test:changed`는 변경된 git 경로가 라우팅 가능한 소스/테스트 파일만 건드린 경우 이를 동일한 범위 지정 레인으로 확장합니다. config/setup 수정은 여전히 넓은 루트 프로젝트 재실행으로 폴백합니다. + - agents, commands, plugins, auto-reply helper, `plugin-sdk` 및 유사한 순수 유틸리티 영역의 import가 가벼운 unit 테스트는 `unit-fast` 레인으로 라우팅되며, 이 레인은 `test/setup-openclaw-runtime.ts`를 건너뜁니다. 상태를 가지거나 런타임이 무거운 파일은 기존 레인에 남습니다. + - 선택된 `plugin-sdk` 및 `commands` helper 소스 파일도 changed 모드 실행을 이러한 가벼운 레인 안의 명시적 형제 테스트에 매핑하므로, helper 수정 시 해당 디렉터리의 전체 무거운 스위트를 다시 실행할 필요가 없습니다. + - `auto-reply`는 이제 세 개의 전용 버킷을 가집니다. 최상위 core helper, 최상위 `reply.*` integration 테스트, 그리고 `src/auto-reply/reply/**` 하위 트리입니다. 이렇게 하면 가장 무거운 reply 하네스 작업이 저렴한 status/chunk/token 테스트에 섞이지 않습니다. - 임베디드 실행기 참고: - - 메시지 도구 탐색 입력이나 압축 런타임 컨텍스트를 변경할 때는 두 수준의 커버리지를 모두 유지하세요. - - 순수 라우팅/정규화 경계에 대해 집중된 헬퍼 회귀 테스트를 추가하세요. - - 또한 임베디드 실행기 통합 스위트도 정상 상태를 유지해야 합니다: + - message-tool 발견 입력 또는 compaction 런타임 컨텍스트를 변경할 때는 두 수준의 커버리지를 모두 유지하세요. + - 순수 routing/normalization 경계에 대해서는 집중된 helper 회귀 테스트를 추가하세요. + - 또한 임베디드 실행기 integration 스위트도 건강하게 유지해야 합니다: `src/agents/pi-embedded-runner/compact.hooks.test.ts`, - `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, 그리고 + `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`. - - 이 스위트들은 범위 지정 id와 압축 동작이 실제 `run.ts` / `compact.ts` 경로를 통해 계속 흐르는지 검증합니다. 헬퍼 전용 테스트만으로는 이러한 통합 경로를 충분히 대체할 수 없습니다. + - 이 스위트들은 범위 지정된 ID와 compaction 동작이 실제 `run.ts` / `compact.ts` 경로를 통해 계속 흐르는지 검증합니다. helper 전용 테스트만으로는 이러한 integration 경로를 충분히 대체할 수 없습니다. - 풀 참고: - 기본 Vitest 구성은 이제 기본적으로 `threads`를 사용합니다. - - 공유 Vitest 구성은 또한 `isolate: false`를 고정하고 루트 프로젝트, e2e, 라이브 구성 전반에서 비격리 실행기를 사용합니다. - - 루트 UI 레인은 `jsdom` 설정과 옵티마이저를 유지하지만, 이제 공유 비격리 실행기에서도 실행됩니다. - - 각 `pnpm test` 샤드는 공유 Vitest 구성으로부터 동일한 `threads` + `isolate: false` 기본값을 상속합니다. - - 공유 `scripts/run-vitest.mjs` 실행기는 이제 대규모 로컬 실행 중 V8 컴파일 변동을 줄이기 위해 기본적으로 Vitest 자식 Node 프로세스에 `--no-maglev`도 추가합니다. 기본 V8 동작과 비교해야 한다면 `OPENCLAW_VITEST_ENABLE_MAGLEV=1`을 설정하세요. + - 공유 Vitest 구성은 또한 `isolate: false`를 고정하고 루트 프로젝트, e2e, live 구성 전반에서 비격리 실행기를 사용합니다. + - 루트 UI 레인은 `jsdom` 설정과 최적화를 유지하지만, 이제 공유 비격리 실행기에서도 실행됩니다. + - 각 `pnpm test` 샤드는 공유 Vitest 구성에서 동일한 `threads` + `isolate: false` 기본값을 상속합니다. + - 공유 `scripts/run-vitest.mjs` 실행기는 이제 큰 로컬 실행 중 V8 컴파일 부담을 줄이기 위해 기본적으로 Vitest 자식 Node 프로세스에 `--no-maglev`도 추가합니다. 기본 V8 동작과 비교해야 한다면 `OPENCLAW_VITEST_ENABLE_MAGLEV=1`을 설정하세요. - 빠른 로컬 반복 참고: - - `pnpm test:changed`는 변경된 경로가 더 작은 스위트에 깔끔하게 매핑될 때 범위 지정 레인을 통해 라우팅합니다. - - `pnpm test:max`와 `pnpm test:changed:max`도 동일한 라우팅 동작을 유지하며, 단지 더 높은 워커 상한을 사용합니다. - - 로컬 워커 자동 스케일링은 이제 의도적으로 더 보수적이며, 호스트 load average가 이미 높을 때도 물러나므로 여러 개의 동시 Vitest 실행이 기본적으로 덜 큰 피해를 주게 됩니다. - - 기본 Vitest 구성은 프로젝트/구성 파일을 `forceRerunTriggers`로 표시하므로 테스트 배선이 바뀔 때 변경 모드 재실행이 정확하게 유지됩니다. - - 구성은 지원되는 호스트에서 `OPENCLAW_VITEST_FS_MODULE_CACHE`를 활성화한 상태로 유지합니다. 직접 프로파일링을 위해 명시적 캐시 위치 하나를 쓰고 싶다면 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`를 설정하세요. + - `pnpm test:changed`는 변경된 경로가 더 작은 스위트에 깔끔하게 매핑될 때 범위 지정 레인을 통해 라우팅됩니다. + - `pnpm test:max`와 `pnpm test:changed:max`도 동일한 라우팅 동작을 유지하며, 단지 워커 상한이 더 높습니다. + - 로컬 워커 자동 스케일링은 이제 의도적으로 보수적이며 호스트 load average가 이미 높은 경우에도 물러나므로, 여러 동시 Vitest 실행이 기본적으로 덜 큰 피해를 주게 됩니다. + - 기본 Vitest 구성은 changed 모드 재실행이 테스트 연결이 바뀌었을 때도 올바르게 유지되도록 프로젝트/구성 파일을 `forceRerunTriggers`로 표시합니다. + - 구성은 지원되는 호스트에서 `OPENCLAW_VITEST_FS_MODULE_CACHE`를 계속 활성화합니다. 직접 프로파일링을 위해 하나의 명시적 캐시 위치를 원하면 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`를 설정하세요. - 성능 디버그 참고: - - `pnpm test:perf:imports`는 Vitest 가져오기 지속 시간 보고와 가져오기 분석 출력을 활성화합니다. - - `pnpm test:perf:imports:changed`는 `origin/main` 이후 변경된 파일로 동일한 프로파일링 보기를 범위 지정합니다. -- `pnpm test:perf:changed:bench -- --ref `는 해당 커밋된 diff에 대해 라우팅된 `test:changed`와 네이티브 루트 프로젝트 경로를 비교하고 wall time과 macOS 최대 RSS를 출력합니다. -- `pnpm test:perf:changed:bench -- --worktree`는 변경된 파일 목록을 `scripts/test-projects.mjs`와 루트 Vitest 구성으로 라우팅하여 현재 dirty tree를 벤치마킹합니다. + - `pnpm test:perf:imports`는 Vitest import-duration 보고와 import-breakdown 출력을 활성화합니다. + - `pnpm test:perf:imports:changed`는 동일한 프로파일링 보기를 `origin/main` 이후 변경된 파일로 범위 지정합니다. +- `pnpm test:perf:changed:bench -- --ref `는 해당 커밋된 diff에 대해 라우팅된 `test:changed`를 네이티브 루트 프로젝트 경로와 비교하고 wall time과 macOS max RSS를 출력합니다. +- `pnpm test:perf:changed:bench -- --worktree`는 변경된 파일 목록을 `scripts/test-projects.mjs`와 루트 Vitest 구성에 라우팅하여 현재 dirty tree를 벤치마크합니다. - `pnpm test:perf:profile:main`은 Vitest/Vite 시작 및 transform 오버헤드에 대한 메인 스레드 CPU 프로파일을 기록합니다. - - `pnpm test:perf:profile:runner`는 파일 병렬화를 비활성화한 상태에서 단위 스위트에 대한 실행기 CPU+힙 프로파일을 기록합니다. + - `pnpm test:perf:profile:runner`는 파일 병렬화를 비활성화한 unit 스위트에 대해 실행기 CPU+heap 프로파일을 기록합니다. -### E2E(게이트웨이 스모크) +### E2E(gateway 스모크) - 명령: `pnpm test:e2e` - 구성: `vitest.e2e.config.ts` - 파일: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts` - 런타임 기본값: - - 저장소의 나머지 부분과 동일하게 Vitest `threads`와 `isolate: false`를 사용합니다. + - repo의 나머지 부분과 동일하게 Vitest `threads`와 `isolate: false`를 사용합니다. - 적응형 워커를 사용합니다(CI: 최대 2, 로컬: 기본 1). - - 콘솔 I/O 오버헤드를 줄이기 위해 기본적으로 무음 모드로 실행합니다. + - 콘솔 I/O 오버헤드를 줄이기 위해 기본적으로 silent 모드로 실행됩니다. - 유용한 재정의: - - 워커 수를 강제로 지정하려면 `OPENCLAW_E2E_WORKERS=`(상한 16). - - 자세한 콘솔 출력을 다시 활성화하려면 `OPENCLAW_E2E_VERBOSE=1`. + - 워커 수를 강제로 지정하려면 `OPENCLAW_E2E_WORKERS=`(상한 16) + - 자세한 콘솔 출력을 다시 활성화하려면 `OPENCLAW_E2E_VERBOSE=1` - 범위: - - 다중 인스턴스 게이트웨이 end-to-end 동작 + - 다중 인스턴스 gateway 종단 간 동작 - WebSocket/HTTP 표면, 노드 페어링, 더 무거운 네트워킹 - 기대 사항: - CI에서 실행됨(파이프라인에서 활성화된 경우) - 실제 키 불필요 - - 단위 테스트보다 더 많은 가변 요소가 있음(더 느릴 수 있음) + - unit 테스트보다 이동 부품이 많음(더 느릴 수 있음) ### E2E: OpenShell 백엔드 스모크 - 명령: `pnpm test:e2e:openshell` - 파일: `test/openshell-sandbox.e2e.test.ts` - 범위: - - Docker를 통해 호스트에서 격리된 OpenShell 게이트웨이를 시작합니다. - - 임시 로컬 Dockerfile로부터 샌드박스를 생성합니다. + - Docker를 통해 호스트에서 격리된 OpenShell gateway를 시작합니다. + - 임시 로컬 Dockerfile에서 sandbox를 생성합니다. - 실제 `sandbox ssh-config` + SSH exec를 통해 OpenClaw의 OpenShell 백엔드를 실행합니다. - - 샌드박스 fs 브리지를 통해 원격 정규 파일 시스템 동작을 검증합니다. + - sandbox fs 브리지를 통해 remote-canonical 파일시스템 동작을 검증합니다. - 기대 사항: - - 옵트인 전용이며 기본 `pnpm test:e2e` 실행의 일부가 아님 - - 로컬 `openshell` CLI와 정상 동작하는 Docker 데몬 필요 - - 격리된 `HOME` / `XDG_CONFIG_HOME`을 사용한 뒤 테스트 게이트웨이와 샌드박스를 제거함 + - 옵트인 전용이며 기본 `pnpm test:e2e` 실행의 일부가 아닙니다. + - 로컬 `openshell` CLI와 동작하는 Docker 데몬이 필요합니다. + - 격리된 `HOME` / `XDG_CONFIG_HOME`을 사용한 뒤 테스트 gateway와 sandbox를 제거합니다. - 유용한 재정의: - - 더 넓은 e2e 스위트를 수동으로 실행할 때 테스트를 활성화하려면 `OPENCLAW_E2E_OPENSHELL=1` - - 기본이 아닌 CLI 바이너리 또는 래퍼 스크립트를 가리키려면 `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` + - 더 넓은 e2e 스위트를 수동 실행할 때 이 테스트를 활성화하려면 `OPENCLAW_E2E_OPENSHELL=1` + - 기본이 아닌 CLI 바이너리나 래퍼 스크립트를 가리키려면 `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` -### 라이브(실제 프로바이더 + 실제 모델) +### Live(실제 provider + 실제 모델) - 명령: `pnpm test:live` - 구성: `vitest.live.config.ts` - 파일: `src/**/*.live.test.ts` - 기본값: `pnpm test:live`에 의해 **활성화됨**(`OPENCLAW_LIVE_TEST=1` 설정) - 범위: - - “이 프로바이더/모델이 오늘 실제 자격 증명으로 정말 동작하는가?” - - 프로바이더 형식 변경, 도구 호출 특이점, 인증 이슈, 속도 제한 동작 포착 + - “이 provider/model이 오늘 실제 자격 증명으로 실제로 동작하는가?” + - provider 포맷 변경, tool-calling 특이점, 인증 문제, rate limit 동작을 포착 - 기대 사항: - - 설계상 CI에서 안정적이지 않음(실제 네트워크, 실제 프로바이더 정책, 할당량, 장애) - - 비용이 들고 속도 제한을 사용함 - - “전체” 실행보다는 범위를 좁힌 하위 집합 실행을 선호 -- 라이브 실행은 누락된 API 키를 가져오기 위해 `~/.profile`을 소싱합니다. -- 기본적으로 라이브 실행은 여전히 `HOME`을 격리하고 구성/인증 자료를 임시 테스트 홈으로 복사하므로 단위 픽스처가 실제 `~/.openclaw`를 변경할 수 없습니다. -- 라이브 테스트가 실제 홈 디렉터리를 사용하도록 의도적으로 해야 할 때만 `OPENCLAW_LIVE_USE_REAL_HOME=1`을 설정하세요. -- `pnpm test:live`는 이제 기본적으로 더 조용한 모드를 사용합니다. `[live] ...` 진행 출력은 유지하지만 추가 `~/.profile` 알림은 숨기고 게이트웨이 부트스트랩 로그/Bonjour 잡음을 음소거합니다. 전체 시작 로그를 다시 보고 싶다면 `OPENCLAW_LIVE_TEST_QUIET=0`을 설정하세요. -- API 키 순환(프로바이더별): 쉼표/세미콜론 형식의 `*_API_KEYS` 또는 `*_API_KEY_1`, `*_API_KEY_2`를 설정합니다(예: `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`). 또는 라이브별 재정의로 `OPENCLAW_LIVE_*_KEY`를 사용할 수 있습니다. 테스트는 속도 제한 응답 시 재시도합니다. -- 진행/하트비트 출력: - - 라이브 스위트는 이제 긴 프로바이더 호출이 Vitest 콘솔 캡처가 조용할 때도 눈에 띄게 활성 상태임을 보여주기 위해 진행 줄을 stderr로 출력합니다. - - `vitest.live.config.ts`는 Vitest 콘솔 가로채기를 비활성화하므로 프로바이더/게이트웨이 진행 줄이 라이브 실행 중 즉시 스트리밍됩니다. - - 직접 모델 하트비트를 조정하려면 `OPENCLAW_LIVE_HEARTBEAT_MS`. - - 게이트웨이/프로브 하트비트를 조정하려면 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS`. + - 설계상 CI에서 안정적이지 않음(실제 네트워크, 실제 provider 정책, 할당량, 장애) + - 비용이 들거나 rate limit을 사용함 + - “전부”보다 범위를 좁힌 부분 집합 실행을 선호 +- live 실행은 누락된 API 키를 가져오기 위해 `~/.profile`을 source합니다. +- 기본적으로 live 실행은 여전히 `HOME`을 격리하고 config/auth 자료를 임시 테스트 홈으로 복사하므로, unit fixture가 실제 `~/.openclaw`를 변경할 수 없습니다. +- live 테스트가 실제 홈 디렉터리를 사용하도록 의도적으로 해야 할 때만 `OPENCLAW_LIVE_USE_REAL_HOME=1`을 설정하세요. +- 이제 `pnpm test:live`는 더 조용한 모드를 기본값으로 사용합니다. `[live] ...` 진행 출력은 유지하지만, 추가 `~/.profile` 알림을 숨기고 gateway bootstrap 로그/Bonjour 잡음을 음소거합니다. 전체 시작 로그를 다시 보고 싶다면 `OPENCLAW_LIVE_TEST_QUIET=0`을 설정하세요. +- API 키 순환(provider별): 쉼표/세미콜론 형식의 `*_API_KEYS` 또는 `*_API_KEY_1`, `*_API_KEY_2`를 설정하세요(예: `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`). 또는 live별 재정의로 `OPENCLAW_LIVE_*_KEY`를 사용할 수 있습니다. 테스트는 rate limit 응답 시 재시도합니다. +- 진행/heartbeat 출력: + - live 스위트는 이제 진행 줄을 stderr로 출력하므로, Vitest 콘솔 캡처가 조용할 때도 긴 provider 호출이 시각적으로 활성 상태임을 확인할 수 있습니다. + - `vitest.live.config.ts`는 Vitest 콘솔 가로채기를 비활성화하므로 provider/gateway 진행 줄이 live 실행 중 즉시 스트리밍됩니다. + - 직접 모델 heartbeat는 `OPENCLAW_LIVE_HEARTBEAT_MS`로 조정하세요. + - gateway/probe heartbeat는 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS`로 조정하세요. ## 어떤 스위트를 실행해야 하나요? -다음 결정 표를 사용하세요. +다음 결정표를 사용하세요. -- 로직/테스트를 수정하는 경우: `pnpm test` 실행(많이 변경했다면 `pnpm test:coverage`도) -- 게이트웨이 네트워킹 / WS 프로토콜 / 페어링을 건드리는 경우: `pnpm test:e2e` 추가 -- “내 봇이 다운됐다” / 프로바이더별 실패 / 도구 호출을 디버깅하는 경우: 범위를 좁힌 `pnpm test:live` 실행 +- 로직/테스트 편집: `pnpm test` 실행(많이 변경했다면 `pnpm test:coverage`도) +- gateway 네트워킹 / WS 프로토콜 / 페어링 수정: `pnpm test:e2e` 추가 +- “내 봇이 다운됐다” / provider별 실패 / tool calling 디버깅: 범위를 좁힌 `pnpm test:live` 실행 -## 라이브: Android 노드 기능 스윕 +## Live: Android 노드 기능 스윕 - 테스트: `src/gateway/android-node.capabilities.live.test.ts` - 스크립트: `pnpm android:test:integration` -- 목표: 연결된 Android 노드가 현재 광고하는 **모든 명령**을 호출하고 명령 계약 동작을 검증합니다. +- 목표: 연결된 Android 노드가 현재 광고하는 **모든 명령을 호출**하고 명령 계약 동작을 검증 - 범위: - - 사전 준비/수동 설정 필요(이 스위트는 앱을 설치/실행/페어링하지 않음) - - 선택된 Android 노드에 대한 명령별 게이트웨이 `node.invoke` 검증 + - 사전 조건이 갖춰진 수동 설정(스위트는 앱을 설치/실행/페어링하지 않음) + - 선택된 Android 노드에 대한 명령별 gateway `node.invoke` 검증 - 필수 사전 설정: - - Android 앱이 이미 연결되고 게이트웨이와 페어링되어 있어야 함 + - Android 앱이 이미 gateway에 연결되고 페어링되어 있어야 함 - 앱이 포그라운드 상태로 유지되어야 함 - - 통과를 기대하는 기능에 대해 권한/캡처 동의가 허용되어 있어야 함 + - 통과를 기대하는 기능에 대해 권한/캡처 동의가 부여되어 있어야 함 - 선택적 대상 재정의: - `OPENCLAW_ANDROID_NODE_ID` 또는 `OPENCLAW_ANDROID_NODE_NAME` - `OPENCLAW_ANDROID_GATEWAY_URL` / `OPENCLAW_ANDROID_GATEWAY_TOKEN` / `OPENCLAW_ANDROID_GATEWAY_PASSWORD` - 전체 Android 설정 세부 정보: [Android App](/ko/platforms/android) -## 라이브: 모델 스모크(프로필 키) +## Live: 모델 스모크(profile 키) -라이브 테스트는 실패를 분리할 수 있도록 두 계층으로 나뉩니다. +live 테스트는 실패를 분리할 수 있도록 두 계층으로 나뉩니다. -- “직접 모델”은 해당 프로바이더/모델이 주어진 키로 최소한 응답할 수 있는지를 알려줍니다. -- “게이트웨이 스모크”는 전체 게이트웨이+에이전트 파이프라인이 해당 모델에서 동작하는지(세션, 히스토리, 도구, 샌드박스 정책 등)를 알려줍니다. +- “직접 모델”은 주어진 키로 provider/model이 최소한 응답할 수 있는지 알려줍니다. +- “Gateway smoke”는 전체 gateway+agent 파이프라인이 해당 모델에서 동작하는지 알려줍니다(세션, 기록, 도구, sandbox 정책 등). -### 1계층: 직접 모델 완성(게이트웨이 없음) +### 계층 1: 직접 모델 완료(gateway 없음) - 테스트: `src/agents/models.profiles.live.test.ts` - 목표: - - 탐색된 모델을 열거 + - 발견된 모델 열거 - `getApiKeyForModel`을 사용해 자격 증명이 있는 모델 선택 - - 모델별로 작은 완성 실행(필요한 경우 대상 회귀 포함) + - 모델별 작은 completion 실행(필요한 경우 대상 회귀도 포함) - 활성화 방법: - `pnpm test:live`(또는 Vitest를 직접 호출할 경우 `OPENCLAW_LIVE_TEST=1`) -- 이 스위트를 실제로 실행하려면 `OPENCLAW_LIVE_MODELS=modern`(또는 `all`, modern의 별칭)을 설정하세요. 그렇지 않으면 `pnpm test:live`가 게이트웨이 스모크에 집중되도록 건너뜁니다. +- 이 스위트를 실제로 실행하려면 `OPENCLAW_LIVE_MODELS=modern`(또는 `all`, `modern`의 별칭)을 설정하세요. 그렇지 않으면 `pnpm test:live`를 gateway smoke에 집중시키기 위해 건너뜁니다. - 모델 선택 방법: - - 현대식 허용 목록(Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4)을 실행하려면 `OPENCLAW_LIVE_MODELS=modern` - - `OPENCLAW_LIVE_MODELS=all`은 현대식 허용 목록의 별칭입니다 - - 또는 `OPENCLAW_LIVE_MODELS="openai/gpt-5.4,anthropic/claude-opus-4-6,..."`(쉼표 허용 목록) - - modern/all 스윕은 기본적으로 선별된 고신호 상한을 사용합니다. 전체 modern 스윕을 하려면 `OPENCLAW_LIVE_MAX_MODELS=0`, 더 작은 상한을 원하면 양수를 설정하세요. -- 프로바이더 선택 방법: - - `OPENCLAW_LIVE_PROVIDERS="google,google-antigravity,google-gemini-cli"`(쉼표 허용 목록) -- 키의 출처: - - 기본값: 프로필 저장소와 env 대체값 - - **프로필 저장소만** 강제하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 설정 -- 이 계층이 존재하는 이유: - - “프로바이더 API가 깨졌는지 / 키가 잘못되었는지”와 “게이트웨이 에이전트 파이프라인이 깨졌는지”를 분리 - - 작고 고립된 회귀를 담음(예: OpenAI Responses/Codex Responses 추론 재생 + 도구 호출 흐름) + - 최신 허용 목록(Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4)을 실행하려면 `OPENCLAW_LIVE_MODELS=modern` + - `OPENCLAW_LIVE_MODELS=all`은 최신 허용 목록의 별칭 + - 또는 `OPENCLAW_LIVE_MODELS="openai/gpt-5.4,anthropic/claude-opus-4-6,..."`(쉼표 구분 허용 목록) + - modern/all 스윕은 기본적으로 엄선된 high-signal 상한을 사용합니다. 최신 전체 스윕을 하려면 `OPENCLAW_LIVE_MAX_MODELS=0`, 더 작은 상한을 원하면 양수를 설정하세요. +- provider 선택 방법: + - `OPENCLAW_LIVE_PROVIDERS="google,google-antigravity,google-gemini-cli"`(쉼표 구분 허용 목록) +- 키 출처: + - 기본값: profile store 및 환경 변수 폴백 + - **profile store만** 강제하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 설정 +- 이것이 존재하는 이유: + - “provider API가 망가졌음 / 키가 유효하지 않음”과 “gateway agent 파이프라인이 망가졌음”을 분리 + - 작고 격리된 회귀를 포함(예: OpenAI Responses/Codex Responses reasoning replay + tool-call 흐름) -### 2계층: 게이트웨이 + 개발 에이전트 스모크(실제 "@openclaw"가 하는 일) +### 계층 2: Gateway + dev agent 스모크(`@openclaw`가 실제로 하는 일) - 테스트: `src/gateway/gateway-models.profiles.live.test.ts` - 목표: - - 프로세스 내부 게이트웨이 시작 + - 프로세스 내 gateway 시작 - `agent:dev:*` 세션 생성/패치(실행별 모델 재정의) - - 키가 있는 모델을 순회하며 다음을 검증: + - 키가 있는 모델들을 반복하면서 다음을 검증: - “의미 있는” 응답(도구 없음) - - 실제 도구 호출이 동작함(read 프로브) - - 선택적 추가 도구 프로브(exec+read 프로브) - - OpenAI 회귀 경로(도구 호출만 → 후속 호출)가 계속 동작함 -- 프로브 세부 정보(실패를 빠르게 설명할 수 있도록): - - `read` 프로브: 테스트가 워크스페이스에 nonce 파일을 쓰고, 에이전트에게 이를 `read`하고 nonce를 그대로 반환하도록 요청합니다. - - `exec+read` 프로브: 테스트가 에이전트에게 `exec`로 임시 파일에 nonce를 쓰고, 이어서 이를 다시 `read`하도록 요청합니다. - - 이미지 프로브: 테스트가 생성된 PNG(고양이 + 무작위 코드)를 첨부하고 모델이 `cat `를 반환하기를 기대합니다. + - 실제 도구 호출 동작(`read` probe) + - 선택적 추가 도구 probe(`exec+read` probe) + - OpenAI 회귀 경로(tool-call-only → 후속 응답)가 계속 동작 +- Probe 세부 정보(실패를 빠르게 설명할 수 있도록): + - `read` probe: 테스트가 워크스페이스에 nonce 파일을 쓰고, 에이전트에게 이를 `read`하고 nonce를 다시 말하도록 요청합니다. + - `exec+read` probe: 테스트가 에이전트에게 `exec`로 temp 파일에 nonce를 쓰고, 다시 `read`하도록 요청합니다. + - image probe: 테스트가 생성한 PNG(cat + 랜덤 코드)를 첨부하고 모델이 `cat `를 반환할 것으로 기대합니다. - 구현 참조: `src/gateway/gateway-models.profiles.live.test.ts` 및 `src/gateway/live-image-probe.ts`. - 활성화 방법: - `pnpm test:live`(또는 Vitest를 직접 호출할 경우 `OPENCLAW_LIVE_TEST=1`) - 모델 선택 방법: - - 기본값: 현대식 허용 목록(Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4) - - `OPENCLAW_LIVE_GATEWAY_MODELS=all`은 현대식 허용 목록의 별칭입니다 - - 또는 범위를 좁히려면 `OPENCLAW_LIVE_GATEWAY_MODELS="provider/model"`(또는 쉼표 목록) 설정 - - modern/all 게이트웨이 스윕은 기본적으로 선별된 고신호 상한을 사용합니다. 전체 modern 스윕을 하려면 `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=0`, 더 작은 상한을 원하면 양수를 설정하세요. -- 프로바이더 선택 방법(“OpenRouter 전체” 피하기): - - `OPENCLAW_LIVE_GATEWAY_PROVIDERS="google,google-antigravity,google-gemini-cli,openai,anthropic,zai,minimax"`(쉼표 허용 목록) -- 도구 + 이미지 프로브는 이 라이브 테스트에서 항상 활성화됩니다: - - `read` 프로브 + `exec+read` 프로브(도구 스트레스) - - 이미지 입력 지원을 광고하는 모델에서는 이미지 프로브 실행 + - 기본값: 최신 허용 목록(Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4) + - `OPENCLAW_LIVE_GATEWAY_MODELS=all`은 최신 허용 목록의 별칭 + - 또는 범위를 좁히려면 `OPENCLAW_LIVE_GATEWAY_MODELS="provider/model"`(또는 쉼표 구분 목록) 설정 + - modern/all gateway 스윕은 기본적으로 엄선된 high-signal 상한을 사용합니다. 최신 전체 스윕을 하려면 `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=0`, 더 작은 상한을 원하면 양수를 설정하세요. +- provider 선택 방법(“OpenRouter 전체” 피하기): + - `OPENCLAW_LIVE_GATEWAY_PROVIDERS="google,google-antigravity,google-gemini-cli,openai,anthropic,zai,minimax"`(쉼표 구분 허용 목록) +- tool + image probe는 이 live 테스트에서 항상 활성화됩니다: + - `read` probe + `exec+read` probe(도구 스트레스) + - 모델이 이미지 입력 지원을 광고할 때 image probe 실행 - 흐름(상위 수준): - - 테스트가 “CAT” + 무작위 코드가 들어간 작은 PNG를 생성합니다(`src/gateway/live-image-probe.ts`) - - 이를 `agent` `attachments: [{ mimeType: "image/png", content: "" }]`를 통해 전송합니다 - - 게이트웨이가 첨부 파일을 `images[]`로 파싱합니다(`src/gateway/server-methods/agent.ts` + `src/gateway/chat-attachments.ts`) - - 임베디드 에이전트가 멀티모달 사용자 메시지를 모델로 전달합니다 - - 검증: 응답에 `cat` + 코드가 포함되어야 함(OCR 허용 오차: 사소한 실수는 허용) + - 테스트가 “CAT” + 랜덤 코드가 있는 작은 PNG를 생성합니다(`src/gateway/live-image-probe.ts`). + - 이를 `agent` `attachments: [{ mimeType: "image/png", content: "" }]`를 통해 전송합니다. + - Gateway가 첨부 파일을 `images[]`로 파싱합니다(`src/gateway/server-methods/agent.ts` + `src/gateway/chat-attachments.ts`). + - 임베디드 에이전트가 멀티모달 사용자 메시지를 모델로 전달합니다. + - 검증: 응답에 `cat` + 코드가 포함됨(OCR 허용 오차: 사소한 실수는 허용) -팁: 현재 사용 중인 머신에서 무엇을 테스트할 수 있는지(그리고 정확한 `provider/model` id)를 보려면 다음을 실행하세요. +팁: 자신의 머신에서 무엇을 테스트할 수 있는지(그리고 정확한 `provider/model` ID)를 보려면 다음을 실행하세요. ```bash openclaw models list openclaw models list --json ``` -## 라이브: CLI 백엔드 스모크(Claude, Codex, Gemini 또는 기타 로컬 CLI) +## Live: CLI 백엔드 스모크(Claude, Codex, Gemini 또는 기타 로컬 CLI) - 테스트: `src/gateway/gateway-cli-backend.live.test.ts` -- 목표: 기본 구성을 건드리지 않고 로컬 CLI 백엔드를 사용해 게이트웨이 + 에이전트 파이프라인을 검증합니다. -- 백엔드별 스모크 기본값은 소유 확장의 `cli-backend.ts` 정의에 있습니다. +- 목표: 기본 config를 건드리지 않고 로컬 CLI 백엔드를 사용해 Gateway + agent 파이프라인을 검증 +- 백엔드별 스모크 기본값은 소유 extension의 `cli-backend.ts` 정의에 있습니다. - 활성화: - `pnpm test:live`(또는 Vitest를 직접 호출할 경우 `OPENCLAW_LIVE_TEST=1`) - `OPENCLAW_LIVE_CLI_BACKEND=1` - 기본값: - - 기본 프로바이더/모델: `claude-cli/claude-sonnet-4-6` - - 명령/인자/이미지 동작은 소유 CLI 백엔드 plugin 메타데이터에서 가져옵니다. + - 기본 provider/model: `claude-cli/claude-sonnet-4-6` + - command/args/image 동작은 소유 CLI 백엔드 plugin 메타데이터에서 가져옵니다. - 재정의(선택 사항): - `OPENCLAW_LIVE_CLI_BACKEND_MODEL="codex-cli/gpt-5.4"` - `OPENCLAW_LIVE_CLI_BACKEND_COMMAND="/full/path/to/codex"` - `OPENCLAW_LIVE_CLI_BACKEND_ARGS='["exec","--json","--color","never","--sandbox","read-only","--skip-git-repo-check"]'` - 실제 이미지 첨부를 보내려면 `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_PROBE=1`(경로는 프롬프트에 주입됨) - - 프롬프트 주입 대신 이미지 파일 경로를 CLI 인자로 전달하려면 `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG="--image"` - - `IMAGE_ARG`가 설정된 경우 이미지 인자 전달 방식을 제어하려면 `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE="repeat"`(또는 `"list"`) - - 두 번째 턴을 보내고 재개 흐름을 검증하려면 `OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE=1` - - 기본 Claude Sonnet -> Opus 동일 세션 연속성 프로브를 비활성화하려면 `OPENCLAW_LIVE_CLI_BACKEND_MODEL_SWITCH_PROBE=0`(선택된 모델이 전환 대상을 지원할 때 강제로 켜려면 `1`) - + - 프롬프트 주입 대신 이미지 파일 경로를 CLI 인수로 전달하려면 `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG="--image"` + - `IMAGE_ARG`가 설정되었을 때 이미지 인수 전달 방식을 제어하려면 `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE="repeat"`(또는 `"list"`) + - 두 번째 턴을 보내고 resume 흐름을 검증하려면 `OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE=1` + - 기본 Claude Sonnet -> Opus 동일 세션 연속성 probe를 비활성화하려면 `OPENCLAW_LIVE_CLI_BACKEND_MODEL_SWITCH_PROBE=0`(선택된 모델이 전환 대상을 지원할 때 강제로 켜려면 `1`) + 예시: ```bash @@ -313,10 +334,11 @@ Docker 레시피: pnpm test:docker:live-cli-backend ``` -단일 프로바이더 Docker 레시피: +단일 provider Docker 레시피: ```bash pnpm test:docker:live-cli-backend:claude +pnpm test:docker:live-cli-backend:claude-subscription pnpm test:docker:live-cli-backend:codex pnpm test:docker:live-cli-backend:gemini ``` @@ -324,19 +346,20 @@ pnpm test:docker:live-cli-backend:gemini 참고: - Docker 실행기는 `scripts/test-live-cli-backend-docker.sh`에 있습니다. -- 저장소 Docker 이미지 내부에서 비루트 `node` 사용자로 라이브 CLI 백엔드 스모크를 실행합니다. -- 소유 확장에서 CLI 스모크 메타데이터를 해석한 뒤, 일치하는 Linux CLI 패키지(`@anthropic-ai/claude-code`, `@openai/codex`, 또는 `@google/gemini-cli`)를 캐시된 쓰기 가능한 접두사 `OPENCLAW_DOCKER_CLI_TOOLS_DIR`(기본값: `~/.cache/openclaw/docker-cli-tools`)에 설치합니다. -- 이제 라이브 CLI 백엔드 스모크는 Claude, Codex, Gemini에 대해 동일한 end-to-end 흐름을 실행합니다: 텍스트 턴, 이미지 분류 턴, 그리고 게이트웨이 CLI를 통해 검증되는 MCP `cron` 도구 호출. -- Claude의 기본 스모크는 또한 세션을 Sonnet에서 Opus로 패치하고 재개된 세션이 이전 메모를 여전히 기억하는지 검증합니다. +- repo Docker 이미지 안에서 비루트 `node` 사용자로 live CLI-backend 스모크를 실행합니다. +- 소유 extension에서 CLI 스모크 메타데이터를 해석한 뒤, 일치하는 Linux CLI 패키지(`@anthropic-ai/claude-code`, `@openai/codex`, `@google/gemini-cli`)를 캐시 가능한 쓰기 가능 prefix `OPENCLAW_DOCKER_CLI_TOOLS_DIR`(기본값: `~/.cache/openclaw/docker-cli-tools`)에 설치합니다. +- `pnpm test:docker:live-cli-backend:claude-subscription`은 `~/.claude/.credentials.json`의 `claudeAiOauth.subscriptionType` 또는 `claude setup-token`의 `CLAUDE_CODE_OAUTH_TOKEN`을 통한 이식 가능한 Claude Code subscription OAuth가 필요합니다. 먼저 Docker에서 직접 `claude -p`를 검증한 뒤, Anthropic API 키 환경 변수를 유지하지 않고 두 번의 Gateway CLI-backend 턴을 실행합니다. 이 subscription 레인은 Claude가 현재 일반 subscription 플랜 한도 대신 추가 사용량 청구를 통해 서드파티 앱 사용을 라우팅하므로, 기본적으로 Claude MCP/tool 및 image probe를 비활성화합니다. +- 이제 live CLI-backend 스모크는 Claude, Codex, Gemini에 대해 동일한 종단 간 흐름을 실행합니다. 텍스트 턴, 이미지 분류 턴, 그다음 gateway CLI를 통해 검증되는 MCP `cron` tool 호출 순서입니다. +- Claude의 기본 스모크는 세션을 Sonnet에서 Opus로 패치하고, 재개된 세션이 이전 메모를 여전히 기억하는지도 검증합니다. -## 라이브: ACP 바인드 스모크(`/acp spawn ... --bind here`) +## Live: ACP 바인드 스모크(`/acp spawn ... --bind here`) - 테스트: `src/gateway/gateway-acp-bind.live.test.ts` -- 목표: 라이브 ACP 에이전트로 실제 ACP 대화 바인드 흐름을 검증합니다: +- 목표: live ACP 에이전트로 실제 ACP 대화 바인드 흐름을 검증 - `/acp spawn --bind here` 전송 - - 합성 message-channel 대화를 제자리에서 바인드 - - 동일한 대화에서 일반 후속 메시지 전송 - - 후속 메시지가 바인드된 ACP 세션 transcript에 도착하는지 검증 + - 합성 message-channel 대화를 해당 위치에 바인드 + - 같은 대화에서 일반 후속 메시지 전송 + - 후속 메시지가 바인드된 ACP 세션 transcript에 도달하는지 검증 - 활성화: - `pnpm test:live src/gateway/gateway-acp-bind.live.test.ts` - `OPENCLAW_LIVE_ACP_BIND=1` @@ -352,7 +375,7 @@ pnpm test:docker:live-cli-backend:gemini - `OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex,gemini` - `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND='npx -y @agentclientprotocol/claude-agent-acp@'` - 참고: - - 이 레인은 관리자 전용 합성 originating-route 필드가 포함된 게이트웨이 `chat.send` 표면을 사용하므로, 테스트가 외부 전달을 가장하지 않고 message-channel 컨텍스트를 부착할 수 있습니다. + - 이 레인은 gateway `chat.send` 표면을 관리자 전용 합성 originating-route 필드와 함께 사용하므로, 테스트가 외부로 실제 전달하는 척하지 않고도 message-channel 컨텍스트를 붙일 수 있습니다. - `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND`가 설정되지 않은 경우, 테스트는 선택된 ACP 하네스 에이전트에 대해 임베디드 `acpx` plugin의 내장 에이전트 레지스트리를 사용합니다. 예시: @@ -380,59 +403,100 @@ pnpm test:docker:live-acp-bind:gemini Docker 참고: - Docker 실행기는 `scripts/test-live-acp-bind-docker.sh`에 있습니다. -- 기본적으로 지원되는 모든 라이브 CLI 에이전트(`claude`, `codex`, `gemini`)에 대해 ACP 바인드 스모크를 순차 실행합니다. +- 기본적으로 지원되는 모든 live CLI 에이전트 `claude`, `codex`, `gemini`에 대해 ACP 바인드 스모크를 순차 실행합니다. - 매트릭스 범위를 좁히려면 `OPENCLAW_LIVE_ACP_BIND_AGENTS=claude`, `OPENCLAW_LIVE_ACP_BIND_AGENTS=codex`, 또는 `OPENCLAW_LIVE_ACP_BIND_AGENTS=gemini`를 사용하세요. -- `~/.profile`을 소싱하고, 일치하는 CLI 인증 자료를 컨테이너에 준비하며, `acpx`를 쓰기 가능한 npm 접두사에 설치한 다음, 없으면 요청된 라이브 CLI(`@anthropic-ai/claude-code`, `@openai/codex`, 또는 `@google/gemini-cli`)를 설치합니다. -- Docker 내부에서 실행기는 `OPENCLAW_LIVE_ACP_BIND_ACPX_COMMAND=$HOME/.npm-global/bin/acpx`를 설정하므로, 소싱된 프로필의 프로바이더 env 변수를 acpx가 자식 하네스 CLI에 계속 제공할 수 있습니다. +- `~/.profile`을 source하고, 일치하는 CLI 인증 자료를 컨테이너에 준비하며, 쓰기 가능한 npm prefix에 `acpx`를 설치한 다음, 필요하면 요청된 live CLI(`@anthropic-ai/claude-code`, `@openai/codex`, `@google/gemini-cli`)를 설치합니다. +- Docker 내부에서는 `OPENCLAW_LIVE_ACP_BIND_ACPX_COMMAND=$HOME/.npm-global/bin/acpx`를 설정하므로, source된 profile의 provider 환경 변수를 acpx가 자식 하네스 CLI에 계속 전달할 수 있습니다. -### 권장 라이브 레시피 +## Live: Codex app-server 하네스 스모크 -범위를 좁힌 명시적 허용 목록이 가장 빠르고 가장 덜 불안정합니다. +- 목표: 일반 gateway `agent` 메서드를 통해 plugin 소유 Codex 하네스를 검증 + - 번들된 `codex` plugin 로드 + - `OPENCLAW_AGENT_RUNTIME=codex` 선택 + - 첫 번째 gateway agent 턴을 `codex/gpt-5.4`로 전송 + - 두 번째 턴을 같은 OpenClaw 세션으로 전송하고 app-server 스레드가 재개되는지 검증 + - 같은 gateway 명령 경로를 통해 `/codex status`와 `/codex models` 실행 +- 테스트: `src/gateway/gateway-codex-harness.live.test.ts` +- 활성화: `OPENCLAW_LIVE_CODEX_HARNESS=1` +- 기본 모델: `codex/gpt-5.4` +- 선택적 image probe: `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=1` +- 선택적 MCP/tool probe: `OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=1` +- 이 스모크는 `OPENCLAW_AGENT_HARNESS_FALLBACK=none`을 설정하므로, 깨진 Codex 하네스가 PI로 조용히 폴백되어 통과하지 못합니다. +- 인증: 셸/profile의 `OPENAI_API_KEY`, 그리고 선택적으로 복사된 `~/.codex/auth.json` 및 `~/.codex/config.toml` -- 단일 모델, 직접 실행(게이트웨이 없음): +로컬 레시피: + +```bash +source ~/.profile +OPENCLAW_LIVE_CODEX_HARNESS=1 \ + OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=1 \ + OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=1 \ + OPENCLAW_LIVE_CODEX_HARNESS_MODEL=codex/gpt-5.4 \ + pnpm test:live -- src/gateway/gateway-codex-harness.live.test.ts +``` + +Docker 레시피: + +```bash +source ~/.profile +pnpm test:docker:live-codex-harness +``` + +Docker 참고: + +- Docker 실행기는 `scripts/test-live-codex-harness-docker.sh`에 있습니다. +- 마운트된 `~/.profile`을 source하고, `OPENAI_API_KEY`를 전달하며, 존재할 경우 Codex CLI 인증 파일을 복사하고, 쓰기 가능한 마운트 npm prefix에 `@openai/codex`를 설치한 뒤, 소스 트리를 준비하고, Codex-harness live 테스트만 실행합니다. +- Docker는 기본적으로 image 및 MCP/tool probe를 활성화합니다. 더 좁은 디버그 실행이 필요할 때는 `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0` 또는 `OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0`을 설정하세요. +- Docker는 또한 `OPENCLAW_AGENT_HARNESS_FALLBACK=none`을 내보내므로, live 테스트 구성과 일치하게 `openai-codex/*` 또는 PI 폴백이 Codex 하네스 회귀를 숨기지 못합니다. + +### 권장 live 레시피 + +좁고 명시적인 허용 목록이 가장 빠르고 불안정성이 가장 적습니다. + +- 단일 모델, 직접(gateway 없음): - `OPENCLAW_LIVE_MODELS="openai/gpt-5.4" pnpm test:live src/agents/models.profiles.live.test.ts` -- 단일 모델, 게이트웨이 스모크: +- 단일 모델, gateway 스모크: - `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.4" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` -- 여러 프로바이더에 걸친 도구 호출: +- 여러 provider에 걸친 tool calling: - `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.4,anthropic/claude-opus-4-6,google/gemini-3-flash-preview,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` -- Google 중심(Gemini API 키 + Antigravity): +- Google 집중(Gemini API 키 + Antigravity): - Gemini(API 키): `OPENCLAW_LIVE_GATEWAY_MODELS="google/gemini-3-flash-preview" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` - Antigravity(OAuth): `OPENCLAW_LIVE_GATEWAY_MODELS="google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-pro-high" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` 참고: - `google/...`는 Gemini API(API 키)를 사용합니다. -- `google-antigravity/...`는 Antigravity OAuth 브리지(Cloud Code Assist 스타일 에이전트 엔드포인트)를 사용합니다. -- `google-gemini-cli/...`는 사용자의 머신에 있는 로컬 Gemini CLI를 사용합니다(별도의 인증 + 도구 동작 특이점 존재). -- Gemini API와 Gemini CLI의 차이: - - API: OpenClaw가 Google의 호스팅된 Gemini API를 HTTP(API 키 / 프로필 인증)로 호출합니다. 대부분의 사용자가 “Gemini”라고 할 때 의미하는 것은 이것입니다. - - CLI: OpenClaw가 로컬 `gemini` 바이너리를 셸 실행합니다. 자체 인증을 가지며 동작 방식이 다를 수 있습니다(스트리밍/도구 지원/버전 차이). +- `google-antigravity/...`는 Antigravity OAuth 브리지(Cloud Code Assist 스타일 agent 엔드포인트)를 사용합니다. +- `google-gemini-cli/...`는 머신의 로컬 Gemini CLI를 사용합니다(별도 인증 + 도구 관련 특이점). +- Gemini API와 Gemini CLI: + - API: OpenClaw가 Google의 호스팅 Gemini API를 HTTP(API 키 / profile 인증)로 호출합니다. 대부분 사용자가 “Gemini”라고 할 때 의미하는 것은 이것입니다. + - CLI: OpenClaw가 로컬 `gemini` 바이너리를 셸 실행합니다. 자체 인증이 있으며 동작이 다를 수 있습니다(스트리밍/도구 지원/버전 차이). -## 라이브: 모델 매트릭스(무엇을 다루는가) +## Live: 모델 매트릭스(무엇을 다루는가) -고정된 “CI 모델 목록”은 없습니다(라이브는 옵트인). 하지만 키를 가진 개발 머신에서 정기적으로 다루기를 **권장하는** 모델은 다음과 같습니다. +고정된 “CI 모델 목록”은 없습니다(live는 옵트인). 하지만 실제 개발 머신에서 키를 가지고 정기적으로 커버하는 것이 **권장되는** 모델은 다음과 같습니다. -### 현대식 스모크 세트(도구 호출 + 이미지) +### 최신 스모크 세트(tool calling + image) -이것은 계속 동작해야 하는 것으로 기대하는 “공통 모델” 실행입니다. +이것은 우리가 계속 동작하기를 기대하는 “일반적인 모델” 실행입니다. - OpenAI(non-Codex): `openai/gpt-5.4`(선택 사항: `openai/gpt-5.4-mini`) - OpenAI Codex: `openai-codex/gpt-5.4` - Anthropic: `anthropic/claude-opus-4-6`(또는 `anthropic/claude-sonnet-4-6`) -- Google(Gemini API): `google/gemini-3.1-pro-preview` 및 `google/gemini-3-flash-preview`(구형 Gemini 2.x 모델은 피하세요) +- Google(Gemini API): `google/gemini-3.1-pro-preview` 및 `google/gemini-3-flash-preview`(오래된 Gemini 2.x 모델은 피하세요) - Google(Antigravity): `google-antigravity/claude-opus-4-6-thinking` 및 `google-antigravity/gemini-3-flash` - Z.AI(GLM): `zai/glm-4.7` - MiniMax: `minimax/MiniMax-M2.7` -도구 + 이미지가 포함된 게이트웨이 스모크 실행: +도구 + image 포함 gateway 스모크 실행: `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.4,openai-codex/gpt-5.4,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3-flash-preview,google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-flash,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` -### 기준선: 도구 호출(Read + 선택적 Exec) +### 기준선: tool calling(Read + 선택적 Exec) -프로바이더 계열마다 최소 하나는 선택하세요. +provider 계열마다 최소 하나는 선택하세요. - OpenAI: `openai/gpt-5.4`(또는 `openai/gpt-5.4-mini`) - Anthropic: `anthropic/claude-opus-4-6`(또는 `anthropic/claude-sonnet-4-6`) @@ -443,78 +507,78 @@ Docker 참고: 선택적 추가 커버리지(있으면 좋음): - xAI: `xai/grok-4`(또는 최신 사용 가능 버전) -- Mistral: `mistral/`…(활성화된 “tools” 지원 모델 하나 선택) +- Mistral: `mistral/`…(활성화된 “tools” 가능 모델 하나 선택) - Cerebras: `cerebras/`…(접근 권한이 있는 경우) -- LM Studio: `lmstudio/`…(로컬; 도구 호출은 API 모드에 따라 다름) +- LM Studio: `lmstudio/`…(로컬; tool calling은 API 모드에 따라 달라짐) -### 비전: 이미지 전송(첨부 파일 → 멀티모달 메시지) +### Vision: 이미지 전송(첨부 파일 → 멀티모달 메시지) -이미지 프로브를 실행하려면 이미지 입력이 가능한 모델 하나 이상을 `OPENCLAW_LIVE_GATEWAY_MODELS`에 포함하세요(Claude/Gemini/OpenAI의 비전 지원 변형 등). +image probe를 실행하려면 `OPENCLAW_LIVE_GATEWAY_MODELS`에 이미지 지원 모델 하나 이상(Claude/Gemini/OpenAI의 vision-capable 변형 등)을 포함하세요. -### 애그리게이터 / 대체 게이트웨이 +### Aggregator / 대체 gateway 키가 활성화되어 있다면 다음을 통한 테스트도 지원합니다. -- OpenRouter: `openrouter/...`(수백 개의 모델; 도구+이미지 지원 후보를 찾으려면 `openclaw models scan` 사용) -- OpenCode: Zen용 `opencode/...`, Go용 `opencode-go/...`(인증은 `OPENCODE_API_KEY` / `OPENCODE_ZEN_API_KEY` 사용) +- OpenRouter: `openrouter/...`(수백 개 모델; `openclaw models scan`으로 tool+image 가능한 후보를 찾으세요) +- OpenCode: Zen용 `opencode/...`, Go용 `opencode-go/...`(인증은 `OPENCODE_API_KEY` / `OPENCODE_ZEN_API_KEY`) -라이브 매트릭스에 포함할 수 있는 추가 프로바이더(자격 증명/구성이 있는 경우): +live 매트릭스에 포함할 수 있는 더 많은 provider(자격 증명/config가 있는 경우): - 내장: `openai`, `openai-codex`, `anthropic`, `google`, `google-vertex`, `google-antigravity`, `google-gemini-cli`, `zai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `groq`, `cerebras`, `mistral`, `github-copilot` -- `models.providers` 경유(사용자 지정 엔드포인트): `minimax`(클라우드/API), 그리고 모든 OpenAI/Anthropic 호환 프록시(LM Studio, vLLM, LiteLLM 등) +- `models.providers`를 통해(사용자 지정 엔드포인트): `minimax`(cloud/API), 그리고 OpenAI/Anthropic 호환 프록시(LM Studio, vLLM, LiteLLM 등) -팁: 문서에 “모든 모델”을 하드코딩하려고 하지 마세요. 권위 있는 목록은 사용자의 머신에서 `discoverModels(...)`가 반환하는 값과 사용 가능한 키의 조합입니다. +팁: 문서에 “모든 모델”을 하드코딩하려고 하지 마세요. 신뢰할 수 있는 목록은 자신의 머신에서 `discoverModels(...)`가 반환하는 것과 사용 가능한 키의 조합입니다. ## 자격 증명(절대 커밋 금지) -라이브 테스트는 CLI와 같은 방식으로 자격 증명을 탐색합니다. 실무적으로는 다음을 의미합니다. +live 테스트는 CLI와 동일한 방식으로 자격 증명을 찾습니다. 실무적으로는 다음을 의미합니다. -- CLI가 동작하면, 라이브 테스트도 동일한 키를 찾아야 합니다. -- 라이브 테스트가 “자격 증명 없음”이라고 하면, `openclaw models list` / 모델 선택을 디버깅하는 것과 같은 방식으로 디버깅하세요. +- CLI가 동작한다면 live 테스트도 같은 키를 찾아야 합니다. +- live 테스트가 “자격 증명 없음”이라고 말하면, `openclaw models list` / 모델 선택을 디버깅하는 것과 같은 방식으로 디버깅하세요. -- 에이전트별 인증 프로필: `~/.openclaw/agents//agent/auth-profiles.json`(라이브 테스트에서 “프로필 키”가 의미하는 것) +- 에이전트별 인증 프로필: `~/.openclaw/agents//agent/auth-profiles.json`(live 테스트에서 “profile keys”가 의미하는 것) - 구성: `~/.openclaw/openclaw.json`(또는 `OPENCLAW_CONFIG_PATH`) -- 레거시 상태 디렉터리: `~/.openclaw/credentials/`(존재할 경우 준비된 라이브 홈으로 복사되지만, 기본 프로필 키 저장소는 아님) -- 로컬 라이브 실행은 기본적으로 활성 구성, 에이전트별 `auth-profiles.json` 파일, 레거시 `credentials/`, 지원되는 외부 CLI 인증 디렉터리를 임시 테스트 홈으로 복사합니다. 준비된 라이브 홈은 `workspace/`와 `sandboxes/`를 건너뛰며, `agents.*.workspace` / `agentDir` 경로 재정의도 제거되어 프로브가 실제 호스트 워크스페이스에 영향을 주지 않도록 합니다. +- 레거시 상태 디렉터리: `~/.openclaw/credentials/`(존재할 경우 준비된 live 홈으로 복사되지만, 메인 profile-key 저장소는 아님) +- live 로컬 실행은 기본적으로 활성 config, 에이전트별 `auth-profiles.json` 파일, 레거시 `credentials/`, 지원되는 외부 CLI 인증 디렉터리를 임시 테스트 홈으로 복사합니다. 준비된 live 홈은 `workspace/`와 `sandboxes/`를 건너뛰며, `agents.*.workspace` / `agentDir` 경로 재정의는 제거되어 probe가 실제 호스트 워크스페이스를 건드리지 않도록 합니다. -env 키에 의존하고 싶다면(예: `~/.profile`에 export된 경우), `source ~/.profile` 후 로컬 테스트를 실행하거나 아래 Docker 실행기를 사용하세요(컨테이너 안으로 `~/.profile`을 마운트할 수 있음). +환경 변수 키에 의존하려면(예: `~/.profile`에 export된 경우), 로컬 테스트 전에 `source ~/.profile`을 실행하거나 아래 Docker 실행기를 사용하세요(컨테이너 안에 `~/.profile`을 마운트할 수 있음). -## Deepgram 라이브(오디오 전사) +## Deepgram live(오디오 전사) - 테스트: `src/media-understanding/providers/deepgram/audio.live.test.ts` - 활성화: `DEEPGRAM_API_KEY=... DEEPGRAM_LIVE_TEST=1 pnpm test:live src/media-understanding/providers/deepgram/audio.live.test.ts` -## BytePlus 코딩 플랜 라이브 +## BytePlus coding plan live - 테스트: `src/agents/byteplus.live.test.ts` - 활성화: `BYTEPLUS_API_KEY=... BYTEPLUS_LIVE_TEST=1 pnpm test:live src/agents/byteplus.live.test.ts` - 선택적 모델 재정의: `BYTEPLUS_CODING_MODEL=ark-code-latest` -## ComfyUI 워크플로 미디어 라이브 +## ComfyUI workflow media live - 테스트: `extensions/comfy/comfy.live.test.ts` - 활성화: `OPENCLAW_LIVE_TEST=1 COMFY_LIVE_TEST=1 pnpm test:live -- extensions/comfy/comfy.live.test.ts` - 범위: - - 번들된 comfy 이미지, 비디오, `music_generate` 경로를 실행합니다 - - `models.providers.comfy.`가 구성되지 않은 경우 각 기능을 건너뜁니다 - - comfy 워크플로 제출, 폴링, 다운로드 또는 plugin 등록을 변경한 후 유용합니다 + - 번들된 comfy image, video, `music_generate` 경로 실행 + - `models.providers.comfy.`가 구성되지 않은 기능은 각각 건너뜀 + - comfy 워크플로 제출, 폴링, 다운로드 또는 plugin 등록을 변경한 뒤 유용함 -## 이미지 생성 라이브 +## 이미지 생성 live - 테스트: `src/image-generation/runtime.live.test.ts` - 명령: `pnpm test:live src/image-generation/runtime.live.test.ts` - 하네스: `pnpm test:live:media image` - 범위: - - 등록된 모든 이미지 생성 프로바이더 plugin을 열거합니다 - - 프로브 전에 로그인 셸(`~/.profile`)에서 누락된 프로바이더 env 변수를 로드합니다 - - 기본적으로 저장된 인증 프로필보다 라이브/env API 키를 우선 사용하므로 `auth-profiles.json`의 오래된 테스트 키가 실제 셸 자격 증명을 가리지 않습니다 - - 사용 가능한 인증/프로필/모델이 없는 프로바이더는 건너뜁니다 - - 공유 런타임 기능을 통해 기본 이미지 생성 변형을 실행합니다: + - 등록된 모든 이미지 생성 provider plugin을 열거 + - 프로브 전에 로그인 셸(`~/.profile`)에서 누락된 provider 환경 변수를 로드 + - 기본적으로 저장된 인증 프로필보다 live/env API 키를 우선 사용하므로, `auth-profiles.json`의 오래된 테스트 키가 실제 셸 자격 증명을 가리지 않음 + - 사용 가능한 인증/프로필/모델이 없는 provider는 건너뜀 + - 공유 런타임 기능을 통해 기본 이미지 생성 변형을 실행: - `google:flash-generate` - `google:pro-generate` - `google:pro-edit` - `openai:default-generate` -- 현재 다루는 번들 프로바이더: +- 현재 커버되는 번들 provider: - `openai` - `google` - 선택적 범위 축소: @@ -522,170 +586,172 @@ env 키에 의존하고 싶다면(예: `~/.profile`에 export된 경우), `sourc - `OPENCLAW_LIVE_IMAGE_GENERATION_MODELS="openai/gpt-image-1,google/gemini-3.1-flash-image-preview"` - `OPENCLAW_LIVE_IMAGE_GENERATION_CASES="google:flash-generate,google:pro-edit"` - 선택적 인증 동작: - - 프로필 저장소 인증만 강제하고 env 전용 재정의를 무시하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` + - profile store 인증을 강제하고 env 전용 재정의를 무시하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` -## 음악 생성 라이브 +## 음악 생성 live - 테스트: `extensions/music-generation-providers.live.test.ts` - 활성화: `OPENCLAW_LIVE_TEST=1 pnpm test:live -- extensions/music-generation-providers.live.test.ts` - 하네스: `pnpm test:live:media music` - 범위: - - 공유 번들 음악 생성 프로바이더 경로를 실행합니다 - - 현재 Google과 MiniMax를 다룹니다 - - 프로브 전에 로그인 셸(`~/.profile`)에서 프로바이더 env 변수를 로드합니다 - - 기본적으로 저장된 인증 프로필보다 라이브/env API 키를 우선 사용하므로 `auth-profiles.json`의 오래된 테스트 키가 실제 셸 자격 증명을 가리지 않습니다 - - 사용 가능한 인증/프로필/모델이 없는 프로바이더는 건너뜁니다 - - 사용 가능한 경우 선언된 런타임 모드를 둘 다 실행합니다: + - 공유 번들 음악 생성 provider 경로 실행 + - 현재 Google과 MiniMax를 다룸 + - 프로브 전에 로그인 셸(`~/.profile`)에서 provider 환경 변수를 로드 + - 기본적으로 저장된 인증 프로필보다 live/env API 키를 우선 사용하므로, `auth-profiles.json`의 오래된 테스트 키가 실제 셸 자격 증명을 가리지 않음 + - 사용 가능한 인증/프로필/모델이 없는 provider는 건너뜀 + - 사용 가능한 경우 선언된 두 런타임 모드를 모두 실행: - 프롬프트만 입력으로 사용하는 `generate` - - 프로바이더가 `capabilities.edit.enabled`를 선언한 경우의 `edit` + - provider가 `capabilities.edit.enabled`를 선언한 경우 `edit` - 현재 공유 레인 커버리지: - `google`: `generate`, `edit` - `minimax`: `generate` - - `comfy`: 별도의 Comfy 라이브 파일에서 다루며, 이 공유 스윕에서는 다루지 않음 + - `comfy`: 별도의 Comfy live 파일에서 다루며, 이 공유 스윕에는 포함되지 않음 - 선택적 범위 축소: - `OPENCLAW_LIVE_MUSIC_GENERATION_PROVIDERS="google,minimax"` - `OPENCLAW_LIVE_MUSIC_GENERATION_MODELS="google/lyria-3-clip-preview,minimax/music-2.5+"` - 선택적 인증 동작: - - 프로필 저장소 인증만 강제하고 env 전용 재정의를 무시하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` + - profile store 인증을 강제하고 env 전용 재정의를 무시하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` -## 비디오 생성 라이브 +## 비디오 생성 live - 테스트: `extensions/video-generation-providers.live.test.ts` - 활성화: `OPENCLAW_LIVE_TEST=1 pnpm test:live -- extensions/video-generation-providers.live.test.ts` - 하네스: `pnpm test:live:media video` - 범위: - - 공유 번들 비디오 생성 프로바이더 경로를 실행합니다 - - 프로브 전에 로그인 셸(`~/.profile`)에서 프로바이더 env 변수를 로드합니다 - - 기본적으로 저장된 인증 프로필보다 라이브/env API 키를 우선 사용하므로 `auth-profiles.json`의 오래된 테스트 키가 실제 셸 자격 증명을 가리지 않습니다 - - 사용 가능한 인증/프로필/모델이 없는 프로바이더는 건너뜁니다 - - 사용 가능한 경우 선언된 런타임 모드를 둘 다 실행합니다: + - 공유 번들 비디오 생성 provider 경로 실행 + - 프로브 전에 로그인 셸(`~/.profile`)에서 provider 환경 변수를 로드 + - 기본적으로 저장된 인증 프로필보다 live/env API 키를 우선 사용하므로, `auth-profiles.json`의 오래된 테스트 키가 실제 셸 자격 증명을 가리지 않음 + - 사용 가능한 인증/프로필/모델이 없는 provider는 건너뜀 + - 사용 가능한 경우 선언된 두 런타임 모드를 모두 실행: - 프롬프트만 입력으로 사용하는 `generate` - - 프로바이더가 `capabilities.imageToVideo.enabled`를 선언하고 선택된 프로바이더/모델이 공유 스윕에서 버퍼 기반 로컬 이미지 입력을 허용하는 경우의 `imageToVideo` - - 프로바이더가 `capabilities.videoToVideo.enabled`를 선언하고 선택된 프로바이더/모델이 공유 스윕에서 버퍼 기반 로컬 비디오 입력을 허용하는 경우의 `videoToVideo` - - 현재 공유 스윕에서 선언되었지만 건너뛰는 `imageToVideo` 프로바이더: - - `vydra`: 번들된 `veo3`는 텍스트 전용이고 번들된 `kling`은 원격 이미지 URL이 필요하기 때문 - - 프로바이더별 Vydra 커버리지: + - provider가 `capabilities.imageToVideo.enabled`를 선언하고 선택된 provider/model이 공유 스윕에서 버퍼 기반 로컬 이미지 입력을 허용하는 경우 `imageToVideo` + - provider가 `capabilities.videoToVideo.enabled`를 선언하고 선택된 provider/model이 공유 스윕에서 버퍼 기반 로컬 비디오 입력을 허용하는 경우 `videoToVideo` + - 현재 공유 스윕에서 선언되었지만 건너뛰는 `imageToVideo` provider: + - `vydra`: 번들 `veo3`는 텍스트 전용이고 번들 `kling`은 원격 이미지 URL이 필요하기 때문 + - provider별 Vydra 커버리지: - `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_VYDRA_VIDEO=1 pnpm test:live -- extensions/vydra/vydra.live.test.ts` - - 이 파일은 기본적으로 `veo3` 텍스트-비디오와 원격 이미지 URL 픽스처를 사용하는 `kling` 레인을 실행합니다 - - 현재 `videoToVideo` 라이브 커버리지: - - 선택된 모델이 `runway/gen4_aleph`일 때만 `runway` - - 현재 공유 스윕에서 선언되었지만 건너뛰는 `videoToVideo` 프로바이더: - - `alibaba`, `qwen`, `xai`: 현재 해당 경로들이 원격 `http(s)` / MP4 참조 URL을 필요로 하기 때문 + - 이 파일은 기본적으로 원격 이미지 URL fixture를 사용하는 `veo3` 텍스트-비디오와 `kling` 레인을 실행합니다 + - 현재 `videoToVideo` live 커버리지: + - 선택된 모델이 `runway/gen4_aleph`인 경우의 `runway`만 + - 현재 공유 스윕에서 선언되었지만 건너뛰는 `videoToVideo` provider: + - `alibaba`, `qwen`, `xai`: 현재 이 경로들이 원격 `http(s)` / MP4 참조 URL을 필요로 하기 때문 - `google`: 현재 공유 Gemini/Veo 레인이 로컬 버퍼 기반 입력을 사용하며, 이 경로는 공유 스윕에서 허용되지 않기 때문 - - `openai`: 현재 공유 레인에 조직별 비디오 인페인트/리믹스 접근 보장이 없기 때문 + - `openai`: 현재 공유 레인에는 org별 비디오 inpaint/remix 접근 보장이 없기 때문 - 선택적 범위 축소: - `OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS="google,openai,runway"` - `OPENCLAW_LIVE_VIDEO_GENERATION_MODELS="google/veo-3.1-fast-generate-preview,openai/sora-2,runway/gen4_aleph"` - 선택적 인증 동작: - - 프로필 저장소 인증만 강제하고 env 전용 재정의를 무시하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` + - profile store 인증을 강제하고 env 전용 재정의를 무시하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` -## 미디어 라이브 하네스 +## 미디어 live 하네스 - 명령: `pnpm test:live:media` - 목적: - - 저장소 네이티브 진입점 하나로 공유 이미지, 음악, 비디오 라이브 스위트를 실행합니다 - - `~/.profile`에서 누락된 프로바이더 env 변수를 자동으로 로드합니다 - - 기본적으로 현재 사용 가능한 인증이 있는 프로바이더로 각 스위트 범위를 자동 축소합니다 - - `scripts/test-live.mjs`를 재사용하므로 하트비트와 조용한 모드 동작이 일관되게 유지됩니다 + - 공유 image, music, video live 스위트를 repo 기본 엔트리포인트 하나로 실행 + - `~/.profile`에서 누락된 provider 환경 변수를 자동 로드 + - 기본적으로 현재 사용 가능한 인증이 있는 provider로 각 스위트 범위를 자동 축소 + - `scripts/test-live.mjs`를 재사용하므로 heartbeat와 quiet-mode 동작이 일관되게 유지됨 - 예시: - `pnpm test:live:media` - `pnpm test:live:media image video --providers openai,google,minimax` - `pnpm test:live:media video --video-providers openai,runway --all-providers` - `pnpm test:live:media music --quiet` -## Docker 실행기(선택적 "Linux에서도 동작하는가" 확인) +## Docker 실행기(선택적 "Linux에서 동작함" 확인) -이 Docker 실행기들은 두 범주로 나뉩니다: +이 Docker 실행기는 두 범주로 나뉩니다. -- 라이브 모델 실행기: `test:docker:live-models`와 `test:docker:live-gateway`는 저장소 Docker 이미지 내부에서 각자 대응되는 프로필 키 라이브 파일만 실행합니다(`src/agents/models.profiles.live.test.ts` 및 `src/gateway/gateway-models.profiles.live.test.ts`). 이때 로컬 구성 디렉터리와 워크스페이스를 마운트하고(마운트된 경우 `~/.profile`도 소싱) 실행합니다. 대응되는 로컬 진입점은 `test:live:models-profiles`와 `test:live:gateway-profiles`입니다. -- Docker 라이브 실행기는 전체 Docker 스윕을 실용적으로 유지하기 위해 기본적으로 더 작은 스모크 상한을 사용합니다: +- Live-model 실행기: `test:docker:live-models` 및 `test:docker:live-gateway`는 각각 대응하는 profile-key live 파일만 repo Docker 이미지 안에서 실행합니다(`src/agents/models.profiles.live.test.ts` 및 `src/gateway/gateway-models.profiles.live.test.ts`). 대응하는 로컬 엔트리포인트는 `test:live:models-profiles` 및 `test:live:gateway-profiles`입니다. +- Docker live 실행기는 전체 Docker 스윕이 실용적이도록 기본적으로 더 작은 스모크 상한을 사용합니다: `test:docker:live-models`는 기본적으로 `OPENCLAW_LIVE_MAX_MODELS=12`를 사용하고, `test:docker:live-gateway`는 기본적으로 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`, `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`, - `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`, 그리고 - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`를 사용합니다. 더 큰 전체 스캔을 명시적으로 원할 때는 해당 env 변수를 재정의하세요. -- `test:docker:all`은 먼저 `test:docker:live-build`를 통해 라이브 Docker 이미지를 한 번 빌드한 다음, 두 개의 라이브 Docker 레인에서 이를 재사용합니다. -- 컨테이너 스모크 실행기: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:gateway-network`, `test:docker:mcp-channels`, `test:docker:plugins`는 하나 이상의 실제 컨테이너를 부팅하고 더 높은 수준의 통합 경로를 검증합니다. + `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`, + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`를 사용합니다. 더 큰 전체 스캔이 명시적으로 필요할 때는 해당 환경 변수를 재정의하세요. +- `test:docker:all`은 먼저 `test:docker:live-build`로 live Docker 이미지를 한 번 빌드한 뒤, 이를 두 개의 live Docker 레인에서 재사용합니다. +- 컨테이너 스모크 실행기: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:gateway-network`, `test:docker:mcp-channels`, `test:docker:plugins`는 하나 이상의 실제 컨테이너를 부팅하고 더 높은 수준의 integration 경로를 검증합니다. -라이브 모델 Docker 실행기는 필요한 CLI 인증 홈만 바인드 마운트하며(실행 범위가 좁혀지지 않은 경우에는 지원되는 모든 홈), 실행 전에 이를 컨테이너 홈으로 복사하므로 외부 CLI OAuth가 호스트 인증 저장소를 변경하지 않고도 토큰을 갱신할 수 있습니다. +live-model Docker 실행기는 필요한 CLI 인증 홈만(또는 실행 범위를 좁히지 않은 경우 지원되는 모든 홈) 바인드 마운트한 뒤, 실행 전에 이를 컨테이너 홈으로 복사하므로 외부 CLI OAuth가 호스트 인증 저장소를 변경하지 않고 토큰을 갱신할 수 있습니다. - 직접 모델: `pnpm test:docker:live-models`(스크립트: `scripts/test-live-models-docker.sh`) - ACP 바인드 스모크: `pnpm test:docker:live-acp-bind`(스크립트: `scripts/test-live-acp-bind-docker.sh`) - CLI 백엔드 스모크: `pnpm test:docker:live-cli-backend`(스크립트: `scripts/test-live-cli-backend-docker.sh`) -- 게이트웨이 + 개발 에이전트: `pnpm test:docker:live-gateway`(스크립트: `scripts/test-live-gateway-models-docker.sh`) -- Open WebUI 라이브 스모크: `pnpm test:docker:openwebui`(스크립트: `scripts/e2e/openwebui-docker.sh`) -- 온보딩 마법사(TTY, 전체 스캐폴딩): `pnpm test:docker:onboard`(스크립트: `scripts/e2e/onboard-docker.sh`) -- 게이트웨이 네트워킹(두 컨테이너, WS 인증 + 상태 확인): `pnpm test:docker:gateway-network`(스크립트: `scripts/e2e/gateway-network-docker.sh`) -- MCP 채널 브리지(시드된 Gateway + stdio 브리지 + 원시 Claude 알림 프레임 스모크): `pnpm test:docker:mcp-channels`(스크립트: `scripts/e2e/mcp-channels-docker.sh`) +- Codex app-server 하네스 스모크: `pnpm test:docker:live-codex-harness`(스크립트: `scripts/test-live-codex-harness-docker.sh`) +- Gateway + dev agent: `pnpm test:docker:live-gateway`(스크립트: `scripts/test-live-gateway-models-docker.sh`) +- Open WebUI live 스모크: `pnpm test:docker:openwebui`(스크립트: `scripts/e2e/openwebui-docker.sh`) +- 온보딩 마법사(TTY, 전체 scaffolding): `pnpm test:docker:onboard`(스크립트: `scripts/e2e/onboard-docker.sh`) +- Gateway 네트워킹(두 컨테이너, WS auth + health): `pnpm test:docker:gateway-network`(스크립트: `scripts/e2e/gateway-network-docker.sh`) +- MCP 채널 브리지(seed된 Gateway + stdio 브리지 + raw Claude notification-frame 스모크): `pnpm test:docker:mcp-channels`(스크립트: `scripts/e2e/mcp-channels-docker.sh`) - Plugins(설치 스모크 + `/plugin` 별칭 + Claude 번들 재시작 의미론): `pnpm test:docker:plugins`(스크립트: `scripts/e2e/plugins-docker.sh`) -라이브 모델 Docker 실행기는 현재 체크아웃도 읽기 전용으로 바인드 마운트하고, 이를 컨테이너 내부의 임시 작업 디렉터리로 준비합니다. 이렇게 하면 런타임 이미지는 가볍게 유지하면서도 정확히 로컬 소스/구성에 대해 Vitest를 실행할 수 있습니다. -준비 단계는 `.pnpm-store`, `.worktrees`, `__openclaw_vitest__`, 앱 로컬 `.build` 또는 Gradle 출력 디렉터리처럼 큰 로컬 전용 캐시와 앱 빌드 출력을 건너뛰므로 Docker 라이브 실행이 머신별 아티팩트를 복사하느라 몇 분씩 소비하지 않습니다. -또한 `OPENCLAW_SKIP_CHANNELS=1`을 설정하므로 게이트웨이 라이브 프로브가 컨테이너 내부에서 실제 Telegram/Discord 등의 채널 워커를 시작하지 않습니다. -`test:docker:live-models`는 여전히 `pnpm test:live`를 실행하므로, 해당 Docker 레인에서 게이트웨이 라이브 커버리지를 좁히거나 제외해야 한다면 `OPENCLAW_LIVE_GATEWAY_*`도 함께 전달하세요. -`test:docker:openwebui`는 더 높은 수준의 호환성 스모크입니다. OpenAI 호환 HTTP 엔드포인트가 활성화된 OpenClaw 게이트웨이 컨테이너를 시작하고, 그 게이트웨이에 연결된 고정 Open WebUI 컨테이너를 시작한 뒤, Open WebUI를 통해 로그인하고, `/api/models`가 `openclaw/default`를 노출하는지 확인한 다음, Open WebUI의 `/api/chat/completions` 프록시를 통해 실제 채팅 요청을 전송합니다. -첫 실행은 Docker가 Open WebUI 이미지를 가져와야 하거나 Open WebUI 자체의 콜드 스타트 설정을 완료해야 할 수 있어 눈에 띄게 느릴 수 있습니다. -이 레인은 사용 가능한 라이브 모델 키를 기대하며, Docker 기반 실행에서는 `OPENCLAW_PROFILE_FILE`(`~/.profile`이 기본값)이 이를 제공하는 기본 방식입니다. +live-model Docker 실행기는 현재 체크아웃도 읽기 전용으로 바인드 마운트하고, 컨테이너 내부의 임시 workdir에 이를 준비합니다. 이렇게 하면 런타임 이미지는 슬림하게 유지하면서도 정확한 로컬 소스/config에 대해 Vitest를 실행할 수 있습니다. +준비 단계는 `.pnpm-store`, `.worktrees`, `__openclaw_vitest__`, 앱 로컬 `.build` 또는 Gradle 출력 디렉터리 같은 큰 로컬 전용 캐시와 앱 빌드 출력을 건너뛰므로, Docker live 실행이 머신별 아티팩트를 복사하느라 몇 분씩 쓰지 않게 됩니다. +또한 `OPENCLAW_SKIP_CHANNELS=1`을 설정하므로 gateway live 프로브가 컨테이너 내부에서 실제 Telegram/Discord 등의 채널 워커를 시작하지 않습니다. +`test:docker:live-models`는 여전히 `pnpm test:live`를 실행하므로, 해당 Docker 레인에서 gateway live 커버리지를 좁히거나 제외해야 할 때는 `OPENCLAW_LIVE_GATEWAY_*`도 함께 전달하세요. +`test:docker:openwebui`는 더 높은 수준의 호환성 스모크입니다. OpenAI 호환 HTTP 엔드포인트를 활성화한 OpenClaw gateway 컨테이너를 시작하고, 해당 gateway를 대상으로 고정된 Open WebUI 컨테이너를 시작하며, Open WebUI를 통해 로그인하고, `/api/models`가 `openclaw/default`를 노출하는지 검증한 다음, Open WebUI의 `/api/chat/completions` 프록시를 통해 실제 채팅 요청을 전송합니다. +첫 실행은 Docker가 Open WebUI 이미지를 가져와야 하거나 Open WebUI가 자체 콜드 스타트 설정을 완료해야 할 수 있으므로 눈에 띄게 더 느릴 수 있습니다. +이 레인은 사용 가능한 live 모델 키를 기대하며, Docker 실행에서 이를 제공하는 기본 방법은 `OPENCLAW_PROFILE_FILE`(기본값 `~/.profile`)입니다. 성공적인 실행은 `{ "ok": true, "model": "openclaw/default", ... }`와 같은 작은 JSON 페이로드를 출력합니다. -`test:docker:mcp-channels`는 의도적으로 결정론적이며 실제 Telegram, Discord, 또는 iMessage 계정이 필요하지 않습니다. 시드된 Gateway 컨테이너를 부팅하고, `openclaw mcp serve`를 시작하는 두 번째 컨테이너를 띄운 다음, 라우팅된 대화 탐색, transcript 읽기, 첨부 파일 메타데이터, 라이브 이벤트 큐 동작, 아웃바운드 전송 라우팅, 그리고 실제 stdio MCP 브리지를 통한 Claude 스타일 채널 + 권한 알림을 검증합니다. 알림 검사는 원시 stdio MCP 프레임을 직접 검사하므로, 특정 클라이언트 SDK가 우연히 노출하는 내용이 아니라 브리지가 실제로 내보내는 내용을 검증합니다. +`test:docker:mcp-channels`는 의도적으로 결정적이며 실제 Telegram, Discord 또는 iMessage 계정이 필요하지 않습니다. seed된 Gateway 컨테이너를 부팅하고, `openclaw mcp serve`를 시작하는 두 번째 컨테이너를 실행한 뒤, 라우팅된 대화 검색, transcript 읽기, 첨부 파일 메타데이터, live event queue 동작, 외부 발신 라우팅, 그리고 실제 stdio MCP 브리지를 통한 Claude 스타일 채널 + 권한 알림을 검증합니다. 알림 검사는 raw stdio MCP 프레임을 직접 검사하므로, 이 스모크는 특정 클라이언트 SDK가 우연히 노출하는 내용이 아니라 브리지가 실제로 방출하는 내용을 검증합니다. -수동 ACP 자연어 스레드 스모크(CI 아님): +수동 ACP 평이한 언어 스레드 스모크(CI 아님): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` - 이 스크립트는 회귀/디버그 워크플로를 위해 유지하세요. ACP 스레드 라우팅 검증에 다시 필요할 수 있으므로 삭제하지 마세요. -유용한 env 변수: +유용한 환경 변수: -- `OPENCLAW_CONFIG_DIR=...`(기본값: `~/.openclaw`)를 `/home/node/.openclaw`에 마운트 -- `OPENCLAW_WORKSPACE_DIR=...`(기본값: `~/.openclaw/workspace`)를 `/home/node/.openclaw/workspace`에 마운트 -- `OPENCLAW_PROFILE_FILE=...`(기본값: `~/.profile`)를 `/home/node/.profile`에 마운트하고 테스트 실행 전에 소싱 -- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(기본값: `~/.cache/openclaw/docker-cli-tools`)를 `/home/node/.npm-global`에 마운트하여 Docker 내부 CLI 설치 캐시로 사용 -- `$HOME` 아래의 외부 CLI 인증 디렉터리/파일은 `/host-auth...` 아래에 읽기 전용으로 마운트된 뒤, 테스트 시작 전에 `/home/node/...`로 복사됨 +- `OPENCLAW_CONFIG_DIR=...`(기본값: `~/.openclaw`)은 `/home/node/.openclaw`에 마운트됩니다. +- `OPENCLAW_WORKSPACE_DIR=...`(기본값: `~/.openclaw/workspace`)은 `/home/node/.openclaw/workspace`에 마운트됩니다. +- `OPENCLAW_PROFILE_FILE=...`(기본값: `~/.profile`)은 `/home/node/.profile`에 마운트되며 테스트 실행 전에 source됩니다. +- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(기본값: `~/.cache/openclaw/docker-cli-tools`)은 Docker 내부 캐시된 CLI 설치를 위해 `/home/node/.npm-global`에 마운트됩니다. +- `$HOME` 아래 외부 CLI 인증 디렉터리/파일은 `/host-auth...` 아래에 읽기 전용으로 마운트된 뒤 테스트 시작 전에 `/home/node/...`로 복사됩니다. - 기본 디렉터리: `.minimax` - 기본 파일: `~/.codex/auth.json`, `~/.codex/config.toml`, `.claude.json`, `~/.claude/.credentials.json`, `~/.claude/settings.json`, `~/.claude/settings.local.json` - - 범위를 좁힌 프로바이더 실행은 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS`에서 추론된 필요한 디렉터리/파일만 마운트함 + - 범위를 좁힌 provider 실행은 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS`에서 추론한 필요한 디렉터리/파일만 마운트합니다. - 수동 재정의: `OPENCLAW_DOCKER_AUTH_DIRS=all`, `OPENCLAW_DOCKER_AUTH_DIRS=none`, 또는 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 같은 쉼표 목록 - 실행 범위를 좁히려면 `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` -- 컨테이너 내부에서 프로바이더를 필터링하려면 `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` -- 자격 증명이 프로필 저장소에서 오도록 강제하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`(env 아님) -- Open WebUI 스모크용으로 게이트웨이가 노출할 모델을 선택하려면 `OPENCLAW_OPENWEBUI_MODEL=...` -- Open WebUI 스모크가 사용하는 nonce 확인 프롬프트를 재정의하려면 `OPENCLAW_OPENWEBUI_PROMPT=...` +- 컨테이너 내부 provider 필터링에는 `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` +- 재빌드가 필요 없는 재실행에서 기존 `openclaw:local-live` 이미지를 재사용하려면 `OPENCLAW_SKIP_DOCKER_BUILD=1` +- 자격 증명이 환경 변수가 아니라 profile store에서 오도록 보장하려면 `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` +- Open WebUI 스모크에 대해 gateway가 노출할 모델을 선택하려면 `OPENCLAW_OPENWEBUI_MODEL=...` +- Open WebUI 스모크에서 사용하는 nonce-check 프롬프트를 재정의하려면 `OPENCLAW_OPENWEBUI_PROMPT=...` - 고정된 Open WebUI 이미지 태그를 재정의하려면 `OPENWEBUI_IMAGE=...` ## 문서 기본 점검 -문서를 수정한 뒤에는 문서 검사 실행: `pnpm check:docs`. -페이지 내 heading 검사까지 필요할 때는 전체 Mintlify 앵커 검증 실행: `pnpm docs:check-links:anchors`. +문서를 수정한 뒤에는 문서 점검을 실행하세요: `pnpm check:docs`. +페이지 내 heading 검사도 필요할 때는 전체 Mintlify anchor 검증을 실행하세요: `pnpm docs:check-links:anchors`. ## 오프라인 회귀(CI 안전) -실제 프로바이더 없이도 가능한 “실제 파이프라인” 회귀입니다. +실제 provider 없이도 “실제 파이프라인” 회귀를 검증하는 항목입니다. -- 게이트웨이 도구 호출(mock OpenAI, 실제 게이트웨이 + 에이전트 루프): `src/gateway/gateway.test.ts`(케이스: "runs a mock OpenAI tool call end-to-end via gateway agent loop") -- 게이트웨이 마법사(WS `wizard.start`/`wizard.next`, 구성 + 인증 토큰 쓰기 강제): `src/gateway/gateway.test.ts`(케이스: "runs wizard over ws and writes auth token config") +- Gateway tool calling(mock OpenAI, 실제 gateway + agent 루프): `src/gateway/gateway.test.ts`(케이스: "runs a mock OpenAI tool call end-to-end via gateway agent loop") +- Gateway wizard(WS `wizard.start`/`wizard.next`, config + auth 쓰기 강제): `src/gateway/gateway.test.ts`(케이스: "runs wizard over ws and writes auth token config") ## 에이전트 신뢰성 평가(Skills) -이미 “에이전트 신뢰성 평가”처럼 동작하는 CI 안전 테스트가 몇 가지 있습니다. +이미 몇 가지 CI 안전 테스트가 “에이전트 신뢰성 평가”처럼 동작합니다. -- 실제 게이트웨이 + 에이전트 루프를 통한 mock 도구 호출(`src/gateway/gateway.test.ts`). -- 세션 연결과 구성 효과를 검증하는 end-to-end 마법사 흐름(`src/gateway/gateway.test.ts`). +- 실제 gateway + agent 루프를 통한 mock tool-calling(`src/gateway/gateway.test.ts`) +- 세션 연결과 config 효과를 검증하는 종단 간 wizard 흐름(`src/gateway/gateway.test.ts`) -Skills에 대해 아직 부족한 점([Skills](/ko/tools/skills) 참고): +Skills에 대해 아직 부족한 항목은 다음과 같습니다([Skills](/ko/tools/skills) 참고). -- **판단:** 프롬프트에 skill이 나열될 때, 에이전트가 올바른 skill을 선택하는가(또는 관련 없는 skill을 피하는가)? -- **준수:** 에이전트가 사용 전에 `SKILL.md`를 읽고 필수 단계/인자를 따르는가? -- **워크플로 계약:** 도구 순서, 세션 히스토리 유지, 샌드박스 경계를 검증하는 다중 턴 시나리오. +- **의사결정**: 프롬프트에 skills가 나열되어 있을 때 에이전트가 올바른 skill을 선택하는가(또는 관련 없는 skill을 피하는가)? +- **준수**: 에이전트가 사용 전에 `SKILL.md`를 읽고 필요한 단계/인수를 따르는가? +- **워크플로 계약**: 도구 순서, 세션 기록 유지, sandbox 경계를 검증하는 다중 턴 시나리오 -향후 평가는 우선 결정론적으로 유지해야 합니다. +향후 평가는 우선 결정적이어야 합니다. -- 도구 호출 + 순서, skill 파일 읽기, 세션 연결을 검증하기 위해 mock 프로바이더를 사용하는 시나리오 실행기 -- skill 중심의 소규모 시나리오 스위트(사용 vs 회피, 게이팅, 프롬프트 주입) -- CI 안전 스위트가 자리 잡은 뒤에만 선택적으로 라이브 평가(옵트인, env 게이트) +- tool 호출 + 순서, skill 파일 읽기, 세션 연결을 검증하기 위해 mock provider를 사용하는 시나리오 실행기 +- skill 중심의 작은 시나리오 스위트(사용 vs 회피, 게이팅, 프롬프트 인젝션) +- CI 안전 스위트가 마련된 뒤에만 선택적으로 env-gated live 평가 추가 ## 계약 테스트(plugin 및 channel 형태) -계약 테스트는 등록된 모든 plugin과 channel이 인터페이스 계약을 준수하는지 검증합니다. 발견된 모든 plugin을 순회하고 형태 및 동작 검증 스위트를 실행합니다. 기본 `pnpm test` 단위 레인은 의도적으로 이러한 공유 seam 및 스모크 파일을 건너뛰므로, 공유 channel 또는 provider 표면을 건드렸다면 계약 명령을 명시적으로 실행하세요. +계약 테스트는 등록된 모든 plugin과 channel이 해당 인터페이스 계약을 준수하는지 검증합니다. 발견된 모든 plugin을 반복하며 형태와 동작에 대한 검증 스위트를 실행합니다. 기본 `pnpm test` unit 레인은 의도적으로 이러한 공유 seam 및 스모크 파일을 건너뛰므로, 공유 channel 또는 provider 표면을 수정할 때는 계약 명령을 명시적으로 실행하세요. ### 명령 @@ -701,11 +767,11 @@ Skills에 대해 아직 부족한 점([Skills](/ko/tools/skills) 참고): - **setup** - 설정 마법사 계약 - **session-binding** - 세션 바인딩 동작 - **outbound-payload** - 메시지 페이로드 구조 -- **inbound** - 인바운드 메시지 처리 -- **actions** - channel 액션 핸들러 -- **threading** - 스레드 ID 처리 -- **directory** - 디렉터리/명단 API -- **group-policy** - 그룹 정책 적용 +- **inbound** - 수신 메시지 처리 +- **actions** - channel action handler +- **threading** - thread ID 처리 +- **directory** - 디렉터리/roster API +- **group-policy** - 그룹 정책 강제 ### Provider 상태 계약 @@ -719,31 +785,31 @@ Skills에 대해 아직 부족한 점([Skills](/ko/tools/skills) 참고): `src/plugins/contracts/*.contract.test.ts`에 위치: - **auth** - 인증 흐름 계약 -- **auth-choice** - 인증 선택 +- **auth-choice** - 인증 선택/선정 - **catalog** - 모델 카탈로그 API -- **discovery** - plugin 탐색 -- **loader** - plugin 로드 +- **discovery** - plugin 발견 +- **loader** - plugin 로딩 - **runtime** - provider 런타임 - **shape** - plugin 형태/인터페이스 - **wizard** - 설정 마법사 ### 실행 시점 -- plugin-sdk export 또는 하위 경로를 변경한 후 +- plugin-sdk export 또는 subpath를 변경한 후 - channel 또는 provider plugin을 추가하거나 수정한 후 -- plugin 등록 또는 탐색을 리팩터링한 후 +- plugin 등록 또는 발견을 리팩터링한 후 계약 테스트는 CI에서 실행되며 실제 API 키가 필요하지 않습니다. -## 회귀 추가하기(가이드) +## 회귀 추가(가이드) -라이브에서 발견된 프로바이더/모델 이슈를 수정할 때: +live에서 발견된 provider/model 문제를 수정할 때: -- 가능하면 CI 안전 회귀를 추가하세요(mock/stub 프로바이더를 사용하거나, 정확한 요청 형태 변환을 캡처) -- 본질적으로 라이브 전용이라면(속도 제한, 인증 정책), 라이브 테스트는 좁은 범위로 유지하고 env 변수를 통해 옵트인으로 만드세요 -- 버그를 잡아내는 가장 작은 계층을 대상으로 삼는 것을 선호하세요: - - 프로바이더 요청 변환/재생 버그 → 직접 모델 테스트 - - 게이트웨이 세션/히스토리/도구 파이프라인 버그 → 게이트웨이 라이브 스모크 또는 CI 안전 게이트웨이 mock 테스트 +- 가능하면 CI 안전 회귀를 추가하세요(mock/stub provider 또는 정확한 요청 형태 변환 캡처) +- 본질적으로 live 전용인 경우(rate limit, auth 정책), live 테스트는 좁고 env 변수를 통한 옵트인으로 유지하세요. +- 버그를 잡는 가장 작은 계층을 목표로 하세요. + - provider 요청 변환/재생 버그 → 직접 모델 테스트 + - gateway 세션/기록/tool 파이프라인 버그 → gateway live 스모크 또는 CI 안전 gateway mock 테스트 - SecretRef 순회 가드레일: - - `src/secrets/exec-secret-ref-id-parity.test.ts`는 레지스트리 메타데이터(`listSecretTargetRegistryEntries()`)에서 SecretRef 클래스별 샘플 대상 하나를 도출한 다음, 순회 세그먼트 exec id가 거부되는지 검증합니다. - - `src/secrets/target-registry-data.ts`에 새로운 `includeInPlan` SecretRef 대상 계열을 추가한다면, 해당 테스트의 `classifyTargetClass`를 업데이트하세요. 이 테스트는 분류되지 않은 대상 id에서 의도적으로 실패하므로 새 클래스가 조용히 건너뛰어질 수 없습니다. + - `src/secrets/exec-secret-ref-id-parity.test.ts`는 레지스트리 메타데이터(`listSecretTargetRegistryEntries()`)에서 SecretRef 클래스별 샘플 대상 하나를 도출한 다음, 순회 세그먼트 exec ID가 거부되는지 검증합니다. + - `src/secrets/target-registry-data.ts`에 새 `includeInPlan` SecretRef 대상 계열을 추가한다면, 해당 테스트의 `classifyTargetClass`를 업데이트하세요. 이 테스트는 분류되지 않은 대상 ID에서 의도적으로 실패하므로 새 클래스가 조용히 건너뛰어질 수 없습니다. diff --git a/docs/ko/help/troubleshooting.md b/docs/ko/help/troubleshooting.md index 425b4615a..a0db2735f 100644 --- a/docs/ko/help/troubleshooting.md +++ b/docs/ko/help/troubleshooting.md @@ -1,25 +1,25 @@ --- read_when: - - OpenClaw가 작동하지 않아 가장 빠른 해결 경로가 필요할 때 - - 깊이 있는 런북으로 들어가기 전에 triage 흐름을 원할 때 -summary: OpenClaw를 위한 증상 우선 문제 해결 허브 + - OpenClaw가 작동하지 않으며 가장 빠른 해결 경로가 필요합니다. + - 심층 런북으로 들어가기 전에 먼저 트리아지 흐름이 필요합니다. +summary: OpenClaw용 증상 우선 문제 해결 허브 title: 일반 문제 해결 x-i18n: - generated_at: "2026-04-08T02:16:36Z" + generated_at: "2026-04-11T02:46:03Z" model: gpt-5.4 provider: openai - source_hash: 8abda90ef80234c2f91a51c5e1f2c004d4a4da12a5d5631b5927762550c6d5e3 + source_hash: 16b38920dbfdc8d4a79bbb5d6fab2c67c9f218a97c36bb4695310d7db9c4614a source_path: help/troubleshooting.md workflow: 15 --- # 문제 해결 -2분밖에 없다면 이 페이지를 triage 시작점으로 사용하세요. +시간이 2분밖에 없다면, 이 페이지를 트리아지 시작점으로 사용하세요. ## 처음 60초 -아래의 정확한 단계를 순서대로 실행하세요: +다음 정확한 순서로 실행하세요. ```bash openclaw status @@ -31,49 +31,48 @@ openclaw channels status --probe openclaw logs --follow ``` -한 줄로 보는 정상 출력: +좋은 출력의 한 줄 요약: - `openclaw status` → 구성된 채널이 표시되고 명백한 인증 오류가 없습니다. - `openclaw status --all` → 전체 보고서가 존재하며 공유할 수 있습니다. -- `openclaw gateway probe` → 예상한 gateway 대상에 도달할 수 있습니다(`Reachable: yes`). `RPC: limited - missing scope: operator.read`는 연결 실패가 아니라 진단 기능 저하입니다. +- `openclaw gateway probe` → 예상한 gateway 대상에 도달할 수 있습니다(`Reachable: yes`). `RPC: limited - missing scope: operator.read`는 연결 실패가 아니라 제한된 진단 상태입니다. - `openclaw gateway status` → `Runtime: running` 및 `RPC probe: ok`. - `openclaw doctor` → 차단하는 config/service 오류가 없습니다. -- `openclaw channels status --probe` → 도달 가능한 gateway는 계정별 실시간 +- `openclaw channels status --probe` → 도달 가능한 gateway는 라이브 계정별 전송 상태와 `works` 또는 `audit ok` 같은 probe/audit 결과를 반환합니다. gateway에 - 도달할 수 없으면 명령은 config 전용 요약으로 대체됩니다. + 도달할 수 없으면, 이 명령은 config 전용 요약으로 대체됩니다. - `openclaw logs --follow` → 안정적인 활동이 보이고 반복되는 치명적 오류가 없습니다. ## Anthropic 긴 컨텍스트 429 -다음이 표시되면: -`HTTP 429: rate_limit_error: Extra usage is required for long context requests`, +다음이 보이면: +`HTTP 429: rate_limit_error: Extra usage is required for long context requests` [/gateway/troubleshooting#anthropic-429-extra-usage-required-for-long-context](/ko/gateway/troubleshooting#anthropic-429-extra-usage-required-for-long-context)로 이동하세요. ## 로컬 OpenAI 호환 백엔드는 직접 호출하면 작동하지만 OpenClaw에서는 실패함 -로컬 또는 자체 호스팅된 `/v1` 백엔드가 작은 직접 -`/v1/chat/completions` 프로브에는 응답하지만 `openclaw infer model run` 또는 일반 -agent 턴에서는 실패하는 경우: +로컬 또는 self-hosted `/v1` 백엔드가 작은 직접 +`/v1/chat/completions` probe에는 응답하지만 `openclaw infer model run` 또는 일반 +에이전트 턴에서는 실패하는 경우: 1. 오류에 `messages[].content`가 문자열이어야 한다는 내용이 있으면 `models.providers..models[].compat.requiresStringContent: true`를 설정하세요. -2. 백엔드가 여전히 OpenClaw agent 턴에서만 실패한다면 +2. 백엔드가 여전히 OpenClaw 에이전트 턴에서만 실패한다면 `models.providers..models[].compat.supportsTools: false`를 설정하고 다시 시도하세요. -3. 아주 작은 직접 호출은 여전히 작동하지만 더 큰 OpenClaw 프롬프트에서 백엔드가 - 충돌한다면, 남은 문제는 업스트림 모델/서버 제한으로 간주하고 - 다음 심화 런북으로 계속 진행하세요: +3. 아주 작은 직접 호출은 여전히 작동하지만 더 큰 OpenClaw 프롬프트에서 백엔드가 충돌한다면 + 남은 문제는 업스트림 모델/서버 제한으로 보고 심층 런북으로 계속 진행하세요: [/gateway/troubleshooting#local-openai-compatible-backend-passes-direct-probes-but-agent-runs-fail](/ko/gateway/troubleshooting#local-openai-compatible-backend-passes-direct-probes-but-agent-runs-fail) -## 누락된 openclaw extensions 때문에 plugin 설치 실패 +## 플러그인 설치가 누락된 openclaw extensions 오류로 실패함 -설치가 `package.json missing openclaw.extensions`와 함께 실패하면 해당 plugin 패키지가 -이제 OpenClaw에서 허용하지 않는 오래된 형식을 사용하고 있는 것입니다. +설치가 `package.json missing openclaw.extensions`로 실패하면, 플러그인 패키지가 +OpenClaw가 더 이상 허용하지 않는 오래된 형식을 사용하고 있는 것입니다. -plugin 패키지에서 다음과 같이 수정하세요: +플러그인 패키지에서 다음과 같이 수정하세요. 1. `package.json`에 `openclaw.extensions`를 추가합니다. -2. 항목이 빌드된 런타임 파일(일반적으로 `./dist/index.js`)을 가리키도록 합니다. -3. plugin을 다시 게시하고 `openclaw plugins install `를 다시 실행합니다. +2. 엔트리가 빌드된 런타임 파일(보통 `./dist/index.js`)을 가리키도록 합니다. +3. 플러그인을 다시 배포한 후 `openclaw plugins install `를 다시 실행합니다. 예시: @@ -87,28 +86,28 @@ plugin 패키지에서 다음과 같이 수정하세요: } ``` -참고: [Plugin architecture](/ko/plugins/architecture) +참조: [Plugin architecture](/ko/plugins/architecture) ## 결정 트리 ```mermaid flowchart TD - A[OpenClaw가 작동하지 않음] --> B{무엇이 먼저 깨지나요} - B --> C[응답이 없음] - B --> D[대시보드 또는 Control UI가 연결되지 않음] - B --> E[Gateway가 시작되지 않거나 서비스가 실행 중이 아님] - B --> F[채널은 연결되지만 메시지가 흐르지 않음] - B --> G[Cron 또는 heartbeat가 실행되지 않았거나 전달되지 않음] - B --> H[Node는 페어링되었지만 camera canvas screen exec 도구가 실패함] - B --> I[브라우저 도구 실패] + A[OpenClaw is not working] --> B{What breaks first} + B --> C[No replies] + B --> D[Dashboard or Control UI will not connect] + B --> E[Gateway will not start or service not running] + B --> F[Channel connects but messages do not flow] + B --> G[Cron or heartbeat did not fire or did not deliver] + B --> H[Node is paired but camera canvas screen exec fails] + B --> I[Browser tool fails] - C --> C1[/응답 없음 섹션/] - D --> D1[/Control UI 섹션/] - E --> E1[/Gateway 섹션/] - F --> F1[/채널 흐름 섹션/] - G --> G1[/자동화 섹션/] - H --> H1[/Node 도구 섹션/] - I --> I1[/브라우저 섹션/] + C --> C1[/No replies section/] + D --> D1[/Control UI section/] + E --> E1[/Gateway section/] + F --> F1[/Channel flow section/] + G --> G1[/Automation section/] + H --> H1[/Node tools section/] + I --> I1[/Browser section/] ``` @@ -121,20 +120,20 @@ flowchart TD openclaw logs --follow ``` - 정상 출력 예시: + 좋은 출력 예시: - `Runtime: running` - `RPC probe: ok` - 채널에 전송 연결 상태가 표시되고, 지원되는 경우 `channels status --probe`에 `works` 또는 `audit ok`가 표시됨 - - 발신자가 승인된 것으로 표시됨(또는 DM 정책이 open/allowlist임) + - 발신자가 승인된 상태로 표시됨(또는 DM 정책이 open/allowlist) 일반적인 로그 시그니처: - - `drop guild message (mention required` → Discord에서 멘션 게이팅 때문에 메시지 처리가 차단됨. - - `pairing request` → 발신자가 승인되지 않았고 DM pairing 승인을 기다리는 중. - - 채널 로그의 `blocked` / `allowlist` → 발신자, 방 또는 그룹이 필터링됨. + - `drop guild message (mention required` → Discord에서 멘션 게이팅이 메시지를 차단했습니다. + - `pairing request` → 발신자가 승인되지 않았고 DM 페어링 승인을 기다리고 있습니다. + - 채널 로그의 `blocked` / `allowlist` → 발신자, 룸 또는 그룹이 필터링되었습니다. - 심화 페이지: + 심층 페이지: - [/gateway/troubleshooting#no-replies](/ko/gateway/troubleshooting#no-replies) - [/channels/troubleshooting](/ko/channels/troubleshooting) @@ -142,7 +141,7 @@ flowchart TD - + ```bash openclaw status openclaw gateway status @@ -151,7 +150,7 @@ flowchart TD openclaw channels status --probe ``` - 정상 출력 예시: + 좋은 출력 예시: - `openclaw gateway status`에 `Dashboard: http://...`가 표시됨 - `RPC probe: ok` @@ -159,23 +158,19 @@ flowchart TD 일반적인 로그 시그니처: - - `device identity required` → HTTP/비보안 컨텍스트에서는 기기 인증을 완료할 수 없음. + - `device identity required` → HTTP/비보안 컨텍스트에서는 디바이스 인증을 완료할 수 없습니다. - `origin not allowed` → 브라우저 `Origin`이 Control UI - gateway 대상에 대해 허용되지 않음. - - `AUTH_TOKEN_MISMATCH`와 재시도 힌트(`canRetryWithDeviceToken=true`) → 신뢰된 device-token 재시도 1회가 자동으로 발생할 수 있음. - - 해당 캐시된 토큰 재시도는 페어링된 - 기기 토큰과 함께 저장된 캐시된 범위 집합을 재사용합니다. 명시적 `deviceToken` / 명시적 `scopes` 호출자는 - 대신 요청한 범위 집합을 유지합니다. + gateway 대상에서 허용되지 않습니다. + - 재시도 힌트가 있는 `AUTH_TOKEN_MISMATCH` (`canRetryWithDeviceToken=true`) → 신뢰된 device-token 재시도 1회가 자동으로 발생할 수 있습니다. + - 해당 캐시된 토큰 재시도는 페어링된 device token과 함께 저장된 캐시된 scope 집합을 재사용합니다. 명시적 `deviceToken` / 명시적 `scopes` 호출자는 요청한 scope 집합을 그대로 유지합니다. - 비동기 Tailscale Serve Control UI 경로에서는 동일한 `{scope, ip}`에 대한 실패한 시도가 limiter가 실패를 기록하기 전에 직렬화되므로, - 동시에 발생한 두 번째 잘못된 재시도에서도 이미 `retry later`가 표시될 수 있습니다. - - localhost 브라우저 origin에서 발생한 `too many failed authentication attempts (retry later)` - → 동일한 `Origin`에서의 반복 실패가 일시적으로 - 잠겼음을 의미합니다. 다른 localhost origin은 별도의 버킷을 사용합니다. - - 그 재시도 이후에도 반복되는 `unauthorized` → 잘못된 토큰/비밀번호, 인증 모드 불일치 또는 오래된 페어링된 기기 토큰. - - `gateway connect failed:` → UI가 잘못된 URL/포트를 대상으로 하고 있거나 gateway에 도달할 수 없음. + 두 번째 동시 잘못된 재시도는 이미 `retry later`를 표시할 수 있습니다. + - localhost 브라우저 origin에서의 `too many failed authentication attempts (retry later)` → 같은 `Origin`에서 반복 실패가 발생해 일시적으로 차단된 상태이며, 다른 localhost origin은 별도 버킷을 사용합니다. + - 그 재시도 이후에도 반복되는 `unauthorized` → 잘못된 토큰/비밀번호, 인증 모드 불일치, 또는 오래된 페어링된 device token입니다. + - `gateway connect failed:` → UI가 잘못된 URL/포트를 대상으로 하거나 gateway에 도달할 수 없습니다. - 심화 페이지: + 심층 페이지: - [/gateway/troubleshooting#dashboard-control-ui-connectivity](/ko/gateway/troubleshooting#dashboard-control-ui-connectivity) - [/web/control-ui](/web/control-ui) @@ -183,7 +178,7 @@ flowchart TD - + ```bash openclaw status openclaw gateway status @@ -192,7 +187,7 @@ flowchart TD openclaw channels status --probe ``` - 정상 출력 예시: + 좋은 출력 예시: - `Service: ... (loaded)` - `Runtime: running` @@ -200,11 +195,11 @@ flowchart TD 일반적인 로그 시그니처: - - `Gateway start blocked: set gateway.mode=local` 또는 `existing config is missing gateway.mode` → gateway 모드가 remote이거나, config 파일에 로컬 모드 표시가 없어 복구가 필요함. - - `refusing to bind gateway ... without auth` → 유효한 gateway 인증 경로(토큰/비밀번호 또는 구성된 trusted-proxy) 없이 non-loopback 바인드 시도. - - `another gateway instance is already listening` 또는 `EADDRINUSE` → 포트가 이미 사용 중임. + - `Gateway start blocked: set gateway.mode=local` 또는 `existing config is missing gateway.mode` → gateway 모드가 remote이거나, config 파일에 local-mode 표시가 없어 복구가 필요합니다. + - `refusing to bind gateway ... without auth` → 유효한 gateway 인증 경로(token/password 또는 구성된 경우 trusted-proxy) 없이 non-loopback bind를 시도했습니다. + - `another gateway instance is already listening` 또는 `EADDRINUSE` → 포트가 이미 사용 중입니다. - 심화 페이지: + 심층 페이지: - [/gateway/troubleshooting#gateway-service-not-running](/ko/gateway/troubleshooting#gateway-service-not-running) - [/gateway/background-process](/ko/gateway/background-process) @@ -221,19 +216,19 @@ flowchart TD openclaw channels status --probe ``` - 정상 출력 예시: + 좋은 출력 예시: - - 채널 전송이 연결되어 있음. - - Pairing/allowlist 검사를 통과함. - - 필요한 경우 멘션이 감지됨. + - 채널 전송이 연결되어 있습니다. + - pairing/allowlist 검사를 통과합니다. + - 필요한 경우 멘션이 감지됩니다. 일반적인 로그 시그니처: - - `mention required` → 그룹 멘션 게이팅 때문에 처리가 차단됨. - - `pairing` / `pending` → DM 발신자가 아직 승인되지 않음. - - `not_in_channel`, `missing_scope`, `Forbidden`, `401/403` → 채널 권한 토큰 문제. + - `mention required` → 그룹 멘션 게이팅이 처리를 차단했습니다. + - `pairing` / `pending` → DM 발신자가 아직 승인되지 않았습니다. + - `not_in_channel`, `missing_scope`, `Forbidden`, `401/403` → 채널 권한 토큰 문제입니다. - 심화 페이지: + 심층 페이지: - [/gateway/troubleshooting#channel-connected-messages-not-flowing](/ko/gateway/troubleshooting#channel-connected-messages-not-flowing) - [/channels/troubleshooting](/ko/channels/troubleshooting) @@ -250,30 +245,31 @@ flowchart TD openclaw logs --follow ``` - 정상 출력 예시: + 좋은 출력 예시: - - `cron.status`가 활성화 상태와 다음 실행 시간을 보여줌. - - `cron runs`에 최근 `ok` 항목이 표시됨. - - Heartbeat가 활성화되어 있고 활성 시간 밖이 아님. + - `cron.status`에 활성화 상태와 다음 wake가 표시됨 + - `cron runs`에 최근 `ok` 항목이 표시됨 + - heartbeat가 활성화되어 있고 활성 시간대 밖이 아님 일반적인 로그 시그니처: -- `cron: scheduler disabled; jobs will not run automatically` → cron이 비활성화됨. -- `heartbeat skipped` with `reason=quiet-hours` → 구성된 활성 시간 외부임. -- `heartbeat skipped` with `reason=empty-heartbeat-file` → `HEARTBEAT.md`가 존재하지만 빈 내용/헤더만 있는 스캐폴딩만 포함함. -- `heartbeat skipped` with `reason=no-tasks-due` → `HEARTBEAT.md` 작업 모드가 활성화되어 있지만 아직 실행 시점이 된 작업 간격이 없음. -- `heartbeat skipped` with `reason=alerts-disabled` → 모든 heartbeat 가시성이 비활성화됨(`showOk`, `showAlerts`, `useIndicator`가 모두 꺼짐). -- `requests-in-flight` → 메인 레인이 바쁨. heartbeat 실행이 지연됨. - `unknown accountId` → heartbeat 전달 대상 account가 존재하지 않음. + - `cron: scheduler disabled; jobs will not run automatically` → cron이 비활성화되어 있습니다. + - `heartbeat skipped` with `reason=quiet-hours` → 구성된 활성 시간대 밖입니다. + - `heartbeat skipped` with `reason=empty-heartbeat-file` → `HEARTBEAT.md`가 존재하지만 빈 내용이거나 헤더만 있는 골격만 포함합니다. + - `heartbeat skipped` with `reason=no-tasks-due` → `HEARTBEAT.md` 작업 모드가 활성화되어 있지만 아직 도래한 작업 간격이 없습니다. + - `heartbeat skipped` with `reason=alerts-disabled` → heartbeat 가시성이 모두 비활성화되어 있습니다(`showOk`, `showAlerts`, `useIndicator`가 모두 꺼짐). + - `requests-in-flight` → 메인 레인이 바쁩니다. heartbeat wake가 연기되었습니다. + - `unknown accountId` → heartbeat 전달 대상 account가 존재하지 않습니다. - 심화 페이지: + 심층 페이지: - - [/gateway/troubleshooting#cron-and-heartbeat-delivery](/ko/gateway/troubleshooting#cron-and-heartbeat-delivery) - - [/automation/cron-jobs#troubleshooting](/ko/automation/cron-jobs#troubleshooting) - - [/gateway/heartbeat](/ko/gateway/heartbeat) + - [/gateway/troubleshooting#cron-and-heartbeat-delivery](/ko/gateway/troubleshooting#cron-and-heartbeat-delivery) + - [/automation/cron-jobs#troubleshooting](/ko/automation/cron-jobs#troubleshooting) + - [/gateway/heartbeat](/ko/gateway/heartbeat) - + ```bash openclaw status openclaw gateway status @@ -282,20 +278,20 @@ flowchart TD openclaw logs --follow ``` - 정상 출력 예시: + 좋은 출력 예시: - - Node가 연결되고 role `node`로 페어링된 상태로 표시됨. - - 호출하려는 명령에 대한 capability가 존재함. - - 도구에 대한 권한 상태가 부여됨. + - Node가 `node` 역할로 연결되고 페어링된 상태로 표시됩니다. + - 호출하는 명령에 대한 capability가 존재합니다. + - 도구에 대한 permission 상태가 허용됨입니다. 일반적인 로그 시그니처: - `NODE_BACKGROUND_UNAVAILABLE` → node 앱을 전경으로 가져오세요. - - `*_PERMISSION_REQUIRED` → OS 권한이 거부되었거나 누락됨. - - `SYSTEM_RUN_DENIED: approval required` → exec 승인이 대기 중임. - - `SYSTEM_RUN_DENIED: allowlist miss` → 명령이 exec allowlist에 없음. + - `*_PERMISSION_REQUIRED` → OS 권한이 거부되었거나 없습니다. + - `SYSTEM_RUN_DENIED: approval required` → exec 승인이 대기 중입니다. + - `SYSTEM_RUN_DENIED: allowlist miss` → 명령이 exec allowlist에 없습니다. - 심화 페이지: + 심층 페이지: - [/gateway/troubleshooting#node-paired-tool-fails](/ko/gateway/troubleshooting#node-paired-tool-fails) - [/nodes/troubleshooting](/ko/nodes/troubleshooting) @@ -303,7 +299,7 @@ flowchart TD - + ```bash openclaw config get tools.exec.host openclaw config get tools.exec.security @@ -314,11 +310,11 @@ flowchart TD 변경된 내용: - `tools.exec.host`가 설정되지 않으면 기본값은 `auto`입니다. - - `host=auto`는 샌드박스 런타임이 활성화되어 있으면 `sandbox`, 그렇지 않으면 `gateway`로 해석됩니다. - - `host=auto`는 라우팅만 담당합니다. 프롬프트 없는 "YOLO" 동작은 gateway/node의 `security=full` + `ask=off`에서 옵니다. - - `gateway`와 `node`에서는 설정되지 않은 `tools.exec.security`의 기본값이 `full`입니다. - - 설정되지 않은 `tools.exec.ask`의 기본값은 `off`입니다. - - 결과적으로, 승인이 보인다면 일부 호스트 로컬 또는 세션별 정책이 현재 기본값보다 더 엄격하게 exec를 제한한 것입니다. + - `host=auto`는 샌드박스 런타임이 활성화되어 있으면 `sandbox`로, 그렇지 않으면 `gateway`로 해석됩니다. + - `host=auto`는 라우팅만 담당합니다. 프롬프트 없는 "YOLO" 동작은 gateway/node의 `security=full`과 `ask=off`에서 옵니다. + - `gateway`와 `node`에서는 `tools.exec.security`가 설정되지 않으면 기본값은 `full`입니다. + - `tools.exec.ask`가 설정되지 않으면 기본값은 `off`입니다. + - 결과적으로 지금 승인이 보인다면, 일부 호스트 로컬 또는 세션별 정책이 현재 기본값보다 더 엄격하게 exec를 제한한 것입니다. 현재 기본 no-approval 동작 복원: @@ -332,24 +328,24 @@ flowchart TD 더 안전한 대안: - 안정적인 호스트 라우팅만 원한다면 `tools.exec.host=gateway`만 설정하세요. - - 호스트 exec는 원하지만 allowlist 누락에 대해서는 검토를 원한다면 `security=allowlist`와 `ask=on-miss`를 사용하세요. - - `host=auto`가 다시 `sandbox`로 해석되길 원한다면 샌드박스 모드를 활성화하세요. + - 호스트 exec는 사용하되 allowlist 미스는 검토하고 싶다면 `security=allowlist`와 `ask=on-miss`를 사용하세요. + - `host=auto`가 다시 `sandbox`로 해석되길 원한다면 sandbox 모드를 활성화하세요. 일반적인 로그 시그니처: - - `Approval required.` → 명령이 `/approve ...`를 기다리는 중입니다. + - `Approval required.` → 명령이 `/approve ...` 승인을 기다리고 있습니다. - `SYSTEM_RUN_DENIED: approval required` → node-host exec 승인이 대기 중입니다. - - `exec host=sandbox requires a sandbox runtime for this session` → 암시적/명시적 sandbox 선택이 있었지만 sandbox 모드가 꺼져 있습니다. + - `exec host=sandbox requires a sandbox runtime for this session` → 암시적/명시적 sandbox 선택이 되었지만 sandbox 모드가 꺼져 있습니다. - 심화 페이지: + 심층 페이지: - [/tools/exec](/ko/tools/exec) - [/tools/exec-approvals](/ko/tools/exec-approvals) - - [/gateway/security#runtime-expectation-drift](/ko/gateway/security#runtime-expectation-drift) + - [/gateway/security#what-the-audit-checks-high-level](/ko/gateway/security#what-the-audit-checks-high-level) - + ```bash openclaw status openclaw gateway status @@ -358,24 +354,24 @@ flowchart TD openclaw doctor ``` - 정상 출력 예시: + 좋은 출력 예시: - - 브라우저 상태에 `running: true`와 선택된 브라우저/프로필이 표시됨. - - `openclaw`가 시작되거나 `user`가 로컬 Chrome 탭을 볼 수 있음. + - Browser 상태에 `running: true`와 선택된 browser/profile이 표시됩니다. + - `openclaw`가 시작되거나, `user`가 로컬 Chrome 탭을 볼 수 있습니다. 일반적인 로그 시그니처: - - `unknown command "browser"` 또는 `unknown command 'browser'` → `plugins.allow`가 설정되어 있고 `browser`를 포함하지 않음. - - `Failed to start Chrome CDP on port` → 로컬 브라우저 시작 실패. - - `browser.executablePath not found` → 구성된 바이너리 경로가 잘못됨. - - `browser.cdpUrl must be http(s) or ws(s)` → 구성된 CDP URL이 지원되지 않는 스킴을 사용함. - - `browser.cdpUrl has invalid port` → 구성된 CDP URL에 잘못되었거나 범위를 벗어난 포트가 있음. - - `No Chrome tabs found for profile="user"` → Chrome MCP attach 프로필에 열린 로컬 Chrome 탭이 없음. - - `Remote CDP for profile "" is not reachable` → 구성된 원격 CDP 엔드포인트에 이 호스트에서 도달할 수 없음. - - `Browser attachOnly is enabled ... not reachable` 또는 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only 프로필에 살아 있는 CDP 대상이 없음. - - attach-only 또는 remote CDP 프로필에서 viewport / dark-mode / locale / offline 재정의가 오래 남아 있음 → `openclaw browser stop --browser-profile `을 실행해 활성 control 세션을 닫고 gateway를 재시작하지 않고 에뮬레이션 상태를 해제하세요. + - `unknown command "browser"` 또는 `unknown command 'browser'` → `plugins.allow`가 설정되어 있으며 `browser`가 포함되어 있지 않습니다. + - `Failed to start Chrome CDP on port` → 로컬 browser 실행에 실패했습니다. + - `browser.executablePath not found` → 구성된 바이너리 경로가 잘못되었습니다. + - `browser.cdpUrl must be http(s) or ws(s)` → 구성된 CDP URL이 지원되지 않는 스킴을 사용하고 있습니다. + - `browser.cdpUrl has invalid port` → 구성된 CDP URL의 포트가 잘못되었거나 범위를 벗어났습니다. + - `No Chrome tabs found for profile="user"` → Chrome MCP attach profile에 열린 로컬 Chrome 탭이 없습니다. + - `Remote CDP for profile "" is not reachable` → 구성된 원격 CDP 엔드포인트에 이 호스트에서 도달할 수 없습니다. + - `Browser attachOnly is enabled ... not reachable` 또는 `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile에 활성 CDP 대상이 없습니다. + - attach-only 또는 원격 CDP profile에서 viewport / dark-mode / locale / offline 재정의가 오래 유지되는 경우 → `openclaw browser stop --browser-profile `을 실행해 활성 제어 세션을 닫고 gateway를 재시작하지 않고도 에뮬레이션 상태를 해제하세요. - 심화 페이지: + 심층 페이지: - [/gateway/troubleshooting#browser-tool-fails](/ko/gateway/troubleshooting#browser-tool-fails) - [/tools/browser#missing-browser-command-or-tool](/ko/tools/browser#missing-browser-command-or-tool) @@ -383,9 +379,10 @@ flowchart TD - [/tools/browser-wsl2-windows-remote-cdp-troubleshooting](/ko/tools/browser-wsl2-windows-remote-cdp-troubleshooting) + -## 관련 문서 +## 관련 항목 - [FAQ](/ko/help/faq) — 자주 묻는 질문 - [Gateway Troubleshooting](/ko/gateway/troubleshooting) — gateway 관련 문제 diff --git a/docs/ko/plugins/codex-harness.md b/docs/ko/plugins/codex-harness.md new file mode 100644 index 000000000..79d58daf2 --- /dev/null +++ b/docs/ko/plugins/codex-harness.md @@ -0,0 +1,486 @@ +--- +read_when: + - 번들된 Codex app-server 하네스를 사용하려고 합니다 + - Codex 모델 참조와 구성 예시가 필요합니다 + - Codex 전용 배포를 위해 PI fallback을 비활성화하려고 합니다 +summary: 번들된 Codex app-server 하네스를 통해 OpenClaw 임베디드 에이전트 턴 실행 +title: Codex 하네스 +x-i18n: + generated_at: "2026-04-11T02:46:04Z" + model: gpt-5.4 + provider: openai + source_hash: 60e1dcf4f1a00c63c3ef31d72feac44bce255421c032c58fa4fd67295b3daf23 + source_path: plugins/codex-harness.md + workflow: 15 +--- + +# Codex 하네스 + +번들된 `codex` plugin을 사용하면 OpenClaw가 내장된 PI 하네스 대신 +Codex app-server를 통해 임베디드 에이전트 턴을 실행할 수 있습니다. + +이는 Codex가 저수준 에이전트 세션을 직접 관리하도록 하려는 경우에 사용합니다: +모델 검색, 네이티브 스레드 재개, 네이티브 compaction, app-server 실행. +OpenClaw는 여전히 채팅 채널, 세션 파일, 모델 선택, 도구, +승인, 미디어 전달, 그리고 사용자에게 보이는 transcript 미러를 관리합니다. + +이 하네스는 기본적으로 꺼져 있습니다. `codex` plugin이 활성화되어 있고 확인된 모델이 `codex/*` 모델일 때만 선택되며, 또는 `embeddedHarness.runtime: "codex"`나 `OPENCLAW_AGENT_RUNTIME=codex`를 명시적으로 강제한 경우에 선택됩니다. +`codex/*`를 전혀 구성하지 않으면 기존의 PI, OpenAI, Anthropic, Gemini, 로컬, +및 custom-provider 실행은 현재 동작을 그대로 유지합니다. + +## 올바른 모델 접두사 선택하기 + +OpenClaw는 OpenAI 접근과 Codex 형태 접근에 대해 별도의 경로를 제공합니다: + +| 모델 참조 | 런타임 경로 | 사용 시점 | +| ---------------------- | -------------------------------------------- | ----------------------------------------------------------------------- | +| `openai/gpt-5.4` | OpenClaw/PI 배선을 통한 OpenAI provider 경로 | `OPENAI_API_KEY`로 직접 OpenAI Platform API에 접근하려는 경우 | +| `openai-codex/gpt-5.4` | PI를 통한 OpenAI Codex OAuth provider 경로 | Codex app-server 하네스 없이 ChatGPT/Codex OAuth를 사용하려는 경우 | +| `codex/gpt-5.4` | 번들된 Codex provider + Codex 하네스 | 임베디드 에이전트 턴에 네이티브 Codex app-server 실행을 사용하려는 경우 | + +Codex 하네스는 `codex/*` 모델 참조만 처리합니다. 기존 `openai/*`, +`openai-codex/*`, Anthropic, Gemini, xAI, 로컬, custom provider 참조는 +기존의 일반 경로를 유지합니다. + +## 요구 사항 + +- 번들된 `codex` plugin을 사용할 수 있는 OpenClaw. +- Codex app-server `0.118.0` 이상. +- app-server 프로세스에서 사용할 수 있는 Codex 인증. + +plugin은 더 오래되었거나 버전이 없는 app-server 핸드셰이크를 차단합니다. 이를 통해 +OpenClaw가 테스트된 프로토콜 표면 위에서 동작하도록 보장합니다. + +라이브 및 Docker 스모크 테스트에서는 인증이 보통 `OPENAI_API_KEY`에서 오며, 선택적으로 +`~/.codex/auth.json` 및 `~/.codex/config.toml` 같은 Codex CLI 파일도 사용할 수 있습니다. +로컬 Codex app-server가 사용하는 것과 동일한 인증 자료를 사용하세요. + +## 최소 구성 + +`codex/gpt-5.4`를 사용하고, 번들된 plugin을 활성화하고, `codex` 하네스를 강제합니다: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + }, + }, + }, + agents: { + defaults: { + model: "codex/gpt-5.4", + embeddedHarness: { + runtime: "codex", + fallback: "none", + }, + }, + }, +} +``` + +구성에서 `plugins.allow`를 사용한다면 거기에 `codex`도 포함하세요: + +```json5 +{ + plugins: { + allow: ["codex"], + entries: { + codex: { + enabled: true, + }, + }, + }, +} +``` + +`agents.defaults.model` 또는 에이전트 모델을 `codex/`로 설정하면 +번들된 `codex` plugin도 자동으로 활성화됩니다. 명시적인 plugin 항목은 +공유 구성에서 여전히 유용한데, 배포 의도를 명확하게 드러내기 때문입니다. + +## 다른 모델을 대체하지 않고 Codex 추가하기 + +`codex/*` 모델에는 Codex를, 그 외에는 PI를 사용하려면 `runtime: "auto"`를 유지하세요: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + }, + }, + }, + agents: { + defaults: { + model: { + primary: "codex/gpt-5.4", + fallbacks: ["openai/gpt-5.4", "anthropic/claude-opus-4-6"], + }, + models: { + "codex/gpt-5.4": { alias: "codex" }, + "codex/gpt-5.4-mini": { alias: "codex-mini" }, + "openai/gpt-5.4": { alias: "gpt" }, + "anthropic/claude-opus-4-6": { alias: "opus" }, + }, + embeddedHarness: { + runtime: "auto", + fallback: "pi", + }, + }, + }, +} +``` + +이 구성에서는: + +- `/model codex` 또는 `/model codex/gpt-5.4`는 Codex app-server 하네스를 사용합니다. +- `/model gpt` 또는 `/model openai/gpt-5.4`는 OpenAI provider 경로를 사용합니다. +- `/model opus`는 Anthropic provider 경로를 사용합니다. +- Codex가 아닌 모델이 선택되면 PI가 호환성 하네스로 계속 사용됩니다. + +## Codex 전용 배포 + +모든 임베디드 에이전트 턴이 Codex 하네스를 사용한다는 것을 보장해야 한다면 +PI fallback을 비활성화하세요: + +```json5 +{ + agents: { + defaults: { + model: "codex/gpt-5.4", + embeddedHarness: { + runtime: "codex", + fallback: "none", + }, + }, + }, +} +``` + +환경 변수 override: + +```bash +OPENCLAW_AGENT_RUNTIME=codex \ +OPENCLAW_AGENT_HARNESS_FALLBACK=none \ +openclaw gateway run +``` + +fallback이 비활성화되면, `codex` plugin이 비활성화되어 있거나, +요청한 모델이 `codex/*` 참조가 아니거나, app-server가 너무 오래되었거나, +app-server를 시작할 수 없는 경우 OpenClaw는 조기에 실패합니다. + +## 에이전트별 Codex + +기본 에이전트는 일반적인 자동 선택을 유지하면서 특정 에이전트 하나만 Codex 전용으로 만들 수 있습니다: + +```json5 +{ + agents: { + defaults: { + embeddedHarness: { + runtime: "auto", + fallback: "pi", + }, + }, + list: [ + { + id: "main", + default: true, + model: "anthropic/claude-opus-4-6", + }, + { + id: "codex", + name: "Codex", + model: "codex/gpt-5.4", + embeddedHarness: { + runtime: "codex", + fallback: "none", + }, + }, + ], + }, +} +``` + +일반적인 세션 명령으로 에이전트와 모델을 전환하세요. `/new`는 새로운 +OpenClaw 세션을 만들고, Codex 하네스는 필요에 따라 자체 sidecar app-server +스레드를 생성하거나 재개합니다. `/reset`은 해당 스레드에 대한 OpenClaw 세션 바인딩을 지웁니다. + +## 모델 검색 + +기본적으로 Codex plugin은 app-server에 사용 가능한 모델을 요청합니다. 검색에 +실패하거나 시간이 초과되면 번들된 fallback 카탈로그를 사용합니다: + +- `codex/gpt-5.4` +- `codex/gpt-5.4-mini` +- `codex/gpt-5.2` + +`plugins.entries.codex.config.discovery` 아래에서 검색을 조정할 수 있습니다: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + config: { + discovery: { + enabled: true, + timeoutMs: 2500, + }, + }, + }, + }, + }, +} +``` + +시작 시 Codex 탐색을 피하고 fallback 카탈로그에만 고정하려면 검색을 비활성화하세요: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + config: { + discovery: { + enabled: false, + }, + }, + }, + }, + }, +} +``` + +## App-server 연결 및 정책 + +기본적으로 plugin은 다음과 같이 로컬에서 Codex를 시작합니다: + +```bash +codex app-server --listen stdio:// +``` + +이 기본값을 유지하면서 Codex 네이티브 정책만 조정할 수 있습니다: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + config: { + appServer: { + approvalPolicy: "on-request", + sandbox: "workspace-write", + serviceTier: "priority", + }, + }, + }, + }, + }, +} +``` + +이미 실행 중인 app-server에는 WebSocket 전송을 사용하세요: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + config: { + appServer: { + transport: "websocket", + url: "ws://127.0.0.1:39175", + authToken: "${CODEX_APP_SERVER_TOKEN}", + requestTimeoutMs: 60000, + }, + }, + }, + }, + }, +} +``` + +지원되는 `appServer` 필드: + +| 필드 | 기본값 | 의미 | +| ------------------- | ---------------------------------------- | ------------------------------------------------------------------------ | +| `transport` | `"stdio"` | `"stdio"`는 Codex를 실행하고, `"websocket"`은 `url`에 연결합니다. | +| `command` | `"codex"` | stdio 전송용 실행 파일. | +| `args` | `["app-server", "--listen", "stdio://"]` | stdio 전송용 인자. | +| `url` | unset | WebSocket app-server URL. | +| `authToken` | unset | WebSocket 전송용 Bearer 토큰. | +| `headers` | `{}` | 추가 WebSocket 헤더. | +| `requestTimeoutMs` | `60000` | app-server control-plane 호출의 타임아웃. | +| `approvalPolicy` | `"never"` | 스레드 시작/재개/턴에 전송되는 네이티브 Codex 승인 정책. | +| `sandbox` | `"workspace-write"` | 스레드 시작/재개에 전송되는 네이티브 Codex 샌드박스 모드. | +| `approvalsReviewer` | `"user"` | Codex guardian이 네이티브 승인을 검토하게 하려면 `"guardian_subagent"`를 사용합니다. | +| `serviceTier` | unset | 선택적 Codex 서비스 티어, 예: `"priority"`. | + +이전 환경 변수도 대응하는 구성 필드가 설정되지 않은 경우 +로컬 테스트용 fallback으로 계속 작동합니다: + +- `OPENCLAW_CODEX_APP_SERVER_BIN` +- `OPENCLAW_CODEX_APP_SERVER_ARGS` +- `OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY` +- `OPENCLAW_CODEX_APP_SERVER_SANDBOX` +- `OPENCLAW_CODEX_APP_SERVER_GUARDIAN=1` + +반복 가능한 배포에는 구성이 권장됩니다. + +## 일반적인 레시피 + +기본 stdio 전송을 사용하는 로컬 Codex: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + }, + }, + }, +} +``` + +PI fallback을 비활성화한 Codex 전용 하네스 검증: + +```json5 +{ + embeddedHarness: { + fallback: "none", + }, + plugins: { + entries: { + codex: { + enabled: true, + }, + }, + }, +} +``` + +guardian이 검토하는 Codex 승인: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + config: { + appServer: { + approvalPolicy: "on-request", + approvalsReviewer: "guardian_subagent", + sandbox: "workspace-write", + }, + }, + }, + }, + }, +} +``` + +명시적 헤더를 사용하는 원격 app-server: + +```json5 +{ + plugins: { + entries: { + codex: { + enabled: true, + config: { + appServer: { + transport: "websocket", + url: "ws://gateway-host:39175", + headers: { + "X-OpenClaw-Agent": "main", + }, + }, + }, + }, + }, + }, +} +``` + +모델 전환은 계속 OpenClaw가 제어합니다. OpenClaw 세션이 +기존 Codex 스레드에 연결되어 있으면, 다음 턴은 현재 선택된 +`codex/*` 모델, provider, 승인 정책, 샌드박스, 서비스 티어를 +다시 app-server로 전송합니다. `codex/gpt-5.4`에서 `codex/gpt-5.2`로 전환하면 +스레드 바인딩은 유지되지만 Codex에 새로 선택한 모델로 계속 진행하라고 요청합니다. + +## Codex 명령 + +번들된 plugin은 `/codex`를 승인된 슬래시 명령으로 등록합니다. 이는 +일반적이며 OpenClaw 텍스트 명령을 지원하는 모든 채널에서 동작합니다. + +일반적인 형식: + +- `/codex status`는 실시간 app-server 연결 상태, 모델, 계정, rate limit, MCP 서버, Skills를 표시합니다. +- `/codex models`는 실시간 Codex app-server 모델 목록을 보여줍니다. +- `/codex threads [filter]`는 최근 Codex 스레드를 나열합니다. +- `/codex resume `는 현재 OpenClaw 세션을 기존 Codex 스레드에 연결합니다. +- `/codex compact`는 Codex app-server에 연결된 스레드를 compact하라고 요청합니다. +- `/codex review`는 연결된 스레드에 대한 Codex 네이티브 review를 시작합니다. +- `/codex account`는 계정 및 rate-limit 상태를 표시합니다. +- `/codex mcp`는 Codex app-server MCP 서버 상태를 나열합니다. +- `/codex skills`는 Codex app-server Skills를 나열합니다. + +`/codex resume`는 하네스가 일반 턴에 사용하는 것과 동일한 sidecar 바인딩 파일을 기록합니다. +다음 메시지에서 OpenClaw는 해당 Codex 스레드를 재개하고, 현재 선택된 OpenClaw `codex/*` 모델을 app-server에 전달하며, 확장된 기록을 계속 활성화한 상태로 유지합니다. + +명령어 표면을 사용하려면 Codex app-server `0.118.0` 이상이 필요합니다. 향후 버전 또는 사용자 지정 app-server가 해당 JSON-RPC 메서드를 노출하지 않는 경우, 개별 +제어 메서드는 `unsupported by this Codex app-server`로 보고됩니다. + +## 도구, 미디어 및 compaction + +Codex 하네스는 저수준 임베디드 에이전트 실행기만 변경합니다. + +OpenClaw는 여전히 도구 목록을 구성하고 하네스에서 동적 도구 결과를 받습니다. +텍스트, 이미지, 비디오, 음악, TTS, 승인, 메시징 도구 출력은 +계속 일반적인 OpenClaw 전달 경로를 통해 처리됩니다. + +선택된 모델이 Codex 하네스를 사용할 때 네이티브 스레드 compaction은 +Codex app-server에 위임됩니다. OpenClaw는 채널 기록, 검색, `/new`, `/reset`, +그리고 향후 모델 또는 하네스 전환을 위해 transcript 미러를 유지합니다. 이 +미러에는 사용자 프롬프트, 최종 assistant 텍스트, 그리고 app-server가 이를 내보낼 경우 +가벼운 Codex reasoning 또는 plan 레코드가 포함됩니다. + +미디어 생성에는 PI가 필요하지 않습니다. 이미지, 비디오, 음악, PDF, TTS, 미디어 +이해는 계속 `agents.defaults.imageGenerationModel`, `videoGenerationModel`, `pdfModel`, +`messages.tts` 같은 해당 provider/model 설정을 사용합니다. + +## 문제 해결 + +**`/model`에 Codex가 나타나지 않음:** `plugins.entries.codex.enabled`를 활성화하고, +`codex/*` 모델 참조를 설정하거나, `plugins.allow`가 `codex`를 제외하고 있는지 확인하세요. + +**OpenClaw가 PI로 fallback함:** 테스트 중에는 `embeddedHarness.fallback: "none"` 또는 +`OPENCLAW_AGENT_HARNESS_FALLBACK=none`을 설정하세요. + +**app-server가 거부됨:** app-server 핸드셰이크가 버전 `0.118.0` 이상을 +보고하도록 Codex를 업그레이드하세요. + +**모델 검색이 느림:** `plugins.entries.codex.config.discovery.timeoutMs`를 낮추거나 +검색을 비활성화하세요. + +**WebSocket 전송이 즉시 실패함:** `appServer.url`, `authToken`, +그리고 원격 app-server가 동일한 Codex app-server 프로토콜 버전을 사용하는지 확인하세요. + +**Codex가 아닌 모델이 PI를 사용함:** 이는 예상된 동작입니다. Codex 하네스는 +`codex/*` 모델 참조만 처리합니다. + +## 관련 항목 + +- [Agent Harness Plugins](/ko/plugins/sdk-agent-harness) +- [Model Providers](/ko/concepts/model-providers) +- [Configuration Reference](/ko/gateway/configuration-reference) +- [Testing](/ko/help/testing#live-codex-app-server-harness-smoke) diff --git a/docs/ko/plugins/manifest.md b/docs/ko/plugins/manifest.md index 49036bf02..5ddb6e39e 100644 --- a/docs/ko/plugins/manifest.md +++ b/docs/ko/plugins/manifest.md @@ -1,62 +1,61 @@ --- read_when: - - OpenClaw plugin을 빌드하고 있습니다 - - plugin 구성 스키마를 배포하거나 plugin 검증 오류를 디버그해야 합니다 -summary: Plugin 매니페스트 + JSON Schema 요구 사항(엄격한 구성 검증) -title: Plugin 매니페스트 + - OpenClaw 플러그인을 빌드하고 있습니다 + - 플러그인 구성 스키마를 제공하거나 플러그인 검증 오류를 디버그해야 합니다 +summary: 플러그인 매니페스트 + JSON 스키마 요구 사항(엄격한 구성 검증) +title: 플러그인 매니페스트 x-i18n: - generated_at: "2026-04-09T01:29:23Z" + generated_at: "2026-04-11T02:46:11Z" model: gpt-5.4 provider: openai - source_hash: 9a7ee4b621a801d2a8f32f8976b0e1d9433c7810eb360aca466031fc0ffb286a + source_hash: 6b254c121d1eb5ea19adbd4148243cf47339c960442ab1ca0e0bfd52e0154c88 source_path: plugins/manifest.md workflow: 15 --- -# Plugin 매니페스트(openclaw.plugin.json) +# 플러그인 매니페스트 (`openclaw.plugin.json`) -이 페이지는 **네이티브 OpenClaw plugin 매니페스트** 전용입니다. +이 페이지는 **네이티브 OpenClaw 플러그인 매니페스트**만을 위한 문서입니다. -호환되는 번들 레이아웃은 [Plugin bundles](/ko/plugins/bundles)를 참조하세요. +호환 가능한 번들 레이아웃은 [플러그인 번들](/ko/plugins/bundles)을 참조하세요. -호환되는 번들 형식은 서로 다른 매니페스트 파일을 사용합니다. +호환 번들 형식은 서로 다른 매니페스트 파일을 사용합니다: - Codex 번들: `.codex-plugin/plugin.json` -- Claude 번들: `.claude-plugin/plugin.json` 또는 매니페스트가 없는 기본 Claude component - 레이아웃 +- Claude 번들: `.claude-plugin/plugin.json` 또는 매니페스트가 없는 기본 Claude 컴포넌트 레이아웃 - Cursor 번들: `.cursor-plugin/plugin.json` -OpenClaw는 이러한 번들 레이아웃도 자동 감지하지만, 여기서 설명하는 `openclaw.plugin.json` 스키마에 대해서는 검증하지 않습니다. +OpenClaw는 이러한 번들 레이아웃도 자동 감지하지만, 여기서 설명하는 `openclaw.plugin.json` 스키마에 대해 검증하지는 않습니다. -호환 번들의 경우, OpenClaw는 현재 레이아웃이 OpenClaw 런타임 기대 사항과 일치할 때 번들 메타데이터와 선언된 skill 루트, Claude command 루트, Claude 번들 `settings.json` 기본값, Claude 번들 LSP 기본값, 지원되는 hook pack을 읽습니다. +호환 번들의 경우, OpenClaw는 현재 레이아웃이 OpenClaw 런타임 기대치와 일치할 때 번들 메타데이터, 선언된 Skills 루트, Claude 명령 루트, Claude 번들 `settings.json` 기본값, Claude 번들 LSP 기본값, 지원되는 훅 팩을 읽습니다. -모든 네이티브 OpenClaw plugin은 **plugin 루트**에 `openclaw.plugin.json` 파일을 **반드시** 포함해야 합니다. OpenClaw는 이 매니페스트를 사용해 **plugin 코드를 실행하지 않고도** 구성을 검증합니다. 매니페스트가 없거나 유효하지 않으면 plugin 오류로 처리되며 구성 검증이 차단됩니다. +모든 네이티브 OpenClaw 플러그인은 반드시 **플러그인 루트**에 `openclaw.plugin.json` 파일을 포함해야 합니다. OpenClaw는 이 매니페스트를 사용해 **플러그인 코드를 실행하지 않고도** 구성을 검증합니다. 매니페스트가 없거나 유효하지 않으면 플러그인 오류로 처리되며 구성 검증이 차단됩니다. -전체 plugin 시스템 가이드는 [Plugins](/ko/tools/plugin)를 참조하세요. +전체 플러그인 시스템 가이드는 [플러그인](/ko/tools/plugin)을 참조하세요. 네이티브 capability 모델과 현재 외부 호환성 지침은 [Capability model](/ko/plugins/architecture#public-capability-model)을 참조하세요. ## 이 파일의 역할 -`openclaw.plugin.json`은 OpenClaw가 plugin 코드를 로드하기 전에 읽는 메타데이터입니다. +`openclaw.plugin.json`은 OpenClaw가 플러그인 코드를 로드하기 전에 읽는 메타데이터입니다. -다음 용도로 사용하세요. +용도: -- plugin 식별자 +- 플러그인 식별자 - 구성 검증 -- plugin 런타임을 부팅하지 않고도 사용할 수 있어야 하는 auth 및 onboarding 메타데이터 -- plugin 런타임 로드 전에 해석되어야 하는 별칭 및 자동 활성화 메타데이터 -- 런타임 로드 전에 plugin을 자동 활성화해야 하는 shorthand model-family 소유 메타데이터 -- 번들 compat wiring 및 계약 커버리지에 사용되는 정적 capability 소유 스냅샷 -- 런타임을 로드하지 않고 catalog 및 검증 표면에 병합되어야 하는 채널별 구성 메타데이터 -- config UI 힌트 +- 플러그인 런타임을 부팅하지 않고도 사용할 수 있어야 하는 인증 및 온보딩 메타데이터 +- 플러그인 런타임이 로드되기 전에 해석되어야 하는 별칭 및 자동 활성화 메타데이터 +- 플러그인 런타임이 로드되기 전에 플러그인을 자동 활성화해야 하는 축약 모델 계열 소유 메타데이터 +- 번들 호환 배선 및 계약 커버리지에 사용되는 정적 capability 소유 스냅샷 +- 런타임을 로드하지 않고도 카탈로그 및 검증 표면에 병합되어야 하는 채널별 구성 메타데이터 +- 구성 UI 힌트 -다음 용도로는 사용하지 마세요. +다음 용도로는 사용하지 마세요: - 런타임 동작 등록 -- 코드 entrypoint 선언 +- 코드 엔트리포인트 선언 - npm 설치 메타데이터 -이들은 plugin 코드와 `package.json`에 속합니다. +이들은 플러그인 코드와 `package.json`에 속합니다. ## 최소 예제 @@ -71,13 +70,13 @@ OpenClaw는 이러한 번들 레이아웃도 자동 감지하지만, 여기서 } ``` -## 자세한 예제 +## 확장 예제 ```json { "id": "openrouter", "name": "OpenRouter", - "description": "OpenRouter provider plugin", + "description": "OpenRouter 제공자 플러그인", "version": "1.0.0", "providers": ["openrouter"], "modelSupport": { @@ -98,19 +97,19 @@ OpenClaw는 이러한 번들 레이아웃도 자동 감지하지만, 여기서 "provider": "openrouter", "method": "api-key", "choiceId": "openrouter-api-key", - "choiceLabel": "OpenRouter API key", + "choiceLabel": "OpenRouter API 키", "groupId": "openrouter", "groupLabel": "OpenRouter", "optionKey": "openrouterApiKey", "cliFlag": "--openrouter-api-key", "cliOption": "--openrouter-api-key ", - "cliDescription": "OpenRouter API key", + "cliDescription": "OpenRouter API 키", "onboardingScopes": ["text-inference"] } ], "uiHints": { "apiKey": { - "label": "API key", + "label": "API 키", "placeholder": "sk-or-v1-...", "sensitive": true } @@ -129,53 +128,76 @@ OpenClaw는 이러한 번들 레이아웃도 자동 감지하지만, 여기서 ## 최상위 필드 참조 -| Field | Required | Type | 의미 | -| ----------------------------------- | -------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `id` | Yes | `string` | 정식 plugin id입니다. 이 id는 `plugins.entries.`에서 사용됩니다. | -| `configSchema` | Yes | `object` | 이 plugin 구성에 대한 인라인 JSON Schema입니다. | -| `enabledByDefault` | No | `true` | 번들 plugin을 기본적으로 활성화된 것으로 표시합니다. 기본적으로 비활성화 상태로 두려면 생략하거나 `true`가 아닌 값을 설정하세요. | -| `legacyPluginIds` | No | `string[]` | 이 정식 plugin id로 정규화되는 레거시 id입니다. | -| `autoEnableWhenConfiguredProviders` | No | `string[]` | auth, config 또는 model ref에서 해당 provider id를 언급할 때 이 plugin을 자동 활성화해야 하는 provider id입니다. | -| `kind` | No | `"memory"` \| `"context-engine"` | `plugins.slots.*`에서 사용하는 배타적 plugin kind를 선언합니다. | -| `channels` | No | `string[]` | 이 plugin이 소유한 channel id입니다. 검색 및 구성 검증에 사용됩니다. | -| `providers` | No | `string[]` | 이 plugin이 소유한 provider id입니다. | -| `modelSupport` | No | `object` | 런타임 전에 plugin을 자동 로드하는 데 사용되는 매니페스트 소유 shorthand model-family 메타데이터입니다. | -| `cliBackends` | No | `string[]` | 이 plugin이 소유한 CLI inference backend id입니다. 명시적 config ref를 기준으로 시작 시 자동 활성화하는 데 사용됩니다. | -| `providerAuthEnvVars` | No | `Record` | OpenClaw가 plugin 코드를 로드하지 않고도 검사할 수 있는 저비용 provider-auth env 메타데이터입니다. | -| `providerAuthAliases` | No | `Record` | auth 조회를 위해 다른 provider id를 재사용해야 하는 provider id입니다. 예를 들어 기본 provider API 키와 auth 프로필을 공유하는 코딩 provider가 해당됩니다. | -| `channelEnvVars` | No | `Record` | OpenClaw가 plugin 코드를 로드하지 않고도 검사할 수 있는 저비용 channel env 메타데이터입니다. env 기반 channel 설정 또는 범용 startup/config helper가 확인해야 하는 auth 표면에 사용하세요. | -| `providerAuthChoices` | No | `object[]` | onboarding 선택기, 선호 provider 결정, 간단한 CLI 플래그 wiring을 위한 저비용 auth-choice 메타데이터입니다. | -| `contracts` | No | `object` | speech, realtime transcription, realtime voice, media-understanding, image-generation, music-generation, video-generation, web-fetch, web search 및 tool 소유권에 대한 정적 번들 capability 스냅샷입니다. | -| `channelConfigs` | No | `Record` | 런타임이 로드되기 전에 검색 및 검증 표면에 병합되는 매니페스트 소유 channel config 메타데이터입니다. | -| `skills` | No | `string[]` | plugin 루트를 기준으로 로드할 skill 디렉터리입니다. | -| `name` | No | `string` | 사람이 읽을 수 있는 plugin 이름입니다. | -| `description` | No | `string` | plugin 표면에 표시되는 짧은 요약입니다. | -| `version` | No | `string` | 정보 제공용 plugin 버전입니다. | -| `uiHints` | No | `Record` | 구성 필드에 대한 UI 레이블, placeholder, 민감도 힌트입니다. | +| 필드 | 필수 여부 | 유형 | 의미 | +| ----------------------------------- | --------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `id` | 예 | `string` | 정식 플러그인 ID입니다. 이 ID는 `plugins.entries.`에서 사용됩니다. | +| `configSchema` | 예 | `object` | 이 플러그인 구성에 대한 인라인 JSON 스키마입니다. | +| `enabledByDefault` | 아니요 | `true` | 번들 플러그인을 기본적으로 활성화된 상태로 표시합니다. 기본적으로 비활성화된 상태로 두려면 이 필드를 생략하거나 `true`가 아닌 값을 설정하세요. | +| `legacyPluginIds` | 아니요 | `string[]` | 이 정식 플러그인 ID로 정규화되는 레거시 ID입니다. | +| `autoEnableWhenConfiguredProviders` | 아니요 | `string[]` | 인증, 구성 또는 모델 참조에서 언급될 때 이 플러그인을 자동 활성화해야 하는 제공자 ID입니다. | +| `kind` | 아니요 | `"memory"` \| `"context-engine"` | `plugins.slots.*`에서 사용되는 배타적 플러그인 종류를 선언합니다. | +| `channels` | 아니요 | `string[]` | 이 플러그인이 소유하는 채널 ID입니다. 검색 및 구성 검증에 사용됩니다. | +| `providers` | 아니요 | `string[]` | 이 플러그인이 소유하는 제공자 ID입니다. | +| `modelSupport` | 아니요 | `object` | 런타임 전에 플러그인을 자동 로드하는 데 사용되는 매니페스트 소유 축약 모델 계열 메타데이터입니다. | +| `cliBackends` | 아니요 | `string[]` | 이 플러그인이 소유하는 CLI 추론 백엔드 ID입니다. 명시적 구성 참조로부터 시작 시 자동 활성화하는 데 사용됩니다. | +| `commandAliases` | 아니요 | `object[]` | 런타임이 로드되기 전에 플러그인 인식 구성 및 CLI 진단을 생성해야 하는, 이 플러그인이 소유하는 명령 이름입니다. | +| `providerAuthEnvVars` | 아니요 | `Record` | OpenClaw가 플러그인 코드를 로드하지 않고도 검사할 수 있는 저비용 제공자 인증 환경 변수 메타데이터입니다. | +| `providerAuthAliases` | 아니요 | `Record` | 예를 들어 기본 제공자 API 키와 인증 프로필을 공유하는 코딩 제공자처럼, 인증 조회 시 다른 제공자 ID를 재사용해야 하는 제공자 ID입니다. | +| `channelEnvVars` | 아니요 | `Record` | OpenClaw가 플러그인 코드를 로드하지 않고도 검사할 수 있는 저비용 채널 환경 변수 메타데이터입니다. 일반 시작/구성 도우미가 인식해야 하는 환경 변수 기반 채널 설정 또는 인증 표면에 사용하세요. | +| `providerAuthChoices` | 아니요 | `object[]` | 온보딩 선택기, 선호 제공자 해석, 간단한 CLI 플래그 배선을 위한 저비용 인증 선택 메타데이터입니다. | +| `contracts` | 아니요 | `object` | 음성, 실시간 전사, 실시간 음성, media-understanding, 이미지 생성, 음악 생성, 비디오 생성, 웹 가져오기, 웹 검색, 도구 소유권에 대한 정적 번들 capability 스냅샷입니다. | +| `channelConfigs` | 아니요 | `Record` | 런타임이 로드되기 전에 검색 및 검증 표면에 병합되는 매니페스트 소유 채널 구성 메타데이터입니다. | +| `skills` | 아니요 | `string[]` | 플러그인 루트를 기준으로 한 로드할 Skills 디렉터리입니다. | +| `name` | 아니요 | `string` | 사람이 읽을 수 있는 플러그인 이름입니다. | +| `description` | 아니요 | `string` | 플러그인 표면에 표시되는 짧은 요약입니다. | +| `version` | 아니요 | `string` | 정보 제공용 플러그인 버전입니다. | +| `uiHints` | 아니요 | `Record` | 구성 필드에 대한 UI 라벨, 플레이스홀더, 민감도 힌트입니다. | ## providerAuthChoices 참조 -각 `providerAuthChoices` 항목은 하나의 onboarding 또는 auth 선택지를 설명합니다. -OpenClaw는 provider 런타임이 로드되기 전에 이를 읽습니다. +각 `providerAuthChoices` 항목은 하나의 온보딩 또는 인증 선택을 설명합니다. +OpenClaw는 제공자 런타임이 로드되기 전에 이를 읽습니다. -| Field | Required | Type | 의미 | -| --------------------- | -------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------ | -| `provider` | Yes | `string` | 이 선택지가 속한 provider id입니다. | -| `method` | Yes | `string` | 전달할 auth method id입니다. | -| `choiceId` | Yes | `string` | onboarding 및 CLI 흐름에서 사용하는 안정적인 auth-choice id입니다. | -| `choiceLabel` | No | `string` | 사용자용 레이블입니다. 생략하면 OpenClaw는 `choiceId`로 폴백합니다. | -| `choiceHint` | No | `string` | 선택기에 표시할 짧은 도움말 텍스트입니다. | -| `assistantPriority` | No | `number` | assistant 기반 대화형 선택기에서 더 낮은 값이 먼저 정렬됩니다. | -| `assistantVisibility` | No | `"visible"` \| `"manual-only"` | assistant 선택기에서는 숨기되 수동 CLI 선택은 계속 허용합니다. | -| `deprecatedChoiceIds` | No | `string[]` | 사용자를 이 대체 선택지로 리디렉션해야 하는 레거시 choice id입니다. | -| `groupId` | No | `string` | 관련 선택지를 그룹화하기 위한 선택적 group id입니다. | -| `groupLabel` | No | `string` | 해당 그룹의 사용자용 레이블입니다. | -| `groupHint` | No | `string` | 그룹에 대한 짧은 도움말 텍스트입니다. | -| `optionKey` | No | `string` | 간단한 단일 플래그 auth 흐름을 위한 내부 option key입니다. | -| `cliFlag` | No | `string` | `--openrouter-api-key` 같은 CLI 플래그 이름입니다. | -| `cliOption` | No | `string` | `--openrouter-api-key ` 같은 전체 CLI option 형태입니다. | -| `cliDescription` | No | `string` | CLI help에 사용되는 설명입니다. | -| `onboardingScopes` | No | `Array<"text-inference" \| "image-generation">` | 이 선택지를 어떤 onboarding 표면에 표시할지 지정합니다. 생략하면 기본값은 `["text-inference"]`입니다. | +| 필드 | 필수 여부 | 유형 | 의미 | +| --------------------- | --------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `provider` | 예 | `string` | 이 선택이 속한 제공자 ID입니다. | +| `method` | 예 | `string` | 디스패치할 인증 메서드 ID입니다. | +| `choiceId` | 예 | `string` | 온보딩 및 CLI 흐름에서 사용되는 안정적인 인증 선택 ID입니다. | +| `choiceLabel` | 아니요 | `string` | 사용자에게 표시되는 라벨입니다. 생략하면 OpenClaw는 `choiceId`로 대체합니다. | +| `choiceHint` | 아니요 | `string` | 선택기에 표시되는 짧은 도움말 텍스트입니다. | +| `assistantPriority` | 아니요 | `number` | assistant 기반 대화형 선택기에서 값이 낮을수록 먼저 정렬됩니다. | +| `assistantVisibility` | 아니요 | `"visible"` \| `"manual-only"` | assistant 선택기에서는 숨기지만 수동 CLI 선택은 계속 허용합니다. | +| `deprecatedChoiceIds` | 아니요 | `string[]` | 사용자를 이 대체 선택으로 리디렉션해야 하는 레거시 선택 ID입니다. | +| `groupId` | 아니요 | `string` | 관련 선택을 묶기 위한 선택적 그룹 ID입니다. | +| `groupLabel` | 아니요 | `string` | 해당 그룹에 대한 사용자 표시 라벨입니다. | +| `groupHint` | 아니요 | `string` | 그룹에 대한 짧은 도움말 텍스트입니다. | +| `optionKey` | 아니요 | `string` | 단일 플래그 인증 흐름을 위한 내부 옵션 키입니다. | +| `cliFlag` | 아니요 | `string` | `--openrouter-api-key` 같은 CLI 플래그 이름입니다. | +| `cliOption` | 아니요 | `string` | `--openrouter-api-key ` 같은 전체 CLI 옵션 형식입니다. | +| `cliDescription` | 아니요 | `string` | CLI 도움말에 사용되는 설명입니다. | +| `onboardingScopes` | 아니요 | `Array<"text-inference" \| "image-generation">` | 이 선택이 표시되어야 하는 온보딩 표면입니다. 생략하면 기본값은 `["text-inference"]`입니다. | + +## commandAliases 참조 + +사용자가 실수로 플러그인 런타임 명령 이름을 `plugins.allow`에 넣거나 루트 CLI 명령으로 실행하려고 할 수 있을 때, 해당 명령을 플러그인이 소유한다면 `commandAliases`를 사용하세요. OpenClaw는 플러그인 런타임 코드를 가져오지 않고도 진단을 위해 이 메타데이터를 사용합니다. + +```json +{ + "commandAliases": [ + { + "name": "dreaming", + "kind": "runtime-slash", + "cliCommand": "memory" + } + ] +} +``` + +| 필드 | 필수 여부 | 유형 | 의미 | +| ------------ | --------- | ----------------- | ------------------------------------------------------------------------------- | +| `name` | 예 | `string` | 이 플러그인에 속한 명령 이름입니다. | +| `kind` | 아니요 | `"runtime-slash"` | 이 별칭을 루트 CLI 명령이 아닌 채팅 슬래시 명령으로 표시합니다. | +| `cliCommand` | 아니요 | `string` | 존재하는 경우 CLI 작업에 대해 제안할 관련 루트 CLI 명령입니다. | ## uiHints 참조 @@ -185,7 +207,7 @@ OpenClaw는 provider 런타임이 로드되기 전에 이를 읽습니다. { "uiHints": { "apiKey": { - "label": "API key", + "label": "API 키", "help": "OpenRouter 요청에 사용됨", "placeholder": "sk-or-v1-...", "sensitive": true @@ -194,20 +216,20 @@ OpenClaw는 provider 런타임이 로드되기 전에 이를 읽습니다. } ``` -각 필드 힌트는 다음을 포함할 수 있습니다. +각 필드 힌트에는 다음이 포함될 수 있습니다: -| Field | Type | 의미 | -| ------------- | ---------- | ------------------------------------- | -| `label` | `string` | 사용자용 필드 레이블입니다. | -| `help` | `string` | 짧은 도움말 텍스트입니다. | -| `tags` | `string[]` | 선택적 UI 태그입니다. | -| `advanced` | `boolean` | 이 필드를 고급 항목으로 표시합니다. | -| `sensitive` | `boolean` | 이 필드를 비밀 또는 민감 정보로 표시합니다. | -| `placeholder` | `string` | 양식 입력의 placeholder 텍스트입니다. | +| 필드 | 유형 | 의미 | +| ------------- | ---------- | --------------------------------------- | +| `label` | `string` | 사용자에게 표시되는 필드 라벨입니다. | +| `help` | `string` | 짧은 도움말 텍스트입니다. | +| `tags` | `string[]` | 선택적 UI 태그입니다. | +| `advanced` | `boolean` | 필드를 고급 항목으로 표시합니다. | +| `sensitive` | `boolean` | 필드를 비밀 또는 민감 정보로 표시합니다. | +| `placeholder` | `string` | 입력 폼용 플레이스홀더 텍스트입니다. | ## contracts 참조 -`contracts`는 OpenClaw가 plugin 런타임을 import하지 않고도 읽을 수 있는 정적 capability 소유 메타데이터에만 사용하세요. +`contracts`는 OpenClaw가 플러그인 런타임을 가져오지 않고도 읽을 수 있는 정적 capability 소유 메타데이터에만 사용하세요. ```json { @@ -225,23 +247,23 @@ OpenClaw는 provider 런타임이 로드되기 전에 이를 읽습니다. } ``` -각 목록은 선택 사항입니다. +각 목록은 선택 사항입니다: -| Field | Type | 의미 | -| -------------------------------- | ---------- | ----------------------------------------------------------- | -| `speechProviders` | `string[]` | 이 plugin이 소유한 speech provider id입니다. | -| `realtimeTranscriptionProviders` | `string[]` | 이 plugin이 소유한 realtime-transcription provider id입니다. | -| `realtimeVoiceProviders` | `string[]` | 이 plugin이 소유한 realtime-voice provider id입니다. | -| `mediaUnderstandingProviders` | `string[]` | 이 plugin이 소유한 media-understanding provider id입니다. | -| `imageGenerationProviders` | `string[]` | 이 plugin이 소유한 image-generation provider id입니다. | -| `videoGenerationProviders` | `string[]` | 이 plugin이 소유한 video-generation provider id입니다. | -| `webFetchProviders` | `string[]` | 이 plugin이 소유한 web-fetch provider id입니다. | -| `webSearchProviders` | `string[]` | 이 plugin이 소유한 web-search provider id입니다. | -| `tools` | `string[]` | 번들 계약 검사에 사용하는 이 plugin 소유의 agent tool 이름입니다. | +| 필드 | 유형 | 의미 | +| -------------------------------- | ---------- | -------------------------------------------------------- | +| `speechProviders` | `string[]` | 이 플러그인이 소유하는 음성 제공자 ID입니다. | +| `realtimeTranscriptionProviders` | `string[]` | 이 플러그인이 소유하는 실시간 전사 제공자 ID입니다. | +| `realtimeVoiceProviders` | `string[]` | 이 플러그인이 소유하는 실시간 음성 제공자 ID입니다. | +| `mediaUnderstandingProviders` | `string[]` | 이 플러그인이 소유하는 media-understanding 제공자 ID입니다. | +| `imageGenerationProviders` | `string[]` | 이 플러그인이 소유하는 이미지 생성 제공자 ID입니다. | +| `videoGenerationProviders` | `string[]` | 이 플러그인이 소유하는 비디오 생성 제공자 ID입니다. | +| `webFetchProviders` | `string[]` | 이 플러그인이 소유하는 웹 가져오기 제공자 ID입니다. | +| `webSearchProviders` | `string[]` | 이 플러그인이 소유하는 웹 검색 제공자 ID입니다. | +| `tools` | `string[]` | 번들 계약 검사를 위해 이 플러그인이 소유하는 에이전트 도구 이름입니다. | ## channelConfigs 참조 -channel plugin이 런타임 로드 전에 저비용 config 메타데이터를 필요로 하는 경우 `channelConfigs`를 사용하세요. +채널 플러그인이 런타임이 로드되기 전에 저비용 구성 메타데이터가 필요할 때 `channelConfigs`를 사용하세요. ```json { @@ -261,26 +283,26 @@ channel plugin이 런타임 로드 전에 저비용 config 메타데이터를 } }, "label": "Matrix", - "description": "Matrix homeserver 연결", + "description": "Matrix 홈서버 연결", "preferOver": ["matrix-legacy"] } } } ``` -각 channel 항목은 다음을 포함할 수 있습니다. +각 채널 항목에는 다음이 포함될 수 있습니다: -| Field | Type | 의미 | -| ------------- | ------------------------ | -------------------------------------------------------------------------------------- | -| `schema` | `object` | `channels.`용 JSON Schema입니다. 선언된 각 channel config 항목에 필수입니다. | -| `uiHints` | `Record` | 해당 channel config 섹션에 대한 선택적 UI 레이블/placeholder/민감도 힌트입니다. | -| `label` | `string` | 런타임 메타데이터가 준비되지 않았을 때 선택기 및 검사 표면에 병합되는 channel 레이블입니다. | -| `description` | `string` | 검사 및 catalog 표면용 짧은 channel 설명입니다. | -| `preferOver` | `string[]` | 선택 표면에서 이 channel이 우선해야 하는 레거시 또는 낮은 우선순위 plugin id입니다. | +| 필드 | 유형 | 의미 | +| ------------- | ------------------------ | ---------------------------------------------------------------------------------------- | +| `schema` | `object` | `channels.`에 대한 JSON 스키마입니다. 선언된 각 채널 구성 항목에 필수입니다. | +| `uiHints` | `Record` | 해당 채널 구성 섹션에 대한 선택적 UI 라벨/플레이스홀더/민감도 힌트입니다. | +| `label` | `string` | 런타임 메타데이터가 준비되지 않았을 때 선택기 및 검사 표면에 병합되는 채널 라벨입니다. | +| `description` | `string` | 검사 및 카탈로그 표면을 위한 짧은 채널 설명입니다. | +| `preferOver` | `string[]` | 선택 표면에서 이 채널이 우선해야 하는 레거시 또는 낮은 우선순위 플러그인 ID입니다. | ## modelSupport 참조 -plugin 런타임이 로드되기 전에 OpenClaw가 `gpt-5.4` 또는 `claude-sonnet-4.6` 같은 shorthand model id로부터 provider plugin을 추론해야 한다면 `modelSupport`를 사용하세요. +플러그인 런타임이 로드되기 전에 OpenClaw가 `gpt-5.4` 또는 `claude-sonnet-4.6` 같은 축약 모델 ID로부터 제공자 플러그인을 추론해야 할 때 `modelSupport`를 사용하세요. ```json { @@ -291,60 +313,60 @@ plugin 런타임이 로드되기 전에 OpenClaw가 `gpt-5.4` 또는 `claude-son } ``` -OpenClaw는 다음 우선순위를 적용합니다. +OpenClaw는 다음 우선순위를 적용합니다: -- 명시적인 `provider/model` ref는 소유 `providers` 매니페스트 메타데이터를 사용합니다 +- 명시적인 `provider/model` 참조는 소유 `providers` 매니페스트 메타데이터를 사용합니다 - `modelPatterns`가 `modelPrefixes`보다 우선합니다 -- 비번들 plugin 하나와 번들 plugin 하나가 모두 일치하면 비번들 plugin이 우선합니다 -- 그 외의 모호성은 사용자 또는 config가 provider를 지정할 때까지 무시됩니다 +- 번들되지 않은 플러그인과 번들 플러그인이 둘 다 일치하면 번들되지 않은 플러그인이 우선합니다 +- 남은 모호성은 사용자나 구성에서 제공자를 지정할 때까지 무시됩니다 필드: -| Field | Type | 의미 | +| 필드 | 유형 | 의미 | | --------------- | ---------- | -------------------------------------------------------------------- | -| `modelPrefixes` | `string[]` | shorthand model id에 대해 `startsWith`로 일치시키는 접두사입니다. | -| `modelPatterns` | `string[]` | 프로필 접미사를 제거한 뒤 shorthand model id에 대해 일치시키는 정규식 소스입니다. | +| `modelPrefixes` | `string[]` | 축약 모델 ID에 대해 `startsWith`로 일치시키는 접두사입니다. | +| `modelPatterns` | `string[]` | 프로필 접미사를 제거한 뒤 축약 모델 ID에 대해 일치시키는 정규식 소스입니다. | 레거시 최상위 capability 키는 더 이상 권장되지 않습니다. `openclaw doctor --fix`를 사용해 `speechProviders`, `realtimeTranscriptionProviders`, `realtimeVoiceProviders`, `mediaUnderstandingProviders`, `imageGenerationProviders`, `videoGenerationProviders`, `webFetchProviders`, `webSearchProviders`를 `contracts` 아래로 이동하세요. 일반 매니페스트 로딩은 더 이상 이러한 최상위 필드를 capability 소유권으로 취급하지 않습니다. -## 매니페스트와 package.json의 차이 +## 매니페스트와 package.json 비교 -두 파일은 서로 다른 역할을 합니다. +두 파일은 서로 다른 역할을 합니다: -| File | 용도 | -| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| `openclaw.plugin.json` | plugin 코드가 실행되기 전에 반드시 존재해야 하는 검색, 구성 검증, auth-choice 메타데이터, UI 힌트 | -| `package.json` | npm 메타데이터, 의존성 설치, 그리고 entrypoint, 설치 게이팅, 설정, catalog 메타데이터에 사용되는 `openclaw` 블록 | +| 파일 | 용도 | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `openclaw.plugin.json` | 검색, 구성 검증, 인증 선택 메타데이터, 플러그인 코드가 실행되기 전에 반드시 존재해야 하는 UI 힌트 | +| `package.json` | npm 메타데이터, 의존성 설치, 엔트리포인트, 설치 게이팅, 설정, 카탈로그 메타데이터에 사용되는 `openclaw` 블록 | -어떤 메타데이터를 어디에 둘지 확신이 없다면 이 규칙을 사용하세요. +어떤 메타데이터를 어디에 넣어야 할지 확신이 없다면 다음 규칙을 사용하세요: -- OpenClaw가 plugin 코드를 로드하기 전에 알아야 한다면 `openclaw.plugin.json`에 넣으세요 -- 패키징, entry 파일, 또는 npm 설치 동작과 관련 있다면 `package.json`에 넣으세요 +- OpenClaw가 플러그인 코드를 로드하기 전에 알아야 하면 `openclaw.plugin.json`에 넣습니다 +- 패키징, 엔트리 파일, npm 설치 동작과 관련된 내용이면 `package.json`에 넣습니다 ### 검색에 영향을 주는 package.json 필드 -일부 사전 런타임 plugin 메타데이터는 의도적으로 `openclaw.plugin.json`이 아니라 `package.json`의 `openclaw` 블록에 있습니다. +일부 사전 런타임 플러그인 메타데이터는 의도적으로 `openclaw.plugin.json`이 아니라 `package.json`의 `openclaw` 블록에 들어 있습니다. -중요한 예: +중요한 예시: -| Field | 의미 | -| ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| `openclaw.extensions` | 네이티브 plugin entrypoint를 선언합니다. | -| `openclaw.setupEntry` | onboarding 및 지연된 channel 시작 중에 사용되는 경량 setup 전용 entrypoint입니다. | -| `openclaw.channel` | 레이블, 문서 경로, 별칭, 선택용 문구 같은 저비용 channel catalog 메타데이터입니다. | -| `openclaw.channel.configuredState` | 전체 channel 런타임을 로드하지 않고도 "env만으로 된 설정이 이미 존재하는가?"에 답할 수 있는 경량 configured-state 검사기 메타데이터입니다. | -| `openclaw.channel.persistedAuthState` | 전체 channel 런타임을 로드하지 않고도 "이미 로그인된 항목이 있는가?"에 답할 수 있는 경량 persisted-auth 검사기 메타데이터입니다. | -| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 번들 및 외부 게시 plugin용 설치/업데이트 힌트입니다. | -| `openclaw.install.defaultChoice` | 여러 설치 소스를 사용할 수 있을 때 선호되는 설치 경로입니다. | -| `openclaw.install.minHostVersion` | `>=2026.3.22` 같은 semver 하한을 사용하는 최소 지원 OpenClaw 호스트 버전입니다. | -| `openclaw.install.allowInvalidConfigRecovery` | 구성이 유효하지 않을 때 제한된 번들 plugin 재설치 복구 경로를 허용합니다. | -| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 시작 중 전체 channel plugin보다 setup 전용 channel 표면을 먼저 로드할 수 있게 합니다. | +| 필드 | 의미 | +| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `openclaw.extensions` | 네이티브 플러그인 엔트리포인트를 선언합니다. | +| `openclaw.setupEntry` | 온보딩 및 지연 채널 시작 중에 사용되는 경량 setup 전용 엔트리포인트입니다. | +| `openclaw.channel` | 라벨, 문서 경로, 별칭, 선택 문구 같은 저비용 채널 카탈로그 메타데이터입니다. | +| `openclaw.channel.configuredState` | 전체 채널 런타임을 로드하지 않고도 "환경 변수만으로 된 설정이 이미 존재하는가?"에 답할 수 있는 경량 configured-state 검사기 메타데이터입니다. | +| `openclaw.channel.persistedAuthState` | 전체 채널 런타임을 로드하지 않고도 "이미 로그인된 항목이 있는가?"에 답할 수 있는 경량 persisted-auth 검사기 메타데이터입니다. | +| `openclaw.install.npmSpec` / `openclaw.install.localPath` | 번들 및 외부 게시 플러그인을 위한 설치/업데이트 힌트입니다. | +| `openclaw.install.defaultChoice` | 여러 설치 소스를 사용할 수 있을 때 선호되는 설치 경로입니다. | +| `openclaw.install.minHostVersion` | `>=2026.3.22` 같은 semver 하한을 사용하는 최소 지원 OpenClaw 호스트 버전입니다. | +| `openclaw.install.allowInvalidConfigRecovery` | 구성이 유효하지 않을 때 제한된 번들 플러그인 재설치 복구 경로를 허용합니다. | +| `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen` | 시작 중 전체 채널 플러그인보다 먼저 setup 전용 채널 표면을 로드할 수 있게 합니다. | -`openclaw.install.minHostVersion`은 설치 중과 매니페스트 레지스트리 로딩 중에 적용됩니다. 유효하지 않은 값은 거부되며, 유효하지만 더 새로운 값은 오래된 호스트에서 plugin을 건너뜁니다. +`openclaw.install.minHostVersion`은 설치 중과 매니페스트 레지스트리 로딩 중에 강제됩니다. 유효하지 않은 값은 거부되고, 더 새롭지만 유효한 값은 오래된 호스트에서 해당 플러그인을 건너뜁니다. -`openclaw.install.allowInvalidConfigRecovery`는 의도적으로 범위가 좁습니다. 임의의 깨진 구성을 설치 가능하게 만들지는 않습니다. 현재는 누락된 번들 plugin 경로 또는 동일 번들 plugin에 대한 오래된 `channels.` 항목 같은 특정한 낡은 번들 plugin 업그레이드 실패에서만 설치 흐름이 복구되도록 허용합니다. 관련 없는 구성 오류는 여전히 설치를 차단하고 운영자를 `openclaw doctor --fix`로 안내합니다. +`openclaw.install.allowInvalidConfigRecovery`는 의도적으로 범위가 좁습니다. 임의의 손상된 구성을 설치 가능하게 만들지는 않습니다. 현재는 번들 플러그인 경로 누락이나 동일한 번들 플러그인에 대한 오래된 `channels.` 항목처럼 특정한 오래된 번들 플러그인 업그레이드 실패에서만 설치 흐름이 복구되도록 허용합니다. 관련 없는 구성 오류는 여전히 설치를 차단하며 운영자를 `openclaw doctor --fix`로 안내합니다. -`openclaw.channel.persistedAuthState`는 작은 검사기 모듈을 위한 package 메타데이터입니다. +`openclaw.channel.persistedAuthState`는 작은 검사기 모듈을 위한 패키지 메타데이터입니다: ```json { @@ -360,9 +382,9 @@ OpenClaw는 다음 우선순위를 적용합니다. } ``` -설정, doctor 또는 configured-state 흐름이 전체 channel plugin이 로드되기 전에 저비용 예/아니오 auth 프로브를 필요로 할 때 사용하세요. 대상 export는 저장된 상태만 읽는 작은 함수여야 하며, 전체 channel 런타임 barrel을 통해 연결해서는 안 됩니다. +설정, doctor 또는 configured-state 흐름이 전체 채널 플러그인이 로드되기 전에 저비용 예/아니오 인증 프로브를 필요로 할 때 사용하세요. 대상 export는 저장된 상태만 읽는 작은 함수여야 하며, 전체 채널 런타임 배럴을 통해 연결하지 마세요. -`openclaw.channel.configuredState`는 저비용 env 전용 configured 검사를 위해 같은 형태를 따릅니다. +`openclaw.channel.configuredState`도 저비용 환경 변수 전용 구성 검사에 대해 같은 형식을 따릅니다: ```json { @@ -378,43 +400,42 @@ OpenClaw는 다음 우선순위를 적용합니다. } ``` -channel이 env 또는 기타 작은 비런타임 입력만으로 configured-state에 답할 수 있을 때 사용하세요. 검사가 전체 config 해석이나 실제 channel 런타임을 필요로 한다면, 대신 그 로직을 plugin `config.hasConfiguredState` hook에 두세요. +채널이 환경 변수나 기타 작은 비런타임 입력만으로 configured-state에 답할 수 있을 때 사용하세요. 검사가 전체 구성 해석이나 실제 채널 런타임을 필요로 한다면, 대신 그 로직을 플러그인 `config.hasConfiguredState` 훅에 두세요. -## JSON Schema 요구 사항 +## JSON 스키마 요구 사항 -- **모든 plugin은 JSON Schema를 반드시 포함해야 하며**, 구성을 전혀 받지 않더라도 예외는 없습니다. +- **모든 플러그인은 반드시 JSON 스키마를 포함해야 합니다**, 구성을 전혀 받지 않더라도 마찬가지입니다. - 빈 스키마도 허용됩니다(예: `{ "type": "object", "additionalProperties": false }`). - 스키마는 런타임이 아니라 구성 읽기/쓰기 시점에 검증됩니다. ## 검증 동작 -- 알 수 없는 `channels.*` 키는 **오류**입니다. 단, 해당 channel id가 plugin 매니페스트에 선언된 경우는 예외입니다. -- `plugins.entries.`, `plugins.allow`, `plugins.deny`, `plugins.slots.*`는 **검색 가능한** plugin id를 참조해야 합니다. 알 수 없는 id는 **오류**입니다. -- plugin이 설치되어 있지만 매니페스트나 스키마가 깨졌거나 누락된 경우 검증이 실패하고 Doctor가 plugin 오류를 보고합니다. -- plugin 구성이 존재하지만 plugin이 **비활성화**되어 있으면 구성은 유지되며 Doctor + 로그에 **경고**가 표시됩니다. +- 알 수 없는 `channels.*` 키는 채널 ID가 플러그인 매니페스트에 선언되지 않은 한 **오류**입니다. +- `plugins.entries.`, `plugins.allow`, `plugins.deny`, `plugins.slots.*`는 반드시 **검색 가능한** 플러그인 ID를 참조해야 합니다. 알 수 없는 ID는 **오류**입니다. +- 플러그인이 설치되어 있지만 매니페스트나 스키마가 손상되었거나 누락된 경우, 검증이 실패하고 Doctor가 플러그인 오류를 보고합니다. +- 플러그인 구성이 존재하지만 플러그인이 **비활성화**된 경우, 구성은 유지되며 Doctor + 로그에 **경고**가 표시됩니다. -전체 `plugins.*` 스키마는 [Configuration reference](/ko/gateway/configuration)를 참조하세요. +전체 `plugins.*` 스키마는 [구성 참조](/ko/gateway/configuration)를 참조하세요. ## 참고 -- 매니페스트는 로컬 파일 시스템 로드를 포함해 **네이티브 OpenClaw plugin에 필수**입니다. -- 런타임은 여전히 plugin 모듈을 별도로 로드합니다. 매니페스트는 검색 + 검증 전용입니다. -- 네이티브 매니페스트는 JSON5로 파싱되므로 최종 값이 여전히 객체이기만 하면 주석, 후행 쉼표, 따옴표 없는 키를 허용합니다. +- 매니페스트는 로컬 파일시스템 로드를 포함한 **네이티브 OpenClaw 플러그인에 필수**입니다. +- 런타임은 여전히 플러그인 모듈을 별도로 로드합니다. 매니페스트는 검색 + 검증만을 위한 것입니다. +- 네이티브 매니페스트는 JSON5로 파싱되므로, 최종 값이 여전히 객체이기만 하면 주석, 후행 쉼표, 따옴표 없는 키가 허용됩니다. - 매니페스트 로더는 문서화된 매니페스트 필드만 읽습니다. 여기에 사용자 정의 최상위 키를 추가하지 마세요. -- `providerAuthEnvVars`는 env 이름을 확인하기 위해 plugin 런타임을 부팅해서는 안 되는 auth 프로브, env-marker 검증 및 유사한 provider-auth 표면을 위한 저비용 메타데이터 경로입니다. -- `providerAuthAliases`는 core에 관계를 하드코딩하지 않고도 provider 변형이 다른 provider의 auth env vars, auth 프로필, config 기반 auth, API 키 onboarding 선택지를 재사용할 수 있게 합니다. -- `channelEnvVars`는 env 이름을 확인하기 위해 plugin 런타임을 부팅해서는 안 되는 shell-env 폴백, setup 프롬프트 및 유사한 channel 표면을 위한 저비용 메타데이터 경로입니다. -- `providerAuthChoices`는 provider 런타임이 로드되기 전에 auth-choice 선택기, `--auth-choice` 해석, 선호 provider 매핑, 간단한 onboarding CLI 플래그 등록을 위한 저비용 메타데이터 경로입니다. provider 코드가 필요한 런타임 wizard 메타데이터는 [Provider runtime hooks](/ko/plugins/architecture#provider-runtime-hooks)를 참조하세요. -- 배타적 plugin kind는 `plugins.slots.*`를 통해 선택됩니다. +- `providerAuthEnvVars`는 인증 프로브, env-marker 검증, 기타 환경 변수 이름을 검사하기 위해 플러그인 런타임을 부팅해서는 안 되는 유사 제공자 인증 표면을 위한 저비용 메타데이터 경로입니다. +- `providerAuthAliases`는 제공자 변형이 다른 제공자의 인증 환경 변수, 인증 프로필, 구성 기반 인증, API 키 온보딩 선택을 재사용할 수 있게 하며, 이 관계를 코어에 하드코딩할 필요가 없습니다. +- `channelEnvVars`는 셸 환경 변수 대체, 설정 프롬프트, 기타 환경 변수 이름을 검사하기 위해 플러그인 런타임을 부팅해서는 안 되는 유사 채널 표면을 위한 저비용 메타데이터 경로입니다. +- `providerAuthChoices`는 제공자 런타임이 로드되기 전에 인증 선택 선택기, `--auth-choice` 해석, 선호 제공자 매핑, 단순 온보딩 CLI 플래그 등록을 위한 저비용 메타데이터 경로입니다. 제공자 코드가 필요한 런타임 wizard 메타데이터는 [제공자 런타임 훅](/ko/plugins/architecture#provider-runtime-hooks)을 참조하세요. +- 배타적 플러그인 종류는 `plugins.slots.*`를 통해 선택됩니다. - `kind: "memory"`는 `plugins.slots.memory`로 선택됩니다. - - `kind: "context-engine"`는 `plugins.slots.contextEngine`으로 선택됩니다 - (기본값: 내장 `legacy`). -- `channels`, `providers`, `cliBackends`, `skills`는 plugin에 필요하지 않다면 생략할 수 있습니다. -- plugin이 네이티브 모듈에 의존하는 경우, 빌드 단계와 package-manager 허용 목록 요구 사항(예: pnpm `allow-build-scripts` + - `kind: "context-engine"`는 `plugins.slots.contextEngine`으로 선택됩니다(기본값: 내장 `legacy`). +- 플러그인에 필요하지 않다면 `channels`, `providers`, `cliBackends`, `skills`는 생략할 수 있습니다. +- 플러그인이 네이티브 모듈에 의존한다면, 빌드 단계와 패키지 관리자 allowlist 요구 사항(예: pnpm `allow-build-scripts` - `pnpm rebuild `)을 문서화하세요. -## 관련 문서 +## 관련 항목 -- [Building Plugins](/ko/plugins/building-plugins) — plugin 시작 가이드 -- [Plugin Architecture](/ko/plugins/architecture) — 내부 아키텍처 -- [SDK Overview](/ko/plugins/sdk-overview) — Plugin SDK 참조 +- [플러그인 빌드](/ko/plugins/building-plugins) — 플러그인 시작하기 +- [플러그인 아키텍처](/ko/plugins/architecture) — 내부 아키텍처 +- [SDK 개요](/ko/plugins/sdk-overview) — Plugin SDK 참조 diff --git a/docs/ko/plugins/sdk-agent-harness.md b/docs/ko/plugins/sdk-agent-harness.md new file mode 100644 index 000000000..a3f0594da --- /dev/null +++ b/docs/ko/plugins/sdk-agent-harness.md @@ -0,0 +1,223 @@ +--- +read_when: + - 임베디드 에이전트 런타임 또는 하니스 레지스트리를 변경하고 있습니다 + - 번들되었거나 신뢰할 수 있는 플러그인에서 에이전트 하니스를 등록하고 있습니다 + - Codex 플러그인이 모델 제공자와 어떻게 연결되는지 이해해야 합니다 +sidebarTitle: Agent Harness +summary: 저수준 임베디드 에이전트 실행기를 대체하는 플러그인을 위한 실험적 SDK 표면 +title: 에이전트 하니스 플러그인 +x-i18n: + generated_at: "2026-04-11T02:46:14Z" + model: gpt-5.4 + provider: openai + source_hash: 43c1f2c087230398b0162ed98449f239c8db1e822e51c7dcd40c54fa6c3374e1 + source_path: plugins/sdk-agent-harness.md + workflow: 15 +--- + +# 에이전트 하니스 플러그인 + +**에이전트 하니스**는 준비된 OpenClaw 에이전트 턴 하나를 실행하는 저수준 실행기입니다. 이것은 모델 제공자도, 채널도, 도구 레지스트리도 아닙니다. + +이 표면은 번들되었거나 신뢰할 수 있는 네이티브 플러그인에만 사용하세요. 매개변수 타입이 의도적으로 현재 임베디드 러너를 반영하기 때문에, 이 계약은 아직 실험적입니다. + +## 하니스를 사용해야 하는 경우 + +모델 계열이 자체 네이티브 세션 런타임을 갖고 있고, 일반적인 OpenClaw 제공자 전송이 잘못된 추상화일 때 에이전트 하니스를 등록하세요. + +예시: + +- 스레드와 compaction을 자체적으로 관리하는 네이티브 코딩 에이전트 서버 +- 네이티브 plan/reasoning/tool 이벤트를 스트리밍해야 하는 로컬 CLI 또는 데몬 +- OpenClaw 세션 transcript 외에 자체 resume id가 필요한 모델 런타임 + +새 LLM API를 추가하기 위해 하니스를 등록해서는 **안 됩니다**. 일반적인 HTTP 또는 WebSocket 모델 API의 경우 [provider plugin](/ko/plugins/sdk-provider-plugins)을 만드세요. + +## 여전히 core가 담당하는 것 + +하니스가 선택되기 전에 OpenClaw는 이미 다음을 결정했습니다. + +- provider와 model +- 런타임 인증 상태 +- thinking level과 컨텍스트 예산 +- OpenClaw transcript/session 파일 +- workspace, sandbox, 도구 정책 +- 채널 응답 콜백과 스트리밍 콜백 +- 모델 폴백 및 live model switching 정책 + +이 분리는 의도된 것입니다. 하니스는 준비된 시도를 실행할 뿐이며, 제공자를 선택하거나, 채널 전달을 대체하거나, 모델을 몰래 전환하지 않습니다. + +## 하니스 등록 + +**가져오기:** `openclaw/plugin-sdk/agent-harness` + +```typescript +import type { AgentHarness } from "openclaw/plugin-sdk/agent-harness"; +import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; + +const myHarness: AgentHarness = { + id: "my-harness", + label: "내 네이티브 에이전트 하니스", + + supports(ctx) { + return ctx.provider === "my-provider" + ? { supported: true, priority: 100 } + : { supported: false }; + }, + + async runAttempt(params) { + // 네이티브 스레드를 시작하거나 재개합니다. + // params.prompt, params.tools, params.images, params.onPartialReply, + // params.onAgentEvent 및 기타 준비된 시도 필드를 사용하세요. + return await runMyNativeTurn(params); + }, +}; + +export default definePluginEntry({ + id: "my-native-agent", + name: "My Native Agent", + description: "선택한 모델을 네이티브 에이전트 데몬을 통해 실행합니다.", + register(api) { + api.registerAgentHarness(myHarness); + }, +}); +``` + +## 선택 정책 + +OpenClaw는 provider/model을 결정한 뒤 하니스를 선택합니다. + +1. `OPENCLAW_AGENT_RUNTIME=`는 해당 id의 등록된 하니스를 강제합니다. +2. `OPENCLAW_AGENT_RUNTIME=pi`는 내장 PI 하니스를 강제합니다. +3. `OPENCLAW_AGENT_RUNTIME=auto`는 등록된 하니스에, 결정된 provider/model을 지원하는지 묻습니다. +4. 일치하는 등록된 하니스가 없으면, PI 폴백이 비활성화되지 않은 한 OpenClaw는 PI를 사용합니다. + +강제된 플러그인 하니스 실패는 실행 실패로 드러납니다. `auto` 모드에서는 선택된 플러그인 하니스가 턴의 부작용을 만들기 전에 실패하면 OpenClaw가 PI로 폴백할 수 있습니다. 대신 그 폴백을 즉시 실패로 처리하려면 `OPENCLAW_AGENT_HARNESS_FALLBACK=none` 또는 `embeddedHarness.fallback: "none"`을 설정하세요. + +번들된 Codex 플러그인은 `codex`를 하니스 id로 등록합니다. Core는 이를 일반적인 플러그인 하니스 id로 취급합니다. Codex 전용 별칭은 공유 런타임 선택기가 아니라 플러그인 또는 운영자 config에 속해야 합니다. + +## provider와 harness의 페어링 + +대부분의 하니스는 provider도 함께 등록해야 합니다. provider는 모델 ref, 인증 상태, 모델 메타데이터, `/model` 선택을 OpenClaw의 나머지 부분에 노출합니다. 그런 다음 하니스는 `supports(...)`에서 해당 provider를 주장합니다. + +번들된 Codex 플러그인은 이 패턴을 따릅니다. + +- provider id: `codex` +- 사용자 모델 ref: `codex/gpt-5.4`, `codex/gpt-5.2` 또는 Codex app server가 반환하는 다른 모델 +- harness id: `codex` +- auth: 합성 provider 가용성, Codex 하니스가 네이티브 Codex 로그인/세션을 관리하기 때문 +- app-server 요청: OpenClaw는 Codex에 순수 모델 id를 보내고, 하니스가 네이티브 app-server 프로토콜과 통신하게 합니다. + +Codex 플러그인은 추가적인 것입니다. 일반 `openai/gpt-*` ref는 여전히 OpenAI provider ref이며 계속해서 일반 OpenClaw provider 경로를 사용합니다. Codex가 관리하는 인증, Codex 모델 탐색, 네이티브 스레드, Codex app-server 실행을 원할 때 `codex/gpt-*`를 선택하세요. `/model`은 OpenAI provider 자격 증명 없이도 Codex app server가 반환한 Codex 모델들 사이를 전환할 수 있습니다. + +운영자 설정, 모델 접두사 예시, Codex 전용 config는 +[Codex Harness](/ko/plugins/codex-harness)를 참조하세요. + +OpenClaw는 Codex app-server `0.118.0` 이상을 요구합니다. Codex 플러그인은 app-server initialize 핸드셰이크를 검사하고 더 오래되었거나 버전이 없는 서버를 차단하여, OpenClaw가 테스트된 프로토콜 표면에서만 실행되도록 합니다. + +## PI 폴백 비활성화 + +기본적으로 OpenClaw는 임베디드 에이전트를 `agents.defaults.embeddedHarness`가 `{ runtime: "auto", fallback: "pi" }`로 설정된 상태로 실행합니다. `auto` 모드에서 등록된 플러그인 하니스는 provider/model 쌍을 주장할 수 있습니다. 일치하는 것이 없거나, 자동 선택된 플러그인 하니스가 출력을 만들기 전에 실패하면 OpenClaw는 PI로 폴백합니다. + +플러그인 하니스만 실행되고 있음을 증명해야 할 때는 `fallback: "none"`을 설정하세요. 이렇게 하면 자동 PI 폴백이 비활성화되지만, 명시적인 `runtime: "pi"` 또는 `OPENCLAW_AGENT_RUNTIME=pi`까지 막지는 않습니다. + +Codex 전용 임베디드 실행의 경우: + +```json +{ + "agents": { + "defaults": { + "model": "codex/gpt-5.4", + "embeddedHarness": { + "runtime": "codex", + "fallback": "none" + } + } + } +} +``` + +등록된 어떤 플러그인 하니스든 일치하는 모델을 주장할 수 있게 하되, OpenClaw가 절대로 조용히 PI로 폴백하지 않게 하려면 `runtime: "auto"`를 유지하고 폴백을 비활성화하세요. + +```json +{ + "agents": { + "defaults": { + "embeddedHarness": { + "runtime": "auto", + "fallback": "none" + } + } + } +} +``` + +에이전트별 재정의도 같은 형태를 사용합니다. + +```json +{ + "agents": { + "defaults": { + "embeddedHarness": { + "runtime": "auto", + "fallback": "pi" + } + }, + "list": [ + { + "id": "codex-only", + "model": "codex/gpt-5.4", + "embeddedHarness": { + "runtime": "codex", + "fallback": "none" + } + } + ] + } +} +``` + +`OPENCLAW_AGENT_RUNTIME`는 여전히 구성된 런타임을 재정의합니다. 환경에서 PI 폴백을 비활성화하려면 `OPENCLAW_AGENT_HARNESS_FALLBACK=none`을 사용하세요. + +```bash +OPENCLAW_AGENT_RUNTIME=codex \ +OPENCLAW_AGENT_HARNESS_FALLBACK=none \ +openclaw gateway run +``` + +폴백이 비활성화되면, 요청된 하니스가 등록되지 않았거나, 결정된 provider/model을 지원하지 않거나, 턴의 부작용을 만들기 전에 실패할 경우 세션이 초기에 실패합니다. 이는 Codex 전용 배포와 Codex app-server 경로가 실제로 사용 중임을 증명해야 하는 live test를 위한 의도된 동작입니다. + +이 설정은 임베디드 에이전트 하니스만 제어합니다. image, video, music, TTS, PDF 또는 기타 provider별 모델 라우팅은 비활성화하지 않습니다. + +## 네이티브 세션과 transcript 미러링 + +하니스는 네이티브 session id, thread id 또는 데몬 측 resume token을 유지할 수 있습니다. 이 바인딩을 OpenClaw 세션과 명시적으로 연결된 상태로 유지하고, 사용자에게 보이는 assistant/tool 출력을 OpenClaw transcript에도 계속 미러링하세요. + +OpenClaw transcript는 다음을 위한 호환성 계층으로 남아 있습니다. + +- 채널에 보이는 세션 기록 +- transcript 검색 및 인덱싱 +- 이후 턴에서 내장 PI 하니스로 다시 전환 +- 일반적인 `/new`, `/reset`, 세션 삭제 동작 + +하니스가 사이드카 바인딩을 저장한다면, 소유한 OpenClaw 세션이 재설정될 때 이를 지울 수 있도록 `reset(...)`을 구현하세요. + +## 도구 및 미디어 결과 + +Core는 OpenClaw 도구 목록을 구성하고 이를 준비된 시도에 전달합니다. 하니스가 동적 도구 호출을 실행할 때는, 채널 미디어를 직접 보내는 대신 하니스 결과 형태를 통해 도구 결과를 반환하세요. + +이렇게 하면 텍스트, image, video, music, TTS, 승인, 메시징 도구 출력이 PI 기반 실행과 동일한 전달 경로를 유지합니다. + +## 현재 제한 사항 + +- 공개 import 경로는 일반적이지만, 일부 시도/결과 타입 별칭은 호환성을 위해 여전히 `Pi` 이름을 사용합니다. +- 서드파티 하니스 설치는 실험적입니다. 네이티브 세션 런타임이 꼭 필요해질 때까지는 provider plugin을 우선 사용하세요. +- 턴 간 하니스 전환은 지원됩니다. 네이티브 도구, 승인, assistant 텍스트 또는 메시지 전송이 시작된 뒤 턴 중간에 하니스를 전환하지 마세요. + +## 관련 문서 + +- [SDK 개요](/ko/plugins/sdk-overview) +- [런타임 헬퍼](/ko/plugins/sdk-runtime) +- [Provider Plugins](/ko/plugins/sdk-provider-plugins) +- [Codex Harness](/ko/plugins/codex-harness) +- [모델 제공자](/ko/concepts/model-providers) diff --git a/docs/ko/plugins/sdk-channel-plugins.md b/docs/ko/plugins/sdk-channel-plugins.md index 153f2bc79..254acaec4 100644 --- a/docs/ko/plugins/sdk-channel-plugins.md +++ b/docs/ko/plugins/sdk-channel-plugins.md @@ -1,100 +1,83 @@ --- read_when: - - 새 메시징 채널 plugin을 구축하고 있을 때 - - OpenClaw를 메시징 플랫폼에 연결하고 싶을 때 - - ChannelPlugin adapter 표면을 이해해야 할 때 + - 새 메시징 채널 plugin을 빌드하고 있습니다 + - OpenClaw를 메시징 플랫폼에 연결하려고 합니다 + - ChannelPlugin 어댑터 표면을 이해해야 합니다 sidebarTitle: Channel Plugins -summary: OpenClaw용 메시징 채널 plugin을 구축하는 단계별 가이드 -title: 채널 Plugin 구축 +summary: OpenClaw용 메시징 채널 plugin을 빌드하는 단계별 가이드 +title: 채널 plugin 빌드하기 x-i18n: - generated_at: "2026-04-08T02:17:22Z" + generated_at: "2026-04-11T02:46:30Z" model: gpt-5.4 provider: openai - source_hash: d23365b6d92006b30e671f9f0afdba40a2b88c845c5d2299d71c52a52985672f + source_hash: 8a026e924f9ae8a3ddd46287674443bcfccb0247be504261522b078e1f440aef source_path: plugins/sdk-channel-plugins.md workflow: 15 --- -# 채널 Plugin 구축 +# 채널 plugin 빌드하기 -이 가이드는 OpenClaw를 메시징 플랫폼에 연결하는 채널 plugin을 구축하는 과정을 안내합니다. 이 가이드를 마치면 DM 보안, -페어링, 답장 스레딩, 아웃바운드 메시징이 작동하는 채널을 갖추게 됩니다. +이 가이드는 OpenClaw를 메시징 플랫폼에 연결하는 채널 plugin을 빌드하는 과정을 안내합니다. 이 가이드를 마치면 DM 보안, 페어링, 답장 스레딩, 아웃바운드 메시징을 갖춘 작동하는 채널을 만들 수 있습니다. - 아직 OpenClaw plugin을 한 번도 만들어본 적이 없다면 먼저 - 기본 패키지 구조와 manifest 설정을 위해 - [시작하기](/ko/plugins/building-plugins)를 읽으세요. + 아직 OpenClaw plugin을 한 번도 빌드해본 적이 없다면, 먼저 기본 패키지 구조와 manifest 설정을 위해 + [시작하기](/ko/plugins/building-plugins)를 읽어보세요. -## 채널 plugin의 작동 방식 +## 채널 plugin의 동작 방식 -채널 plugin은 자체 send/edit/react 도구가 필요하지 않습니다. OpenClaw는 -코어에 하나의 공유 `message` 도구를 유지합니다. plugin이 담당하는 영역은 다음과 같습니다: +채널 plugin은 자체 send/edit/react tool이 필요하지 않습니다. OpenClaw는 core에 하나의 공유 `message` tool을 유지합니다. plugin이 담당하는 것은 다음과 같습니다: -- **설정** — 계정 해석 및 설정 wizard -- **보안** — DM 정책 및 허용 목록 +- **설정** — 계정 해석과 설정 wizard +- **보안** — DM 정책과 허용 목록 - **페어링** — DM 승인 흐름 -- **세션 문법** — provider별 대화 id가 기본 채팅, 스레드 id, 부모 대체 경로에 어떻게 매핑되는지 -- **아웃바운드** — 플랫폼으로 텍스트, 미디어, 투표를 보내기 -- **스레딩** — 답장을 어떻게 스레드로 연결할지 +- **세션 문법** — provider별 대화 ID가 기본 채팅, 스레드 ID, 부모 폴백으로 매핑되는 방식 +- **아웃바운드** — 플랫폼으로 텍스트, 미디어, 투표 보내기 +- **스레딩** — 답장이 스레드화되는 방식 -코어는 공유 메시지 도구, 프롬프트 연결, 바깥쪽 세션 키 형태, -일반적인 `:thread:` 기록 관리, 그리고 디스패치를 담당합니다. +core는 공유 message tool, 프롬프트 연결, 바깥쪽 세션 키 형태, 일반적인 `:thread:` 기록 관리, 그리고 디스패치를 담당합니다. -플랫폼이 대화 id 안에 추가 범위를 저장한다면, 그 파싱은 -plugin에서 `messaging.resolveSessionConversation(...)`으로 유지하세요. 이것이 `rawId`를 -기본 대화 id, 선택적 스레드 id, 명시적 `baseConversationId`, -그리고 모든 `parentConversationCandidates`로 매핑하는 정식 훅입니다. -`parentConversationCandidates`를 반환할 때는 가장 좁은 부모부터 -가장 넓은/기본 대화 순으로 정렬해 두세요. +플랫폼이 대화 ID 안에 추가 범위 정보를 저장한다면, 그 파싱은 plugin 안에 `messaging.resolveSessionConversation(...)`로 유지하세요. 이것이 `rawId`를 기본 대화 ID, 선택적 스레드 ID, 명시적 `baseConversationId`, 그리고 모든 `parentConversationCandidates`로 매핑하는 정식 훅입니다. `parentConversationCandidates`를 반환할 때는 가장 좁은 부모에서 가장 넓은/기본 대화 순으로 정렬된 상태를 유지하세요. -채널 레지스트리가 부팅되기 전에 같은 파싱이 필요한 번들 plugin은 -일치하는 `resolveSessionConversation(...)` export를 가진 최상위 -`session-key-api.ts` 파일도 노출할 수 있습니다. 코어는 런타임 plugin 레지스트리를 -아직 사용할 수 없을 때만 이 부트스트랩 안전 표면을 사용합니다. +채널 레지스트리가 부팅되기 전에 동일한 파싱이 필요한 번들 plugin은 일치하는 `resolveSessionConversation(...)` export가 있는 최상위 `session-key-api.ts` 파일도 노출할 수 있습니다. core는 런타임 plugin 레지스트리를 아직 사용할 수 없을 때만 그 부트스트랩 안전 표면을 사용합니다. -`messaging.resolveParentConversationCandidates(...)`는 plugin이 -일반/raw id 위에 부모 대체 경로만 필요로 할 때를 위한 레거시 호환성 대체 수단으로 -여전히 사용할 수 있습니다. 두 훅이 모두 존재하면 코어는 먼저 -`resolveSessionConversation(...).parentConversationCandidates`를 사용하고, -정식 훅이 이를 생략할 때만 `resolveParentConversationCandidates(...)`로 대체합니다. +`messaging.resolveParentConversationCandidates(...)`는 plugin이 일반/raw ID 위에 부모 폴백만 필요로 할 때의 레거시 호환성 폴백으로 계속 사용할 수 있습니다. 두 훅이 모두 존재하면 core는 먼저 `resolveSessionConversation(...).parentConversationCandidates`를 사용하고, 정식 훅이 이를 생략한 경우에만 `resolveParentConversationCandidates(...)`로 폴백합니다. -## 승인 및 채널 기능 +## 승인과 채널 기능 대부분의 채널 plugin은 승인 전용 코드가 필요하지 않습니다. -- 코어는 동일 채팅의 `/approve`, 공유 승인 버튼 페이로드, 일반적인 대체 전달을 담당합니다. -- 채널에 승인 전용 동작이 필요할 때는 채널 plugin에 하나의 `approvalCapability` 객체를 두는 방식을 선호하세요. -- `ChannelPlugin.approvals`는 제거되었습니다. 승인 전달/네이티브/렌더링/인증 관련 정보는 `approvalCapability`에 두세요. -- `plugin.auth`는 login/logout 전용입니다. 코어는 더 이상 그 객체에서 승인 인증 훅을 읽지 않습니다. -- `approvalCapability.authorizeActorAction`과 `approvalCapability.getActionAvailabilityState`가 정식 승인 인증 연결 지점입니다. +- core는 동일 채팅 `/approve`, 공유 승인 버튼 페이로드, 일반적인 폴백 전달을 담당합니다. +- 채널에 승인 전용 동작이 필요할 때는 채널 plugin에 하나의 `approvalCapability` 객체를 두는 방식을 우선하세요. +- `ChannelPlugin.approvals`는 제거되었습니다. 승인 전달/native/render/auth 관련 정보는 `approvalCapability`에 넣으세요. +- `plugin.auth`는 login/logout 전용입니다. core는 더 이상 그 객체에서 승인 인증 훅을 읽지 않습니다. +- `approvalCapability.authorizeActorAction`과 `approvalCapability.getActionAvailabilityState`가 정식 승인 인증 경계면입니다. - 동일 채팅 승인 인증 가용성에는 `approvalCapability.getActionAvailabilityState`를 사용하세요. -- 채널이 네이티브 exec 승인을 노출한다면, 동일 채팅 승인 인증과 다를 때 시작 표면/네이티브 클라이언트 상태를 위해 `approvalCapability.getExecInitiatingSurfaceState`를 사용하세요. 코어는 이 exec 전용 훅으로 `enabled`와 `disabled`를 구분하고, 시작 채널이 네이티브 exec 승인을 지원하는지 판단하며, 네이티브 클라이언트 대체 안내에 해당 채널을 포함합니다. 일반적인 경우에는 `createApproverRestrictedNativeApprovalCapability(...)`가 이를 채워 줍니다. -- 중복된 로컬 승인 프롬프트 숨기기나 전달 전 타이핑 표시 보내기 같은 채널 전용 페이로드 수명 주기 동작에는 `outbound.shouldSuppressLocalPayloadPrompt` 또는 `outbound.beforeDeliverPayload`를 사용하세요. -- `approvalCapability.delivery`는 네이티브 승인 라우팅 또는 대체 억제에만 사용하세요. -- 채널 소유 네이티브 승인 관련 정보에는 `approvalCapability.nativeRuntime`를 사용하세요. 핫 채널 엔트리포인트에서는 `createLazyChannelApprovalNativeRuntimeAdapter(...)`로 이를 지연 로드 상태로 유지하세요. 그러면 코어가 승인 수명 주기를 조립할 수 있으면서도 필요 시 런타임 모듈을 가져올 수 있습니다. -- 채널이 공유 렌더러 대신 진짜로 커스텀 승인 페이로드가 필요할 때만 `approvalCapability.render`를 사용하세요. -- 채널이 비활성 경로 응답에서 네이티브 exec 승인을 활성화하는 데 필요한 정확한 설정 키를 설명하고 싶다면 `approvalCapability.describeExecApprovalSetup`을 사용하세요. 이 훅은 `{ channel, channelLabel, accountId }`를 받습니다. 이름 있는 계정 채널은 최상위 기본값 대신 `channels..accounts..execApprovals.*` 같은 계정 범위 경로를 렌더링해야 합니다. -- 채널이 기존 설정에서 안정적인 소유자형 DM 정체성을 추론할 수 있다면, 승인 전용 코어 로직을 추가하지 말고 `openclaw/plugin-sdk/approval-runtime`의 `createResolvedApproverActionAuthAdapter`를 사용해 동일 채팅 `/approve`를 제한하세요. -- 채널에 네이티브 승인 전달이 필요하다면, 채널 코드는 대상 정규화와 전송/표시 관련 정보에만 집중시키세요. `openclaw/plugin-sdk/approval-runtime`의 `createChannelExecApprovalProfile`, `createChannelNativeOriginTargetResolver`, `createChannelApproverDmTargetResolver`, `createApproverRestrictedNativeApprovalCapability`를 사용하세요. 채널 전용 정보는 `approvalCapability.nativeRuntime` 뒤에 두고, 이상적으로는 `createChannelApprovalNativeRuntimeAdapter(...)` 또는 `createLazyChannelApprovalNativeRuntimeAdapter(...)`를 통해 두세요. 그러면 코어가 핸들러를 조립하고 요청 필터링, 라우팅, 중복 제거, 만료, gateway 구독, 다른 곳으로 라우팅됨 알림을 담당할 수 있습니다. `nativeRuntime`은 몇 개의 더 작은 연결 지점으로 나뉩니다: -- `availability` — 계정이 설정되었는지, 요청을 처리해야 하는지 여부 -- `presentation` — 공유 승인 뷰 모델을 보류/해결됨/만료된 네이티브 페이로드 또는 최종 작업으로 매핑 -- `transport` — 대상을 준비하고 네이티브 승인 메시지를 전송/업데이트/삭제 -- `interactions` — 네이티브 버튼 또는 반응을 위한 선택적 bind/unbind/clear-action 훅 +- 채널이 native exec 승인을 노출한다면, 동일 채팅 승인 인증과 시작 표면/native 클라이언트 상태가 다를 때 `approvalCapability.getExecInitiatingSurfaceState`를 사용하세요. core는 이 exec 전용 훅을 사용해 `enabled`와 `disabled`를 구분하고, 시작 채널이 native exec 승인을 지원하는지 판단하며, native 클라이언트 폴백 안내에 그 채널을 포함합니다. `createApproverRestrictedNativeApprovalCapability(...)`는 일반적인 경우에 이를 채워줍니다. +- 중복된 로컬 승인 프롬프트 숨김이나 전달 전 타이핑 표시 전송 같은 채널별 페이로드 수명 주기 동작에는 `outbound.shouldSuppressLocalPayloadPrompt` 또는 `outbound.beforeDeliverPayload`를 사용하세요. +- `approvalCapability.delivery`는 native 승인 라우팅 또는 폴백 억제에만 사용하세요. +- `approvalCapability.nativeRuntime`는 채널 소유 native 승인 정보를 위해 사용하세요. hot 채널 엔트리포인트에서는 `createLazyChannelApprovalNativeRuntimeAdapter(...)`로 이를 지연 로드 상태로 유지하세요. 이 방식은 core가 승인 수명 주기를 조합할 수 있게 하면서도 필요 시 런타임 모듈을 동적으로 import할 수 있습니다. +- 채널이 공유 렌더러 대신 정말로 사용자 정의 승인 페이로드가 필요할 때만 `approvalCapability.render`를 사용하세요. +- 채널이 비활성 경로 응답에서 native exec 승인을 활성화하는 데 필요한 정확한 설정 항목을 설명하고 싶다면 `approvalCapability.describeExecApprovalSetup`을 사용하세요. 이 훅은 `{ channel, channelLabel, accountId }`를 받습니다. 이름 있는 계정 채널은 최상위 기본값 대신 `channels..accounts..execApprovals.*` 같은 계정 범위 경로를 렌더링해야 합니다. +- 채널이 기존 설정에서 안정적인 소유자 유사 DM 정체성을 추론할 수 있다면, 승인 전용 core 로직을 추가하지 않고 동일 채팅 `/approve`를 제한하기 위해 `openclaw/plugin-sdk/approval-runtime`의 `createResolvedApproverActionAuthAdapter`를 사용하세요. +- 채널에 native 승인 전달이 필요하다면, 채널 코드는 대상 정규화와 전송/표현 정보에 집중하도록 유지하세요. `openclaw/plugin-sdk/approval-runtime`의 `createChannelExecApprovalProfile`, `createChannelNativeOriginTargetResolver`, `createChannelApproverDmTargetResolver`, `createApproverRestrictedNativeApprovalCapability`를 사용하세요. 채널별 정보는 `approvalCapability.nativeRuntime` 뒤에 두고, 가능하면 `createChannelApprovalNativeRuntimeAdapter(...)` 또는 `createLazyChannelApprovalNativeRuntimeAdapter(...)`를 통해 노출하세요. 그러면 core가 핸들러를 조합하고 요청 필터링, 라우팅, 중복 제거, 만료, gateway 구독, 다른 경로로 라우팅됨 알림을 담당할 수 있습니다. `nativeRuntime`은 몇 개의 더 작은 경계면으로 나뉩니다: +- `availability` — 계정이 설정되어 있는지와 요청을 처리해야 하는지 여부 +- `presentation` — 공유 승인 뷰 모델을 대기 중/해결됨/만료됨 native 페이로드나 최종 액션으로 매핑 +- `transport` — 대상 준비와 native 승인 메시지 전송/업데이트/삭제 +- `interactions` — native 버튼이나 리액션을 위한 선택적 bind/unbind/clear-action 훅 - `observe` — 선택적 전달 진단 훅 -- 채널에 클라이언트, 토큰, Bolt 앱, 웹훅 리시버 같은 런타임 소유 객체가 필요하다면 `openclaw/plugin-sdk/channel-runtime-context`를 통해 등록하세요. 일반적인 runtime-context 레지스트리를 사용하면 승인 전용 래퍼 접착 코드를 추가하지 않고도 코어가 채널 시작 상태에서 기능 기반 핸들러를 부트스트랩할 수 있습니다. -- 기능 기반 연결 지점으로 아직 충분히 표현할 수 없을 때만 더 낮은 수준의 `createChannelApprovalHandler` 또는 `createChannelNativeApprovalRuntime`을 사용하세요. -- 네이티브 승인 채널은 `accountId`와 `approvalKind`를 모두 해당 헬퍼들을 통해 라우팅해야 합니다. `accountId`는 다중 계정 승인 정책을 올바른 봇 계정 범위로 유지하고, `approvalKind`는 코어에 하드코딩된 분기 없이도 채널에서 exec 대 plugin 승인 동작을 사용할 수 있게 합니다. -- 이제 코어가 승인 재라우팅 알림도 담당합니다. 채널 plugin은 `createChannelNativeApprovalRuntime`에서 자체적인 "승인이 DM/다른 채널로 갔음" 후속 메시지를 보내지 말고, 공유 승인 기능 헬퍼를 통해 정확한 origin + approver-DM 라우팅을 노출한 뒤 코어가 시작 채팅에 알림을 게시하기 전에 실제 전달 결과를 집계하게 하세요. -- 전달된 승인 id 종류를 처음부터 끝까지 보존하세요. 네이티브 클라이언트는 채널 로컬 상태를 기준으로 exec 대 plugin 승인 라우팅을 추측하거나 다시 쓰면 안 됩니다. -- 서로 다른 승인 종류는 의도적으로 서로 다른 네이티브 표면을 노출할 수 있습니다. - 현재 번들 예시는 다음과 같습니다: - - Slack은 exec 및 plugin id 모두에 대해 네이티브 승인 라우팅을 계속 사용할 수 있게 유지합니다. - - Matrix는 exec와 plugin 승인 모두에 대해 동일한 네이티브 DM/채널 라우팅과 반응 UX를 유지하면서도 승인 종류별로 인증이 다를 수 있게 합니다. -- `createApproverRestrictedNativeApprovalAdapter`는 여전히 호환성 래퍼로 존재하지만, 새 코드에서는 기능 빌더를 선호하고 plugin에 `approvalCapability`를 노출해야 합니다. +- 채널에 client, token, Bolt 앱, webhook receiver 같은 런타임 소유 객체가 필요하다면 `openclaw/plugin-sdk/channel-runtime-context`를 통해 등록하세요. 일반적인 runtime-context 레지스트리는 core가 승인 전용 래퍼 glue를 추가하지 않고도 채널 시작 상태에서 기능 중심 핸들러를 부트스트랩할 수 있게 해줍니다. +- 기능 중심 경계면이 아직 충분히 표현력이 없을 때만 하위 수준의 `createChannelApprovalHandler` 또는 `createChannelNativeApprovalRuntime`을 사용하세요. +- native 승인 채널은 `accountId`와 `approvalKind`를 모두 해당 헬퍼들을 통해 라우팅해야 합니다. `accountId`는 다중 계정 승인 정책이 올바른 봇 계정 범위에 머물도록 하고, `approvalKind`는 core에 하드코딩된 분기 없이도 채널에서 exec와 plugin 승인 동작을 구분 가능하게 합니다. +- 이제 승인 재라우팅 알림도 core가 담당합니다. 채널 plugin은 `createChannelNativeApprovalRuntime`에서 자체적으로 "승인이 DM 또는 다른 채널로 갔다"는 후속 메시지를 보내지 말고, 대신 공유 승인 기능 헬퍼를 통해 정확한 origin + approver-DM 라우팅을 노출하고, 시작 채팅에 알림을 게시하기 전에 core가 실제 전달 결과를 집계하도록 하세요. +- 전달된 승인 ID 종류를 처음부터 끝까지 보존하세요. native 클라이언트는 채널 로컬 상태에서 exec와 plugin 승인 라우팅을 추측하거나 다시 써서는 안 됩니다. +- 서로 다른 승인 종류는 의도적으로 서로 다른 native 표면을 노출할 수 있습니다. + 현재 번들 예시: + - Slack은 exec 및 plugin ID 모두에 대해 native 승인 라우팅을 계속 제공합니다. + - Matrix는 exec와 plugin 승인 모두에서 동일한 native DM/채널 라우팅과 리액션 UX를 유지하면서도, 승인 종류별로 인증은 다르게 둘 수 있습니다. +- `createApproverRestrictedNativeApprovalAdapter`는 여전히 호환성 래퍼로 존재하지만, 새 코드에서는 기능 빌더를 우선 사용하고 plugin에 `approvalCapability`를 노출해야 합니다. -핫 채널 엔트리포인트에서는 해당 계열 전체가 아니라 한 부분만 -필요할 때 더 좁은 런타임 하위 경로를 선호하세요: +hot 채널 엔트리포인트에서는 이 계열 전체가 아니라 일부만 필요할 경우 더 좁은 런타임 하위 경로를 우선 사용하세요: - `openclaw/plugin-sdk/approval-auth-runtime` - `openclaw/plugin-sdk/approval-client-runtime` @@ -106,96 +89,64 @@ plugin에서 `messaging.resolveSessionConversation(...)`으로 유지하세요. - `openclaw/plugin-sdk/approval-reply-runtime` - `openclaw/plugin-sdk/channel-runtime-context` -마찬가지로 더 넓은 우산형 -표면이 필요하지 않을 때는 `openclaw/plugin-sdk/setup-runtime`, -`openclaw/plugin-sdk/setup-adapter-runtime`, -`openclaw/plugin-sdk/reply-runtime`, -`openclaw/plugin-sdk/reply-dispatch-runtime`, -`openclaw/plugin-sdk/reply-reference`, 그리고 -`openclaw/plugin-sdk/reply-chunking`을 선호하세요. +마찬가지로, 더 넓은 umbrella 표면이 필요하지 않다면 `openclaw/plugin-sdk/setup-runtime`, `openclaw/plugin-sdk/setup-adapter-runtime`, `openclaw/plugin-sdk/reply-runtime`, `openclaw/plugin-sdk/reply-dispatch-runtime`, `openclaw/plugin-sdk/reply-reference`, `openclaw/plugin-sdk/reply-chunking`을 우선 사용하세요. -특히 setup의 경우: +설정과 관련해서는 특히 다음과 같습니다: -- `openclaw/plugin-sdk/setup-runtime`은 런타임 안전 setup 헬퍼를 다룹니다: - import-safe setup 패치 adapter(`createPatchedAccountSetupAdapter`, - `createEnvPatchedAccountSetupAdapter`, - `createSetupInputPresenceValidator`), lookup-note 출력, - `promptResolvedAllowFrom`, `splitSetupEntries`, 그리고 위임된 - setup-proxy 빌더 -- `openclaw/plugin-sdk/setup-adapter-runtime`은 `createEnvPatchedAccountSetupAdapter`를 위한 좁은 env 인식 adapter 연결 지점입니다 -- `openclaw/plugin-sdk/channel-setup`은 선택적 설치 setup - 빌더와 몇 가지 setup 안전 기본 요소를 다룹니다: +- `openclaw/plugin-sdk/setup-runtime`은 런타임 안전 설정 헬퍼를 포함합니다: + import-safe setup patch adapter(`createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`), lookup-note 출력, `promptResolvedAllowFrom`, `splitSetupEntries`, 그리고 위임 setup-proxy 빌더 +- `openclaw/plugin-sdk/setup-adapter-runtime`은 `createEnvPatchedAccountSetupAdapter`를 위한 더 좁은 env 인식 adapter 경계면입니다. +- `openclaw/plugin-sdk/channel-setup`은 선택 설치 설정 빌더와 몇 가지 setup-safe 기본 요소를 포함합니다: `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, -채널이 env 기반 setup 또는 auth를 지원하고 일반적인 시작/설정 -흐름이 런타임 로드 전에 해당 env 이름을 알아야 한다면, plugin manifest의 -`channelEnvVars`에 이를 선언하세요. 채널 런타임 `envVars` 또는 로컬 상수는 -operator 대상 복사용으로만 유지하세요. -`createOptionalChannelSetupWizard`, `DEFAULT_ACCOUNT_ID`, -`createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, 그리고 -`splitSetupEntries` +채널이 env 기반 설정 또는 인증을 지원하고, 일반적인 시작/설정 흐름이 런타임 로드 전에 해당 env 이름을 알아야 한다면, plugin manifest에 `channelEnvVars`로 선언하세요. 채널 런타임 `envVars` 또는 로컬 상수는 운영자 대상 문구에만 유지하세요. +`createOptionalChannelSetupWizard`, `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, 그리고 `splitSetupEntries` -- 더 무거운 공유 setup/config 헬퍼인 - `moveSingleAccountChannelSectionToDefaultAccount(...)`도 필요할 때만 - 더 넓은 `openclaw/plugin-sdk/setup` 연결 지점을 사용하세요 +- 더 무거운 공유 설정/구성 헬퍼(예: `moveSingleAccountChannelSectionToDefaultAccount(...)`)도 필요한 경우에만 더 넓은 `openclaw/plugin-sdk/setup` 경계면을 사용하세요. -채널이 setup 표면에서 "먼저 이 plugin을 설치하세요"만 광고하고 싶다면, -`createOptionalChannelSetupSurface(...)`를 선호하세요. 생성된 -adapter/wizard는 config 쓰기와 최종화에서 fail closed로 동작하며, -검증, 최종화, 문서 링크 복사 전반에 걸쳐 동일한 설치 필요 메시지를 재사용합니다. +채널이 설정 표면에서 "먼저 이 plugin을 설치하세요"만 알리고 싶다면, `createOptionalChannelSetupSurface(...)`를 우선 사용하세요. 생성된 adapter/wizard는 설정 쓰기와 최종화에서 fail closed로 동작하며, 검증, 최종화, 문서 링크 문구 전반에서 동일한 설치 필요 메시지를 재사용합니다. -다른 핫 채널 경로에서도 더 넓은 레거시 표면보다 좁은 헬퍼를 선호하세요: +다른 hot 채널 경로에서도, 더 넓은 레거시 표면보다 더 좁은 헬퍼를 우선 사용하세요: -- 다중 계정 config 및 - 기본 계정 대체를 위한 `openclaw/plugin-sdk/account-core`, - `openclaw/plugin-sdk/account-id`, - `openclaw/plugin-sdk/account-resolution`, 그리고 - `openclaw/plugin-sdk/account-helpers` -- 인바운드 경로/envelope 및 - record-and-dispatch 연결을 위한 `openclaw/plugin-sdk/inbound-envelope`와 - `openclaw/plugin-sdk/inbound-reply-dispatch` -- 대상 파싱/매칭을 위한 `openclaw/plugin-sdk/messaging-targets` -- 미디어 로딩 및 아웃바운드 - 정체성/send 위임을 위한 `openclaw/plugin-sdk/outbound-media`와 - `openclaw/plugin-sdk/outbound-runtime` -- 스레드 바인딩 수명 주기 - 및 adapter 등록을 위한 `openclaw/plugin-sdk/thread-bindings-runtime` -- 레거시 agent/media - 페이로드 필드 레이아웃이 여전히 필요할 때만 `openclaw/plugin-sdk/agent-media-payload` -- Telegram 커스텀 명령 정규화, 중복/충돌 검증, - 그리고 대체 안정 명령 config 계약을 위한 `openclaw/plugin-sdk/telegram-command-config` +- 다중 계정 설정과 기본 계정 폴백에는 `openclaw/plugin-sdk/account-core`, `openclaw/plugin-sdk/account-id`, `openclaw/plugin-sdk/account-resolution`, `openclaw/plugin-sdk/account-helpers` +- 인바운드 경로/envelope와 기록 후 디스패치 연결에는 `openclaw/plugin-sdk/inbound-envelope`와 `openclaw/plugin-sdk/inbound-reply-dispatch` +- 대상 파싱/매칭에는 `openclaw/plugin-sdk/messaging-targets` +- 미디어 로딩과 아웃바운드 정체성/전송 delegate에는 `openclaw/plugin-sdk/outbound-media`와 `openclaw/plugin-sdk/outbound-runtime` +- 스레드 바인딩 수명 주기와 adapter 등록에는 `openclaw/plugin-sdk/thread-bindings-runtime` +- 레거시 agent/media 페이로드 필드 레이아웃이 여전히 필요한 경우에만 `openclaw/plugin-sdk/agent-media-payload` +- Telegram 사용자 정의 명령 정규화, 중복/충돌 검증, 폴백 안정 명령 설정 계약에는 `openclaw/plugin-sdk/telegram-command-config` -인증 전용 채널은 보통 기본 경로에서 멈출 수 있습니다. 코어가 승인을 처리하고 plugin은 아웃바운드/auth 기능만 노출하면 됩니다. Matrix, Slack, Telegram, 커스텀 채팅 전송 계층 같은 네이티브 승인 채널은 자체 승인 수명 주기를 구현하지 말고 공유 네이티브 헬퍼를 사용해야 합니다. +인증 전용 채널은 보통 기본 경로로 충분합니다. core가 승인을 처리하고 plugin은 아웃바운드/인증 기능만 노출하면 됩니다. Matrix, Slack, Telegram, 그리고 사용자 정의 채팅 전송 계층 같은 native 승인 채널은 자체 승인 수명 주기를 구현하는 대신 공유 native 헬퍼를 사용해야 합니다. ## 인바운드 멘션 정책 -인바운드 멘션 처리는 두 계층으로 나누어 유지하세요: +인바운드 멘션 처리는 다음 두 계층으로 분리해 유지하세요: -- plugin 소유 증거 수집 +- plugin 소유의 증거 수집 - 공유 정책 평가 공유 계층에는 `openclaw/plugin-sdk/channel-inbound`를 사용하세요. -plugin 로컬 로직에 적합한 항목: +plugin 로컬 로직에 적합한 예: -- 봇에 대한 reply 감지 +- 봇에게 답장했는지 감지 - 봇 인용 감지 -- 스레드 참여 확인 +- 스레드 참여 여부 확인 - 서비스/시스템 메시지 제외 -- 봇 참여를 입증하는 데 필요한 플랫폼 네이티브 캐시 +- 봇 참여를 입증하는 데 필요한 플랫폼 native 캐시 -공유 헬퍼에 적합한 항목: +공유 헬퍼에 적합한 예: - `requireMention` - 명시적 멘션 결과 -- 암시적 멘션 허용 목록 +- 암묵적 멘션 허용 목록 - 명령 우회 - 최종 건너뛰기 결정 권장 흐름: -1. 로컬 멘션 사실을 계산합니다. -2. 그 사실을 `resolveInboundMentionDecision({ facts, policy })`에 전달합니다. +1. 로컬 멘션 정보를 계산합니다. +2. 그 정보를 `resolveInboundMentionDecision({ facts, policy })`에 전달합니다. 3. 인바운드 게이트에서 `decision.effectiveWasMentioned`, `decision.shouldBypassMention`, `decision.shouldSkip`를 사용합니다. ```typescript @@ -235,8 +186,7 @@ const decision = resolveInboundMentionDecision({ if (decision.shouldSkip) return; ``` -`api.runtime.channel.mentions`는 이미 런타임 주입에 의존하는 -번들 채널 plugin을 위해 동일한 공유 멘션 헬퍼를 노출합니다: +`api.runtime.channel.mentions`는 이미 런타임 주입에 의존하는 번들 채널 plugin을 위해 동일한 공유 멘션 헬퍼를 노출합니다: - `buildMentionRegexes` - `matchesMentionPatterns` @@ -244,18 +194,15 @@ if (decision.shouldSkip) return; - `implicitMentionKindWhen` - `resolveInboundMentionDecision` -이전의 `resolveMentionGating*` 헬퍼는 -`openclaw/plugin-sdk/channel-inbound`에 호환성 export로만 남아 있습니다. 새 코드는 -`resolveInboundMentionDecision({ facts, policy })`를 사용해야 합니다. +이전의 `resolveMentionGating*` 헬퍼는 `openclaw/plugin-sdk/channel-inbound`에 호환성 export로만 남아 있습니다. 새 코드에서는 `resolveInboundMentionDecision({ facts, policy })`를 사용해야 합니다. -## 따라 하기 +## 단계별 안내 - 표준 plugin 파일을 만드세요. `package.json`의 `channel` 필드가 - 이것을 채널 plugin으로 만듭니다. 전체 패키지 메타데이터 표면은 - [Plugin 설정 및 Config](/ko/plugins/sdk-setup#openclawchannel)를 참고하세요: + 표준 plugin 파일을 생성하세요. `package.json`의 `channel` 필드는 이것이 채널 plugin임을 나타냅니다. 전체 패키지 메타데이터 표면은 + [Plugin 설정 및 구성](/ko/plugins/sdk-setup#openclaw-channel)을 참조하세요: ```json package.json @@ -304,9 +251,8 @@ if (decision.shouldSkip) return; - - `ChannelPlugin` 인터페이스에는 선택적인 adapter 표면이 많이 있습니다. 먼저 - 최소 구성인 `id`와 `setup`부터 시작한 뒤, 필요할 때 adapter를 추가하세요. + + `ChannelPlugin` 인터페이스에는 많은 선택적 adapter 표면이 있습니다. 최소 구성인 `id`와 `setup`부터 시작하고, 필요에 따라 adapter를 추가하세요. `src/channel.ts`를 만드세요: @@ -401,24 +347,23 @@ if (decision.shouldSkip) return; }); ``` - - 저수준 adapter 인터페이스를 직접 구현하는 대신 선언적 옵션을 전달하면 - 빌더가 이를 조합해 줍니다: + + 하위 수준 adapter 인터페이스를 직접 구현하는 대신 선언적 옵션을 전달하면, 빌더가 이를 조합해 구성해 줍니다: - | Option | 연결되는 항목 | + | 옵션 | 연결되는 항목 | | --- | --- | - | `security.dm` | config 필드에서 범위가 지정된 DM 보안 resolver | - | `pairing.text` | 코드 교환이 있는 텍스트 기반 DM 페어링 흐름 | - | `threading` | reply-to-mode resolver(고정, 계정 범위, 또는 커스텀) | - | `outbound.attachedResults` | 결과 메타데이터(메시지 ID)를 반환하는 send 함수 | + | `security.dm` | 설정 필드에서 범위가 지정된 DM 보안 resolver | + | `pairing.text` | 코드 교환을 사용하는 텍스트 기반 DM 페어링 흐름 | + | `threading` | 답장 모드 resolver(고정, 계정 범위, 또는 사용자 정의) | + | `outbound.attachedResults` | 결과 메타데이터(메시지 ID)를 반환하는 전송 함수 | 완전한 제어가 필요하다면 선언적 옵션 대신 원시 adapter 객체를 전달할 수도 있습니다. - - `index.ts`를 만드세요: + + `index.ts`를 생성하세요: ```typescript index.ts import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core"; @@ -453,21 +398,15 @@ if (decision.shouldSkip) return; }); ``` - 채널 소유 CLI descriptor는 `registerCliMetadata(...)`에 두세요. 그러면 OpenClaw가 - 전체 채널 런타임을 활성화하지 않고도 루트 도움말에 이를 표시할 수 있고, - 일반적인 전체 로드도 실제 명령 등록을 위해 동일한 descriptor를 가져오게 됩니다. - `registerFull(...)`은 런타임 전용 작업에 유지하세요. - `registerFull(...)`이 gateway RPC 메서드를 등록한다면 - plugin 전용 접두사를 사용하세요. 코어 admin 네임스페이스(`config.*`, - `exec.approvals.*`, `wizard.*`, `update.*`)는 예약되어 있으며 항상 - `operator.admin`으로 해석됩니다. - `defineChannelPluginEntry`는 등록 모드 분리를 자동으로 처리합니다. 모든 - 옵션은 [엔트리포인트](/ko/plugins/sdk-entrypoints#definechannelpluginentry)를 참고하세요. + 채널 소유 CLI descriptor는 `registerCliMetadata(...)`에 두어 OpenClaw가 전체 채널 런타임을 활성화하지 않고도 루트 도움말에 이를 표시할 수 있게 하세요. 그러면서 일반 전체 로드 시에는 실제 명령 등록을 위해 같은 descriptor를 그대로 가져오게 됩니다. 런타임 전용 작업은 `registerFull(...)`에 유지하세요. + `registerFull(...)`가 Gateway RPC 메서드를 등록한다면, plugin 전용 접두사를 사용하세요. 핵심 관리자 네임스페이스(`config.*`, `exec.approvals.*`, `wizard.*`, `update.*`)는 예약되어 있으며 항상 `operator.admin`으로 해석됩니다. + `defineChannelPluginEntry`는 등록 모드 분리를 자동으로 처리합니다. 모든 옵션은 + [엔트리포인트](/ko/plugins/sdk-entrypoints#definechannelpluginentry)를 참조하세요. - - 온보딩 중 경량 로딩을 위해 `setup-entry.ts`를 만드세요: + + 온보딩 중 경량 로드를 위해 `setup-entry.ts`를 생성하세요: ```typescript setup-entry.ts import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core"; @@ -476,17 +415,14 @@ if (decision.shouldSkip) return; export default defineSetupPluginEntry(acmeChatPlugin); ``` - OpenClaw는 채널이 비활성화되었거나 - 설정되지 않았을 때 전체 entry 대신 이것을 로드합니다. - 이렇게 하면 setup 흐름에서 무거운 런타임 코드를 끌어오지 않게 됩니다. - 자세한 내용은 [Setup 및 Config](/ko/plugins/sdk-setup#setup-entry)를 참고하세요. + OpenClaw는 채널이 비활성화되었거나 설정되지 않았을 때 전체 엔트리 대신 이것을 로드합니다. + 이를 통해 설정 흐름 중에 무거운 런타임 코드를 끌어오지 않게 됩니다. + 자세한 내용은 [설정 및 구성](/ko/plugins/sdk-setup#setup-entry)을 참조하세요. - - plugin은 플랫폼에서 메시지를 받아 OpenClaw로 전달해야 합니다. - 일반적인 패턴은 요청을 검증하고 - 채널의 인바운드 핸들러를 통해 디스패치하는 웹훅입니다: + + plugin은 플랫폼에서 메시지를 수신하고 이를 OpenClaw로 전달해야 합니다. 일반적인 패턴은 요청을 검증하고 채널의 인바운드 핸들러를 통해 이를 디스패치하는 webhook입니다: ```typescript registerFull(api) { @@ -510,16 +446,15 @@ if (decision.shouldSkip) return; ``` - 인바운드 메시지 처리는 채널별입니다. 각 채널 plugin이 - 자체 인바운드 파이프라인을 담당합니다. 실제 패턴은 번들 채널 plugin - (예: Microsoft Teams 또는 Google Chat plugin 패키지)을 확인하세요. + 인바운드 메시지 처리는 채널별로 다릅니다. 각 채널 plugin은 자체 인바운드 파이프라인을 소유합니다. 실제 패턴은 번들 채널 plugin + (예: Microsoft Teams 또는 Google Chat plugin 패키지)을 살펴보세요. -동일 위치의 테스트를 `src/channel.test.ts`에 작성하세요: +같은 위치의 `src/channel.test.ts`에 테스트를 작성하세요: ```typescript src/channel.test.ts import { describe, it, expect } from "vitest"; @@ -557,21 +492,21 @@ if (decision.shouldSkip) return; pnpm test -- /acme-chat/ ``` - 공유 테스트 헬퍼는 [테스팅](/ko/plugins/sdk-testing)을 참고하세요. + 공유 테스트 헬퍼는 [테스팅](/ko/plugins/sdk-testing)을 참조하세요. ## 파일 구조 -``` +```text /acme-chat/ -├── package.json # openclaw.channel metadata -├── openclaw.plugin.json # config schema가 포함된 Manifest +├── package.json # openclaw.channel 메타데이터 +├── openclaw.plugin.json # 설정 스키마가 포함된 manifest ├── index.ts # defineChannelPluginEntry ├── setup-entry.ts # defineSetupPluginEntry -├── api.ts # 공개 export(선택 사항) -├── runtime-api.ts # 내부 런타임 export(선택 사항) +├── api.ts # 공개 export (선택 사항) +├── runtime-api.ts # 내부 런타임 export (선택 사항) └── src/ ├── channel.ts # createChatChannelPlugin을 통한 ChannelPlugin ├── channel.test.ts # 테스트 @@ -583,10 +518,10 @@ if (decision.shouldSkip) return; - 고정, 계정 범위, 또는 커스텀 답장 모드 + 고정, 계정 범위, 또는 사용자 정의 답장 모드 - - describeMessageTool 및 작업 검색 + + describeMessageTool 및 액션 디스커버리 inferTargetChatType, looksLikeId, resolveTarget @@ -597,15 +532,12 @@ if (decision.shouldSkip) return; -일부 번들 헬퍼 연결 지점은 번들 plugin 유지 관리와 -호환성을 위해 여전히 존재합니다. 새 채널 plugin에 권장되는 패턴은 아니며, -해당 번들 plugin 계열을 직접 유지 관리하는 경우가 아니라면 -일반 SDK 표면의 범용 channel/setup/reply/runtime 하위 경로를 선호하세요. +일부 번들 헬퍼 경계면은 번들 plugin 유지 관리와 호환성을 위해 여전히 존재합니다. 하지만 이것이 새 채널 plugin에 권장되는 패턴은 아닙니다. 해당 번들 plugin 계열을 직접 유지 관리하는 경우가 아니라면, 공통 SDK 표면의 일반적인 channel/setup/reply/runtime 하위 경로를 우선 사용하세요. ## 다음 단계 -- [Provider Plugin](/ko/plugins/sdk-provider-plugins) — plugin이 모델도 제공하는 경우 +- [Provider Plugins](/ko/plugins/sdk-provider-plugins) — plugin이 모델도 제공하는 경우 - [SDK 개요](/ko/plugins/sdk-overview) — 전체 하위 경로 import 참조 -- [SDK 테스팅](/ko/plugins/sdk-testing) — 테스트 유틸리티 및 계약 테스트 +- [SDK 테스팅](/ko/plugins/sdk-testing) — 테스트 유틸리티와 계약 테스트 - [Plugin Manifest](/ko/plugins/manifest) — 전체 manifest 스키마 diff --git a/docs/ko/plugins/sdk-overview.md b/docs/ko/plugins/sdk-overview.md index 07e4572b1..ac25887fa 100644 --- a/docs/ko/plugins/sdk-overview.md +++ b/docs/ko/plugins/sdk-overview.md @@ -1,29 +1,29 @@ --- read_when: - - 어떤 SDK 하위 경로에서 import해야 하는지 알아야 합니다 + - 어느 SDK 하위 경로에서 가져와야 하는지 알아야 합니다 - OpenClawPluginApi의 모든 등록 메서드에 대한 참조가 필요합니다 - - 특정 SDK export를 찾고 있습니다 + - 특정 SDK 내보내기를 찾고 있습니다 sidebarTitle: SDK Overview -summary: import 맵, 등록 API 참조, SDK 아키텍처 -title: Plugin SDK 개요 +summary: 가져오기 맵, 등록 API 참조, SDK 아키텍처 +title: 플러그인 SDK 개요 x-i18n: - generated_at: "2026-04-09T01:31:11Z" + generated_at: "2026-04-11T02:46:48Z" model: gpt-5.4 provider: openai - source_hash: bf205af060971931df97dca4af5110ce173d2b7c12f56ad7c62d664a402f2381 + source_hash: 4bfeb5896f68e3e4ee8cf434d43a019e0d1fe5af57f5bf7a5172847c476def0c source_path: plugins/sdk-overview.md workflow: 15 --- -# Plugin SDK 개요 +# 플러그인 SDK 개요 -Plugin SDK는 plugins와 core 사이의 타입이 지정된 계약입니다. 이 페이지는 **무엇을 import할지**와 **무엇을 등록할 수 있는지**에 대한 참조입니다. +플러그인 SDK는 플러그인과 core 사이의 타입 지정 계약입니다. 이 페이지는 **무엇을 import해야 하는지**와 **무엇을 등록할 수 있는지**에 대한 참조입니다. **사용 방법 가이드를 찾고 있나요?** - - 첫 plugin이라면? [Getting Started](/ko/plugins/building-plugins)부터 시작하세요 - - Channel plugin이라면? [Channel Plugins](/ko/plugins/sdk-channel-plugins)를 참조하세요 - - Provider plugin이라면? [Provider Plugins](/ko/plugins/sdk-provider-plugins)를 참조하세요 + - 첫 플러그인이라면 [Getting Started](/ko/plugins/building-plugins)에서 시작하세요 + - 채널 플러그인이라면 [Channel Plugins](/ko/plugins/sdk-channel-plugins)을 참조하세요 + - provider plugin이라면 [Provider Plugins](/ko/plugins/sdk-provider-plugins)을 참조하세요 ## import 규칙 @@ -35,251 +35,266 @@ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core"; ``` -각 하위 경로는 작고 독립적인 모듈입니다. 이렇게 하면 시작 속도가 빨라지고 순환 의존성 문제를 방지할 수 있습니다. channel 전용 entry/build helper의 경우 `openclaw/plugin-sdk/channel-core`를 우선 사용하고, 더 넓은 umbrella 표면과 `buildChannelConfigSchema` 같은 공용 helper에는 `openclaw/plugin-sdk/core`를 유지하세요. +각 하위 경로는 작고 독립적인 모듈입니다. 이렇게 하면 시작 속도가 빨라지고 +순환 의존성 문제를 방지할 수 있습니다. 채널 전용 엔트리/빌드 헬퍼에는 +`openclaw/plugin-sdk/channel-core`를 우선 사용하고, 더 넓은 umbrella 표면과 +`buildChannelConfigSchema` 같은 공유 헬퍼에는 `openclaw/plugin-sdk/core`를 유지하세요. -`openclaw/plugin-sdk/slack`, `openclaw/plugin-sdk/discord`, `openclaw/plugin-sdk/signal`, `openclaw/plugin-sdk/whatsapp` 또는 channel 브랜드 helper seam 같은 provider 이름 기반 convenience seam을 추가하거나 이에 의존하지 마세요. 번들 plugins는 자체 `api.ts` 또는 `runtime-api.ts` barrel 안에서 일반적인 SDK 하위 경로를 조합해야 하며, core는 해당 plugin 로컬 barrel을 사용하거나 필요가 진짜 cross-channel일 때 좁고 일반적인 SDK 계약을 추가해야 합니다. +`openclaw/plugin-sdk/slack`, `openclaw/plugin-sdk/discord`, +`openclaw/plugin-sdk/signal`, `openclaw/plugin-sdk/whatsapp` 또는 +채널 브랜드 헬퍼 표면 같은 provider 이름 기반 편의 seam을 추가하거나 이에 의존하지 마세요. +번들 플러그인은 자체 `api.ts` 또는 `runtime-api.ts` 배럴 안에서 일반적인 +SDK 하위 경로를 조합해야 하며, core는 해당 필요가 진정으로 채널 간 요구일 때 +그 플러그인 로컬 배럴을 사용하거나 좁은 범위의 일반 SDK 계약을 추가해야 합니다. -생성된 export 맵에는 여전히 `plugin-sdk/feishu`, `plugin-sdk/feishu-setup`, `plugin-sdk/zalo`, `plugin-sdk/zalo-setup`, `plugin-sdk/matrix*` 같은 소수의 번들 plugin helper seam이 포함되어 있습니다. 이러한 하위 경로는 번들 plugin 유지 관리 및 호환성 전용으로 존재하며, 아래 공통 표에서는 의도적으로 생략되었고 새로운 서드파티 plugins에 권장되는 import 경로도 아닙니다. +생성된 export 맵에는 여전히 `plugin-sdk/feishu`, `plugin-sdk/feishu-setup`, +`plugin-sdk/zalo`, `plugin-sdk/zalo-setup`, `plugin-sdk/matrix*`와 같은 +소수의 번들 플러그인 헬퍼 seam이 포함되어 있습니다. 이 하위 경로들은 +번들 플러그인 유지보수 및 호환성을 위해서만 존재하며, 아래의 일반 표에서는 의도적으로 제외되어 있고 +새로운 서드파티 플러그인에 권장되는 import 경로가 아닙니다. ## 하위 경로 참조 -가장 자주 사용하는 하위 경로를 용도별로 묶었습니다. 200개가 넘는 하위 경로의 전체 생성 목록은 `scripts/lib/plugin-sdk-entrypoints.json`에 있습니다. +용도별로 그룹화한 가장 일반적으로 사용되는 하위 경로입니다. 200개가 넘는 하위 경로의 +생성된 전체 목록은 `scripts/lib/plugin-sdk-entrypoints.json`에 있습니다. -예약된 번들 plugin helper 하위 경로도 이 생성 목록에 계속 나타납니다. 문서 페이지에서 명시적으로 public으로 권장하지 않는 한, 이를 구현 세부 사항/호환성 표면으로 취급하세요. +예약된 번들 플러그인 헬퍼 하위 경로는 여전히 그 생성된 목록에 나타납니다. +문서 페이지가 이를 공개 표면으로 명시적으로 안내하지 않는 한, 구현 세부 사항/호환성 표면으로 취급하세요. -### Plugin entry +### 플러그인 엔트리 -| Subpath | 주요 exports | -| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| `plugin-sdk/plugin-entry` | `definePluginEntry` | +| 하위 경로 | 주요 export | +| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `plugin-sdk/plugin-entry` | `definePluginEntry` | | `plugin-sdk/core` | `defineChannelPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase`, `defineSetupPluginEntry`, `buildChannelConfigSchema` | -| `plugin-sdk/config-schema` | `OpenClawSchema` | -| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | +| `plugin-sdk/config-schema` | `OpenClawSchema` | +| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | - - | Subpath | 주요 exports | + + | 하위 경로 | 주요 export | | --- | --- | | `plugin-sdk/channel-core` | `defineChannelPluginEntry`, `defineSetupPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase` | | `plugin-sdk/config-schema` | 루트 `openclaw.json` Zod 스키마 export (`OpenClawSchema`) | | `plugin-sdk/channel-setup` | `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, `createOptionalChannelSetupWizard`, 그리고 `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, `splitSetupEntries` | - | `plugin-sdk/setup` | 공용 setup wizard helper, 허용 목록 프롬프트, setup 상태 빌더 | + | `plugin-sdk/setup` | 공유 setup wizard 헬퍼, allowlist 프롬프트, setup 상태 빌더 | | `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` | | `plugin-sdk/setup-adapter-runtime` | `createEnvPatchedAccountSetupAdapter` | | `plugin-sdk/setup-tools` | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` | - | `plugin-sdk/account-core` | 다중 계정 config/action-gate helper, 기본 계정 폴백 helper | - | `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`, account-id 정규화 helper | - | `plugin-sdk/account-resolution` | 계정 조회 + 기본 폴백 helper | - | `plugin-sdk/account-helpers` | 좁은 범위의 account-list/account-action helper | + | `plugin-sdk/account-core` | 다중 계정 config/액션 게이트 헬퍼, 기본 계정 폴백 헬퍼 | + | `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`, account-id 정규화 헬퍼 | + | `plugin-sdk/account-resolution` | 계정 조회 + 기본값 폴백 헬퍼 | + | `plugin-sdk/account-helpers` | 좁은 범위의 account-list/account-action 헬퍼 | | `plugin-sdk/channel-pairing` | `createChannelPairingController` | | `plugin-sdk/channel-reply-pipeline` | `createChannelReplyPipeline` | | `plugin-sdk/channel-config-helpers` | `createHybridChannelConfigAdapter` | - | `plugin-sdk/channel-config-schema` | Channel config 스키마 타입 | - | `plugin-sdk/telegram-command-config` | 번들 계약 폴백이 포함된 Telegram 사용자 지정 command 정규화/검증 helper | + | `plugin-sdk/channel-config-schema` | 채널 config 스키마 타입 | + | `plugin-sdk/telegram-command-config` | 번들 계약 폴백이 있는 Telegram 사용자 지정 명령 정규화/검증 헬퍼 | | `plugin-sdk/channel-policy` | `resolveChannelGroupRequireMention` | | `plugin-sdk/channel-lifecycle` | `createAccountStatusSink` | - | `plugin-sdk/inbound-envelope` | 공용 수신 라우트 + envelope 빌더 helper | - | `plugin-sdk/inbound-reply-dispatch` | 공용 수신 record-and-dispatch helper | - | `plugin-sdk/messaging-targets` | 대상 파싱/매칭 helper | - | `plugin-sdk/outbound-media` | 공용 송신 미디어 로딩 helper | - | `plugin-sdk/outbound-runtime` | 송신 identity/send delegate helper | - | `plugin-sdk/thread-bindings-runtime` | 스레드 바인딩 lifecycle 및 adapter helper | - | `plugin-sdk/agent-media-payload` | 레거시 agent 미디어 payload 빌더 | - | `plugin-sdk/conversation-runtime` | 대화/스레드 바인딩, 페어링, configured-binding helper | - | `plugin-sdk/runtime-config-snapshot` | 런타임 config 스냅샷 helper | - | `plugin-sdk/runtime-group-policy` | 런타임 group-policy 해석 helper | - | `plugin-sdk/channel-status` | 공용 channel 상태 스냅샷/요약 helper | - | `plugin-sdk/channel-config-primitives` | 좁은 범위의 channel config-schema primitives | - | `plugin-sdk/channel-config-writes` | Channel config-write 권한 부여 helper | - | `plugin-sdk/channel-plugin-common` | 공용 channel plugin prelude exports | - | `plugin-sdk/allowlist-config-edit` | 허용 목록 config 편집/읽기 helper | - | `plugin-sdk/group-access` | 공용 group-access 결정 helper | - | `plugin-sdk/direct-dm` | 공용 direct-DM auth/guard helper | - | `plugin-sdk/interactive-runtime` | 대화형 reply payload 정규화/축소 helper | - | `plugin-sdk/channel-inbound` | 수신 debounce, mention 매칭, mention-policy helper 및 envelope helper | - | `plugin-sdk/channel-send-result` | Reply 결과 타입 | + | `plugin-sdk/inbound-envelope` | 공유 인바운드 라우트 + 엔벌로프 빌더 헬퍼 | + | `plugin-sdk/inbound-reply-dispatch` | 공유 인바운드 기록 및 디스패치 헬퍼 | + | `plugin-sdk/messaging-targets` | 대상 파싱/매칭 헬퍼 | + | `plugin-sdk/outbound-media` | 공유 아웃바운드 미디어 로딩 헬퍼 | + | `plugin-sdk/outbound-runtime` | 아웃바운드 ID/전송 delegate 헬퍼 | + | `plugin-sdk/thread-bindings-runtime` | 스레드 바인딩 생명주기 및 어댑터 헬퍼 | + | `plugin-sdk/agent-media-payload` | 레거시 에이전트 미디어 payload 빌더 | + | `plugin-sdk/conversation-runtime` | 대화/스레드 바인딩, 페어링, 구성된 바인딩 헬퍼 | + | `plugin-sdk/runtime-config-snapshot` | 런타임 config 스냅샷 헬퍼 | + | `plugin-sdk/runtime-group-policy` | 런타임 그룹 정책 해결 헬퍼 | + | `plugin-sdk/channel-status` | 공유 채널 상태 스냅샷/요약 헬퍼 | + | `plugin-sdk/channel-config-primitives` | 좁은 범위의 채널 config 스키마 프리미티브 | + | `plugin-sdk/channel-config-writes` | 채널 config 쓰기 권한 부여 헬퍼 | + | `plugin-sdk/channel-plugin-common` | 공유 채널 플러그인 프렐류드 export | + | `plugin-sdk/allowlist-config-edit` | allowlist config 편집/읽기 헬퍼 | + | `plugin-sdk/group-access` | 공유 group-access 결정 헬퍼 | + | `plugin-sdk/direct-dm` | 공유 direct-DM 인증/가드 헬퍼 | + | `plugin-sdk/interactive-runtime` | 대화형 응답 payload 정규화/축소 헬퍼 | + | `plugin-sdk/channel-inbound` | 인바운드 디바운스, 멘션 매칭, 멘션 정책 헬퍼, 엔벌로프 헬퍼 | + | `plugin-sdk/channel-send-result` | 응답 결과 타입 | | `plugin-sdk/channel-actions` | `createMessageToolButtonsSchema`, `createMessageToolCardSchema` | - | `plugin-sdk/channel-targets` | 대상 파싱/매칭 helper | - | `plugin-sdk/channel-contract` | Channel 계약 타입 | - | `plugin-sdk/channel-feedback` | 피드백/reaction wiring | - | `plugin-sdk/channel-secret-runtime` | `collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment` 및 secret 대상 타입 같은 좁은 범위의 secret-contract helper | + | `plugin-sdk/channel-targets` | 대상 파싱/매칭 헬퍼 | + | `plugin-sdk/channel-contract` | 채널 계약 타입 | + | `plugin-sdk/channel-feedback` | 피드백/리액션 wiring | + | `plugin-sdk/channel-secret-runtime` | `collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment` 및 secret 대상 타입과 같은 좁은 범위의 secret 계약 헬퍼 | - - | Subpath | 주요 exports | + + | 하위 경로 | 주요 export | | --- | --- | | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | - | `plugin-sdk/provider-setup` | 선별된 local/self-hosted provider setup helper | - | `plugin-sdk/self-hosted-provider-setup` | 집중된 OpenAI 호환 self-hosted provider setup helper | - | `plugin-sdk/cli-backend` | CLI backend 기본값 + watchdog 상수 | - | `plugin-sdk/provider-auth-runtime` | provider plugins용 런타임 API 키 해석 helper | - | `plugin-sdk/provider-auth-api-key` | `upsertApiKeyProfile` 같은 API 키 onboarding/profile-write helper | + | `plugin-sdk/provider-setup` | 선별된 로컬/셀프호스팅 provider setup 헬퍼 | + | `plugin-sdk/self-hosted-provider-setup` | 집중된 OpenAI 호환 셀프호스팅 provider setup 헬퍼 | + | `plugin-sdk/cli-backend` | CLI 백엔드 기본값 + watchdog 상수 | + | `plugin-sdk/provider-auth-runtime` | provider plugin용 런타임 API 키 해결 헬퍼 | + | `plugin-sdk/provider-auth-api-key` | `upsertApiKeyProfile` 같은 API 키 온보딩/profile-write 헬퍼 | | `plugin-sdk/provider-auth-result` | 표준 OAuth auth-result 빌더 | - | `plugin-sdk/provider-auth-login` | provider plugins용 공용 대화형 로그인 helper | - | `plugin-sdk/provider-env-vars` | Provider auth env-var 조회 helper | + | `plugin-sdk/provider-auth-login` | provider plugin용 공유 대화형 로그인 헬퍼 | + | `plugin-sdk/provider-env-vars` | provider 인증 env var 조회 헬퍼 | | `plugin-sdk/provider-auth` | `createProviderApiKeyAuthMethod`, `ensureApiKeyFromOptionEnvOrPrompt`, `upsertAuthProfile`, `upsertApiKeyProfile`, `writeOAuthCredentials` | - | `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`, 공용 replay-policy 빌더, provider-endpoint helper, `normalizeNativeXaiModelId` 같은 model-id 정규화 helper | + | `plugin-sdk/provider-model-shared` | `ProviderReplayFamily`, `buildProviderReplayFamilyHooks`, `normalizeModelCompat`, 공유 replay-policy 빌더, provider 엔드포인트 헬퍼, `normalizeNativeXaiModelId` 같은 모델 id 정규화 헬퍼 | | `plugin-sdk/provider-catalog-shared` | `findCatalogTemplate`, `buildSingleProviderApiKeyCatalog`, `supportsNativeStreamingUsageCompat`, `applyProviderNativeStreamingUsageCompat` | - | `plugin-sdk/provider-http` | 일반적인 provider HTTP/endpoint capability helper | - | `plugin-sdk/provider-web-fetch-contract` | `enablePluginInConfig` 및 `WebFetchProviderPlugin` 같은 좁은 범위의 web-fetch config/selection 계약 helper | - | `plugin-sdk/provider-web-fetch` | Web-fetch provider 등록/cache helper | - | `plugin-sdk/provider-web-search-config-contract` | plugin-enable wiring이 필요 없는 provider를 위한 좁은 범위의 web-search config/credential helper | - | `plugin-sdk/provider-web-search-contract` | `createWebSearchProviderContractFields`, `enablePluginInConfig`, `resolveProviderWebSearchPluginConfig`, 범위가 지정된 credential setter/getter 같은 좁은 범위의 web-search config/credential 계약 helper | - | `plugin-sdk/provider-web-search` | Web-search provider 등록/cache/런타임 helper | - | `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`, `buildProviderToolCompatFamilyHooks`, Gemini 스키마 정리 + 진단, `resolveXaiModelCompatPatch` / `applyXaiModelCompat` 같은 xAI 호환 helper | - | `plugin-sdk/provider-usage` | `fetchClaudeUsage` 등 | - | `plugin-sdk/provider-stream` | `ProviderStreamFamily`, `buildProviderStreamFamilyHooks`, `composeProviderStreamWrappers`, stream wrapper 타입, 공용 Anthropic/Bedrock/Google/Kilocode/Moonshot/OpenAI/OpenRouter/Z.A.I/MiniMax/Copilot wrapper helper | - | `plugin-sdk/provider-onboard` | Onboarding config patch helper | - | `plugin-sdk/global-singleton` | 프로세스 로컬 singleton/map/cache helper | + | `plugin-sdk/provider-http` | 일반 provider HTTP/엔드포인트 기능 헬퍼 | + | `plugin-sdk/provider-web-fetch-contract` | `enablePluginInConfig` 및 `WebFetchProviderPlugin` 같은 좁은 범위의 web-fetch config/선택 계약 헬퍼 | + | `plugin-sdk/provider-web-fetch` | web-fetch provider 등록/캐시 헬퍼 | + | `plugin-sdk/provider-web-search-config-contract` | 플러그인 활성화 wiring이 필요하지 않은 provider용 좁은 범위의 web-search config/자격 증명 헬퍼 | + | `plugin-sdk/provider-web-search-contract` | `createWebSearchProviderContractFields`, `enablePluginInConfig`, `resolveProviderWebSearchPluginConfig`, 범위 지정 자격 증명 setter/getter 같은 좁은 범위의 web-search config/자격 증명 계약 헬퍼 | + | `plugin-sdk/provider-web-search` | web-search provider 등록/캐시/런타임 헬퍼 | + | `plugin-sdk/provider-tools` | `ProviderToolCompatFamily`, `buildProviderToolCompatFamilyHooks`, Gemini 스키마 정리 + 진단, `resolveXaiModelCompatPatch` / `applyXaiModelCompat` 같은 xAI 호환 헬퍼 | + | `plugin-sdk/provider-usage` | `fetchClaudeUsage` 및 유사 항목 | + | `plugin-sdk/provider-stream` | `ProviderStreamFamily`, `buildProviderStreamFamilyHooks`, `composeProviderStreamWrappers`, 스트림 래퍼 타입, 공유 Anthropic/Bedrock/Google/Kilocode/Moonshot/OpenAI/OpenRouter/Z.A.I/MiniMax/Copilot 래퍼 헬퍼 | + | `plugin-sdk/provider-onboard` | 온보딩 config 패치 헬퍼 | + | `plugin-sdk/global-singleton` | 프로세스 로컬 singleton/map/cache 헬퍼 | - - | Subpath | 주요 exports | + + | 하위 경로 | 주요 export | | --- | --- | - | `plugin-sdk/command-auth` | `resolveControlCommandGate`, command 레지스트리 helper, sender-authorization helper | - | `plugin-sdk/command-status` | `buildCommandsMessagePaginated`, `buildHelpMessage` 같은 command/help 메시지 빌더 | - | `plugin-sdk/approval-auth-runtime` | 승인자 해석 및 same-chat action-auth helper | - | `plugin-sdk/approval-client-runtime` | 네이티브 exec 승인 profile/filter helper | - | `plugin-sdk/approval-delivery-runtime` | 네이티브 승인 capability/delivery adapter | - | `plugin-sdk/approval-gateway-runtime` | 공용 승인 gateway-resolution helper | - | `plugin-sdk/approval-handler-adapter-runtime` | 핫 channel entrypoint용 경량 네이티브 승인 adapter 로딩 helper | - | `plugin-sdk/approval-handler-runtime` | 더 넓은 범위의 승인 handler 런타임 helper. 좁은 adapter/gateway seam으로 충분하면 그것을 우선 사용하세요 | - | `plugin-sdk/approval-native-runtime` | 네이티브 승인 대상 + account-binding helper | - | `plugin-sdk/approval-reply-runtime` | Exec/plugin 승인 reply payload helper | - | `plugin-sdk/command-auth-native` | 네이티브 command auth + 네이티브 session-target helper | - | `plugin-sdk/command-detection` | 공용 command 감지 helper | - | `plugin-sdk/command-surface` | Command-body 정규화 및 command-surface helper | + | `plugin-sdk/command-auth` | `resolveControlCommandGate`, 명령 레지스트리 헬퍼, 발신자 인증 헬퍼 | + | `plugin-sdk/command-status` | `buildCommandsMessagePaginated`, `buildHelpMessage` 같은 명령/도움말 메시지 빌더 | + | `plugin-sdk/approval-auth-runtime` | 승인자 해결 및 동일 채팅 액션 인증 헬퍼 | + | `plugin-sdk/approval-client-runtime` | 네이티브 exec 승인 프로필/필터 헬퍼 | + | `plugin-sdk/approval-delivery-runtime` | 네이티브 승인 기능/전달 어댑터 | + | `plugin-sdk/approval-gateway-runtime` | 공유 승인 게이트웨이 해결 헬퍼 | + | `plugin-sdk/approval-handler-adapter-runtime` | hot 채널 엔트리포인트용 경량 네이티브 승인 어댑터 로딩 헬퍼 | + | `plugin-sdk/approval-handler-runtime` | 더 넓은 승인 핸들러 런타임 헬퍼; 더 좁은 adapter/gateway seam으로 충분하다면 그것을 우선 사용하세요 | + | `plugin-sdk/approval-native-runtime` | 네이티브 승인 대상 + account-binding 헬퍼 | + | `plugin-sdk/approval-reply-runtime` | exec/plugin 승인 응답 payload 헬퍼 | + | `plugin-sdk/command-auth-native` | 네이티브 명령 인증 + 네이티브 session-target 헬퍼 | + | `plugin-sdk/command-detection` | 공유 명령 감지 헬퍼 | + | `plugin-sdk/command-surface` | 명령 본문 정규화 및 명령 표면 헬퍼 | | `plugin-sdk/allow-from` | `formatAllowFromLowercase` | - | `plugin-sdk/channel-secret-runtime` | channel/plugin secret 표면용 좁은 범위의 secret-contract 수집 helper | - | `plugin-sdk/secret-ref-runtime` | secret-contract/config 파싱용 좁은 범위의 `coerceSecretRef` 및 SecretRef 타입 helper | - | `plugin-sdk/security-runtime` | 공용 신뢰, DM 게이팅, 외부 콘텐츠, secret 수집 helper | - | `plugin-sdk/ssrf-policy` | 호스트 허용 목록 및 private-network SSRF 정책 helper | - | `plugin-sdk/ssrf-runtime` | pinned-dispatcher, SSRF 보호 fetch, SSRF 정책 helper | - | `plugin-sdk/secret-input` | Secret 입력 파싱 helper | - | `plugin-sdk/webhook-ingress` | Webhook 요청/대상 helper | - | `plugin-sdk/webhook-request-guards` | 요청 본문 크기/시간 초과 helper | + | `plugin-sdk/channel-secret-runtime` | 채널/플러그인 secret 표면용 좁은 범위의 secret 계약 수집 헬퍼 | + | `plugin-sdk/secret-ref-runtime` | secret 계약/config 파싱용 좁은 범위의 `coerceSecretRef` 및 SecretRef 타이핑 헬퍼 | + | `plugin-sdk/security-runtime` | 공유 trust, DM 게이팅, 외부 콘텐츠, secret 수집 헬퍼 | + | `plugin-sdk/ssrf-policy` | 호스트 allowlist 및 private-network SSRF 정책 헬퍼 | + | `plugin-sdk/ssrf-runtime` | pinned-dispatcher, SSRF 보호 fetch, SSRF 정책 헬퍼 | + | `plugin-sdk/secret-input` | secret 입력 파싱 헬퍼 | + | `plugin-sdk/webhook-ingress` | webhook 요청/대상 헬퍼 | + | `plugin-sdk/webhook-request-guards` | 요청 본문 크기/타임아웃 헬퍼 | - | Subpath | 주요 exports | + | 하위 경로 | 주요 export | | --- | --- | - | `plugin-sdk/runtime` | 폭넓은 런타임/로깅/백업/plugin 설치 helper | - | `plugin-sdk/runtime-env` | 좁은 범위의 런타임 env, logger, timeout, retry, backoff helper | - | `plugin-sdk/channel-runtime-context` | 일반적인 channel runtime-context 등록 및 조회 helper | + | `plugin-sdk/runtime` | 광범위한 런타임/로깅/백업/플러그인 설치 헬퍼 | + | `plugin-sdk/runtime-env` | 좁은 범위의 런타임 env, logger, timeout, retry, backoff 헬퍼 | + | `plugin-sdk/channel-runtime-context` | 일반 채널 런타임 컨텍스트 등록 및 조회 헬퍼 | | `plugin-sdk/runtime-store` | `createPluginRuntimeStore` | - | `plugin-sdk/plugin-runtime` | 공용 plugin command/hook/http/interactive helper | - | `plugin-sdk/hook-runtime` | 공용 webhook/internal hook 파이프라인 helper | - | `plugin-sdk/lazy-runtime` | `createLazyRuntimeModule`, `createLazyRuntimeMethod`, `createLazyRuntimeSurface` 같은 지연 런타임 import/binding helper | - | `plugin-sdk/process-runtime` | 프로세스 exec helper | - | `plugin-sdk/cli-runtime` | CLI 서식 지정, 대기, 버전 helper | - | `plugin-sdk/gateway-runtime` | Gateway client 및 channel-status patch helper | - | `plugin-sdk/config-runtime` | Config 로드/쓰기 helper | - | `plugin-sdk/telegram-command-config` | 번들 Telegram 계약 표면을 사용할 수 없을 때도 Telegram command-name/description 정규화 및 중복/충돌 검사 | - | `plugin-sdk/approval-runtime` | Exec/plugin 승인 helper, 승인-capability 빌더, auth/profile helper, 네이티브 라우팅/런타임 helper | - | `plugin-sdk/reply-runtime` | 공용 수신/reply 런타임 helper, chunking, dispatch, heartbeat, reply planner | - | `plugin-sdk/reply-dispatch-runtime` | 좁은 범위의 reply dispatch/finalize helper | - | `plugin-sdk/reply-history` | `buildHistoryContext`, `recordPendingHistoryEntry`, `clearHistoryEntriesIfEnabled` 같은 공용 짧은 기간 reply-history helper | + | `plugin-sdk/plugin-runtime` | 공유 플러그인 명령/hook/http/interactive 헬퍼 | + | `plugin-sdk/hook-runtime` | 공유 webhook/internal hook 파이프라인 헬퍼 | + | `plugin-sdk/lazy-runtime` | `createLazyRuntimeModule`, `createLazyRuntimeMethod`, `createLazyRuntimeSurface` 같은 지연 런타임 import/바인딩 헬퍼 | + | `plugin-sdk/process-runtime` | 프로세스 exec 헬퍼 | + | `plugin-sdk/cli-runtime` | CLI 서식, 대기, 버전 헬퍼 | + | `plugin-sdk/gateway-runtime` | 게이트웨이 클라이언트 및 채널 상태 패치 헬퍼 | + | `plugin-sdk/config-runtime` | config 로드/쓰기 헬퍼 | + | `plugin-sdk/telegram-command-config` | 번들된 Telegram 계약 표면을 사용할 수 없더라도 Telegram 명령 이름/설명 정규화 및 중복/충돌 검사 | + | `plugin-sdk/approval-runtime` | exec/plugin 승인 헬퍼, 승인 기능 빌더, 인증/프로필 헬퍼, 네이티브 라우팅/런타임 헬퍼 | + | `plugin-sdk/reply-runtime` | 공유 인바운드/응답 런타임 헬퍼, chunking, dispatch, heartbeat, 응답 플래너 | + | `plugin-sdk/reply-dispatch-runtime` | 좁은 범위의 응답 dispatch/finalize 헬퍼 | + | `plugin-sdk/reply-history` | `buildHistoryContext`, `recordPendingHistoryEntry`, `clearHistoryEntriesIfEnabled` 같은 공유 단기 reply-history 헬퍼 | | `plugin-sdk/reply-reference` | `createReplyReferencePlanner` | - | `plugin-sdk/reply-chunking` | 좁은 범위의 텍스트/markdown chunking helper | - | `plugin-sdk/session-store-runtime` | 세션 저장소 경로 + updated-at helper | - | `plugin-sdk/state-paths` | 상태/OAuth 디렉터리 경로 helper | - | `plugin-sdk/routing` | `resolveAgentRoute`, `buildAgentSessionKey`, `resolveDefaultAgentBoundAccountId` 같은 route/session-key/account 바인딩 helper | - | `plugin-sdk/status-helpers` | 공용 channel/account 상태 요약 helper, 런타임 상태 기본값, issue 메타데이터 helper | - | `plugin-sdk/target-resolver-runtime` | 공용 대상 해석 helper | - | `plugin-sdk/string-normalization-runtime` | slug/string 정규화 helper | + | `plugin-sdk/reply-chunking` | 좁은 범위의 텍스트/Markdown chunking 헬퍼 | + | `plugin-sdk/session-store-runtime` | 세션 저장소 경로 + updated-at 헬퍼 | + | `plugin-sdk/state-paths` | 상태/OAuth 디렉터리 경로 헬퍼 | + | `plugin-sdk/routing` | `resolveAgentRoute`, `buildAgentSessionKey`, `resolveDefaultAgentBoundAccountId` 같은 라우트/세션 키/account binding 헬퍼 | + | `plugin-sdk/status-helpers` | 공유 채널/계정 상태 요약 헬퍼, 런타임 상태 기본값, 이슈 메타데이터 헬퍼 | + | `plugin-sdk/target-resolver-runtime` | 공유 대상 해결 헬퍼 | + | `plugin-sdk/string-normalization-runtime` | slug/문자열 정규화 헬퍼 | | `plugin-sdk/request-url` | fetch/request 유사 입력에서 문자열 URL 추출 | - | `plugin-sdk/run-command` | 정규화된 stdout/stderr 결과를 반환하는 시간 제한 command 실행기 | - | `plugin-sdk/param-readers` | 공용 tool/CLI 매개변수 리더 | - | `plugin-sdk/tool-payload` | tool 결과 객체에서 정규화된 payload 추출 | - | `plugin-sdk/tool-send` | tool args에서 정식 send 대상 필드 추출 | - | `plugin-sdk/temp-path` | 공용 임시 다운로드 경로 helper | - | `plugin-sdk/logging-core` | 서브시스템 logger 및 redaction helper | - | `plugin-sdk/markdown-table-runtime` | Markdown 표 모드 helper | - | `plugin-sdk/json-store` | 작은 JSON 상태 읽기/쓰기 helper | - | `plugin-sdk/file-lock` | 재진입 가능한 파일 잠금 helper | - | `plugin-sdk/persistent-dedupe` | 디스크 기반 dedupe cache helper | - | `plugin-sdk/acp-runtime` | ACP 런타임/세션 및 reply-dispatch helper | - | `plugin-sdk/agent-config-primitives` | 좁은 범위의 agent 런타임 config-schema primitives | - | `plugin-sdk/boolean-param` | 느슨한 boolean 매개변수 리더 | - | `plugin-sdk/dangerous-name-runtime` | 위험한 이름 매칭 해석 helper | - | `plugin-sdk/device-bootstrap` | 디바이스 bootstrap 및 페어링 토큰 helper | - | `plugin-sdk/extension-shared` | 공용 passive-channel, 상태, ambient proxy helper primitives | - | `plugin-sdk/models-provider-runtime` | `/models` command/provider reply helper | - | `plugin-sdk/skill-commands-runtime` | Skills command 목록 helper | - | `plugin-sdk/native-command-registry` | 네이티브 command 레지스트리/build/serialize helper | - | `plugin-sdk/provider-zai-endpoint` | Z.AI endpoint 감지 helper | - | `plugin-sdk/infra-runtime` | 시스템 이벤트/heartbeat helper | - | `plugin-sdk/collection-runtime` | 작은 bounded cache helper | - | `plugin-sdk/diagnostic-runtime` | 진단 플래그 및 이벤트 helper | - | `plugin-sdk/error-runtime` | 오류 그래프, 서식 지정, 공용 오류 분류 helper, `isApprovalNotFoundError` | - | `plugin-sdk/fetch-runtime` | 래핑된 fetch, proxy, pinned lookup helper | - | `plugin-sdk/host-runtime` | 호스트명 및 SCP 호스트 정규화 helper | - | `plugin-sdk/retry-runtime` | Retry config 및 retry 실행 helper | - | `plugin-sdk/agent-runtime` | agent 디렉터리/식별자/워크스페이스 helper | - | `plugin-sdk/directory-runtime` | config 기반 디렉터리 질의/dedup | + | `plugin-sdk/run-command` | 정규화된 stdout/stderr 결과를 반환하는 시간 제한 명령 실행기 | + | `plugin-sdk/param-readers` | 일반 도구/CLI 매개변수 읽기 헬퍼 | + | `plugin-sdk/tool-payload` | 도구 결과 객체에서 정규화된 payload 추출 | + | `plugin-sdk/tool-send` | 도구 인수에서 정식 send 대상 필드 추출 | + | `plugin-sdk/temp-path` | 공유 임시 다운로드 경로 헬퍼 | + | `plugin-sdk/logging-core` | 서브시스템 logger 및 민감 정보 가리기 헬퍼 | + | `plugin-sdk/markdown-table-runtime` | Markdown 표 모드 헬퍼 | + | `plugin-sdk/json-store` | 작은 JSON 상태 읽기/쓰기 헬퍼 | + | `plugin-sdk/file-lock` | 재진입 가능한 파일 잠금 헬퍼 | + | `plugin-sdk/persistent-dedupe` | 디스크 기반 dedupe 캐시 헬퍼 | + | `plugin-sdk/acp-runtime` | ACP 런타임/세션 및 reply-dispatch 헬퍼 | + | `plugin-sdk/agent-config-primitives` | 좁은 범위의 에이전트 런타임 config 스키마 프리미티브 | + | `plugin-sdk/boolean-param` | 느슨한 불리언 매개변수 읽기 헬퍼 | + | `plugin-sdk/dangerous-name-runtime` | 위험한 이름 매칭 해결 헬퍼 | + | `plugin-sdk/device-bootstrap` | 디바이스 bootstrap 및 페어링 토큰 헬퍼 | + | `plugin-sdk/extension-shared` | 공유 passive-channel, 상태, ambient proxy 헬퍼 프리미티브 | + | `plugin-sdk/models-provider-runtime` | `/models` 명령/provider 응답 헬퍼 | + | `plugin-sdk/skill-commands-runtime` | Skills 명령 목록 헬퍼 | + | `plugin-sdk/native-command-registry` | 네이티브 명령 레지스트리/build/serialize 헬퍼 | + | `plugin-sdk/agent-harness` | 저수준 에이전트 하니스를 위한 실험적 신뢰 플러그인 표면: 하니스 타입, 활성 실행 steer/abort 헬퍼, OpenClaw 도구 브리지 헬퍼, 시도 결과 유틸리티 | + | `plugin-sdk/provider-zai-endpoint` | Z.AI 엔드포인트 감지 헬퍼 | + | `plugin-sdk/infra-runtime` | 시스템 이벤트/heartbeat 헬퍼 | + | `plugin-sdk/collection-runtime` | 작은 bounded cache 헬퍼 | + | `plugin-sdk/diagnostic-runtime` | 진단 플래그 및 이벤트 헬퍼 | + | `plugin-sdk/error-runtime` | 오류 그래프, 서식 지정, 공유 오류 분류 헬퍼, `isApprovalNotFoundError` | + | `plugin-sdk/fetch-runtime` | 래핑된 fetch, 프록시, pinned lookup 헬퍼 | + | `plugin-sdk/host-runtime` | 호스트명 및 SCP 호스트 정규화 헬퍼 | + | `plugin-sdk/retry-runtime` | retry config 및 retry 실행기 헬퍼 | + | `plugin-sdk/agent-runtime` | 에이전트 디렉터리/ID/workspace 헬퍼 | + | `plugin-sdk/directory-runtime` | config 기반 디렉터리 조회/dedup | | `plugin-sdk/keyed-async-queue` | `KeyedAsyncQueue` | - - | Subpath | 주요 exports | + + | 하위 경로 | 주요 export | | --- | --- | - | `plugin-sdk/media-runtime` | 공용 미디어 fetch/transform/store helper 및 미디어 payload 빌더 | - | `plugin-sdk/media-generation-runtime` | 공용 media-generation failover helper, 후보 선택, 모델 누락 메시지 처리 | - | `plugin-sdk/media-understanding` | Media understanding provider 타입 및 provider용 이미지/오디오 helper export | - | `plugin-sdk/text-runtime` | assistant-visible-text 제거, markdown render/chunking/table helper, redaction helper, directive-tag helper, safe-text 유틸리티 같은 공용 텍스트/markdown/로깅 helper | - | `plugin-sdk/text-chunking` | 송신 텍스트 chunking helper | - | `plugin-sdk/speech` | Speech provider 타입 및 provider용 directive, 레지스트리, 검증 helper | - | `plugin-sdk/speech-core` | 공용 speech provider 타입, 레지스트리, directive, 정규화 helper | - | `plugin-sdk/realtime-transcription` | Realtime transcription provider 타입 및 레지스트리 helper | - | `plugin-sdk/realtime-voice` | Realtime voice provider 타입 및 레지스트리 helper | - | `plugin-sdk/image-generation` | Image generation provider 타입 | - | `plugin-sdk/image-generation-core` | 공용 image-generation 타입, failover, auth, 레지스트리 helper | - | `plugin-sdk/music-generation` | Music generation provider/request/result 타입 | - | `plugin-sdk/music-generation-core` | 공용 music-generation 타입, failover helper, provider 조회, model-ref 파싱 | - | `plugin-sdk/video-generation` | Video generation provider/request/result 타입 | - | `plugin-sdk/video-generation-core` | 공용 video-generation 타입, failover helper, provider 조회, model-ref 파싱 | - | `plugin-sdk/webhook-targets` | Webhook 대상 레지스트리 및 route-install helper | - | `plugin-sdk/webhook-path` | Webhook 경로 정규화 helper | - | `plugin-sdk/web-media` | 공용 원격/로컬 미디어 로딩 helper | - | `plugin-sdk/zod` | Plugin SDK 소비자를 위한 재export된 `zod` | + | `plugin-sdk/media-runtime` | 공유 미디어 fetch/transform/store 헬퍼와 미디어 payload 빌더 | + | `plugin-sdk/media-generation-runtime` | 공유 미디어 생성 failover 헬퍼, 후보 선택, 누락된 모델 메시지 처리 | + | `plugin-sdk/media-understanding` | 미디어 이해 provider 타입과 provider용 image/audio 헬퍼 export | + | `plugin-sdk/text-runtime` | 어시스턴트 표시 텍스트 제거, Markdown 렌더/chunking/표 헬퍼, 민감 정보 가리기 헬퍼, directive 태그 헬퍼, safe-text 유틸리티 같은 공유 텍스트/Markdown/로깅 헬퍼 | + | `plugin-sdk/text-chunking` | 아웃바운드 텍스트 chunking 헬퍼 | + | `plugin-sdk/speech` | 음성 provider 타입과 provider용 directive, 레지스트리, 검증 헬퍼 | + | `plugin-sdk/speech-core` | 공유 음성 provider 타입, 레지스트리, directive, 정규화 헬퍼 | + | `plugin-sdk/realtime-transcription` | 실시간 전사 provider 타입 및 레지스트리 헬퍼 | + | `plugin-sdk/realtime-voice` | 실시간 음성 provider 타입 및 레지스트리 헬퍼 | + | `plugin-sdk/image-generation` | 이미지 생성 provider 타입 | + | `plugin-sdk/image-generation-core` | 공유 이미지 생성 타입, failover, 인증, 레지스트리 헬퍼 | + | `plugin-sdk/music-generation` | 음악 생성 provider/요청/결과 타입 | + | `plugin-sdk/music-generation-core` | 공유 음악 생성 타입, failover 헬퍼, provider 조회, model-ref 파싱 | + | `plugin-sdk/video-generation` | 비디오 생성 provider/요청/결과 타입 | + | `plugin-sdk/video-generation-core` | 공유 비디오 생성 타입, failover 헬퍼, provider 조회, model-ref 파싱 | + | `plugin-sdk/webhook-targets` | webhook 대상 레지스트리 및 라우트 설치 헬퍼 | + | `plugin-sdk/webhook-path` | webhook 경로 정규화 헬퍼 | + | `plugin-sdk/web-media` | 공유 원격/로컬 미디어 로딩 헬퍼 | + | `plugin-sdk/zod` | 플러그인 SDK 소비자를 위한 `zod` 재내보내기 | | `plugin-sdk/testing` | `installCommonResolveTargetErrorCases`, `shouldAckReaction` | - - | Subpath | 주요 exports | + + | 하위 경로 | 주요 export | | --- | --- | - | `plugin-sdk/memory-core` | manager/config/file/CLI helper를 위한 번들 memory-core helper 표면 | - | `plugin-sdk/memory-core-engine-runtime` | Memory index/search 런타임 파사드 | - | `plugin-sdk/memory-core-host-engine-foundation` | Memory host foundation engine exports | - | `plugin-sdk/memory-core-host-engine-embeddings` | Memory host embedding engine exports | - | `plugin-sdk/memory-core-host-engine-qmd` | Memory host QMD engine exports | - | `plugin-sdk/memory-core-host-engine-storage` | Memory host storage engine exports | - | `plugin-sdk/memory-core-host-multimodal` | Memory host multimodal helper | - | `plugin-sdk/memory-core-host-query` | Memory host query helper | - | `plugin-sdk/memory-core-host-secret` | Memory host secret helper | - | `plugin-sdk/memory-core-host-events` | Memory host 이벤트 저널 helper | - | `plugin-sdk/memory-core-host-status` | Memory host 상태 helper | - | `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI 런타임 helper | - | `plugin-sdk/memory-core-host-runtime-core` | Memory host core 런타임 helper | - | `plugin-sdk/memory-core-host-runtime-files` | Memory host 파일/런타임 helper | - | `plugin-sdk/memory-host-core` | 메모리 host core 런타임 helper를 위한 vendor-neutral 별칭 | - | `plugin-sdk/memory-host-events` | 메모리 host 이벤트 저널 helper를 위한 vendor-neutral 별칭 | - | `plugin-sdk/memory-host-files` | 메모리 host 파일/런타임 helper를 위한 vendor-neutral 별칭 | - | `plugin-sdk/memory-host-markdown` | 메모리 인접 plugins를 위한 공용 managed-markdown helper | - | `plugin-sdk/memory-host-search` | search-manager 접근을 위한 활성 메모리 런타임 파사드 | - | `plugin-sdk/memory-host-status` | 메모리 host 상태 helper를 위한 vendor-neutral 별칭 | - | `plugin-sdk/memory-lancedb` | 번들 memory-lancedb helper 표면 | + | `plugin-sdk/memory-core` | manager/config/file/CLI 헬퍼를 위한 번들된 memory-core 헬퍼 표면 | + | `plugin-sdk/memory-core-engine-runtime` | 메모리 인덱스/검색 런타임 파사드 | + | `plugin-sdk/memory-core-host-engine-foundation` | 메모리 호스트 foundation 엔진 export | + | `plugin-sdk/memory-core-host-engine-embeddings` | 메모리 호스트 embedding 엔진 export | + | `plugin-sdk/memory-core-host-engine-qmd` | 메모리 호스트 QMD 엔진 export | + | `plugin-sdk/memory-core-host-engine-storage` | 메모리 호스트 스토리지 엔진 export | + | `plugin-sdk/memory-core-host-multimodal` | 메모리 호스트 멀티모달 헬퍼 | + | `plugin-sdk/memory-core-host-query` | 메모리 호스트 쿼리 헬퍼 | + | `plugin-sdk/memory-core-host-secret` | 메모리 호스트 secret 헬퍼 | + | `plugin-sdk/memory-core-host-events` | 메모리 호스트 이벤트 저널 헬퍼 | + | `plugin-sdk/memory-core-host-status` | 메모리 호스트 상태 헬퍼 | + | `plugin-sdk/memory-core-host-runtime-cli` | 메모리 호스트 CLI 런타임 헬퍼 | + | `plugin-sdk/memory-core-host-runtime-core` | 메모리 호스트 core 런타임 헬퍼 | + | `plugin-sdk/memory-core-host-runtime-files` | 메모리 호스트 파일/런타임 헬퍼 | + | `plugin-sdk/memory-host-core` | 메모리 호스트 core 런타임 헬퍼의 벤더 중립 별칭 | + | `plugin-sdk/memory-host-events` | 메모리 호스트 이벤트 저널 헬퍼의 벤더 중립 별칭 | + | `plugin-sdk/memory-host-files` | 메모리 호스트 파일/런타임 헬퍼의 벤더 중립 별칭 | + | `plugin-sdk/memory-host-markdown` | 메모리 인접 플러그인을 위한 공유 managed-markdown 헬퍼 | + | `plugin-sdk/memory-host-search` | search-manager 액세스를 위한 활성 메모리 런타임 파사드 | + | `plugin-sdk/memory-host-status` | 메모리 호스트 상태 헬퍼의 벤더 중립 별칭 | + | `plugin-sdk/memory-lancedb` | 번들된 memory-lancedb 헬퍼 표면 | - - | Family | 현재 하위 경로 | 의도된 용도 | + + | 계열 | 현재 하위 경로 | 의도된 용도 | | --- | --- | --- | - | Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | 번들 browser plugin 지원 helper(`browser-support`는 호환성 barrel로 유지됨) | - | Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | 번들 Matrix helper/런타임 표면 | - | Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | 번들 LINE helper/런타임 표면 | - | IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | 번들 IRC helper 표면 | - | Channel 전용 helper | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | 번들 channel 호환성/helper seam | - | Auth/plugin 전용 helper | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | 번들 기능/plugin helper seam; `plugin-sdk/github-copilot-token`은 현재 `DEFAULT_COPILOT_API_BASE_URL`, `deriveCopilotApiBaseUrlFromToken`, `resolveCopilotApiToken`을 export합니다 | + | Browser | `plugin-sdk/browser-cdp`, `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-control-auth`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-profiles`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/browser-support` | 번들된 browser 플러그인 지원 헬퍼(`browser-support`는 호환성 배럴로 유지됨) | + | Matrix | `plugin-sdk/matrix`, `plugin-sdk/matrix-helper`, `plugin-sdk/matrix-runtime-heavy`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/matrix-runtime-surface`, `plugin-sdk/matrix-surface`, `plugin-sdk/matrix-thread-bindings` | 번들된 Matrix 헬퍼/런타임 표면 | + | Line | `plugin-sdk/line`, `plugin-sdk/line-core`, `plugin-sdk/line-runtime`, `plugin-sdk/line-surface` | 번들된 LINE 헬퍼/런타임 표면 | + | IRC | `plugin-sdk/irc`, `plugin-sdk/irc-surface` | 번들된 IRC 헬퍼 표면 | + | 채널별 헬퍼 | `plugin-sdk/googlechat`, `plugin-sdk/zalouser`, `plugin-sdk/bluebubbles`, `plugin-sdk/bluebubbles-policy`, `plugin-sdk/mattermost`, `plugin-sdk/mattermost-policy`, `plugin-sdk/feishu-conversation`, `plugin-sdk/msteams`, `plugin-sdk/nextcloud-talk`, `plugin-sdk/nostr`, `plugin-sdk/tlon`, `plugin-sdk/twitch` | 번들된 채널 호환성/헬퍼 seam | + | 인증/플러그인별 헬퍼 | `plugin-sdk/github-copilot-login`, `plugin-sdk/github-copilot-token`, `plugin-sdk/diagnostics-otel`, `plugin-sdk/diffs`, `plugin-sdk/llm-task`, `plugin-sdk/thread-ownership`, `plugin-sdk/voice-call` | 번들된 기능/플러그인 헬퍼 seam. 현재 `plugin-sdk/github-copilot-token`은 `DEFAULT_COPILOT_API_BASE_URL`, `deriveCopilotApiBaseUrlFromToken`, `resolveCopilotApiToken`을 export합니다. | @@ -287,53 +302,56 @@ import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core"; `register(api)` 콜백은 다음 메서드를 가진 `OpenClawPluginApi` 객체를 받습니다. -### Capability 등록 +### 기능 등록 -| Method | 등록되는 항목 | -| ------------------------------------------------ | -------------------------------- | -| `api.registerProvider(...)` | 텍스트 추론(LLM) | -| `api.registerCliBackend(...)` | 로컬 CLI 추론 backend | -| `api.registerChannel(...)` | 메시징 channel | -| `api.registerSpeechProvider(...)` | 텍스트 음성 변환 / STT 합성 | -| `api.registerRealtimeTranscriptionProvider(...)` | 스트리밍 realtime transcription | -| `api.registerRealtimeVoiceProvider(...)` | 양방향 realtime 음성 세션 | -| `api.registerMediaUnderstandingProvider(...)` | 이미지/오디오/비디오 분석 | -| `api.registerImageGenerationProvider(...)` | 이미지 생성 | -| `api.registerMusicGenerationProvider(...)` | 음악 생성 | -| `api.registerVideoGenerationProvider(...)` | 비디오 생성 | -| `api.registerWebFetchProvider(...)` | 웹 fetch / scrape provider | -| `api.registerWebSearchProvider(...)` | 웹 검색 | +| 메서드 | 등록 대상 | +| ------------------------------------------------ | ------------------------------------- | +| `api.registerProvider(...)` | 텍스트 추론(LLM) | +| `api.registerAgentHarness(...)` | 실험적 저수준 에이전트 실행기 | +| `api.registerCliBackend(...)` | 로컬 CLI 추론 백엔드 | +| `api.registerChannel(...)` | 메시징 채널 | +| `api.registerSpeechProvider(...)` | 텍스트 음성 변환 / STT 합성 | +| `api.registerRealtimeTranscriptionProvider(...)` | 스트리밍 실시간 전사 | +| `api.registerRealtimeVoiceProvider(...)` | 양방향 실시간 음성 세션 | +| `api.registerMediaUnderstandingProvider(...)` | 이미지/오디오/비디오 분석 | +| `api.registerImageGenerationProvider(...)` | 이미지 생성 | +| `api.registerMusicGenerationProvider(...)` | 음악 생성 | +| `api.registerVideoGenerationProvider(...)` | 비디오 생성 | +| `api.registerWebFetchProvider(...)` | 웹 fetch / scrape provider | +| `api.registerWebSearchProvider(...)` | 웹 검색 | -### 도구 및 commands +### 도구 및 명령 -| Method | 등록되는 항목 | -| ------------------------------- | ---------------------------------------------- | -| `api.registerTool(tool, opts?)` | agent 도구(필수 또는 `{ optional: true }`) | -| `api.registerCommand(def)` | 사용자 지정 command(LLM 우회) | +| 메서드 | 등록 대상 | +| ------------------------------- | --------------------------------------------- | +| `api.registerTool(tool, opts?)` | 에이전트 도구(필수 또는 `{ optional: true }`) | +| `api.registerCommand(def)` | 사용자 지정 명령(LLM 우회) | ### 인프라 -| Method | 등록되는 항목 | -| ---------------------------------------------- | ---------------------------------------- | -| `api.registerHook(events, handler, opts?)` | 이벤트 hook | -| `api.registerHttpRoute(params)` | Gateway HTTP endpoint | -| `api.registerGatewayMethod(name, handler)` | Gateway RPC 메서드 | -| `api.registerCli(registrar, opts?)` | CLI 하위 명령 | -| `api.registerService(service)` | 백그라운드 서비스 | -| `api.registerInteractiveHandler(registration)` | 대화형 handler | -| `api.registerMemoryPromptSupplement(builder)` | 추가형 memory 인접 프롬프트 섹션 | -| `api.registerMemoryCorpusSupplement(adapter)` | 추가형 memory 검색/읽기 corpus | +| 메서드 | 등록 대상 | +| ---------------------------------------------- | --------------------------------------- | +| `api.registerHook(events, handler, opts?)` | 이벤트 hook | +| `api.registerHttpRoute(params)` | 게이트웨이 HTTP 엔드포인트 | +| `api.registerGatewayMethod(name, handler)` | 게이트웨이 RPC 메서드 | +| `api.registerCli(registrar, opts?)` | CLI 하위 명령 | +| `api.registerService(service)` | 백그라운드 서비스 | +| `api.registerInteractiveHandler(registration)` | 대화형 핸들러 | +| `api.registerMemoryPromptSupplement(builder)` | 추가형 메모리 인접 프롬프트 섹션 | +| `api.registerMemoryCorpusSupplement(adapter)` | 추가형 메모리 검색/읽기 corpus | -예약된 core 관리자 네임스페이스(`config.*`, `exec.approvals.*`, `wizard.*`, `update.*`)는 plugin이 더 좁은 gateway 메서드 범위를 할당하려고 해도 항상 `operator.admin`으로 유지됩니다. plugin 소유 메서드에는 plugin 전용 접두사를 사용하는 것이 좋습니다. +예약된 core 관리자 네임스페이스(`config.*`, `exec.approvals.*`, `wizard.*`, +`update.*`)는 플러그인이 더 좁은 게이트웨이 메서드 scope를 할당하려고 해도 항상 `operator.admin`으로 유지됩니다. 플러그인 소유 메서드에는 플러그인별 접두사를 우선 사용하세요. ### CLI 등록 메타데이터 -`api.registerCli(registrar, opts?)`는 두 가지 종류의 최상위 메타데이터를 받습니다. +`api.registerCli(registrar, opts?)`는 두 종류의 최상위 메타데이터를 받습니다. -- `commands`: registrar가 소유한 명시적 command 루트 -- `descriptors`: 루트 CLI help, 라우팅, 지연 plugin CLI 등록에 사용되는 파싱 시점 command descriptor +- `commands`: registrar가 소유하는 명시적 명령 루트 +- `descriptors`: 루트 CLI 도움말, 라우팅, 지연 플러그인 CLI 등록에 사용되는 파싱 시점 명령 descriptor -plugin command를 일반 루트 CLI 경로에서 지연 로드 상태로 유지하려면, 해당 registrar가 노출하는 모든 최상위 command 루트를 포괄하는 `descriptors`를 제공하세요. +플러그인 명령이 일반 루트 CLI 경로에서 계속 지연 로드되게 하려면, +해당 registrar가 노출하는 모든 최상위 명령 루트를 포괄하는 `descriptors`를 제공하세요. ```typescript api.registerCli( @@ -345,7 +363,7 @@ api.registerCli( descriptors: [ { name: "matrix", - description: "Matrix 계정, 검증, 디바이스 및 프로필 상태 관리", + description: "Matrix 계정, 검증, 디바이스, 프로필 상태를 관리합니다", hasSubcommands: true, }, ], @@ -353,107 +371,131 @@ api.registerCli( ); ``` -지연 루트 CLI 등록이 필요하지 않을 때만 `commands`를 단독으로 사용하세요. 이 eager 호환성 경로는 여전히 지원되지만, 파싱 시점 지연 로드를 위한 descriptor 기반 placeholder는 설치하지 않습니다. +일반 루트 CLI 등록에 지연 로딩이 필요하지 않을 때만 `commands`를 단독으로 사용하세요. +이 eager 호환성 경로는 계속 지원되지만, 파싱 시점 지연 로딩을 위한 +descriptor 기반 placeholder는 설치하지 않습니다. -### CLI backend 등록 +### CLI 백엔드 등록 -`api.registerCliBackend(...)`를 사용하면 plugin이 `codex-cli` 같은 로컬 AI CLI backend의 기본 config를 소유할 수 있습니다. +`api.registerCliBackend(...)`를 사용하면 플러그인이 `codex-cli` 같은 로컬 +AI CLI 백엔드의 기본 config를 소유할 수 있습니다. -- backend `id`는 `codex-cli/gpt-5` 같은 model ref의 provider 접두사가 됩니다. -- backend `config`는 `agents.defaults.cliBackends.`와 동일한 형태를 사용합니다. -- 사용자 config가 여전히 우선합니다. OpenClaw는 CLI를 실행하기 전에 plugin 기본값 위에 `agents.defaults.cliBackends.`를 병합합니다. -- 병합 후 backend에 호환성 재작성(예: 이전 플래그 형태 정규화)이 필요하다면 `normalizeConfig`를 사용하세요. +- 백엔드 `id`는 `codex-cli/gpt-5` 같은 모델 ref의 provider 접두사가 됩니다. +- 백엔드 `config`는 `agents.defaults.cliBackends.`와 동일한 형태를 사용합니다. +- 사용자 config가 여전히 우선합니다. OpenClaw는 CLI를 실행하기 전에 + 플러그인 기본값 위에 `agents.defaults.cliBackends.`를 병합합니다. +- 백엔드가 병합 후 호환성 재작성이 필요하면 `normalizeConfig`를 사용하세요 + (예: 오래된 플래그 형태 정규화). -### 배타적 슬롯 +### 독점 슬롯 -| Method | 등록되는 항목 | -| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `api.registerContextEngine(id, factory)` | 컨텍스트 엔진(한 번에 하나만 활성). `assemble()` 콜백은 `availableTools`와 `citationsMode`를 받아 엔진이 프롬프트 추가 내용을 맞춤 조정할 수 있게 합니다. | -| `api.registerMemoryCapability(capability)` | 통합 memory capability | -| `api.registerMemoryPromptSection(builder)` | Memory 프롬프트 섹션 빌더 | -| `api.registerMemoryFlushPlan(resolver)` | Memory flush plan resolver | -| `api.registerMemoryRuntime(runtime)` | Memory 런타임 adapter | +| 메서드 | 등록 대상 | +| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `api.registerContextEngine(id, factory)` | 컨텍스트 엔진(한 번에 하나만 활성). `assemble()` 콜백은 엔진이 프롬프트 추가를 조정할 수 있도록 `availableTools`와 `citationsMode`를 받습니다. | +| `api.registerMemoryCapability(capability)` | 통합 메모리 기능 | +| `api.registerMemoryPromptSection(builder)` | 메모리 프롬프트 섹션 빌더 | +| `api.registerMemoryFlushPlan(resolver)` | 메모리 flush 계획 해결기 | +| `api.registerMemoryRuntime(runtime)` | 메모리 런타임 어댑터 | -### Memory embedding adapters +### 메모리 임베딩 어댑터 -| Method | 등록되는 항목 | -| ---------------------------------------------- | -------------------------------------------------- | -| `api.registerMemoryEmbeddingProvider(adapter)` | 활성 plugin용 memory embedding adapter | +| 메서드 | 등록 대상 | +| ---------------------------------------------- | ---------------------------------------------- | +| `api.registerMemoryEmbeddingProvider(adapter)` | 활성 플러그인용 메모리 임베딩 어댑터 | -- `registerMemoryCapability`가 권장되는 배타적 memory-plugin API입니다. -- `registerMemoryCapability`는 companion plugins가 특정 memory plugin의 private 레이아웃에 직접 접근하지 않고 `openclaw/plugin-sdk/memory-host-core`를 통해 export된 memory artifact를 사용할 수 있도록 `publicArtifacts.listArtifacts(...)`도 노출할 수 있습니다. -- `registerMemoryPromptSection`, `registerMemoryFlushPlan`, `registerMemoryRuntime`는 레거시 호환용 배타적 memory-plugin API입니다. -- `registerMemoryEmbeddingProvider`를 사용하면 활성 memory plugin이 하나 이상의 embedding adapter id(예: `openai`, `gemini`, 또는 plugin이 정의한 사용자 지정 id)를 등록할 수 있습니다. -- `agents.defaults.memorySearch.provider` 및 `agents.defaults.memorySearch.fallback` 같은 사용자 config는 이러한 등록된 adapter id를 기준으로 해석됩니다. +- `registerMemoryCapability`가 선호되는 독점 메모리 플러그인 API입니다. +- `registerMemoryCapability`는 동반 플러그인이 특정 메모리 플러그인의 비공개 레이아웃에 접근하는 대신 + `openclaw/plugin-sdk/memory-host-core`를 통해 export된 메모리 아티팩트를 소비할 수 있도록 + `publicArtifacts.listArtifacts(...)`도 노출할 수 있습니다. +- `registerMemoryPromptSection`, `registerMemoryFlushPlan`, `registerMemoryRuntime`은 + 레거시 호환 독점 메모리 플러그인 API입니다. +- `registerMemoryEmbeddingProvider`를 사용하면 활성 메모리 플러그인이 + 하나 이상의 임베딩 어댑터 id(예: `openai`, `gemini`, 또는 플러그인 정의 사용자 지정 id)를 등록할 수 있습니다. +- `agents.defaults.memorySearch.provider`, + `agents.defaults.memorySearch.fallback` 같은 사용자 config는 + 이렇게 등록된 어댑터 id를 기준으로 해결됩니다. -### 이벤트 및 lifecycle +### 이벤트 및 생명주기 -| Method | 동작 | -| -------------------------------------------- | ---------------------------- | -| `api.on(hookName, handler, opts?)` | 타입 지정된 lifecycle hook | -| `api.onConversationBindingResolved(handler)` | 대화 바인딩 콜백 | +| 메서드 | 동작 | +| -------------------------------------------- | ----------------------------- | +| `api.on(hookName, handler, opts?)` | 타입 지정 생명주기 hook | +| `api.onConversationBindingResolved(handler)` | 대화 바인딩 콜백 | ### Hook 결정 의미 -- `before_tool_call`: `{ block: true }`를 반환하면 종료됩니다. 어떤 handler든 이를 설정하면 더 낮은 우선순위 handler는 건너뜁니다. -- `before_tool_call`: `{ block: false }`를 반환하면 결정 없음(`block` 생략과 동일)으로 처리되며, override가 아닙니다. -- `before_install`: `{ block: true }`를 반환하면 종료됩니다. 어떤 handler든 이를 설정하면 더 낮은 우선순위 handler는 건너뜁니다. -- `before_install`: `{ block: false }`를 반환하면 결정 없음(`block` 생략과 동일)으로 처리되며, override가 아닙니다. -- `reply_dispatch`: `{ handled: true, ... }`를 반환하면 종료됩니다. 어떤 handler든 dispatch를 처리했다고 선언하면 더 낮은 우선순위 handler와 기본 모델 dispatch 경로를 건너뜁니다. -- `message_sending`: `{ cancel: true }`를 반환하면 종료됩니다. 어떤 handler든 이를 설정하면 더 낮은 우선순위 handler는 건너뜁니다. -- `message_sending`: `{ cancel: false }`를 반환하면 결정 없음(`cancel` 생략과 동일)으로 처리되며, override가 아닙니다. +- `before_tool_call`: `{ block: true }`를 반환하면 최종 결정입니다. 어떤 핸들러든 이것을 설정하면 우선순위가 더 낮은 핸들러는 건너뜁니다. +- `before_tool_call`: `{ block: false }`를 반환하면 결정 없음으로 취급됩니다(`block` 생략과 동일). 재정의가 아닙니다. +- `before_install`: `{ block: true }`를 반환하면 최종 결정입니다. 어떤 핸들러든 이것을 설정하면 우선순위가 더 낮은 핸들러는 건너뜁니다. +- `before_install`: `{ block: false }`를 반환하면 결정 없음으로 취급됩니다(`block` 생략과 동일). 재정의가 아닙니다. +- `reply_dispatch`: `{ handled: true, ... }`를 반환하면 최종 결정입니다. 어떤 핸들러든 디스패치를 맡으면 우선순위가 더 낮은 핸들러와 기본 모델 디스패치 경로는 건너뜁니다. +- `message_sending`: `{ cancel: true }`를 반환하면 최종 결정입니다. 어떤 핸들러든 이것을 설정하면 우선순위가 더 낮은 핸들러는 건너뜁니다. +- `message_sending`: `{ cancel: false }`를 반환하면 결정 없음으로 취급됩니다(`cancel` 생략과 동일). 재정의가 아닙니다. ### API 객체 필드 -| Field | Type | 설명 | -| ------------------------ | ------------------------- | -------------------------------------------------------------------------------------------- | -| `api.id` | `string` | Plugin id | -| `api.name` | `string` | 표시 이름 | -| `api.version` | `string?` | Plugin 버전(선택 사항) | -| `api.description` | `string?` | Plugin 설명(선택 사항) | -| `api.source` | `string` | Plugin 소스 경로 | -| `api.rootDir` | `string?` | Plugin 루트 디렉터리(선택 사항) | -| `api.config` | `OpenClawConfig` | 현재 config 스냅샷(사용 가능할 경우 활성 in-memory 런타임 스냅샷) | -| `api.pluginConfig` | `Record` | `plugins.entries..config`의 plugin 전용 config | -| `api.runtime` | `PluginRuntime` | [Runtime helpers](/ko/plugins/sdk-runtime) | -| `api.logger` | `PluginLogger` | 범위가 지정된 logger(`debug`, `info`, `warn`, `error`) | -| `api.registrationMode` | `PluginRegistrationMode` | 현재 로드 모드. `"setup-runtime"`은 가벼운 전체 entry 이전 시작/setup 구간입니다 | -| `api.resolvePath(input)` | `(string) => string` | plugin 루트를 기준으로 경로 해석 | +| 필드 | 타입 | 설명 | +| ------------------------ | ------------------------- | ------------------------------------------------------------------------------------------- | +| `api.id` | `string` | 플러그인 id | +| `api.name` | `string` | 표시 이름 | +| `api.version` | `string?` | 플러그인 버전(선택 사항) | +| `api.description` | `string?` | 플러그인 설명(선택 사항) | +| `api.source` | `string` | 플러그인 소스 경로 | +| `api.rootDir` | `string?` | 플러그인 루트 디렉터리(선택 사항) | +| `api.config` | `OpenClawConfig` | 현재 config 스냅샷(사용 가능한 경우 활성 in-memory 런타임 스냅샷) | +| `api.pluginConfig` | `Record` | `plugins.entries..config`의 플러그인별 config | +| `api.runtime` | `PluginRuntime` | [런타임 헬퍼](/ko/plugins/sdk-runtime) | +| `api.logger` | `PluginLogger` | 범위 지정 logger(`debug`, `info`, `warn`, `error`) | +| `api.registrationMode` | `PluginRegistrationMode` | 현재 로드 모드. `"setup-runtime"`은 가벼운 전체 엔트리 전 시작/startup/setup 구간입니다 | +| `api.resolvePath(input)` | `(string) => string` | 플러그인 루트를 기준으로 경로 해결 | ## 내부 모듈 규칙 -plugin 내부에서는 내부 import에 로컬 barrel 파일을 사용하세요. +플러그인 내부에서는 내부 import에 로컬 배럴 파일을 사용하세요. ``` my-plugin/ - api.ts # 외부 소비자를 위한 public exports - runtime-api.ts # 내부 전용 런타임 exports - index.ts # Plugin entry point - setup-entry.ts # 가벼운 setup 전용 entry(선택 사항) + api.ts # 외부 소비자를 위한 공개 export + runtime-api.ts # 내부 전용 런타임 export + index.ts # 플러그인 엔트리포인트 + setup-entry.ts # 가벼운 setup 전용 엔트리(선택 사항) ``` - 프로덕션 코드에서 `openclaw/plugin-sdk/`을 통해 자신의 plugin을 절대 import하지 마세요. 내부 import는 `./api.ts` 또는 `./runtime-api.ts`를 통해 처리하세요. SDK 경로는 외부 계약 전용입니다. + 프로덕션 코드에서 절대로 `openclaw/plugin-sdk/`을 통해 + 자기 자신의 플러그인을 import하지 마세요. 내부 import는 `./api.ts` 또는 + `./runtime-api.ts`를 통해 연결하세요. SDK 경로는 외부 계약 전용입니다. -파사드로 로드되는 번들 plugin public 표면(`api.ts`, `runtime-api.ts`, `index.ts`, `setup-entry.ts` 및 유사한 public entry 파일)은 이제 OpenClaw가 이미 실행 중일 때 활성 런타임 config 스냅샷을 우선 사용합니다. 아직 런타임 스냅샷이 없으면 디스크의 해석된 config 파일로 폴백합니다. +파사드 로드된 번들 플러그인 공개 표면(`api.ts`, `runtime-api.ts`, +`index.ts`, `setup-entry.ts`, 그 밖의 유사한 공개 엔트리 파일)은 이제 +OpenClaw가 이미 실행 중일 때 활성 런타임 config 스냅샷을 우선 사용합니다. +아직 런타임 스냅샷이 없으면 디스크의 해결된 config 파일로 폴백합니다. -Provider plugins는 helper가 의도적으로 provider 전용이고 아직 일반적인 SDK 하위 경로에 속하지 않을 경우 좁은 범위의 plugin 로컬 계약 barrel도 노출할 수 있습니다. 현재 번들 예시: Anthropic provider는 Anthropic 베타 헤더와 `service_tier` 로직을 일반적인 `plugin-sdk/*` 계약으로 올리는 대신 Claude stream helper를 자체 public `api.ts` / `contract-api.ts` seam에 유지합니다. +provider plugin은 헬퍼가 의도적으로 provider 전용이고 아직 일반 SDK +하위 경로에 속하지 않을 때 좁은 범위의 플러그인 로컬 계약 배럴을 노출할 수도 있습니다. +현재 번들 예시: Anthropic provider는 Anthropic 베타 헤더와 `service_tier` +로직을 일반 `plugin-sdk/*` 계약으로 승격하는 대신, Claude stream 헬퍼를 자체 공개 `api.ts` / `contract-api.ts` seam에 유지합니다. 그 밖의 현재 번들 예시: -- `@openclaw/openai-provider`: `api.ts`는 provider 빌더, 기본 model helper, realtime provider 빌더를 export합니다 -- `@openclaw/openrouter-provider`: `api.ts`는 provider 빌더와 onboarding/config helper를 export합니다 +- `@openclaw/openai-provider`: `api.ts`는 provider 빌더, + 기본 모델 헬퍼, 실시간 provider 빌더를 export합니다 +- `@openclaw/openrouter-provider`: `api.ts`는 provider 빌더와 + 온보딩/config 헬퍼를 export합니다 - 확장 프로덕션 코드도 `openclaw/plugin-sdk/` import를 피해야 합니다. helper가 정말 공용이어야 한다면 두 plugins를 결합하는 대신 `openclaw/plugin-sdk/speech`, `.../provider-model-shared` 또는 다른 capability 지향 표면 같은 중립적인 SDK 하위 경로로 승격하세요. + 확장 프로덕션 코드 역시 `openclaw/plugin-sdk/` + import를 피해야 합니다. 헬퍼가 진짜로 공유되어야 한다면, 두 플러그인을 결합하는 대신 + `openclaw/plugin-sdk/speech`, `.../provider-model-shared` 또는 다른 + 기능 중심 표면 같은 중립적인 SDK 하위 경로로 승격하세요. ## 관련 문서 -- [Entry Points](/ko/plugins/sdk-entrypoints) — `definePluginEntry` 및 `defineChannelPluginEntry` 옵션 -- [Runtime Helpers](/ko/plugins/sdk-runtime) — 전체 `api.runtime` 네임스페이스 참조 -- [Setup and Config](/ko/plugins/sdk-setup) — 패키징, 매니페스트, config 스키마 -- [Testing](/ko/plugins/sdk-testing) — 테스트 유틸리티 및 lint 규칙 -- [SDK Migration](/ko/plugins/sdk-migration) — 더 이상 권장되지 않는 표면에서 마이그레이션 -- [Plugin Internals](/ko/plugins/architecture) — 심화 아키텍처 및 capability 모델 +- [엔트리포인트](/ko/plugins/sdk-entrypoints) — `definePluginEntry` 및 `defineChannelPluginEntry` 옵션 +- [런타임 헬퍼](/ko/plugins/sdk-runtime) — 전체 `api.runtime` 네임스페이스 참조 +- [설정 및 Config](/ko/plugins/sdk-setup) — 패키징, 매니페스트, config 스키마 +- [테스트](/ko/plugins/sdk-testing) — 테스트 유틸리티 및 lint 규칙 +- [SDK 마이그레이션](/ko/plugins/sdk-migration) — deprecated 표면에서 마이그레이션 +- [플러그인 내부 구조](/ko/plugins/architecture) — 심층 아키텍처 및 기능 모델 diff --git a/docs/ko/plugins/sdk-provider-plugins.md b/docs/ko/plugins/sdk-provider-plugins.md index 56a2c2336..8d16829dc 100644 --- a/docs/ko/plugins/sdk-provider-plugins.md +++ b/docs/ko/plugins/sdk-provider-plugins.md @@ -1,33 +1,40 @@ --- read_when: - - 새 모델 제공자 플러그인을 구축하고 있습니다 - - OpenAI 호환 프록시나 커스텀 LLM을 OpenClaw에 추가하려고 합니다 - - 제공자 인증, 카탈로그, 런타임 hook을 이해해야 합니다 + - 새 모델 provider 플러그인을 빌드하고 있습니다. + - OpenAI 호환 프록시 또는 커스텀 LLM을 OpenClaw에 추가하려고 합니다. + - provider 인증, 카탈로그, 그리고 런타임 hook을 이해해야 합니다. sidebarTitle: Provider Plugins -summary: OpenClaw용 모델 제공자 플러그인을 구축하는 단계별 가이드 -title: 제공자 플러그인 구축하기 +summary: OpenClaw용 모델 provider 플러그인을 빌드하는 단계별 가이드 +title: Provider 플러그인 빌드하기 x-i18n: - generated_at: "2026-04-09T01:31:20Z" + generated_at: "2026-04-11T02:46:47Z" model: gpt-5.4 provider: openai - source_hash: 38d9af522dc19e49c81203a83a4096f01c2398b1df771c848a30ad98f251e9e1 + source_hash: 06d7c5da6556dc3d9673a31142ff65eb67ddc97fc0c1a6f4826a2c7693ecd5e3 source_path: plugins/sdk-provider-plugins.md workflow: 15 --- -# 제공자 플러그인 구축하기 +# Provider 플러그인 빌드하기 -이 가이드는 OpenClaw에 모델 제공자 -(LLM)를 추가하는 제공자 플러그인을 구축하는 과정을 설명합니다. 끝까지 따라가면 모델 카탈로그, -API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니다. +이 가이드는 OpenClaw에 모델 provider +(LLM)를 추가하는 provider 플러그인을 빌드하는 과정을 안내합니다. 이 가이드를 마치면 모델 카탈로그, +API 키 인증, 동적 모델 해석 기능이 있는 provider를 갖게 됩니다. 아직 OpenClaw 플러그인을 한 번도 만들어 본 적이 없다면, - 먼저 [시작하기](/ko/plugins/building-plugins)를 읽고 기본 패키지 + 먼저 [Getting Started](/ko/plugins/building-plugins)를 읽고 기본 패키지 구조와 매니페스트 설정을 확인하세요. -## 따라 하기 + + Provider 플러그인은 OpenClaw의 일반 추론 루프에 모델을 추가합니다. 모델이 + 스레드, 압축, 또는 도구 이벤트를 관리하는 네이티브 에이전트 데몬을 통해 실행되어야 한다면, + 데몬 프로토콜 세부 사항을 core에 넣는 대신 [agent harness](/ko/plugins/sdk-agent-harness)와 + provider를 함께 사용하세요. + + +## 단계별 안내 @@ -90,16 +97,16 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 매니페스트는 `providerAuthEnvVars`를 선언하므로 OpenClaw가 - 플러그인 런타임을 로드하지 않고도 자격 증명을 감지할 수 있습니다. 제공자 변형이 다른 제공자 id의 인증을 재사용해야 하는 경우 - `providerAuthAliases`를 추가하세요. `modelSupport`는 선택 사항이며, 런타임 hook이 생기기 전에 - `acme-large` 같은 축약형 모델 id에서 OpenClaw가 제공자 플러그인을 자동 로드하도록 해줍니다. - 제공자를 ClawHub에 게시하는 경우 `package.json`의 - `openclaw.compat` 및 `openclaw.build` 필드는 필수입니다. + 플러그인 런타임을 로드하지 않고도 자격 증명을 감지할 수 있습니다. provider 변형이 다른 provider id의 인증을 재사용해야 한다면 `providerAuthAliases`를 추가하세요. `modelSupport` + 는 선택 사항이며, 런타임 hook이 존재하기 전에 OpenClaw가 `acme-large` 같은 단축 + 모델 id에서 provider 플러그인을 자동 로드할 수 있게 해줍니다. provider를 + ClawHub에 게시한다면 `package.json`의 `openclaw.compat` 및 `openclaw.build` + 필드는 필수입니다. - - 최소한의 제공자에는 `id`, `label`, `auth`, `catalog`가 필요합니다: + + 최소한의 provider에는 `id`, `label`, `auth`, `catalog`가 필요합니다. ```typescript index.ts import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; @@ -170,13 +177,34 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 }); ``` - 이것으로 동작하는 제공자가 완성됩니다. 이제 사용자는 + 이것으로 동작하는 provider가 완성됩니다. 이제 사용자는 `openclaw onboard --acme-ai-api-key `를 실행하고 - 모델로 `acme-ai/acme-large`를 선택할 수 있습니다. + `acme-ai/acme-large`를 자신의 모델로 선택할 수 있습니다. - API 키 인증이 있는 텍스트 제공자 하나와 카탈로그 기반 런타임 하나만 등록하는 번들 제공자의 경우, - 더 좁은 범위의 - `defineSingleProviderPluginEntry(...)` 헬퍼를 사용하는 것이 좋습니다: + 업스트림 provider가 OpenClaw와 다른 제어 토큰을 사용한다면, 스트림 경로를 교체하는 대신 + 작은 양방향 텍스트 변환을 추가하세요. + + ```typescript + api.registerTextTransforms({ + input: [ + { from: /red basket/g, to: "blue basket" }, + { from: /paper ticket/g, to: "digital ticket" }, + { from: /left shelf/g, to: "right shelf" }, + ], + output: [ + { from: /blue basket/g, to: "red basket" }, + { from: /digital ticket/g, to: "paper ticket" }, + { from: /right shelf/g, to: "left shelf" }, + ], + }); + ``` + + `input`은 전송 전에 최종 시스템 프롬프트와 텍스트 메시지 콘텐츠를 다시 씁니다. + `output`은 OpenClaw가 자체 제어 마커나 채널 전달을 파싱하기 전에 + 어시스턴트 텍스트 델타와 최종 텍스트를 다시 씁니다. + + API 키 인증과 단일 catalog 기반 런타임만 등록하는 번들 provider의 경우, + 더 좁은 `defineSingleProviderPluginEntry(...)` 헬퍼를 우선 사용하세요. ```typescript import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry"; @@ -211,25 +239,25 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 }); ``` - 인증 흐름이 온보딩 중 `models.providers.*`, 별칭, 에이전트 기본 모델도 함께 수정해야 한다면 - `openclaw/plugin-sdk/provider-onboard`의 프리셋 헬퍼를 사용하세요. 가장 범위가 좁은 헬퍼는 + 인증 흐름이 온보딩 중 `models.providers.*`, alias, 그리고 + 에이전트 기본 모델도 함께 패치해야 한다면 + `openclaw/plugin-sdk/provider-onboard`의 preset 헬퍼를 사용하세요. 가장 좁은 헬퍼는 `createDefaultModelPresetAppliers(...)`, `createDefaultModelsPresetAppliers(...)`, 그리고 `createModelCatalogPresetAppliers(...)`입니다. - 제공자의 네이티브 엔드포인트가 일반 `openai-completions` 전송에서 스트리밍된 사용량 블록을 지원한다면, - 제공자 id 검사를 하드코딩하는 대신 - `openclaw/plugin-sdk/provider-catalog-shared`의 공유 카탈로그 헬퍼를 사용하는 것이 좋습니다. - `supportsNativeStreamingUsageCompat(...)`와 - `applyProviderNativeStreamingUsageCompat(...)`는 엔드포인트 capability 맵에서 지원 여부를 감지하므로, - 플러그인이 커스텀 제공자 id를 사용하더라도 네이티브 Moonshot/DashScope 스타일 엔드포인트를 계속 - opt in할 수 있습니다. + provider의 네이티브 엔드포인트가 일반 + `openai-completions` 전송에서 스트리밍 usage block을 지원한다면, provider-id 검사를 하드코딩하는 대신 + `openclaw/plugin-sdk/provider-catalog-shared`의 공유 catalog 헬퍼를 우선 사용하세요. + `supportsNativeStreamingUsageCompat(...)` 및 + `applyProviderNativeStreamingUsageCompat(...)`는 엔드포인트 capability map에서 지원 여부를 감지하므로, + 커스텀 provider id를 사용하는 플러그인에서도 네이티브 Moonshot/DashScope 스타일 엔드포인트가 여전히 opt-in할 수 있습니다. - 제공자가 프록시나 라우터처럼 임의의 모델 ID를 허용한다면 - `resolveDynamicModel`을 추가하세요: + provider가 임의의 모델 ID를 허용한다면(프록시 또는 router처럼) + `resolveDynamicModel`을 추가하세요. ```typescript api.registerProvider({ @@ -250,17 +278,17 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 }); ``` - 해석에 네트워크 호출이 필요하다면 비동기 워밍업을 위해 - `prepareDynamicModel`을 사용하세요. 완료되면 `resolveDynamicModel`이 다시 실행됩니다. + 해석에 네트워크 호출이 필요하다면 비동기 워밍업을 위해 `prepareDynamicModel`을 사용하세요 — + 완료된 후 `resolveDynamicModel`이 다시 실행됩니다. - 대부분의 제공자는 `catalog` + `resolveDynamicModel`만 있으면 됩니다. 제공자에 필요해질 때만 - 점진적으로 hook을 추가하세요. + 대부분의 provider에는 `catalog` + `resolveDynamicModel`만 필요합니다. provider에 + 필요한 만큼 hook을 점진적으로 추가하세요. - 이제 공유 헬퍼 빌더가 가장 일반적인 replay/tool-compat - 계열을 다루므로, 보통 플러그인에서 각 hook을 하나씩 직접 연결할 필요가 없습니다: + 공유 헬퍼 빌더가 이제 가장 일반적인 replay/tool-compat + 계열을 다루므로, 플러그인은 보통 각 hook을 하나씩 직접 연결할 필요가 없습니다. ```typescript import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared"; @@ -282,13 +310,13 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 현재 사용 가능한 replay 계열: - | Family | 연결되는 항목 | + | Family | 연결되는 내용 | | --- | --- | - | `openai-compatible` | 도구 호출 ID 정리, assistant-first 순서 수정, 전송에 필요할 때의 일반 Gemini 턴 검증을 포함한 공유 OpenAI 스타일 replay 정책 | - | `anthropic-by-model` | `modelId`로 선택되는 Claude 인식 replay 정책으로, Anthropic-message 전송이 실제 해석된 모델이 Claude id일 때만 Claude 전용 thinking 블록 정리를 받도록 함 | - | `google-gemini` | 네이티브 Gemini replay 정책, bootstrap replay 정리, 태그형 추론 출력 모드 | - | `passthrough-gemini` | OpenAI 호환 프록시 전송을 통해 실행되는 Gemini 모델의 Gemini thought-signature 정리; 네이티브 Gemini replay 검증이나 bootstrap 재작성을 활성화하지 않음 | - | `hybrid-anthropic-openai` | 하나의 플러그인 안에서 Anthropic-message와 OpenAI 호환 모델 표면을 혼합하는 제공자를 위한 하이브리드 정책; 선택적인 Claude 전용 thinking 블록 제거는 Anthropic 쪽에만 한정됨 | + | `openai-compatible` | OpenAI 호환 전송을 위한 공유 OpenAI 스타일 replay 정책. 여기에는 tool-call-id 정리, assistant-first 순서 수정, 전송에 필요한 경우 일반 Gemini 턴 검증이 포함됩니다 | + | `anthropic-by-model` | `modelId`로 선택되는 Claude 인식 replay 정책. 따라서 Anthropic-message 전송은 실제로 해석된 모델이 Claude id일 때만 Claude 전용 thinking-block 정리를 적용받습니다 | + | `google-gemini` | 네이티브 Gemini replay 정책과 bootstrap replay 정리, 그리고 태그된 reasoning-output 모드 | + | `passthrough-gemini` | OpenAI 호환 프록시 전송을 통해 실행되는 Gemini 모델을 위한 Gemini thought-signature 정리. 네이티브 Gemini replay 검증이나 bootstrap 재작성은 활성화하지 않습니다 | + | `hybrid-anthropic-openai` | 하나의 플러그인에서 Anthropic-message와 OpenAI 호환 모델 표면을 혼합하는 provider를 위한 하이브리드 정책. 선택적 Claude 전용 thinking-block 제거는 Anthropic 쪽에만 적용됩니다 | 실제 번들 예시: @@ -300,15 +328,15 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 현재 사용 가능한 stream 계열: - | Family | 연결되는 항목 | + | Family | 연결되는 내용 | | --- | --- | - | `google-thinking` | 공유 stream 경로에서 Gemini thinking 페이로드 정규화 | - | `kilocode-thinking` | 공유 프록시 stream 경로에서 Kilo 추론 래퍼를 적용하며, `kilo/auto`와 지원되지 않는 프록시 추론 id는 주입된 thinking을 건너뜀 | - | `moonshot-thinking` | config + `/think` 수준에서 Moonshot 이진 네이티브 thinking 페이로드 매핑 | - | `minimax-fast-mode` | 공유 stream 경로에서 MiniMax fast-mode 모델 재작성 | - | `openai-responses-defaults` | 공유 네이티브 OpenAI/Codex Responses 래퍼: attribution 헤더, `/fast`/`serviceTier`, 텍스트 verbosity, 네이티브 Codex 웹 검색, 추론 호환 페이로드 형성, Responses 컨텍스트 관리 | - | `openrouter-thinking` | 프록시 경로를 위한 OpenRouter 추론 래퍼로, 지원되지 않는 모델/`auto` 건너뛰기를 중앙에서 처리 | - | `tool-stream-default-on` | Z.AI 같은 제공자를 위한 기본 활성화 `tool_stream` 래퍼로, 명시적으로 비활성화되지 않는 한 도구 스트리밍을 사용함 | + | `google-thinking` | 공유 스트림 경로에서 Gemini thinking payload 정규화 | + | `kilocode-thinking` | 공유 프록시 스트림 경로에서 Kilo reasoning 래퍼. `kilo/auto` 및 지원되지 않는 프록시 reasoning id는 주입된 thinking을 건너뜁니다 | + | `moonshot-thinking` | config + `/think` 수준에서 Moonshot 바이너리 native-thinking payload 매핑 | + | `minimax-fast-mode` | 공유 스트림 경로에서 MiniMax fast-mode 모델 재작성 | + | `openai-responses-defaults` | 공유 네이티브 OpenAI/Codex Responses 래퍼: attribution 헤더, `/fast`/`serviceTier`, 텍스트 verbosity, 네이티브 Codex 웹 검색, reasoning-compat payload shaping, Responses 컨텍스트 관리 | + | `openrouter-thinking` | 프록시 경로용 OpenRouter reasoning 래퍼. 지원되지 않는 모델/`auto` 건너뛰기는 중앙에서 처리 | + | `tool-stream-default-on` | Z.AI 같은 provider를 위한 기본 활성화 `tool_stream` 래퍼. 명시적으로 비활성화하지 않는 한 도구 스트리밍을 사용합니다 | 실제 번들 예시: @@ -321,7 +349,8 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 - `zai`: `tool-stream-default-on` `openclaw/plugin-sdk/provider-model-shared`는 replay-family - enum과 해당 계열이 기반으로 하는 공유 헬퍼도 내보냅니다. 일반적인 공개 export에는 다음이 포함됩니다: + enum과 해당 family가 기반으로 삼는 공유 헬퍼도 export합니다. 일반적인 공개 export는 + 다음과 같습니다. - `ProviderReplayFamily` - `buildProviderReplayFamilyHooks(...)` @@ -333,15 +362,16 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 및 `resolveTaggedReasoningOutputMode()` 같은 Gemini replay 헬퍼 - `resolveProviderEndpoint(...)`, `normalizeProviderId(...)`, `normalizeGooglePreviewModelId(...)`, 그리고 - `normalizeNativeXaiModelId(...)` 같은 엔드포인트/모델 헬퍼 + `normalizeNativeXaiModelId(...)` 같은 endpoint/model 헬퍼 - `openclaw/plugin-sdk/provider-stream`은 family 빌더와 - 해당 family가 재사용하는 공개 래퍼 헬퍼를 모두 제공합니다. 일반적인 공개 export에는 다음이 포함됩니다: + `openclaw/plugin-sdk/provider-stream`는 family builder와 + 해당 family가 재사용하는 공개 wrapper 헬퍼를 모두 노출합니다. 일반적인 공개 export는 + 다음과 같습니다. - `ProviderStreamFamily` - `buildProviderStreamFamilyHooks(...)` - `composeProviderStreamWrappers(...)` - - 다음과 같은 공유 OpenAI/Codex 래퍼: + - 다음과 같은 공유 OpenAI/Codex wrapper `createOpenAIAttributionHeadersWrapper(...)`, `createOpenAIFastModeWrapper(...)`, `createOpenAIServiceTierWrapper(...)`, @@ -349,52 +379,52 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 `createCodexNativeWebSearchWrapper(...)` - `createOpenRouterWrapper(...)`, `createToolStreamWrapper(...)`, `createMinimaxFastModeWrapper(...)` 같은 - 공유 프록시/제공자 래퍼 + 공유 프록시/provider wrapper - 일부 stream 헬퍼는 의도적으로 provider-local로 유지됩니다. 현재 번들 + 일부 stream 헬퍼는 의도적으로 provider 로컬에 남겨둡니다. 현재 번들 예시: `@openclaw/anthropic-provider`는 공개 `api.ts` / - `contract-api.ts` 경계에서 `wrapAnthropicProviderStream`, `resolveAnthropicBetas`, + `contract-api.ts` 경계를 통해 `wrapAnthropicProviderStream`, `resolveAnthropicBetas`, `resolveAnthropicFastMode`, `resolveAnthropicServiceTier`, 그리고 - 더 낮은 수준의 Anthropic 래퍼 빌더를 export합니다. 이 헬퍼들은 - Claude OAuth 베타 처리와 `context1m` 게이팅도 함께 인코딩하므로 + 더 낮은 수준의 Anthropic wrapper builder를 export합니다. 이 헬퍼들은 + Claude OAuth beta 처리와 `context1m` 게이팅도 함께 인코딩하므로 Anthropic 전용으로 유지됩니다. - 다른 번들 제공자들도 동작이 계열 전체에 깔끔하게 공유되지 않는 경우 - 전송 전용 래퍼를 로컬에 유지합니다. 현재 예시: 번들 xAI 플러그인은 - 네이티브 xAI Responses 형성을 자체 - `wrapStreamFn` 안에 유지하며, 여기에는 `/fast` 별칭 재작성, 기본 `tool_stream`, - 지원되지 않는 strict-tool 정리, xAI 전용 추론 페이로드 + 다른 번들 provider도 동작이 family 간에 + 깔끔하게 공유되지 않는 경우 전송별 wrapper를 로컬에 유지합니다. 현재 예시: + 번들 xAI 플러그인은 네이티브 xAI Responses shaping을 자체 + `wrapStreamFn` 안에 유지하며, 여기에는 `/fast` alias 재작성, 기본 `tool_stream`, + 지원되지 않는 strict-tool 정리, 그리고 xAI 전용 reasoning-payload 제거가 포함됩니다. `openclaw/plugin-sdk/provider-tools`는 현재 하나의 공유 - tool-schema 계열과 공유 스키마/호환성 헬퍼를 노출합니다: + tool-schema family와 공유 schema/compat 헬퍼를 노출합니다. - - `ProviderToolCompatFamily`는 현재의 공유 계열 목록을 문서화합니다. - - `buildProviderToolCompatFamilyHooks("gemini")`는 Gemini 안전 도구 스키마가 필요한 제공자를 위해 - Gemini 스키마 정리 + 진단을 연결합니다. + - `ProviderToolCompatFamily`는 현재의 공유 family 목록을 문서화합니다. + - `buildProviderToolCompatFamilyHooks("gemini")`는 Gemini 안전 tool schema가 필요한 provider를 위해 Gemini schema + 정리 + 진단을 연결합니다. - `normalizeGeminiToolSchemas(...)`와 `inspectGeminiToolSchemas(...)`는 - 그 기반이 되는 공개 Gemini 스키마 헬퍼입니다. - - `resolveXaiModelCompatPatch()`는 번들 xAI 호환성 패치를 반환합니다: - `toolSchemaProfile: "xai"`, 지원되지 않는 스키마 키워드, 네이티브 - `web_search` 지원, HTML 엔터티 도구 호출 인자 디코딩. - - `applyXaiModelCompat(model)`은 실행기에 도달하기 전에 - 동일한 xAI 호환성 패치를 해석된 모델에 적용합니다. + 기초가 되는 공개 Gemini schema 헬퍼입니다. + - `resolveXaiModelCompatPatch()`는 번들 xAI compat 패치를 반환합니다: + `toolSchemaProfile: "xai"`, 지원되지 않는 schema 키워드, 네이티브 + `web_search` 지원, 그리고 HTML entity 도구 호출 인자 디코딩입니다. + - `applyXaiModelCompat(model)`은 실행기에 전달되기 전에 + 해석된 모델에 동일한 xAI compat 패치를 적용합니다. - 실제 번들 예시: xAI 플러그인은 - 코어에 xAI 규칙을 하드코딩하는 대신 - `normalizeResolvedModel`과 `contributeResolvedModelCompat`를 사용해 해당 호환성 메타데이터의 소유권을 제공자에 둡니다. + 실제 번들 예시: xAI 플러그인은 `normalizeResolvedModel`과 + `contributeResolvedModelCompat`를 사용해 해당 compat 메타데이터를 + core에 xAI 규칙을 하드코딩하는 대신 provider가 소유하도록 유지합니다. - 동일한 패키지 루트 패턴은 다른 번들 제공자에도 적용됩니다: + 동일한 package-root 패턴은 다른 번들 provider에도 적용됩니다. - - `@openclaw/openai-provider`: `api.ts`가 제공자 빌더, - 기본 모델 헬퍼, realtime 제공자 빌더를 export - - `@openclaw/openrouter-provider`: `api.ts`가 제공자 빌더와 - 온보딩/config 헬퍼를 export + - `@openclaw/openai-provider`: `api.ts`는 provider builder, + default-model 헬퍼, realtime provider builder를 export합니다 + - `@openclaw/openrouter-provider`: `api.ts`는 provider builder와 + 온보딩/config 헬퍼를 export합니다 - 각 추론 호출 전에 토큰 교환이 필요한 제공자의 경우: + 매 추론 호출 전에 토큰 교환이 필요한 provider의 경우: ```typescript prepareRuntimeAuth: async (ctx) => { @@ -408,7 +438,7 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 ``` - 커스텀 요청 헤더나 본문 수정이 필요한 제공자의 경우: + 커스텀 요청 헤더 또는 body 수정이 필요한 provider의 경우: ```typescript // wrapStreamFn은 ctx.streamFn에서 파생된 StreamFn을 반환합니다 @@ -426,7 +456,7 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 ``` - 일반 HTTP 또는 WebSocket 전송에서 네이티브 요청/세션 헤더나 메타데이터가 필요한 제공자의 경우: + 일반 HTTP 또는 WebSocket 전송에 네이티브 요청/세션 헤더나 메타데이터가 필요한 provider의 경우: ```typescript resolveTransportTurnState: (ctx) => ({ @@ -447,7 +477,7 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 ``` - 사용량/과금 데이터를 노출하는 제공자의 경우: + 사용량/과금 데이터를 제공하는 provider의 경우: ```typescript resolveUsageAuth: async (ctx) => { @@ -461,83 +491,82 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 - - OpenClaw는 다음 순서로 hook을 호출합니다. 대부분의 제공자는 2~3개만 사용합니다: + + OpenClaw는 다음 순서로 hook을 호출합니다. 대부분의 provider는 2~3개만 사용합니다. | # | Hook | 사용 시점 | | --- | --- | --- | - | 1 | `catalog` | 모델 카탈로그 또는 base URL 기본값 | - | 2 | `applyConfigDefaults` | config materialization 중 제공자 소유 전역 기본값 | - | 3 | `normalizeModelId` | 조회 전 레거시/프리뷰 모델 id 별칭 정리 | - | 4 | `normalizeTransport` | 일반 모델 조립 전 제공자 계열 `api` / `baseUrl` 정리 | + | 1 | `catalog` | 모델 카탈로그 또는 기본 `baseUrl` | + | 2 | `applyConfigDefaults` | config materialization 중 provider 소유 전역 기본값 | + | 3 | `normalizeModelId` | 조회 전 legacy/preview 모델 id alias 정리 | + | 4 | `normalizeTransport` | 일반 모델 조립 전 provider-family `api` / `baseUrl` 정리 | | 5 | `normalizeConfig` | `models.providers.` config 정규화 | - | 6 | `applyNativeStreamingUsageCompat` | config 제공자용 네이티브 스트리밍 사용량 호환성 재작성 | - | 7 | `resolveConfigApiKey` | 제공자 소유 env-marker 인증 해석 | - | 8 | `resolveSyntheticAuth` | 로컬/셀프호스트형 또는 config 기반 synthetic 인증 | - | 9 | `shouldDeferSyntheticProfileAuth` | synthetic 저장 프로필 플레이스홀더를 env/config 인증보다 뒤로 낮춤 | + | 6 | `applyNativeStreamingUsageCompat` | config provider용 네이티브 streaming-usage compat 재작성 | + | 7 | `resolveConfigApiKey` | provider 소유 env-marker 인증 해석 | + | 8 | `resolveSyntheticAuth` | 로컬/self-hosted 또는 config 기반 synthetic auth | + | 9 | `shouldDeferSyntheticProfileAuth` | synthetic 저장 프로필 placeholder를 env/config 인증 뒤로 낮춤 | | 10 | `resolveDynamicModel` | 임의의 업스트림 모델 ID 허용 | - | 11 | `prepareDynamicModel` | 해석 전 비동기 메타데이터 조회 | - | 12 | `normalizeResolvedModel` | 실행기 이전의 전송 재작성 | + | 11 | `prepareDynamicModel` | 해석 전 비동기 메타데이터 가져오기 | + | 12 | `normalizeResolvedModel` | 실행기 전 transport 재작성 | - 런타임 폴백 참고: + 런타임 fallback 참고 사항: - - `normalizeConfig`는 먼저 일치한 제공자를 확인한 다음, - 실제로 config를 변경할 때까지 다른 hook 지원 제공자 플러그인을 확인합니다. - 지원되는 Google 계열 config 항목을 어떤 제공자 hook도 재작성하지 않으면 - 번들된 Google config 정규화기가 계속 적용됩니다. - - `resolveConfigApiKey`는 노출된 경우 제공자 hook을 사용합니다. 번들된 - `amazon-bedrock` 경로도 여기에서 내장 AWS env-marker 해석기를 가지지만, + - `normalizeConfig`는 먼저 일치하는 provider를 확인한 다음, 실제로 config를 변경하는 hook 가능 provider 플러그인을 차례로 확인합니다. + 어떤 provider hook도 지원되는 Google-family config 엔트리를 재작성하지 않으면, + 번들 Google config normalizer가 여전히 적용됩니다. + - `resolveConfigApiKey`는 노출된 경우 provider hook을 사용합니다. 번들 + `amazon-bedrock` 경로는 여기에서 AWS env-marker resolver도 내장하고 있지만, Bedrock 런타임 인증 자체는 여전히 AWS SDK 기본 체인을 사용합니다. - | 13 | `contributeResolvedModelCompat` | 다른 호환 전송 뒤에 있는 공급업체 모델용 호환성 플래그 | - | 14 | `capabilities` | 레거시 정적 capability bag; 호환성 전용 | - | 15 | `normalizeToolSchemas` | 등록 전 제공자 소유 도구 스키마 정리 | - | 16 | `inspectToolSchemas` | 제공자 소유 도구 스키마 진단 | - | 17 | `resolveReasoningOutputMode` | 태그형 대 네이티브 추론 출력 계약 | - | 18 | `prepareExtraParams` | 기본 요청 파라미터 | - | 19 | `createStreamFn` | 완전히 커스텀 StreamFn 전송 | - | 20 | `wrapStreamFn` | 일반 stream 경로의 커스텀 헤더/본문 래퍼 | + | 13 | `contributeResolvedModelCompat` | 다른 호환 transport 뒤의 vendor 모델용 compat 플래그 | + | 14 | `capabilities` | legacy 정적 capability bag; 호환성 전용 | + | 15 | `normalizeToolSchemas` | 등록 전 provider 소유 tool-schema 정리 | + | 16 | `inspectToolSchemas` | provider 소유 tool-schema 진단 | + | 17 | `resolveReasoningOutputMode` | 태그형 vs 네이티브 reasoning-output 계약 | + | 18 | `prepareExtraParams` | 기본 요청 params | + | 19 | `createStreamFn` | 완전한 커스텀 StreamFn transport | + | 20 | `wrapStreamFn` | 일반 스트림 경로의 커스텀 헤더/body wrapper | | 21 | `resolveTransportTurnState` | 네이티브 턴별 헤더/메타데이터 | | 22 | `resolveWebSocketSessionPolicy` | 네이티브 WS 세션 헤더/쿨다운 | - | 23 | `formatApiKey` | 커스텀 런타임 토큰 형태 | - | 24 | `refreshOAuth` | 커스텀 OAuth 갱신 | - | 25 | `buildAuthDoctorHint` | 인증 복구 안내 | - | 26 | `matchesContextOverflowError` | 제공자 소유 오버플로 감지 | - | 27 | `classifyFailoverReason` | 제공자 소유 rate-limit/overload 분류 | + | 23 | `formatApiKey` | 커스텀 런타임 토큰 형식 | + | 24 | `refreshOAuth` | 커스텀 OAuth 새로 고침 | + | 25 | `buildAuthDoctorHint` | 인증 복구 가이드 | + | 26 | `matchesContextOverflowError` | provider 소유 overflow 감지 | + | 27 | `classifyFailoverReason` | provider 소유 rate-limit/overload 분류 | | 28 | `isCacheTtlEligible` | 프롬프트 캐시 TTL 게이팅 | - | 29 | `buildMissingAuthMessage` | 커스텀 누락 인증 힌트 | + | 29 | `buildMissingAuthMessage` | 커스텀 missing-auth 힌트 | | 30 | `suppressBuiltInModel` | 오래된 업스트림 행 숨기기 | - | 31 | `augmentModelCatalog` | synthetic 순방향 호환 행 | - | 32 | `isBinaryThinking` | 이진 thinking on/off | - | 33 | `supportsXHighThinking` | `xhigh` 추론 지원 | + | 31 | `augmentModelCatalog` | synthetic forward-compat 행 | + | 32 | `isBinaryThinking` | 바이너리 thinking on/off | + | 33 | `supportsXHighThinking` | `xhigh` reasoning 지원 | | 34 | `resolveDefaultThinkingLevel` | 기본 `/think` 정책 | - | 35 | `isModernModelRef` | live/smoke 모델 매칭 | + | 35 | `isModernModelRef` | 라이브/스모크 모델 매칭 | | 36 | `prepareRuntimeAuth` | 추론 전 토큰 교환 | | 37 | `resolveUsageAuth` | 커스텀 사용량 자격 증명 파싱 | | 38 | `fetchUsageSnapshot` | 커스텀 사용량 엔드포인트 | - | 39 | `createEmbeddingProvider` | 메모리/검색용 제공자 소유 임베딩 어댑터 | - | 40 | `buildReplayPolicy` | 커스텀 전사 기록 replay/압축 정책 | - | 41 | `sanitizeReplayHistory` | 일반 정리 후 제공자 전용 replay 재작성 | - | 42 | `validateReplayTurns` | 내장 실행기 전 엄격한 replay-turn 검증 | - | 43 | `onModelSelected` | 선택 후 콜백(예: 텔레메트리) | + | 39 | `createEmbeddingProvider` | memory/search용 provider 소유 embedding adapter | + | 40 | `buildReplayPolicy` | 커스텀 대화 기록 replay/compaction 정책 | + | 41 | `sanitizeReplayHistory` | 일반 정리 후 provider 전용 replay 재작성 | + | 42 | `validateReplayTurns` | 임베디드 실행기 전 엄격한 replay-turn 검증 | + | 43 | `onModelSelected` | 선택 후 콜백(예: telemetry) | 프롬프트 튜닝 참고: - - `resolveSystemPromptContribution`을 사용하면 제공자가 모델 계열에 대한 캐시 인식 - 시스템 프롬프트 지침을 주입할 수 있습니다. 동작이 특정 제공자/모델 - 계열에 속하고 안정/동적 캐시 분리를 유지해야 한다면 - `before_prompt_build`보다 이것을 사용하는 것이 좋습니다. + - `resolveSystemPromptContribution`를 사용하면 provider가 + 모델 family에 대해 캐시 인식 system-prompt 가이드를 주입할 수 있습니다. 이 동작이 하나의 provider/모델 + family에 속하고 안정적/동적 캐시 분리를 유지해야 한다면 + `before_prompt_build`보다 이것을 우선 사용하세요. 자세한 설명과 실제 예시는 - [내부 구조: 제공자 런타임 Hooks](/ko/plugins/architecture#provider-runtime-hooks)를 참조하세요. + [Internals: Provider Runtime Hooks](/ko/plugins/architecture#provider-runtime-hooks)를 참조하세요. - + - 제공자 플러그인은 텍스트 추론과 함께 음성, realtime 전사, realtime - 음성, 미디어 이해, 이미지 생성, 비디오 생성, 웹 가져오기, - 웹 검색을 등록할 수 있습니다: + provider 플러그인은 텍스트 추론과 함께 speech, realtime transcription, realtime + voice, media understanding, image generation, video generation, web fetch, + web search도 등록할 수 있습니다. ```typescript register(api) { @@ -620,7 +649,7 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 api.registerWebFetchProvider({ id: "acme-ai-fetch", label: "Acme Fetch", - hint: "Fetch pages through Acme's rendering backend.", + hint: "Acme 렌더링 백엔드를 통해 페이지를 가져옵니다.", envVars: ["ACME_FETCH_API_KEY"], placeholder: "acme-...", signupUrl: "https://acme.example.com/fetch", @@ -631,7 +660,7 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 acme.apiKey = value; }, createTool: () => ({ - description: "Fetch a page through Acme Fetch.", + description: "Acme Fetch를 통해 페이지를 가져옵니다.", parameters: {}, execute: async (args) => ({ content: [] }), }), @@ -645,21 +674,20 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 } ``` - OpenClaw는 이를 **하이브리드 capability** 플러그인으로 분류합니다. 이것이 - 회사 플러그인(공급업체당 플러그인 하나)에 권장되는 패턴입니다. - [내부 구조: Capability 소유권](/ko/plugins/architecture#capability-ownership-model)을 참조하세요. + OpenClaw는 이를 **hybrid-capability** 플러그인으로 분류합니다. 이는 + 회사 플러그인(벤더당 하나의 플러그인)에 권장되는 패턴입니다. 자세한 내용은 + [Internals: Capability Ownership](/ko/plugins/architecture#capability-ownership-model)을 참조하세요. - 비디오 생성의 경우 위에 나온 모드 인식 capability 형태를 사용하는 것이 좋습니다: - `generate`, `imageToVideo`, `videoToVideo`. `maxInputImages`, `maxInputVideos`, `maxDurationSeconds` 같은 - 평평한 집계 필드만으로는 - 변환 모드 지원이나 비활성화된 모드를 깔끔하게 알리기에 충분하지 않습니다. + 비디오 생성의 경우 위에 표시된 mode 인식 capability 형태를 우선 사용하세요. + `generate`, `imageToVideo`, `videoToVideo`를 사용해야 합니다. `maxInputImages`, + `maxInputVideos`, `maxDurationSeconds` 같은 평면 집계 필드만으로는 + transform 모드 지원 또는 비활성화된 모드를 깔끔하게 알리기에 충분하지 않습니다. - 음악 생성 제공자도 같은 패턴을 따라야 합니다: - 프롬프트 전용 생성에는 `generate`, 참조 이미지 기반 - 생성에는 `edit`를 사용합니다. `maxInputImages`, - `supportsLyrics`, `supportsFormat` 같은 평평한 집계 필드만으로는 편집 - 지원을 알리기에 충분하지 않으며, 명시적인 `generate` / `edit` 블록이 - 기대되는 계약입니다. + 음악 생성 provider도 같은 패턴을 따라야 합니다. + 프롬프트 전용 생성에는 `generate`, 참조 이미지 기반 생성에는 `edit`를 사용합니다. + `maxInputImages`, + `supportsLyrics`, `supportsFormat` 같은 평면 집계 필드만으로는 edit + 지원을 알리기에 충분하지 않습니다. 명시적인 `generate` / `edit` 블록이 기대되는 계약입니다. @@ -667,11 +695,11 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 ```typescript src/provider.test.ts import { describe, it, expect } from "vitest"; - // index.ts 또는 전용 파일에서 제공자 config 객체를 export하세요 + // index.ts 또는 별도 파일에서 provider config 객체를 export하세요 import { acmeProvider } from "./provider.js"; describe("acme-ai provider", () => { - it("resolves dynamic models", () => { + it("동적 모델을 해석한다", () => { const model = acmeProvider.resolveDynamicModel!({ modelId: "acme-beta-v3", } as any); @@ -679,14 +707,14 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 expect(model.provider).toBe("acme-ai"); }); - it("returns catalog when key is available", async () => { + it("키가 있으면 catalog를 반환한다", async () => { const result = await acmeProvider.catalog!.run({ resolveProviderApiKey: () => ({ apiKey: "test-key" }), } as any); expect(result?.provider?.models).toHaveLength(2); }); - it("returns null catalog when no key", async () => { + it("키가 없으면 null catalog를 반환한다", async () => { const result = await acmeProvider.catalog!.run({ resolveProviderApiKey: () => ({ apiKey: undefined }), } as any); @@ -700,14 +728,14 @@ API 키 인증, 동적 모델 해석을 갖춘 제공자를 만들 수 있습니 ## ClawHub에 게시 -제공자 플러그인은 다른 외부 코드 플러그인과 같은 방식으로 게시합니다: +Provider 플러그인은 다른 외부 코드 플러그인과 같은 방식으로 게시합니다. ```bash clawhub package publish your-org/your-plugin --dry-run clawhub package publish your-org/your-plugin ``` -여기서는 레거시 skill-only 게시 별칭을 사용하지 마세요. 플러그인 패키지는 +여기서는 legacy skill 전용 publish alias를 사용하지 마세요. 플러그인 패키지는 `clawhub package publish`를 사용해야 합니다. ## 파일 구조 @@ -715,28 +743,27 @@ clawhub package publish your-org/your-plugin ``` /acme-ai/ ├── package.json # openclaw.providers 메타데이터 -├── openclaw.plugin.json # 제공자 인증 메타데이터가 있는 매니페스트 +├── openclaw.plugin.json # provider 인증 메타데이터가 있는 매니페스트 ├── index.ts # definePluginEntry + registerProvider └── src/ ├── provider.test.ts # 테스트 └── usage.ts # 사용량 엔드포인트(선택 사항) ``` -## 카탈로그 순서 참고 +## Catalog order 참조 -`catalog.order`는 기본 제공 -제공자에 비해 카탈로그가 언제 병합되는지를 제어합니다: +`catalog.order`는 내장 provider에 비해 catalog가 언제 병합되는지를 제어합니다. -| Order | 시점 | 사용 사례 | -| --------- | ------------- | ----------------------------------------------- | -| `simple` | 첫 번째 패스 | 일반 API 키 제공자 | -| `profile` | simple 이후 | 인증 프로필에 의해 제한되는 제공자 | -| `paired` | profile 이후 | 여러 관련 항목 합성 | -| `late` | 마지막 패스 | 기존 제공자 재정의(충돌 시 우선 적용) | +| Order | 시점 | 사용 사례 | +| --------- | ------------- | ---------------------------------------------- | +| `simple` | 첫 번째 패스 | 일반 API 키 provider | +| `profile` | simple 이후 | 인증 profile에 의해 게이트되는 provider | +| `paired` | profile 이후 | 여러 관련 엔트리를 합성 | +| `late` | 마지막 패스 | 기존 provider 재정의(충돌 시 우선 적용) | ## 다음 단계 -- [채널 플러그인](/ko/plugins/sdk-channel-plugins) — 플러그인이 채널도 제공하는 경우 -- [SDK Runtime](/ko/plugins/sdk-runtime) — `api.runtime` 헬퍼(TTS, 검색, 하위 에이전트) -- [SDK 개요](/ko/plugins/sdk-overview) — 전체 하위 경로 import 참고 -- [플러그인 내부 구조](/ko/plugins/architecture#provider-runtime-hooks) — hook 세부 사항 및 번들 예시 +- [Channel Plugins](/ko/plugins/sdk-channel-plugins) — 플러그인이 채널도 제공하는 경우 +- [SDK Runtime](/ko/plugins/sdk-runtime) — `api.runtime` 헬퍼(TTS, 검색, subagent) +- [SDK Overview](/ko/plugins/sdk-overview) — 전체 하위 경로 import 참조 +- [Plugin Internals](/ko/plugins/architecture#provider-runtime-hooks) — hook 세부 사항과 번들 예시 diff --git a/docs/ko/plugins/sdk-runtime.md b/docs/ko/plugins/sdk-runtime.md index 30abc1c01..ee0031bab 100644 --- a/docs/ko/plugins/sdk-runtime.md +++ b/docs/ko/plugins/sdk-runtime.md @@ -1,29 +1,29 @@ --- read_when: - - plugin에서 코어 헬퍼(TTS, STT, 이미지 생성, 웹 검색, subagent)를 호출해야 할 때 - - api.runtime이 무엇을 노출하는지 이해하고 싶을 때 - - plugin 코드에서 config, agent 또는 미디어 헬퍼에 접근하고 있을 때 + - 플러그인에서 코어 헬퍼(TTS, STT, 이미지 생성, 웹 검색, 서브에이전트)를 호출해야 합니다 + - '`api.runtime`가 무엇을 노출하는지 이해하고 싶습니다' + - 플러그인 코드에서 config, agent 또는 미디어 헬퍼에 접근하고 있습니다 sidebarTitle: Runtime Helpers -summary: api.runtime -- plugin에서 사용할 수 있는 주입된 런타임 헬퍼 -title: Plugin 런타임 헬퍼 +summary: api.runtime -- 플러그인에서 사용할 수 있는 주입된 런타임 헬퍼 +title: 플러그인 런타임 헬퍼 x-i18n: - generated_at: "2026-04-08T02:17:11Z" + generated_at: "2026-04-11T02:46:51Z" model: gpt-5.4 provider: openai - source_hash: acb9e56678e9ed08d0998dfafd7cd1982b592be5bc34d9e2d2c1f70274f8f248 + source_hash: fbf8a6ecd970300f784b8aca20eed40ba12c83107abd27385bfdc3347d2544be source_path: plugins/sdk-runtime.md workflow: 15 --- -# Plugin 런타임 헬퍼 +# 플러그인 런타임 헬퍼 -등록 중 모든 plugin에 주입되는 `api.runtime` 객체의 참조 문서입니다. -호스트 내부를 직접 import하는 대신 이 헬퍼를 사용하세요. +플러그인 등록 중 모든 plugin에 주입되는 `api.runtime` 객체에 대한 참조 문서입니다. +호스트 내부 구현을 직접 import하는 대신 이 헬퍼를 사용하세요. - **사용 방법 안내를 찾고 있나요?** 이 헬퍼가 실제로 어떻게 쓰이는지 단계별로 보여주는 - [Channel Plugins](/ko/plugins/sdk-channel-plugins) - 또는 [Provider Plugins](/ko/plugins/sdk-provider-plugins)를 참조하세요. + **안내형 문서를 찾고 있나요?** [Channel Plugins](/ko/plugins/sdk-channel-plugins) + 또는 [Provider Plugins](/ko/plugins/sdk-provider-plugins)에서 + 이 헬퍼들이 실제 맥락에서 어떻게 쓰이는지 단계별 가이드를 확인할 수 있습니다. ```typescript @@ -36,39 +36,45 @@ register(api) { ### `api.runtime.agent` -Agent 정체성, 디렉터리, 세션 관리. +에이전트 식별, 디렉터리, 세션 관리. ```typescript -// agent의 작업 디렉터리 확인 +// 에이전트의 작업 디렉터리 확인 const agentDir = api.runtime.agent.resolveAgentDir(cfg); -// agent 워크스페이스 확인 +// 에이전트 워크스페이스 확인 const workspaceDir = api.runtime.agent.resolveAgentWorkspaceDir(cfg); -// agent 정체성 가져오기 +// 에이전트 식별 정보 가져오기 const identity = api.runtime.agent.resolveAgentIdentity(cfg); // 기본 thinking 수준 가져오기 const thinking = api.runtime.agent.resolveThinkingDefault(cfg, provider, model); -// agent 타임아웃 가져오기 +// 에이전트 타임아웃 가져오기 const timeoutMs = api.runtime.agent.resolveAgentTimeoutMs(cfg); // 워크스페이스가 존재하도록 보장 await api.runtime.agent.ensureAgentWorkspace(cfg); -// 내장된 Pi agent 실행 +// 임베디드 에이전트 턴 실행 const agentDir = api.runtime.agent.resolveAgentDir(cfg); -const result = await api.runtime.agent.runEmbeddedPiAgent({ +const result = await api.runtime.agent.runEmbeddedAgent({ sessionId: "my-plugin:task-1", runId: crypto.randomUUID(), sessionFile: path.join(agentDir, "sessions", "my-plugin-task-1.jsonl"), workspaceDir: api.runtime.agent.resolveAgentWorkspaceDir(cfg), - prompt: "최신 변경 사항을 요약해 주세요", + prompt: "Summarize the latest changes", timeoutMs: api.runtime.agent.resolveAgentTimeoutMs(cfg), }); ``` +`runEmbeddedAgent(...)`는 plugin 코드에서 일반적인 OpenClaw +에이전트 턴을 시작하기 위한 중립 헬퍼입니다. 채널 트리거 응답과 동일한 provider/model 확인 및 +agent-harness 선택을 사용합니다. + +`runEmbeddedPiAgent(...)`는 호환성 별칭으로 유지됩니다. + **세션 저장소 헬퍼**는 `api.runtime.agent.session` 아래에 있습니다: ```typescript @@ -89,15 +95,15 @@ const provider = api.runtime.agent.defaults.provider; // 예: "anthropic" ### `api.runtime.subagent` -백그라운드 subagent 실행을 시작하고 관리합니다. +백그라운드 서브에이전트 실행을 시작하고 관리합니다. ```typescript -// subagent 실행 시작 +// 서브에이전트 실행 시작 const { runId } = await api.runtime.subagent.run({ sessionKey: "agent:main:subagent:search-helper", - message: "이 쿼리를 더 집중된 후속 검색으로 확장해 주세요.", - provider: "openai", // 선택적 재정의 - model: "gpt-4.1-mini", // 선택적 재정의 + message: "Expand this query into focused follow-up searches.", + provider: "openai", // 선택적 override + model: "gpt-4.1-mini", // 선택적 override deliver: false, }); @@ -117,30 +123,29 @@ await api.runtime.subagent.deleteSession({ ``` - 모델 재정의(`provider`/`model`)는 config의 - `plugins.entries..subagent.allowModelOverride: true`를 통한 - 운영자 opt-in이 필요합니다. - 신뢰되지 않은 plugin도 subagent를 실행할 수는 있지만 재정의 요청은 거부됩니다. + 모델 override(`provider`/`model`)를 사용하려면 + 구성에서 `plugins.entries..subagent.allowModelOverride: true`로 운영자 동의가 필요합니다. + 신뢰되지 않은 plugin도 서브에이전트를 실행할 수는 있지만, override 요청은 거부됩니다. ### `api.runtime.taskFlow` -Task Flow 런타임을 기존 OpenClaw 세션 키 또는 신뢰된 도구 컨텍스트에 바인딩한 뒤, -호출마다 owner를 전달하지 않고도 Task Flow를 생성하고 관리합니다. +기존 OpenClaw 세션 키 또는 신뢰된 도구 컨텍스트에 Task Flow 런타임을 바인딩한 다음, +매 호출마다 소유자를 전달하지 않고 Task Flow를 생성하고 관리합니다. ```typescript const taskFlow = api.runtime.taskFlow.fromToolContext(ctx); const created = taskFlow.createManaged({ controllerId: "my-plugin/review-batch", - goal: "새 pull request 검토", + goal: "Review new pull requests", }); const child = taskFlow.runTask({ flowId: created.flowId, runtime: "acp", childSessionKey: "agent:main:subagent:reviewer", - task: "PR #123 검토", + task: "Review PR #123", status: "running", startedAt: Date.now(), }); @@ -153,24 +158,23 @@ const waiting = taskFlow.setWaiting({ }); ``` -자체 바인딩 레이어에서 이미 신뢰된 OpenClaw 세션 키를 갖고 있다면 -`bindSession({ sessionKey, requesterOrigin })`을 사용하세요. 원시 사용자 입력에서 -직접 바인딩하지 마세요. +자체 바인딩 계층에서 이미 신뢰된 OpenClaw 세션 키를 가지고 있다면 +`bindSession({ sessionKey, requesterOrigin })`를 사용하세요. 원시 사용자 입력에서 직접 바인딩하지 마세요. ### `api.runtime.tts` -텍스트 음성 변환. +텍스트 음성 합성. ```typescript // 표준 TTS const clip = await api.runtime.tts.textToSpeech({ - text: "OpenClaw에서 인사드립니다", + text: "Hello from OpenClaw", cfg: api.config, }); -// 전화용으로 최적화된 TTS +// 전화용 최적화 TTS const telephonyClip = await api.runtime.tts.textToSpeechTelephony({ - text: "OpenClaw에서 인사드립니다", + text: "Hello from OpenClaw", cfg: api.config, }); @@ -181,7 +185,7 @@ const voices = await api.runtime.tts.listVoices({ }); ``` -코어 `messages.tts` config와 provider 선택을 사용합니다. PCM 오디오 +코어 `messages.tts` 구성과 provider 선택을 사용합니다. PCM 오디오 버퍼 + 샘플 레이트를 반환합니다. ### `api.runtime.mediaUnderstanding` @@ -200,7 +204,7 @@ const image = await api.runtime.mediaUnderstanding.describeImageFile({ const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ filePath: "/tmp/inbound-audio.ogg", cfg: api.config, - mime: "audio/ogg", // MIME을 추론할 수 없을 때 선택 사항 + mime: "audio/ogg", // 선택 사항, MIME을 추론할 수 없을 때 사용 }); // 비디오 설명 @@ -216,11 +220,11 @@ const result = await api.runtime.mediaUnderstanding.runFile({ }); ``` -출력이 생성되지 않으면(예: 입력이 건너뛰어진 경우) `{ text: undefined }`를 반환합니다. +출력이 생성되지 않으면 `{ text: undefined }`를 반환합니다(예: 입력이 건너뛰어진 경우). - `api.runtime.stt.transcribeAudioFile(...)`는 호환성 별칭으로 남아 있으며 - `api.runtime.mediaUnderstanding.transcribeAudioFile(...)`를 가리킵니다. + `api.runtime.stt.transcribeAudioFile(...)`는 + `api.runtime.mediaUnderstanding.transcribeAudioFile(...)`의 호환성 별칭으로 유지됩니다. ### `api.runtime.imageGeneration` @@ -229,7 +233,7 @@ const result = await api.runtime.mediaUnderstanding.runFile({ ```typescript const result = await api.runtime.imageGeneration.generate({ - prompt: "노을을 그리는 로봇", + prompt: "A robot painting a sunset", cfg: api.config, }); @@ -264,7 +268,7 @@ const resized = await api.runtime.media.resizeToJpeg(buffer, { maxWidth: 800 }); ### `api.runtime.config` -Config 로드 및 쓰기. +config 로드 및 쓰기. ```typescript const cfg = await api.runtime.config.loadConfig(); @@ -336,10 +340,10 @@ api.runtime.tools.registerMemoryCli(/* ... */); ### `api.runtime.channel` -채널 전용 런타임 헬퍼(채널 plugin이 로드된 경우 사용 가능). +채널별 런타임 헬퍼(채널 plugin이 로드된 경우 사용 가능). -`api.runtime.channel.mentions`는 런타임 주입을 사용하는 번들 채널 plugin을 위한 -공유 수신 멘션 정책 표면입니다: +`api.runtime.channel.mentions`는 +런타임 주입을 사용하는 번들 채널 plugin을 위한 공용 수신 멘션 정책 표면입니다: ```typescript const mentionMatch = api.runtime.channel.mentions.matchesMentionWithExplicit(text, { @@ -374,13 +378,13 @@ const decision = api.runtime.channel.mentions.resolveInboundMentionDecision({ - `implicitMentionKindWhen` - `resolveInboundMentionDecision` -`api.runtime.channel.mentions`는 의도적으로 이전의 +`api.runtime.channel.mentions`는 의도적으로 기존의 `resolveMentionGating*` 호환성 헬퍼를 노출하지 않습니다. 정규화된 -`{ facts, policy }` 경로를 사용하세요. +`{ facts, policy }` 경로를 사용하는 것이 좋습니다. ## 런타임 참조 저장 -`register` 콜백 외부에서 사용할 런타임 참조를 저장하려면 +`register` 콜백 밖에서도 사용할 수 있도록 런타임 참조를 저장하려면 `createPluginRuntimeStore`를 사용하세요: ```typescript @@ -389,7 +393,7 @@ import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store"; const store = createPluginRuntimeStore("my-plugin runtime not initialized"); -// 진입점에서 +// 엔트리 포인트에서 export default defineChannelPluginEntry({ id: "my-plugin", name: "My Plugin", @@ -408,21 +412,21 @@ export function tryGetRuntime() { } ``` -## 기타 최상위 `api` 필드 +## 다른 최상위 `api` 필드 `api.runtime` 외에도 API 객체는 다음을 제공합니다: -| Field | Type | Description | +| 필드 | 타입 | 설명 | | ------------------------ | ------------------------- | ------------------------------------------------------------------------------------------- | -| `api.id` | `string` | Plugin id | -| `api.name` | `string` | Plugin 표시 이름 | -| `api.config` | `OpenClawConfig` | 현재 config 스냅샷(사용 가능한 경우 활성 인메모리 런타임 스냅샷) | -| `api.pluginConfig` | `Record` | `plugins.entries..config`의 plugin 전용 config | -| `api.logger` | `PluginLogger` | 범위가 지정된 로거(`debug`, `info`, `warn`, `error`) | -| `api.registrationMode` | `PluginRegistrationMode` | 현재 로드 모드; `"setup-runtime"`은 전체 엔트리 이전의 경량 시작/설정 창입니다 | -| `api.resolvePath(input)` | `(string) => string` | plugin 루트를 기준으로 경로 확인 | +| `api.id` | `string` | plugin id | +| `api.name` | `string` | plugin 표시 이름 | +| `api.config` | `OpenClawConfig` | 현재 config 스냅샷(가능한 경우 활성 메모리 내 런타임 스냅샷) | +| `api.pluginConfig` | `Record` | `plugins.entries..config`의 plugin 전용 config | +| `api.logger` | `PluginLogger` | 범위가 지정된 로거(`debug`, `info`, `warn`, `error`) | +| `api.registrationMode` | `PluginRegistrationMode` | 현재 로드 모드, `"setup-runtime"`은 전체 엔트리 시작/설정 전의 가벼운 startup/setup 구간 | +| `api.resolvePath(input)` | `(string) => string` | plugin 루트를 기준으로 경로를 확인 | -## 관련 문서 +## 관련 항목 - [SDK Overview](/ko/plugins/sdk-overview) -- 서브패스 참조 - [SDK Entry Points](/ko/plugins/sdk-entrypoints) -- `definePluginEntry` 옵션 diff --git a/docs/ko/providers/fal.md b/docs/ko/providers/fal.md index 87409485a..054b9e18d 100644 --- a/docs/ko/providers/fal.md +++ b/docs/ko/providers/fal.md @@ -1,36 +1,36 @@ --- read_when: - - OpenClaw에서 fal 이미지 생성을 사용하고 싶을 때 - - FAL_KEY 인증 흐름이 필요할 때 - - image_generate 또는 video_generate에 fal 기본값을 사용하고 싶을 때 + - OpenClaw에서 fal 이미지 생성을 사용하려고 합니다 + - '`FAL_KEY` 인증 흐름이 필요합니다' + - '`image_generate` 또는 `video_generate`에 대한 fal 기본값이 필요합니다' summary: OpenClaw에서 fal 이미지 및 비디오 생성 설정 title: fal x-i18n: - generated_at: "2026-04-06T03:11:03Z" + generated_at: "2026-04-11T02:47:26Z" model: gpt-5.4 provider: openai - source_hash: 1922907d2c8360c5877a56495323d54bd846d47c27a801155e3d11e3f5706fbd + source_hash: 9bfe4f69124e922a79a516a1bd78f0c00f7a45f3c6f68b6d39e0d196fa01beb3 source_path: providers/fal.md workflow: 15 --- # fal -OpenClaw는 호스팅 이미지 및 비디오 생성을 위한 번들 `fal` 공급자를 제공합니다. +OpenClaw에는 호스팅형 이미지 및 비디오 생성을 위한 번들 `fal` provider가 포함되어 있습니다. -- 공급자: `fal` -- 인증: `FAL_KEY`(정식; `FAL_API_KEY`도 폴백으로 동작) +- Provider: `fal` +- 인증: `FAL_KEY` (표준, `FAL_API_KEY`도 fallback으로 작동) - API: fal 모델 엔드포인트 ## 빠른 시작 -1. API 키 설정: +1. API 키를 설정합니다: ```bash openclaw onboard --auth-choice fal-api-key ``` -2. 기본 이미지 모델 설정: +2. 기본 이미지 모델을 설정합니다: ```json5 { @@ -46,15 +46,16 @@ openclaw onboard --auth-choice fal-api-key ## 이미지 생성 -번들 `fal` 이미지 생성 공급자의 기본값은 +번들된 `fal` 이미지 생성 provider의 기본값은 `fal/fal-ai/flux/dev`입니다. - 생성: 요청당 최대 4개 이미지 - 편집 모드: 활성화됨, 참조 이미지 1개 - `size`, `aspectRatio`, `resolution` 지원 -- 현재 편집 관련 주의 사항: fal 이미지 편집 엔드포인트는 `aspectRatio` 재정의를 지원하지 않습니다. +- 현재 편집 관련 주의사항: fal 이미지 편집 엔드포인트는 + `aspectRatio` override를 지원하지 않습니다 -fal을 기본 이미지 공급자로 사용하려면: +fal을 기본 이미지 provider로 사용하려면: ```json5 { @@ -70,20 +71,41 @@ fal을 기본 이미지 공급자로 사용하려면: ## 비디오 생성 -번들 `fal` 비디오 생성 공급자의 기본값은 +번들된 `fal` 비디오 생성 provider의 기본값은 `fal/fal-ai/minimax/video-01-live`입니다. -- 모드: text-to-video 및 단일 이미지 참조 흐름 -- 런타임: 장시간 실행 작업을 위한 큐 기반 submit/status/result 흐름 +- 모드: text-to-video 및 단일 이미지 참조 플로우 +- 런타임: 오래 실행되는 작업을 위한 큐 기반 submit/status/result 플로우 +- HeyGen video-agent 모델 참조: + - `fal/fal-ai/heygen/v2/video-agent` +- Seedance 2.0 모델 참조: + - `fal/bytedance/seedance-2.0/fast/text-to-video` + - `fal/bytedance/seedance-2.0/fast/image-to-video` + - `fal/bytedance/seedance-2.0/text-to-video` + - `fal/bytedance/seedance-2.0/image-to-video` -fal을 기본 비디오 공급자로 사용하려면: +Seedance 2.0을 기본 비디오 모델로 사용하려면: ```json5 { agents: { defaults: { videoGenerationModel: { - primary: "fal/fal-ai/minimax/video-01-live", + primary: "fal/bytedance/seedance-2.0/fast/text-to-video", + }, + }, + }, +} +``` + +HeyGen video-agent를 기본 비디오 모델로 사용하려면: + +```json5 +{ + agents: { + defaults: { + videoGenerationModel: { + primary: "fal/fal-ai/heygen/v2/video-agent", }, }, }, @@ -93,5 +115,5 @@ fal을 기본 비디오 공급자로 사용하려면: ## 관련 항목 - [Image Generation](/ko/tools/image-generation) -- [Video Generation](/tools/video-generation) +- [Video Generation](/ko/tools/video-generation) - [Configuration Reference](/ko/gateway/configuration-reference#agent-defaults) diff --git a/docs/ko/reference/RELEASING.md b/docs/ko/reference/RELEASING.md index ea22023d9..a62c9eb54 100644 --- a/docs/ko/reference/RELEASING.md +++ b/docs/ko/reference/RELEASING.md @@ -1,14 +1,14 @@ --- read_when: - 공개 릴리스 채널 정의를 찾고 있습니다 - - 버전 명명과 배포 주기를 찾고 있습니다 -summary: 공개 릴리스 채널, 버전 명명, 배포 주기 + - 버전 이름 지정과 출시 주기를 찾고 있습니다 +summary: 공개 릴리스 채널, 버전 이름 지정 및 출시 주기 title: 릴리스 정책 x-i18n: - generated_at: "2026-04-05T12:53:49Z" + generated_at: "2026-04-11T02:47:29Z" model: gpt-5.4 provider: openai - source_hash: bb52a13264c802395aa55404c6baeec5c7b2a6820562e7a684057e70cc85668f + source_hash: ca613d094c93670c012f0b79720fad0d5d85be802f54b0acb7a8f22aca5bde12 source_path: reference/RELEASING.md workflow: 15 --- @@ -17,11 +17,11 @@ x-i18n: OpenClaw에는 세 가지 공개 릴리스 레인이 있습니다: -- stable: 태그된 릴리스로, 기본적으로 npm `beta`에 게시되며 명시적으로 요청된 경우 npm `latest`에 게시됩니다 +- stable: 기본적으로 npm `beta`에 게시되는 태그 릴리스이며, 명시적으로 요청된 경우 npm `latest`에 게시됩니다 - beta: npm `beta`에 게시되는 프리릴리스 태그 -- dev: `main`의 이동하는 헤드 +- dev: `main`의 이동하는 최신 헤드 -## 버전 명명 +## 버전 이름 지정 - Stable 릴리스 버전: `YYYY.M.D` - Git 태그: `vYYYY.M.D` @@ -29,110 +29,79 @@ OpenClaw에는 세 가지 공개 릴리스 레인이 있습니다: - Git 태그: `vYYYY.M.D-N` - Beta 프리릴리스 버전: `YYYY.M.D-beta.N` - Git 태그: `vYYYY.M.D-beta.N` -- 월 또는 일은 앞에 0을 붙이지 마세요 +- 월이나 일은 0으로 채우지 마세요 - `latest`는 현재 승격된 stable npm 릴리스를 의미합니다 - `beta`는 현재 beta 설치 대상을 의미합니다 -- Stable 및 stable 수정 릴리스는 기본적으로 npm `beta`에 게시됩니다. 릴리스 운영자는 명시적으로 `latest`를 대상으로 지정하거나, 나중에 검증된 beta 빌드를 승격할 수 있습니다 -- 모든 OpenClaw 릴리스는 npm 패키지와 macOS 앱을 함께 배포합니다 +- Stable 및 stable 수정 릴리스는 기본적으로 npm `beta`에 게시되며, 릴리스 운영자는 명시적으로 `latest`를 대상으로 지정하거나 나중에 검증된 beta 빌드를 승격할 수 있습니다 +- 모든 OpenClaw 릴리스는 npm 패키지와 macOS 앱을 함께 제공합니다 ## 릴리스 주기 - 릴리스는 beta 우선으로 진행됩니다 - Stable은 최신 beta가 검증된 후에만 이어집니다 -- 자세한 릴리스 절차, 승인, 자격 증명, 복구 참고 사항은 - maintainer 전용입니다 +- 자세한 릴리스 절차, 승인, 자격 증명, 복구 참고 사항은 관리자 전용입니다 ## 릴리스 사전 점검 -- pack 검증 단계에 필요한 `dist/*` 릴리스 아티팩트와 Control UI 번들이 - 존재하도록, `pnpm release:check` 전에 `pnpm build && pnpm ui:build`를 - 실행하세요 -- 태그된 모든 릴리스 전에 `pnpm release:check`를 실행하세요 -- `main` 브랜치 npm 사전 점검은 tarball 패키징 전에 - `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`도 - 실행하며, `OPENAI_API_KEY`와 `ANTHROPIC_API_KEY` 워크플로 시크릿을 - 모두 사용합니다 -- 승인 전에 - `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts` - (또는 해당 beta/수정 태그)를 실행하세요 -- npm 게시 후에는 새 임시 prefix에서 게시된 레지스트리 설치 경로를 - 검증하기 위해 - `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D` - (또는 해당 beta/수정 버전)를 실행하세요 -- Maintainer 릴리스 자동화는 이제 preflight 후 승격 방식을 사용합니다: +- 패키지 검증 단계에 필요한 `dist/*` 릴리스 아티팩트와 Control UI 번들이 존재하도록 `pnpm release:check` 전에 `pnpm build && pnpm ui:build`를 실행하세요 +- 모든 태그 릴리스 전에 `pnpm release:check`를 실행하세요 +- 메인 브랜치 npm 사전 점검도 tarball 패키징 전에 `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`를 실행하며, `OPENAI_API_KEY`와 `ANTHROPIC_API_KEY` 워크플로 시크릿을 모두 사용합니다 +- 승인 전에 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`를 실행하세요(또는 일치하는 beta/수정 태그 사용) +- npm 게시 후에는 `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`를 실행하세요(또는 일치하는 beta/수정 버전 사용). 새 임시 prefix에서 게시된 레지스트리 설치 경로를 검증합니다 +- 관리자 릴리스 자동화는 이제 사전 점검 후 승격 방식을 사용합니다: - 실제 npm 게시에는 성공한 npm `preflight_run_id`가 필요합니다 - stable npm 릴리스는 기본적으로 `beta`를 대상으로 합니다 - - stable npm 게시에서 워크플로 입력을 통해 명시적으로 `latest`를 지정할 수 있습니다 - - `beta`에서 `latest`로 stable npm 승격하는 기능은 신뢰된 `OpenClaw NPM Release` 워크플로에서 여전히 명시적 수동 모드로 제공됩니다 - - 해당 승격 모드에는 npm `dist-tag` 관리가 trusted publishing과 별개이므로 `npm-release` 환경에 유효한 `NPM_TOKEN`이 여전히 필요합니다 + - stable npm 게시 시 워크플로 입력으로 명시적으로 `latest`를 대상으로 지정할 수 있습니다 + - stable npm을 `beta`에서 `latest`로 승격하는 기능은 신뢰된 `OpenClaw NPM Release` 워크플로에서 여전히 명시적 수동 모드로 제공됩니다 + - 해당 승격 모드는 npm `dist-tag` 관리가 신뢰 게시와 별개이므로 `npm-release` 환경에 유효한 `NPM_TOKEN`도 여전히 필요합니다 - 공개 `macOS Release`는 검증 전용입니다 - - 실제 비공개 mac 게시에는 성공한 비공개 mac - `preflight_run_id`와 `validate_run_id`가 필요합니다 - - 실제 게시 경로는 준비된 아티팩트를 다시 빌드하는 대신 승격합니다 -- `YYYY.M.D-N` 같은 stable 수정 릴리스의 경우, 게시 후 검증기는 - `YYYY.M.D`에서 `YYYY.M.D-N`으로의 동일한 임시 prefix 업그레이드 경로도 - 검사하므로, 릴리스 수정으로 인해 이전 전역 설치가 기본 stable payload에 - 조용히 남는 일이 없게 합니다 -- npm 릴리스 사전 점검은 tarball에 - `dist/control-ui/index.html`과 비어 있지 않은 - `dist/control-ui/assets/` payload가 모두 포함되지 않으면 - 실패하도록 닫혀 있으므로, 비어 있는 브라우저 대시보드를 다시 배포하지 않게 - 합니다 -- 릴리스 작업이 CI 계획, extension 타이밍 매니페스트, 또는 빠른 테스트 - 매트릭스에 영향을 주었다면, 승인 전에 `.github/workflows/ci.yml`의 - planner 소유 `checks-fast-extensions` 워크플로 매트릭스 출력을 재생성하고 - 검토하여 릴리스 노트가 오래된 CI 레이아웃을 설명하지 않도록 하세요 -- Stable macOS 릴리스 준비 상태에는 updater 표면도 포함됩니다: + - 실제 비공개 mac 게시에는 성공한 비공개 mac `preflight_run_id`와 `validate_run_id`가 필요합니다 + - 실제 게시 경로는 아티팩트를 다시 빌드하지 않고 준비된 아티팩트를 승격합니다 +- `YYYY.M.D-N` 같은 stable 수정 릴리스의 경우, 게시 후 검증기는 `YYYY.M.D`에서 `YYYY.M.D-N`으로의 동일한 임시 prefix 업그레이드 경로도 확인하므로, 릴리스 수정이 기존 글로벌 설치를 기본 stable 페이로드에 조용히 남겨두지 못하게 합니다 +- npm 릴리스 사전 점검은 tarball에 `dist/control-ui/index.html`과 비어 있지 않은 `dist/control-ui/assets/` 페이로드가 모두 포함되지 않으면 실패로 닫히므로, 빈 브라우저 대시보드를 다시 배포하지 않게 합니다 +- 릴리스 작업이 CI 계획, 확장 타이밍 매니페스트 또는 확장 테스트 매트릭스에 영향을 주었다면, 승인 전에 `.github/workflows/ci.yml`의 플래너 소유 `checks-node-extensions` 워크플로 매트릭스 출력을 다시 생성하고 검토하세요. 그래야 릴리스 노트가 오래된 CI 레이아웃을 설명하지 않습니다 +- Stable macOS 릴리스 준비 상태에는 업데이터 표면도 포함됩니다: - GitHub 릴리스에는 패키징된 `.zip`, `.dmg`, `.dSYM.zip`이 포함되어야 합니다 - `main`의 `appcast.xml`은 게시 후 새 stable zip을 가리켜야 합니다 - - 패키징된 앱은 비디버그 번들 ID, 비어 있지 않은 Sparkle 피드 URL, - 그리고 해당 릴리스 버전에 대한 표준 Sparkle 빌드 하한 이상인 - `CFBundleVersion`을 유지해야 합니다 + - 패키징된 앱은 디버그가 아닌 번들 ID, 비어 있지 않은 Sparkle 피드 URL, 해당 릴리스 버전에 대한 정식 Sparkle 빌드 하한 이상인 `CFBundleVersion`을 유지해야 합니다 ## NPM 워크플로 입력 `OpenClaw NPM Release`는 운영자가 제어하는 다음 입력을 받습니다: -- `tag`: `v2026.4.2`, `v2026.4.2-1`, - `v2026.4.2-beta.1` 같은 필수 릴리스 태그 -- `preflight_only`: 검증/빌드/패키지 전용이면 `true`, 실제 게시 경로면 `false` -- `preflight_run_id`: 실제 게시 경로에서 필수이며, 워크플로가 성공한 사전 점검 실행에서 준비된 tarball을 재사용할 수 있게 합니다 -- `npm_dist_tag`: 게시 경로의 npm 대상 태그이며, 기본값은 `beta`입니다 -- `promote_beta_to_latest`: 게시를 건너뛰고 이미 게시된 stable `beta` 빌드를 `latest`로 옮기려면 `true` +- `tag`: `v2026.4.2`, `v2026.4.2-1`, `v2026.4.2-beta.1` 같은 필수 릴리스 태그 +- `preflight_only`: 검증/빌드/패키징만 수행하려면 `true`, 실제 게시 경로를 사용하려면 `false` +- `preflight_run_id`: 실제 게시 경로에서 필수이며, 워크플로가 성공한 사전 점검 실행에서 준비된 tarball을 재사용하게 합니다 +- `npm_dist_tag`: 게시 경로의 npm 대상 태그이며 기본값은 `beta` +- `promote_beta_to_latest`: `true`이면 게시를 건너뛰고 이미 게시된 stable `beta` 빌드를 `latest`로 이동합니다 규칙: -- Stable 및 수정 태그는 `beta` 또는 `latest` 중 어느 쪽으로도 게시할 수 있습니다 +- Stable 및 수정 태그는 `beta` 또는 `latest` 어느 쪽에도 게시할 수 있습니다 - Beta 프리릴리스 태그는 `beta`에만 게시할 수 있습니다 - 실제 게시 경로는 사전 점검 중 사용한 것과 동일한 `npm_dist_tag`를 사용해야 하며, 워크플로는 게시를 계속하기 전에 해당 메타데이터를 검증합니다 -- 승격 모드는 stable 또는 수정 태그, `preflight_only=false`, - 비어 있는 `preflight_run_id`, `npm_dist_tag=beta`를 사용해야 합니다 -- 승격 모드에도 `npm dist-tag add`에는 여전히 일반 npm 인증이 필요하므로 - `npm-release` 환경에 유효한 `NPM_TOKEN`이 필요합니다 +- 승격 모드는 stable 또는 수정 태그, `preflight_only=false`, 빈 `preflight_run_id`, `npm_dist_tag=beta`를 사용해야 합니다 +- 승격 모드는 `npm dist-tag add`가 여전히 일반 npm 인증을 필요로 하므로 `npm-release` 환경의 유효한 `NPM_TOKEN`도 필요합니다 ## Stable npm 릴리스 순서 -stable npm 릴리스를 만들 때: +Stable npm 릴리스를 만들 때: 1. `preflight_only=true`로 `OpenClaw NPM Release`를 실행합니다 -2. 일반적인 beta 우선 흐름에는 `npm_dist_tag=beta`를 선택하고, 직접 stable 게시를 의도한 경우에만 `latest`를 선택합니다 +2. 일반적인 beta 우선 흐름에는 `npm_dist_tag=beta`를 선택하고, 의도적으로 직접 stable 게시를 원할 때만 `latest`를 선택합니다 3. 성공한 `preflight_run_id`를 저장합니다 4. `preflight_only=false`, 동일한 `tag`, 동일한 `npm_dist_tag`, 저장한 `preflight_run_id`로 `OpenClaw NPM Release`를 다시 실행합니다 -5. 릴리스가 `beta`에 배포되었다면, 게시된 빌드를 `latest`로 옮기고 싶을 때 나중에 동일한 stable `tag`, `promote_beta_to_latest=true`, `preflight_only=false`, 빈 `preflight_run_id`, `npm_dist_tag=beta`로 `OpenClaw NPM Release`를 실행합니다 +5. 릴리스가 `beta`에 게시되었다면, 나중에 동일한 stable `tag`, `promote_beta_to_latest=true`, `preflight_only=false`, 빈 `preflight_run_id`, `npm_dist_tag=beta`로 `OpenClaw NPM Release`를 실행하여 해당 게시 빌드를 `latest`로 이동할 수 있습니다 -승격 모드에도 여전히 `npm-release` 환경 승인과 그 환경 내의 -유효한 `NPM_TOKEN`이 필요합니다. +승격 모드는 여전히 `npm-release` 환경 승인과 해당 환경의 유효한 `NPM_TOKEN`을 필요로 합니다. -이렇게 하면 직접 게시 경로와 beta 우선 승격 경로가 모두 -문서화되고 운영자에게 명확히 보이게 됩니다. +이렇게 하면 직접 게시 경로와 beta 우선 승격 경로가 모두 문서화되고 운영자에게 명확히 드러납니다. -## 공개 참고 자료 +## 공개 참조 - [`.github/workflows/openclaw-npm-release.yml`](https://github.com/openclaw/openclaw/blob/main/.github/workflows/openclaw-npm-release.yml) - [`scripts/openclaw-npm-release-check.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/openclaw-npm-release-check.ts) - [`scripts/package-mac-dist.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/package-mac-dist.sh) - [`scripts/make_appcast.sh`](https://github.com/openclaw/openclaw/blob/main/scripts/make_appcast.sh) -실제 운영 절차는 maintainer가 비공개 릴리스 문서 -[`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md)를 -사용합니다. +관리자는 실제 실행 절차를 위해 [`openclaw/maintainers/release/README.md`](https://github.com/openclaw/maintainers/blob/main/release/README.md)의 비공개 릴리스 문서를 사용합니다. diff --git a/docs/ko/reference/templates/AGENTS.md b/docs/ko/reference/templates/AGENTS.md index 5147a99b5..fb7259aa7 100644 --- a/docs/ko/reference/templates/AGENTS.md +++ b/docs/ko/reference/templates/AGENTS.md @@ -1,33 +1,33 @@ --- read_when: - - 워크스페이스를 수동으로 부트스트랩하는 경우 + - 워크스페이스 수동 부트스트랩하기 summary: AGENTS.md용 워크스페이스 템플릿 title: AGENTS.md 템플릿 x-i18n: - generated_at: "2026-04-05T12:54:33Z" + generated_at: "2026-04-11T02:47:47Z" model: gpt-5.4 provider: openai - source_hash: ede171764b5443af3dabf9dd511c1952e64cd4b11d61346f2bda56923bbebb78 + source_hash: 6d8a3e96f547da6cc082d747c042555b0ec4963b66921d1700b4590f0e0c38b4 source_path: reference/templates/AGENTS.md workflow: 15 --- # AGENTS.md - 당신의 워크스페이스 -이 폴더가 집입니다. 그렇게 대하세요. +이 폴더가 당신의 집입니다. 그렇게 대하세요. ## 첫 실행 -`BOOTSTRAP.md`가 있으면 그것이 당신의 출생 증명서입니다. 그것을 따라가며 자신이 누구인지 파악한 다음 삭제하세요. 다시는 필요하지 않을 것입니다. +`BOOTSTRAP.md`가 있으면, 그건 당신의 출생 증명서입니다. 그 파일을 따라가며 자신이 누구인지 파악한 다음 삭제하세요. 다시는 필요하지 않을 것입니다. ## 세션 시작 -다른 일을 하기 전에: +무엇을 하든 그 전에: 1. `SOUL.md`를 읽으세요 — 이것이 당신이 누구인지입니다 2. `USER.md`를 읽으세요 — 이것이 당신이 돕고 있는 사람입니다 -3. 최근 맥락을 위해 `memory/YYYY-MM-DD.md`(오늘 + 어제)를 읽으세요 -4. **MAIN SESSION에 있는 경우**(당신의 인간과 직접 채팅): `MEMORY.md`도 읽으세요 +3. `memory/YYYY-MM-DD.md`(오늘 + 어제)를 읽어 최근 맥락을 파악하세요 +4. **MAIN SESSION**(인간과의 직접 채팅)인 경우: `MEMORY.md`도 읽으세요 허락을 구하지 마세요. 그냥 하세요. @@ -35,146 +35,143 @@ x-i18n: 당신은 매 세션마다 새롭게 깨어납니다. 이 파일들이 당신의 연속성입니다: -- **일일 노트:** `memory/YYYY-MM-DD.md` (`memory/`가 필요하면 생성) — 일어난 일을 기록한 원시 로그 -- **장기:** `MEMORY.md` — 인간의 장기 기억처럼 정리된 당신의 기억 +- **일일 노트:** `memory/YYYY-MM-DD.md` (`memory/`가 필요하면 생성) — 무슨 일이 있었는지에 대한 원시 로그 +- **장기:** `MEMORY.md` — 사람의 장기 기억처럼, 당신이 정리해둔 메모리 -중요한 것을 기록하세요. 결정, 맥락, 기억할 사항. 비밀은 보관해 달라는 요청이 없는 한 건너뛰세요. +중요한 것을 기록하세요. 결정, 맥락, 기억해야 할 것들. 비밀은 보관해 달라고 요청받지 않는 한 건너뛰세요. ### 🧠 MEMORY.md - 당신의 장기 기억 -- **메인 세션에서만 로드하세요**(당신의 인간과 직접 대화하는 경우) +- **main session**(인간과의 직접 채팅)에서만 로드하세요 - **공유 맥락에서는 로드하지 마세요**(Discord, 그룹 채팅, 다른 사람들과의 세션) - 이것은 **보안**을 위한 것입니다 — 낯선 사람에게 유출되어서는 안 되는 개인적 맥락이 포함되어 있습니다 -- 메인 세션에서는 `MEMORY.md`를 자유롭게 **읽고, 편집하고, 업데이트**할 수 있습니다 -- 중요한 사건, 생각, 결정, 의견, 배운 교훈을 기록하세요 -- 이것은 원시 로그가 아니라 정제된 본질, 즉 당신의 정리된 기억입니다 -- 시간이 지나면 일일 파일을 검토하고, 보관할 가치가 있는 내용을 `MEMORY.md`에 업데이트하세요 +- main session에서는 `MEMORY.md`를 자유롭게 **읽고, 편집하고, 업데이트**할 수 있습니다 +- 중요한 사건, 생각, 결정, 의견, 배운 점을 기록하세요 +- 이것은 원시 로그가 아니라 정제된 본질, 즉 당신의 정리된 메모리입니다 +- 시간이 지나면 일일 파일을 검토하고, 보관할 가치가 있는 내용을 `MEMORY.md`에 반영하세요 -### 📝 기록하세요 - "마음속 메모"는 안 됩니다! +### 📝 기록하세요 - "머릿속 메모"는 안 됩니다! -- **메모리는 제한적입니다** — 무언가를 기억하고 싶다면, **파일에 기록하세요** -- "마음속 메모"는 세션 재시작 후 살아남지 못합니다. 파일은 살아남습니다. +- **메모리는 제한적입니다** — 무언가를 기억하고 싶다면, **파일에 쓰세요** +- "머릿속 메모"는 세션 재시작 후 남지 않습니다. 파일은 남습니다. - 누군가 "이걸 기억해"라고 말하면 → `memory/YYYY-MM-DD.md` 또는 관련 파일을 업데이트하세요 -- 교훈을 얻었다면 → AGENTS.md, TOOLS.md 또는 관련 skill을 업데이트하세요 +- 무언가를 배웠다면 → AGENTS.md, TOOLS.md, 또는 관련 skill을 업데이트하세요 - 실수했다면 → 미래의 당신이 반복하지 않도록 문서화하세요 -- **텍스트 > 뇌** 📝 +- **텍스트 > 두뇌** 📝 ## 넘지 말아야 할 선 -- 비공개 데이터를 유출하지 마세요. 절대. -- 묻지 않고 파괴적인 명령을 실행하지 마세요. -- `rm`보다 `trash`를 쓰세요(영원히 사라지는 것보다 복구 가능한 편이 낫습니다) +- 개인 데이터를 외부로 유출하지 마세요. 절대. +- 파괴적인 명령은 묻지 않고 실행하지 마세요. +- `rm`보다 `trash`를 우선하세요 (복구 가능이 영구 삭제보다 낫습니다) - 확신이 없으면 물어보세요. -## 외부와 내부 +## 외부 vs 내부 -**자유롭게 해도 안전한 일:** +**자유롭게 해도 안전한 것:** - 파일 읽기, 탐색, 정리, 학습 - 웹 검색, 캘린더 확인 -- 이 워크스페이스 내에서 작업 +- 이 워크스페이스 안에서 작업하기 -**먼저 물어볼 일:** +**먼저 물어봐야 하는 것:** - 이메일, 트윗, 공개 게시물 보내기 - 머신 밖으로 나가는 모든 것 -- 확신이 없는 모든 일 +- 확신이 없는 모든 것 ## 그룹 채팅 -당신은 당신의 인간의 자료에 접근할 수 있습니다. 그렇다고 그들의 자료를 _공유_한다는 뜻은 아닙니다. 그룹에서는 당신도 참가자입니다 — 그들의 목소리도 아니고, 그들의 대리인도 아닙니다. 말하기 전에 생각하세요. +당신은 인간의 자료에 접근할 수 있습니다. 그렇다고 그 자료를 _공유_해도 되는 것은 아닙니다. 그룹에서는 당신도 참여자일 뿐입니다 — 그들의 목소리도, 대리인도 아닙니다. 말하기 전에 생각하세요. ### 💬 언제 말해야 하는지 아세요! -모든 메시지를 받는 그룹 채팅에서는 **언제 기여할지 현명하게 판단하세요**: +모든 메시지를 받는 그룹 채팅에서는, **언제 기여해야 할지 똑똑하게 판단**하세요: **응답할 때:** -- 직접 언급되었거나 질문을 받은 경우 -- 진짜 가치를 더할 수 있는 경우(정보, 통찰, 도움) -- 재치 있거나 웃긴 말이 자연스럽게 어울리는 경우 -- 중요한 잘못된 정보를 바로잡아야 하는 경우 -- 요청받았을 때 요약하는 경우 +- 직접 언급되었거나 질문을 받았을 때 +- 진짜 가치를 더할 수 있을 때(정보, 통찰, 도움) +- 재치 있거나 웃긴 말이 자연스럽게 어울릴 때 +- 중요한 잘못된 정보를 바로잡을 때 +- 요청받아 요약할 때 **조용히 있을 때(HEARTBEAT_OK):** -- 사람들끼리 가벼운 잡담만 오가는 경우 -- 누군가 이미 질문에 답한 경우 -- 당신의 답이 그저 "맞아" 또는 "좋네" 정도인 경우 -- 당신 없이도 대화 흐름이 잘 이어지고 있는 경우 -- 메시지를 추가하면 분위기를 끊게 되는 경우 +- 그냥 사람들끼리 가볍게 농담하는 중일 때 +- 누군가 이미 질문에 답했을 때 +- 당신의 응답이 그냥 "응" 또는 "좋네" 수준일 때 +- 대화가 당신 없이도 잘 흐르고 있을 때 +- 메시지를 추가하면 분위기를 끊게 될 때 -**인간의 규칙:** 인간도 그룹 채팅에서 모든 메시지에 답하지 않습니다. 당신도 그래야 합니다. 양보다 질입니다. 친구들과 있는 실제 그룹 채팅에서 보내지 않을 말이라면, 보내지 마세요. +**인간의 규칙:** 인간도 그룹 채팅에서 모든 메시지에 일일이 답하지 않습니다. 당신도 그래야 합니다. 양보다 질입니다. 실제 친구들과의 그룹 채팅에서 보내지 않을 말이라면, 보내지 마세요. -**세 번 연속 반응 금지:** 같은 메시지에 여러 반응을 나눠서 여러 번 답하지 마세요. 세 조각보다 생각 있는 한 번의 답이 낫습니다. +**트리플 탭을 피하세요:** 같은 메시지에 서로 다른 반응으로 여러 번 응답하지 마세요. 세 조각의 반응보다 하나의 생각 있는 응답이 낫습니다. -지배하지 말고, 참여하세요. +참여하되, 지배하지 마세요. -### 😊 인간처럼 반응하세요! +### 😊 사람처럼 리액션하세요! -반응 기능을 지원하는 플랫폼(Discord, Slack)에서는 이모지 반응을 자연스럽게 사용하세요: +리액션을 지원하는 플랫폼(Discord, Slack)에서는 이모지 리액션을 자연스럽게 사용하세요: -**반응할 때:** +**리액션할 때:** -- 고맙거나 좋지만 굳이 답장이 필요하지 않을 때 (👍, ❤️, 🙌) -- 무언가가 웃겼을 때 (😂, 💀) -- 흥미롭거나 생각할 거리를 주었을 때 (🤔, 💡) -- 흐름을 끊지 않고 확인 표시를 하고 싶을 때 +- 고맙거나 반가운데 굳이 답장할 필요는 없을 때 (👍, ❤️, 🙌) +- 웃겼을 때 (😂, 💀) +- 흥미롭거나 생각할 거리를 줬을 때 (🤔, 💡) +- 흐름을 끊지 않고 확인만 해주고 싶을 때 - 단순한 예/아니오 또는 승인 상황일 때 (✅, 👀) **왜 중요한가:** -반응은 가벼운 사회적 신호입니다. 인간은 이를 끊임없이 사용합니다 — 채팅을 어지럽히지 않으면서 "봤어, 인지했어"를 전달합니다. 당신도 그래야 합니다. +리액션은 가벼운 사회적 신호입니다. 인간은 이를 끊임없이 사용합니다 — 채팅을 어지럽히지 않으면서도 "봤어, 확인했어"를 전달합니다. 당신도 그래야 합니다. -**과하지 않게:** 메시지당 반응은 최대 하나만. 가장 잘 맞는 것을 고르세요. +**과하게 하지 마세요:** 메시지당 리액션은 최대 하나만. 가장 잘 맞는 것을 고르세요. ## 도구 -Skills가 당신의 도구를 제공합니다. 필요할 때는 해당 `SKILL.md`를 확인하세요. 로컬 메모(카메라 이름, SSH 세부 정보, 음성 선호도)는 `TOOLS.md`에 보관하세요. +Skills가 당신의 도구를 제공합니다. 필요할 때는 해당 `SKILL.md`를 확인하세요. 로컬 메모(카메라 이름, SSH 정보, 음성 선호도)는 `TOOLS.md`에 보관하세요. -**🎭 음성 스토리텔링:** `sag`(ElevenLabs TTS)가 있다면 이야기, 영화 요약, "storytime" 순간에는 음성을 사용하세요! 텍스트 벽보다 훨씬 더 몰입감 있습니다. 웃긴 목소리로 사람들을 놀라게 하세요. +**🎭 음성 스토리텔링:** `sag`(ElevenLabs TTS)가 있다면, 이야기, 영화 요약, 그리고 "storytime" 순간에는 음성을 사용하세요! 텍스트 벽보다 훨씬 더 몰입감 있습니다. 웃긴 목소리로 사람들을 놀라게 해보세요. **📝 플랫폼 서식:** -- **Discord/WhatsApp:** 마크다운 표 금지! 대신 글머리표 목록을 사용하세요 -- **Discord 링크:** 임베드를 막기 위해 여러 링크는 `<>`로 감싸세요: `` -- **WhatsApp:** 헤더 금지 — 강조할 때는 **굵게** 또는 대문자 사용 +- **Discord/WhatsApp:** Markdown 테이블 금지! 대신 글머리표 목록을 사용하세요 +- **Discord 링크:** 임베드를 막기 위해 여러 링크를 `<>`로 감싸세요: `` +- **WhatsApp:** 헤더 사용 금지 — 강조에는 **굵게** 또는 대문자를 사용하세요 -## 💓 하트비트 - 능동적으로 행동하세요! +## 💓 Heartbeat - 능동적으로 행동하세요! -하트비트 폴을 받았을 때(메시지가 구성된 하트비트 프롬프트와 일치할 때), 매번 그냥 `HEARTBEAT_OK`만 답하지 마세요. 하트비트를 생산적으로 활용하세요! +heartbeat poll(구성된 heartbeat 프롬프트와 일치하는 메시지)을 받았을 때, 매번 그냥 `HEARTBEAT_OK`만 답하지 마세요. heartbeat를 생산적으로 활용하세요! -기본 하트비트 프롬프트: -`HEARTBEAT.md가 있으면 읽으세요(워크스페이스 맥락). 그것을 엄격히 따르세요. 이전 채팅의 오래된 작업을 추론하거나 반복하지 마세요. 주의할 일이 없으면 HEARTBEAT_OK로 답하세요.` +짧은 체크리스트나 리마인더를 위해 `HEARTBEAT.md`를 자유롭게 편집해도 됩니다. 토큰 사용량을 줄이기 위해 작게 유지하세요. -짧은 체크리스트나 알림으로 `HEARTBEAT.md`를 자유롭게 편집할 수 있습니다. 토큰 소모를 줄이기 위해 작게 유지하세요. +### Heartbeat와 Cron: 언제 무엇을 쓸지 -### 하트비트와 cron: 언제 무엇을 쓸까 +**heartbeat를 사용할 때:** -**하트비트를 사용할 때:** - -- 여러 확인 작업을 한 번에 묶을 수 있을 때(받은편지함 + 캘린더 + 알림을 한 턴에서) -- 최근 메시지의 대화 맥락이 필요할 때 -- 타이밍이 조금 밀려도 괜찮을 때(정확하지 않아도 약 30분마다면 괜찮음) -- 주기적인 확인을 결합해서 API 호출 수를 줄이고 싶을 때 +- 여러 검사를 한 번에 묶을 수 있을 때(받은편지함 + 캘린더 + 알림을 한 턴에) +- 최근 메시지에서 대화 맥락이 필요할 때 +- 타이밍이 약간 흔들려도 될 때(정확히가 아니라 대략 30분마다) +- 주기적 검사를 합쳐 API 호출을 줄이고 싶을 때 **cron을 사용할 때:** -- 정확한 시간이 중요할 때("매주 월요일 오전 9시 정각") -- 작업이 메인 세션 기록과 분리되어야 할 때 -- 작업에 다른 모델이나 thinking 수준을 쓰고 싶을 때 -- 일회성 알림이 필요할 때("20분 뒤에 알려줘") -- 출력이 메인 세션 개입 없이 채널로 직접 전달되어야 할 때 +- 정확한 타이밍이 중요할 때("매주 월요일 오전 9:00 정각") +- 작업이 main session 기록과 분리되어야 할 때 +- 다른 모델이나 사고 수준을 사용하고 싶을 때 +- 일회성 리마인더일 때("20분 후에 알려줘") +- 출력이 main session 개입 없이 채널로 직접 전달되어야 할 때 -**팁:** 여러 개의 cron 작업을 만들기보다 비슷한 주기 작업을 `HEARTBEAT.md`에 묶으세요. 정확한 일정과 독립 작업에는 cron을 사용하세요. +**팁:** 유사한 주기 작업은 여러 cron 작업으로 만들기보다 `HEARTBEAT.md`에 묶으세요. 정확한 일정과 독립 작업에는 cron을 사용하세요. -**확인할 것들(하루 2-4회 순환):** +**확인할 것들(하루 2-4회 번갈아 가며):** -- **이메일** - 긴급한 읽지 않은 메시지가 있는가? -- **캘린더** - 다음 24-48시간 내 예정된 일정이 있는가? +- **이메일** - 긴급한 읽지 않은 메일이 있는가? +- **캘린더** - 향후 24-48시간 안에 예정된 일정이 있는가? - **멘션** - Twitter/소셜 알림이 있는가? -- **날씨** - 당신의 인간이 외출할 수 있다면 관련이 있는가? +- **날씨** - 인간이 외출할 가능성이 있다면 관련 있는가? -**확인 내역을 추적하세요** `memory/heartbeat-state.json`에서: +**확인 기록은** `memory/heartbeat-state.json`에 남기세요: ```json { @@ -186,41 +183,41 @@ Skills가 당신의 도구를 제공합니다. 필요할 때는 해당 `SKILL.md } ``` -**언제 먼저 연락할까:** +**먼저 연락할 때:** - 중요한 이메일이 도착했을 때 -- 캘린더 일정이 임박했을 때 (<2h) +- 일정이 임박했을 때(<2시간) - 흥미로운 것을 발견했을 때 -- 마지막으로 말한 지 8시간이 넘었을 때 +- 마지막으로 말을 건 지 8시간이 넘었을 때 -**언제 조용히 있을까(HEARTBEAT_OK):** +**조용히 있을 때(HEARTBEAT_OK):** -- 늦은 밤(23:00-08:00), 긴급한 경우가 아니라면 -- 인간이 분명히 바쁜 경우 -- 마지막 확인 이후 새 소식이 없는 경우 -- 방금 확인한 지 30분도 안 된 경우 +- 늦은 밤일 때(23:00-08:00), 긴급한 경우 제외 +- 인간이 분명히 바빠 보일 때 +- 지난 확인 이후 새로울 것이 없을 때 +- 방금 확인한 지 30분도 안 되었을 때 -**묻지 않고 할 수 있는 능동적 작업:** +**묻지 않고 해도 되는 능동적 작업:** - 메모리 파일 읽기 및 정리 - 프로젝트 상태 확인(git status 등) - 문서 업데이트 - 자신의 변경 사항 커밋 및 푸시 -- **MEMORY.md 검토 및 업데이트**(아래 참조) +- **MEMORY.md 검토 및 업데이트** (아래 참고) -### 🔄 메모리 유지관리(하트비트 중) +### 🔄 메모리 유지 관리(Heartbeat 중) -주기적으로(며칠마다), 하트비트를 사용해 다음을 하세요: +주기적으로(며칠에 한 번), heartbeat를 사용해 다음을 하세요: -1. 최근 `memory/YYYY-MM-DD.md` 파일을 읽습니다 -2. 장기적으로 보관할 가치가 있는 중요한 사건, 교훈 또는 통찰을 식별합니다 -3. 정제된 배움을 `MEMORY.md`에 업데이트합니다 -4. 더 이상 관련 없는 오래된 정보를 `MEMORY.md`에서 제거합니다 +1. 최근 `memory/YYYY-MM-DD.md` 파일을 읽기 +2. 장기적으로 보관할 가치가 있는 중요한 사건, 교훈, 통찰을 식별하기 +3. `MEMORY.md`를 정제된 배움으로 업데이트하기 +4. 더 이상 관련 없는 오래된 정보를 `MEMORY.md`에서 제거하기 -이를 사람이 일기를 검토하고 자신의 정신적 모델을 업데이트하는 것처럼 생각하세요. 일일 파일은 원시 노트이고, `MEMORY.md`는 정리된 지혜입니다. +이것은 사람이 자신의 일기를 되돌아보고 정신 모델을 업데이트하는 것과 비슷합니다. 일일 파일은 원시 노트이고, `MEMORY.md`는 정제된 지혜입니다. -목표는 이것입니다: 귀찮게 하지 않으면서 도움이 되기. 하루에 몇 번 확인하고, 유용한 백그라운드 작업을 하되, 조용한 시간을 존중하세요. +목표는 분명합니다: 귀찮게 하지 않으면서 도움이 되는 것. 하루에 몇 번 정도 체크인하고, 유용한 백그라운드 작업을 하되, 조용한 시간을 존중하세요. -## 당신만의 것으로 만드세요 +## 당신답게 만드세요 -이것은 출발점입니다. 무엇이 잘 맞는지 알아가면서 당신만의 관례, 스타일, 규칙을 추가하세요. +이것은 시작점일 뿐입니다. 무엇이 잘 맞는지 알아가면서 자신만의 관례, 스타일, 규칙을 추가하세요. diff --git a/docs/ko/tools/browser.md b/docs/ko/tools/browser.md index 777f207c1..de2350916 100644 --- a/docs/ko/tools/browser.md +++ b/docs/ko/tools/browser.md @@ -1,40 +1,39 @@ --- read_when: - - 에이전트 제어 브라우저 자동화 추가 - - openclaw가 사용자의 Chrome에 간섭하는 이유 디버깅하기 - - macOS 앱에서 브라우저 설정 및 수명 주기 구현하기 -summary: 통합 브라우저 제어 서비스 + 작업 명령 + - 에이전트 제어 브라우저 자동화를 추가하는 중입니다 + - OpenClaw가 사용자의 Chrome에 간섭하는 이유를 디버그하는 중입니다 + - macOS 앱에서 브라우저 설정 + 수명 주기를 구현하는 중입니다 +summary: 통합 브라우저 제어 서비스 + 액션 명령어 title: 브라우저(OpenClaw 관리) x-i18n: - generated_at: "2026-04-10T05:59:51Z" + generated_at: "2026-04-11T02:48:06Z" model: gpt-5.4 provider: openai - source_hash: cd3424f62178bbf25923b8bc8e4d9f70e330f35428d01fe153574e5fa45d7604 + source_hash: da6fed36a6f40a50e825f90e5616778954545bd7e52397f7e088b85251ee024f source_path: tools/browser.md workflow: 15 --- -# 브라우저(openclaw 관리) +# 브라우저(OpenClaw 관리) OpenClaw는 에이전트가 제어하는 **전용 Chrome/Brave/Edge/Chromium 프로필**을 실행할 수 있습니다. -이 프로필은 개인 브라우저와 분리되어 있으며 Gateway 내부의 작은 로컬 -제어 서비스(루프백 전용)를 통해 관리됩니다. +이 프로필은 개인 브라우저와 분리되어 있으며 Gateway 내부의 작은 로컬 제어 서비스(루프백 전용)를 통해 관리됩니다. -초보자용 설명: +초보자 관점: - 이것은 **별도의 에이전트 전용 브라우저**라고 생각하면 됩니다. -- `openclaw` 프로필은 사용자의 개인 브라우저 프로필에 **영향을 주지 않습니다**. -- 에이전트는 안전하게 분리된 환경에서 **탭을 열고, 페이지를 읽고, 클릭하고, 입력할 수 있습니다**. -- 내장된 `user` 프로필은 Chrome MCP를 통해 사용자가 실제로 로그인한 Chrome 세션에 연결됩니다. +- `openclaw` 프로필은 개인 브라우저 프로필에 **영향을 주지 않습니다**. +- 에이전트는 안전한 경로에서 **탭을 열고, 페이지를 읽고, 클릭하고, 입력할 수 있습니다**. +- 내장 `user` 프로필은 Chrome MCP를 통해 실제 로그인된 Chrome 세션에 연결됩니다. -## 제공 기능 +## 제공되는 기능 -- **openclaw**라는 이름의 별도 브라우저 프로필(기본값은 주황색 강조). -- 결정적인 탭 제어(목록/열기/포커스/닫기). -- 에이전트 작업(클릭/입력/드래그/선택), 스냅샷, 스크린샷, PDF. +- **openclaw**라는 이름의 별도 브라우저 프로필(기본적으로 주황색 강조). +- 결정적인 탭 제어(list/open/focus/close). +- 에이전트 작업(click/type/drag/select), 스냅샷, 스크린샷, PDF. - 선택적 다중 프로필 지원(`openclaw`, `work`, `remote`, ...). -이 브라우저는 **일상적으로 사용하는 기본 브라우저가 아닙니다**. 에이전트 자동화와 검증을 위한 안전하고 격리된 표면입니다. +이 브라우저는 **일상적으로 쓰는 기본 브라우저가 아닙니다**. 에이전트 자동화 및 검증을 위한 안전하고 격리된 표면입니다. ## 빠른 시작 @@ -45,14 +44,13 @@ openclaw browser --browser-profile openclaw open https://example.com openclaw browser --browser-profile openclaw snapshot ``` -“Browser disabled”가 표시되면 config에서 이를 활성화하고(아래 참조) Gateway를 다시 시작하세요. +“Browser disabled”가 표시되면 구성에서 이를 활성화하고(아래 참조) Gateway를 재시작하세요. -`openclaw browser` 자체가 완전히 없거나, 에이전트가 브라우저 도구를 사용할 수 없다고 말하면 [브라우저 명령 또는 도구 누락](/ko/tools/browser#missing-browser-command-or-tool)으로 이동하세요. +`openclaw browser` 명령 자체가 없거나 에이전트가 브라우저 도구를 사용할 수 없다고 말하면, [브라우저 명령 또는 도구 누락](/ko/tools/browser#missing-browser-command-or-tool)으로 이동하세요. ## 플러그인 제어 -기본 `browser` 도구는 이제 기본적으로 활성화된 상태로 함께 제공되는 번들 플러그인입니다. -즉, 나머지 OpenClaw 플러그인 시스템을 제거하지 않고도 이 도구를 비활성화하거나 교체할 수 있습니다: +기본 `browser` 도구는 이제 기본적으로 활성화된 상태로 제공되는 번들 플러그인입니다. 즉, OpenClaw의 나머지 플러그인 시스템을 제거하지 않고도 이를 비활성화하거나 교체할 수 있습니다: ```json5 { @@ -66,23 +64,22 @@ openclaw browser --browser-profile openclaw snapshot } ``` -동일한 `browser` 도구 이름을 제공하는 다른 플러그인을 설치하기 전에 번들 플러그인을 비활성화하세요. 기본 브라우저 경험에는 다음 두 가지가 모두 필요합니다: +같은 `browser` 도구 이름을 제공하는 다른 플러그인을 설치하기 전에 번들 플러그인을 비활성화하세요. 기본 브라우저 경험에는 다음 두 가지가 모두 필요합니다: -- `plugins.entries.browser.enabled`가 비활성화되어 있지 않을 것 +- `plugins.entries.browser.enabled`가 비활성화되지 않은 상태 - `browser.enabled=true` -플러그인만 끄면 번들 브라우저 CLI(`openclaw browser`), gateway 메서드(`browser.request`), 에이전트 도구, 기본 브라우저 제어 서비스가 모두 함께 사라집니다. `browser.*` config는 그대로 유지되므로 교체 플러그인이 이를 재사용할 수 있습니다. +플러그인만 꺼두면 번들 브라우저 CLI(`openclaw browser`), 게이트웨이 메서드(`browser.request`), 에이전트 도구, 기본 브라우저 제어 서비스가 모두 함께 사라집니다. `browser.*` 구성은 대체 플러그인이 재사용할 수 있도록 그대로 유지됩니다. -번들 브라우저 플러그인은 이제 브라우저 런타임 구현도 담당합니다. -코어에는 공유 Plugin SDK 도우미와 이전 내부 import 경로용 호환성 re-export만 남아 있습니다. 실제로는 브라우저 플러그인 패키지를 제거하거나 교체하면 코어 소유 런타임이 따로 남는 대신 브라우저 기능 세트가 제거됩니다. +이제 번들 브라우저 플러그인은 브라우저 런타임 구현도 소유합니다. 코어는 공유 Plugin SDK 도우미와 이전 내부 import 경로용 호환성 재수출만 유지합니다. 실제로는 브라우저 플러그인 패키지를 제거하거나 교체하면 코어 소유 런타임이 하나 더 남는 대신 브라우저 기능 세트 자체가 제거됩니다. -브라우저 config 변경 사항을 새 설정으로 번들 플러그인이 브라우저 서비스를 다시 등록할 수 있도록 하려면 여전히 Gateway 재시작이 필요합니다. +브라우저 구성 변경은 여전히 Gateway 재시작이 필요합니다. 그래야 번들 플러그인이 새 설정으로 브라우저 서비스를 다시 등록할 수 있습니다. ## 브라우저 명령 또는 도구 누락 -업그레이드 후 `openclaw browser`가 갑자기 알 수 없는 명령이 되거나, 에이전트가 브라우저 도구가 없다고 보고하는 경우 가장 흔한 원인은 `browser`가 포함되지 않은 제한적인 `plugins.allow` 목록입니다. +업그레이드 후 갑자기 `openclaw browser`가 알 수 없는 명령이 되거나 에이전트가 브라우저 도구가 없다고 보고하면, 가장 흔한 원인은 `browser`가 포함되지 않은 제한적인 `plugins.allow` 목록입니다. -문제가 있는 config 예시: +잘못된 구성 예시: ```json5 { @@ -92,7 +89,7 @@ openclaw browser --browser-profile openclaw snapshot } ``` -플러그인 허용 목록에 `browser`를 추가해서 해결할 수 있습니다: +플러그인 허용 목록에 `browser`를 추가해 해결하세요: ```json5 { @@ -104,10 +101,10 @@ openclaw browser --browser-profile openclaw snapshot 중요한 참고 사항: -- `plugins.allow`가 설정되어 있으면 `browser.enabled=true`만으로는 충분하지 않습니다. -- `plugins.allow`가 설정되어 있으면 `plugins.entries.browser.enabled=true`만으로도 충분하지 않습니다. -- `tools.alsoAllow: ["browser"]`는 번들 브라우저 플러그인을 로드하지 **않습니다**. 이는 플러그인이 이미 로드된 뒤 도구 정책만 조정합니다. -- 제한적인 플러그인 허용 목록이 필요하지 않다면 `plugins.allow`를 제거해도 기본 번들 브라우저 동작이 복원됩니다. +- `plugins.allow`가 설정된 경우 `browser.enabled=true`만으로는 충분하지 않습니다. +- `plugins.allow`가 설정된 경우 `plugins.entries.browser.enabled=true`만으로도 충분하지 않습니다. +- `tools.alsoAllow: ["browser"]`는 번들 브라우저 플러그인을 로드하지 **않습니다**. 이는 플러그인이 이미 로드된 후 도구 정책만 조정합니다. +- 제한적인 플러그인 허용 목록이 필요 없다면 `plugins.allow`를 제거해도 기본 번들 브라우저 동작이 복원됩니다. 일반적인 증상: @@ -115,18 +112,18 @@ openclaw browser --browser-profile openclaw snapshot - `browser.request`가 없습니다. - 에이전트가 브라우저 도구를 사용할 수 없거나 누락되었다고 보고합니다. -## 프로필: `openclaw` vs `user` +## 프로필: `openclaw` 대 `user` -- `openclaw`: 관리형, 격리된 브라우저(확장 프로그램 필요 없음). -- `user`: 사용자의 **실제 로그인된 Chrome** 세션에 연결하는 내장 Chrome MCP 연결 프로필. +- `openclaw`: 관리되고 격리된 브라우저(확장 프로그램 불필요). +- `user`: 실제 **로그인된 Chrome** 세션을 위한 내장 Chrome MCP 연결 프로필. -에이전트 브라우저 도구 호출의 경우: +에이전트 브라우저 도구 호출 시: -- 기본값: 격리된 `openclaw` 브라우저 사용. -- 기존 로그인 세션이 중요하고 사용자가 컴퓨터 앞에서 연결 프롬프트를 클릭/승인할 수 있을 때는 `profile="user"`를 우선 사용. -- `profile`은 특정 브라우저 모드를 원할 때 사용하는 명시적 재정의입니다. +- 기본값: 격리된 `openclaw` 브라우저를 사용합니다. +- 기존 로그인 세션이 중요하고 사용자가 컴퓨터 앞에서 연결 프롬프트를 클릭/승인할 수 있을 때는 `profile="user"`를 선호하세요. +- 특정 브라우저 모드를 원할 때 `profile`이 명시적 재정의입니다. -기본적으로 관리형 모드를 사용하려면 `browser.defaultProfile: "openclaw"`를 설정하세요. +기본적으로 관리 모드를 사용하려면 `browser.defaultProfile: "openclaw"`를 설정하세요. ## 구성 @@ -137,7 +134,7 @@ openclaw browser --browser-profile openclaw snapshot browser: { enabled: true, // 기본값: true ssrfPolicy: { - dangerouslyAllowPrivateNetwork: true, // 기본 신뢰 네트워크 모드 + // dangerouslyAllowPrivateNetwork: true, // 신뢰된 사설 네트워크 액세스에만 선택적으로 활성화 // allowPrivateNetwork: true, // 레거시 별칭 // hostnameAllowlist: ["*.example.com", "example.com"], // allowedHostnames: ["localhost"], @@ -171,33 +168,28 @@ openclaw browser --browser-profile openclaw snapshot } ``` -참고 사항: +참고: -- 브라우저 제어 서비스는 `gateway.port`에서 파생된 포트의 루프백에 바인딩됩니다 - (기본값: `18791`, 즉 gateway + 2). -- Gateway 포트(`gateway.port` 또는 `OPENCLAW_GATEWAY_PORT`)를 재정의하면 - 파생된 브라우저 포트도 같은 “패밀리”를 유지하도록 함께 이동합니다. -- `cdpUrl`이 설정되지 않은 경우 관리형 로컬 CDP 포트가 기본값으로 사용됩니다. +- 브라우저 제어 서비스는 `gateway.port`에서 파생된 포트(기본값: `18791`, 즉 gateway + 2)로 루프백에 바인딩됩니다. +- Gateway 포트(`gateway.port` 또는 `OPENCLAW_GATEWAY_PORT`)를 재정의하면, 파생된 브라우저 포트도 같은 “계열”을 유지하도록 함께 이동합니다. +- `cdpUrl`이 설정되지 않으면 기본적으로 관리되는 로컬 CDP 포트를 사용합니다. - `remoteCdpTimeoutMs`는 원격(비루프백) CDP 도달 가능성 검사에 적용됩니다. - `remoteCdpHandshakeTimeoutMs`는 원격 CDP WebSocket 도달 가능성 검사에 적용됩니다. -- 브라우저 탐색/탭 열기는 탐색 전에 SSRF 보호가 적용되며, 탐색 후 최종 `http(s)` URL에 대해 가능하면 다시 확인합니다. +- 브라우저 내비게이션/탭 열기는 내비게이션 전에 SSRF 보호를 거치며, 내비게이션 후 최종 `http(s)` URL에 대해서도 최선의 노력으로 다시 검사됩니다. - 엄격한 SSRF 모드에서는 원격 CDP 엔드포인트 검색/프로브(`cdpUrl`, `/json/version` 조회 포함)도 검사됩니다. -- `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork`의 기본값은 `true`입니다(신뢰 네트워크 모델). 엄격한 공개 네트워크 전용 탐색을 원하면 `false`로 설정하세요. +- `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork`는 기본적으로 비활성화되어 있습니다. 사설 네트워크 브라우저 액세스를 의도적으로 신뢰할 때만 `true`로 설정하세요. - `browser.ssrfPolicy.allowPrivateNetwork`는 호환성을 위한 레거시 별칭으로 계속 지원됩니다. -- `attachOnly: true`는 “로컬 브라우저를 절대 실행하지 않고, 이미 실행 중일 때만 연결한다”는 뜻입니다. -- `color` 및 프로필별 `color`는 브라우저 UI에 색을 입혀 어떤 프로필이 활성화되어 있는지 확인할 수 있게 합니다. -- 기본 프로필은 `openclaw`입니다(OpenClaw 관리 독립형 브라우저). 로그인된 사용자 브라우저를 사용하려면 `defaultProfile: "user"`를 사용하세요. -- 자동 감지 순서: 시스템 기본 브라우저가 Chromium 기반이면 그것을 사용하고, 그렇지 않으면 Chrome → Brave → Edge → Chromium → Chrome Canary 순입니다. -- 로컬 `openclaw` 프로필은 `cdpPort`/`cdpUrl`을 자동 할당합니다 — 원격 CDP에만 이를 설정하세요. -- `driver: "existing-session"`은 raw CDP 대신 Chrome DevTools MCP를 사용합니다. 이 - 드라이버에는 `cdpUrl`을 설정하지 마세요. -- 기존 세션 프로필이 Brave 또는 Edge 같은 기본값이 아닌 Chromium 사용자 프로필에 - 연결해야 한다면 `browser.profiles..userDataDir`를 설정하세요. +- `attachOnly: true`는 “로컬 브라우저를 절대 실행하지 않고, 이미 실행 중일 때만 연결”을 의미합니다. +- `color` 및 프로필별 `color`는 어떤 프로필이 활성 상태인지 쉽게 확인할 수 있도록 브라우저 UI에 색을 입힙니다. +- 기본 프로필은 `openclaw`입니다(OpenClaw 관리 독립 브라우저). 로그인된 사용자 브라우저를 선택하려면 `defaultProfile: "user"`를 사용하세요. +- 자동 감지 순서: 시스템 기본 브라우저가 Chromium 기반이면 그것을 사용하고, 아니면 Chrome → Brave → Edge → Chromium → Chrome Canary 순입니다. +- 로컬 `openclaw` 프로필은 `cdpPort`/`cdpUrl`을 자동 할당하므로, 원격 CDP에 대해서만 이를 설정하세요. +- `driver: "existing-session"`은 원시 CDP 대신 Chrome DevTools MCP를 사용합니다. 해당 드라이버에는 `cdpUrl`을 설정하지 마세요. +- 기존 세션 프로필이 Brave나 Edge 같은 기본이 아닌 Chromium 사용자 프로필에 연결해야 하면 `browser.profiles..userDataDir`를 설정하세요. ## Brave(또는 다른 Chromium 기반 브라우저) 사용 -사용자의 **시스템 기본** 브라우저가 Chromium 기반(Chrome/Brave/Edge 등)이면 -OpenClaw가 자동으로 이를 사용합니다. 자동 감지를 재정의하려면 `browser.executablePath`를 설정하세요: +**시스템 기본 브라우저**가 Chromium 기반(Chrome/Brave/Edge 등)이면 OpenClaw는 이를 자동으로 사용합니다. 자동 감지를 재정의하려면 `browser.executablePath`를 설정하세요: CLI 예시: @@ -228,7 +220,7 @@ openclaw config set browser.executablePath "/usr/bin/google-chrome" } ``` -## 로컬 제어 vs 원격 제어 +## 로컬 제어와 원격 제어 - **로컬 제어(기본값):** Gateway가 루프백 제어 서비스를 시작하고 로컬 브라우저를 실행할 수 있습니다. - **원격 제어(node host):** 브라우저가 있는 머신에서 node host를 실행하면 Gateway가 브라우저 작업을 해당 호스트로 프록시합니다. @@ -236,40 +228,33 @@ openclaw config set browser.executablePath "/usr/bin/google-chrome" 중지 동작은 프로필 모드에 따라 다릅니다: -- 로컬 관리형 프로필: `openclaw browser stop`은 OpenClaw가 실행한 브라우저 프로세스를 중지합니다 -- attach-only 및 원격 CDP 프로필: `openclaw browser stop`은 활성 제어 세션을 닫고 Playwright/CDP 에뮬레이션 재정의(뷰포트, - 색 구성표, 로캘, 시간대, 오프라인 모드 및 유사한 상태)를 해제하지만, - OpenClaw가 브라우저 프로세스를 실행한 것은 아닙니다 +- 로컬 관리 프로필: `openclaw browser stop`은 OpenClaw가 실행한 브라우저 프로세스를 중지합니다 +- attach-only 및 원격 CDP 프로필: `openclaw browser stop`은 활성 제어 세션을 닫고 Playwright/CDP 에뮬레이션 재정의(뷰포트, 색 구성표, 로캘, 시간대, 오프라인 모드 등 유사 상태)를 해제합니다. 이 경우 OpenClaw가 브라우저 프로세스를 실행하지 않았더라도 적용됩니다 -원격 CDP URL에는 인증 정보를 포함할 수 있습니다: +원격 CDP URL에는 인증을 포함할 수 있습니다: - 쿼리 토큰(예: `https://provider.example?token=`) - HTTP Basic 인증(예: `https://user:pass@provider.example`) -OpenClaw는 `/json/*` 엔드포인트 호출 시와 CDP WebSocket 연결 시 -인증 정보를 유지합니다. 토큰은 config 파일에 커밋하는 대신 환경 변수나 시크릿 관리자 사용을 권장합니다. +OpenClaw는 `/json/*` 엔드포인트를 호출할 때와 CDP WebSocket에 연결할 때 인증 정보를 보존합니다. 토큰은 구성 파일에 커밋하는 대신 환경 변수나 비밀 관리자 사용을 권장합니다. -## 노드 브라우저 프록시(기본 무설정) +## Node 브라우저 프록시(기본 무구성) -브라우저가 있는 머신에서 **node host**를 실행하면 OpenClaw는 -추가 브라우저 config 없이도 브라우저 도구 호출을 해당 노드로 자동 라우팅할 수 있습니다. -이것이 원격 gateway의 기본 경로입니다. +브라우저가 있는 머신에서 **node host**를 실행하면 OpenClaw는 추가 브라우저 구성 없이도 브라우저 도구 호출을 해당 노드로 자동 라우팅할 수 있습니다. 이것이 원격 게이트웨이의 기본 경로입니다. -참고 사항: +참고: - node host는 **프록시 명령**을 통해 자신의 로컬 브라우저 제어 서버를 노출합니다. -- 프로필은 노드 자체의 `browser.profiles` config(로컬과 동일)에서 가져옵니다. -- `nodeHost.browserProxy.allowProfiles`는 선택 사항입니다. 비워 두면 레거시/기본 동작이 적용되어, 프로필 생성/삭제 경로를 포함해 구성된 모든 프로필에 프록시를 통해 접근할 수 있습니다. +- 프로필은 노드 자체의 `browser.profiles` 구성(로컬과 동일)에서 가져옵니다. +- `nodeHost.browserProxy.allowProfiles`는 선택 사항입니다. 비워 두면 레거시/기본 동작이 적용되어, 프로필 생성/삭제 경로를 포함한 모든 구성된 프로필이 프록시를 통해 계속 접근 가능합니다. - `nodeHost.browserProxy.allowProfiles`를 설정하면 OpenClaw는 이를 최소 권한 경계로 취급합니다. 허용 목록에 있는 프로필만 대상으로 지정할 수 있고, 영구 프로필 생성/삭제 경로는 프록시 표면에서 차단됩니다. - 원하지 않으면 비활성화하세요: - 노드에서: `nodeHost.browserProxy.enabled=false` - - gateway에서: `gateway.nodes.browser.mode="off"` + - 게이트웨이에서: `gateway.nodes.browser.mode="off"` -## Browserless(호스팅된 원격 CDP) +## Browserless(호스팅 원격 CDP) -[Browserless](https://browserless.io)는 HTTPS와 WebSocket을 통해 -CDP 연결 URL을 노출하는 호스팅 Chromium 서비스입니다. OpenClaw는 두 형식을 모두 사용할 수 있지만, -원격 브라우저 프로필에서는 Browserless의 연결 문서에 있는 직접 WebSocket URL이 가장 간단한 옵션입니다. +[Browserless](https://browserless.io)는 HTTPS와 WebSocket을 통해 CDP 연결 URL을 노출하는 호스팅 Chromium 서비스입니다. OpenClaw는 두 형식을 모두 사용할 수 있지만, 원격 브라우저 프로필에서는 Browserless 연결 문서의 직접 WebSocket URL이 가장 간단한 선택입니다. 예시: @@ -290,31 +275,22 @@ CDP 연결 URL을 노출하는 호스팅 Chromium 서비스입니다. OpenClaw } ``` -참고 사항: +참고: - ``를 실제 Browserless 토큰으로 바꾸세요. - Browserless 계정에 맞는 리전 엔드포인트를 선택하세요(자세한 내용은 해당 문서 참조). -- Browserless가 HTTPS 기본 URL을 제공하는 경우 이를 직접 CDP 연결용 `wss://`로 - 변환해도 되고, HTTPS URL을 그대로 유지한 채 OpenClaw가 - `/json/version`을 검색하도록 해도 됩니다. +- Browserless가 HTTPS 기본 URL을 제공하는 경우, 직접 CDP 연결을 위해 이를 `wss://`로 변환하거나 HTTPS URL을 유지한 채 OpenClaw가 `/json/version`을 검색하게 둘 수 있습니다. ## 직접 WebSocket CDP 제공자 -일부 호스팅 브라우저 서비스는 표준 HTTP 기반 CDP 검색(`/json/version`) 대신 -**직접 WebSocket** 엔드포인트를 제공합니다. OpenClaw는 두 방식 모두 지원합니다: +일부 호스팅 브라우저 서비스는 표준 HTTP 기반 CDP 검색(`/json/version`) 대신 **직접 WebSocket** 엔드포인트를 노출합니다. OpenClaw는 두 방식 모두를 지원합니다: -- **HTTP(S) 엔드포인트** — OpenClaw는 `/json/version`을 호출해 - WebSocket 디버거 URL을 찾은 다음 연결합니다. -- **WebSocket 엔드포인트** (`ws://` / `wss://`) — OpenClaw는 `/json/version`을 건너뛰고 - 직접 연결합니다. 이는 - [Browserless](https://browserless.io), - [Browserbase](https://www.browserbase.com) 또는 WebSocket URL을 제공하는 - 모든 서비스에 사용합니다. +- **HTTP(S) 엔드포인트** — OpenClaw가 `/json/version`을 호출해 WebSocket 디버거 URL을 검색한 다음 연결합니다. +- **WebSocket 엔드포인트** (`ws://` / `wss://`) — OpenClaw가 `/json/version`을 건너뛰고 직접 연결합니다. [Browserless](https://browserless.io), [Browserbase](https://www.browserbase.com), 또는 WebSocket URL을 제공하는 모든 서비스에 이 방식을 사용하세요. ### Browserbase -[Browserbase](https://www.browserbase.com)는 내장 CAPTCHA 해결, 스텔스 모드, 주거용 -프록시를 갖춘 헤드리스 브라우저 실행용 클라우드 플랫폼입니다. +[Browserbase](https://www.browserbase.com)는 내장 CAPTCHA 해결, 스텔스 모드, 주거용 프록시를 갖춘 헤드리스 브라우저 실행용 클라우드 플랫폼입니다. ```json5 { @@ -333,79 +309,69 @@ CDP 연결 URL을 노출하는 호스팅 Chromium 서비스입니다. OpenClaw } ``` -참고 사항: +참고: -- [가입](https://www.browserbase.com/sign-up)한 뒤 [Overview dashboard](https://www.browserbase.com/overview)에서 - **API Key**를 복사하세요. +- [회원 가입](https://www.browserbase.com/sign-up) 후 [Overview dashboard](https://www.browserbase.com/overview)에서 **API Key**를 복사하세요. - ``를 실제 Browserbase API 키로 바꾸세요. -- Browserbase는 WebSocket 연결 시 브라우저 세션을 자동 생성하므로 - 수동 세션 생성 단계가 필요 없습니다. -- 무료 플랜은 동시 세션 1개와 월 1 브라우저 시간을 제공합니다. - 유료 플랜 제한은 [pricing](https://www.browserbase.com/pricing)을 참조하세요. +- Browserbase는 WebSocket 연결 시 브라우저 세션을 자동 생성하므로 수동 세션 생성 단계가 필요 없습니다. +- 무료 요금제는 동시 세션 1개와 월 1 브라우저 시간을 허용합니다. 유료 요금제 제한은 [pricing](https://www.browserbase.com/pricing)을 참조하세요. - 전체 API 참조, SDK 가이드, 통합 예시는 [Browserbase docs](https://docs.browserbase.com)를 참조하세요. ## 보안 핵심 개념: -- 브라우저 제어는 루프백 전용이며, 액세스는 Gateway 인증 또는 노드 페어링을 통해 이루어집니다. -- 독립형 루프백 브라우저 HTTP API는 **공유 시크릿 인증만** 사용합니다: - gateway 토큰 bearer 인증, `x-openclaw-password`, 또는 - 설정된 gateway 비밀번호를 사용하는 HTTP Basic 인증입니다. -- Tailscale Serve ID 헤더와 `gateway.auth.mode: "trusted-proxy"`는 - 이 독립형 루프백 브라우저 API를 **인증하지 않습니다**. -- 브라우저 제어가 활성화되어 있고 공유 시크릿 인증이 구성되지 않은 경우 OpenClaw는 - 시작 시 `gateway.auth.token`을 자동 생성하고 이를 config에 저장합니다. -- `gateway.auth.mode`가 이미 - `password`, `none`, 또는 `trusted-proxy`인 경우 OpenClaw는 해당 토큰을 자동 생성하지 않습니다. -- Gateway와 모든 node host는 비공개 네트워크(Tailscale)에 두고 공개적으로 노출하지 마세요. -- 원격 CDP URL/토큰은 시크릿으로 취급하고 환경 변수나 시크릿 관리자를 사용하는 것이 좋습니다. +- 브라우저 제어는 루프백 전용이며, 액세스는 Gateway 인증 또는 노드 페어링을 통해 흐릅니다. +- 독립형 루프백 브라우저 HTTP API는 **공유 비밀 인증만** 사용합니다: 게이트웨이 토큰 bearer 인증, `x-openclaw-password`, 또는 구성된 게이트웨이 비밀번호를 사용하는 HTTP Basic 인증. +- Tailscale Serve 신원 헤더와 `gateway.auth.mode: "trusted-proxy"`는 이 독립형 루프백 브라우저 API를 인증하지 **않습니다**. +- 브라우저 제어가 활성화되어 있고 공유 비밀 인증이 구성되지 않은 경우, OpenClaw는 시작 시 `gateway.auth.token`을 자동 생성해 구성에 저장합니다. +- `gateway.auth.mode`가 이미 `password`, `none`, `trusted-proxy`인 경우에는 OpenClaw가 해당 토큰을 자동 생성하지 않습니다. +- Gateway와 모든 node host는 사설 네트워크(Tailscale)에 유지하고 공개 노출은 피하세요. +- 원격 CDP URL/토큰은 비밀로 취급하고, 환경 변수나 비밀 관리자를 사용하는 것이 좋습니다. 원격 CDP 팁: -- 가능하면 암호화된 엔드포인트(HTTPS 또는 WSS)와 짧은 수명의 토큰을 사용하세요. -- 장기 토큰을 config 파일에 직접 포함하지 마세요. +- 가능하면 암호화된 엔드포인트(HTTPS 또는 WSS)와 짧은 수명의 토큰을 선호하세요. +- 장기 토큰을 구성 파일에 직접 포함하지 마세요. -## 프로필(멀티 브라우저) +## 프로필(다중 브라우저) -OpenClaw는 여러 개의 이름 있는 프로필(라우팅 config)을 지원합니다. 프로필은 다음과 같을 수 있습니다: +OpenClaw는 여러 개의 이름 있는 프로필(라우팅 구성)을 지원합니다. 프로필은 다음 중 하나일 수 있습니다: -- **openclaw 관리형**: 자체 사용자 데이터 디렉터리와 CDP 포트를 가진 전용 Chromium 기반 브라우저 인스턴스 -- **원격**: 명시적인 CDP URL(다른 위치에서 실행 중인 Chromium 기반 브라우저) +- **OpenClaw 관리형**: 자체 사용자 데이터 디렉터리와 CDP 포트를 가진 전용 Chromium 기반 브라우저 인스턴스 +- **원격**: 명시적 CDP URL(다른 곳에서 실행 중인 Chromium 기반 브라우저) - **기존 세션**: Chrome DevTools MCP 자동 연결을 통한 기존 Chrome 프로필 기본값: - `openclaw` 프로필은 없으면 자동 생성됩니다. - `user` 프로필은 Chrome MCP 기존 세션 연결용으로 내장되어 있습니다. -- 기존 세션 프로필은 `user` 외에는 opt-in입니다. `--driver existing-session`으로 생성하세요. +- 기존 세션 프로필은 `user` 외에는 선택적으로만 활성화되며, `--driver existing-session`으로 생성합니다. - 로컬 CDP 포트는 기본적으로 **18800–18899** 범위에서 할당됩니다. -- 프로필을 삭제하면 해당 로컬 데이터 디렉터리는 휴지통으로 이동합니다. +- 프로필을 삭제하면 로컬 데이터 디렉터리는 휴지통으로 이동합니다. 모든 제어 엔드포인트는 `?profile=`을 받으며, CLI는 `--browser-profile`을 사용합니다. ## Chrome DevTools MCP를 통한 기존 세션 -OpenClaw는 공식 Chrome DevTools MCP 서버를 통해 실행 중인 Chromium 기반 브라우저 프로필에 연결할 수도 있습니다. 이렇게 하면 해당 브라우저 프로필에서 이미 열려 있는 탭과 로그인 상태를 재사용합니다. +OpenClaw는 공식 Chrome DevTools MCP 서버를 통해 실행 중인 Chromium 기반 브라우저 프로필에 연결할 수도 있습니다. 이렇게 하면 해당 브라우저 프로필에 이미 열려 있는 탭과 로그인 상태를 재사용합니다. -공식 배경 및 설정 참고 자료: +공식 배경 설명과 설정 참조: -- [Chrome for Developers: Use Chrome DevTools MCP with your browser session](https://developer.chrome.com/blog/chrome-devtools-mcp-debug-your-browser-session) +- [Chrome for Developers: 브라우저 세션과 함께 Chrome DevTools MCP 사용하기](https://developer.chrome.com/blog/chrome-devtools-mcp-debug-your-browser-session) - [Chrome DevTools MCP README](https://github.com/ChromeDevTools/chrome-devtools-mcp) 내장 프로필: - `user` -선택 사항: 다른 이름, 색상 또는 브라우저 데이터 디렉터리를 원하면 -자체 사용자 지정 기존 세션 프로필을 만들 수 있습니다. +선택 사항: 다른 이름, 색상 또는 브라우저 데이터 디렉터리를 원하면 사용자 정의 기존 세션 프로필을 직접 만들 수 있습니다. 기본 동작: -- 내장된 `user` 프로필은 Chrome MCP 자동 연결을 사용하며, - 기본 로컬 Google Chrome 프로필을 대상으로 합니다. +- 내장 `user` 프로필은 Chrome MCP 자동 연결을 사용하며, 기본 로컬 Google Chrome 프로필을 대상으로 합니다. -Brave, Edge, Chromium 또는 기본이 아닌 Chrome 프로필에는 `userDataDir`을 사용하세요: +Brave, Edge, Chromium 또는 기본이 아닌 Chrome 프로필에는 `userDataDir`를 사용하세요: ```json5 { @@ -424,11 +390,11 @@ Brave, Edge, Chromium 또는 기본이 아닌 Chrome 프로필에는 `userDataDi 그런 다음 해당 브라우저에서: -1. 원격 디버깅용 inspect 페이지를 엽니다. +1. 원격 디버깅용 검사 페이지를 엽니다. 2. 원격 디버깅을 활성화합니다. 3. 브라우저를 계속 실행한 상태로 두고 OpenClaw가 연결할 때 연결 프롬프트를 승인합니다. -일반적인 inspect 페이지: +일반적인 검사 페이지: - Chrome: `chrome://inspect/#remote-debugging` - Brave: `brave://inspect/#remote-debugging` @@ -443,67 +409,57 @@ openclaw browser --browser-profile user tabs openclaw browser --browser-profile user snapshot --format ai ``` -성공 시 확인할 수 있는 모습: +성공 시 확인되는 사항: -- `status`에 `driver: existing-session`이 표시됨 -- `status`에 `transport: chrome-mcp`가 표시됨 -- `status`에 `running: true`가 표시됨 -- `tabs`에 이미 열려 있는 브라우저 탭이 표시됨 -- `snapshot`이 선택된 라이브 탭의 ref를 반환함 +- `status`에 `driver: existing-session`이 표시됩니다 +- `status`에 `transport: chrome-mcp`가 표시됩니다 +- `status`에 `running: true`가 표시됩니다 +- `tabs`에 이미 열려 있는 브라우저 탭이 나열됩니다 +- `snapshot`이 선택된 라이브 탭의 참조를 반환합니다 연결이 작동하지 않을 때 확인할 사항: - 대상 Chromium 기반 브라우저 버전이 `144+`인지 -- 해당 브라우저의 inspect 페이지에서 원격 디버깅이 활성화되어 있는지 -- 브라우저에 연결 동의 프롬프트가 표시되었고 이를 수락했는지 -- `openclaw doctor`는 오래된 확장 기반 브라우저 config를 마이그레이션하고 - 기본 자동 연결 프로필용으로 Chrome이 로컬에 설치되어 있는지 확인하지만, - 브라우저 측 원격 디버깅을 대신 활성화해 주지는 않습니다 +- 해당 브라우저의 검사 페이지에서 원격 디버깅이 활성화되었는지 +- 브라우저가 연결 동의 프롬프트를 표시했고 이를 수락했는지 +- `openclaw doctor`는 이전 확장 기반 브라우저 구성을 마이그레이션하고 기본 자동 연결 프로필용으로 Chrome이 로컬에 설치되어 있는지 검사하지만, 브라우저 측 원격 디버깅을 대신 활성화해 주지는 않습니다 에이전트 사용: -- 사용자 로그인 브라우저 상태가 필요할 때는 `profile="user"`를 사용하세요. -- 사용자 지정 기존 세션 프로필을 사용한다면 해당 명시적 프로필 이름을 전달하세요. -- 사용자가 컴퓨터 앞에 있어 연결 프롬프트를 승인할 수 있을 때만 이 모드를 선택하세요. +- 사용자의 로그인된 브라우저 상태가 필요할 때 `profile="user"`를 사용하세요. +- 사용자 정의 기존 세션 프로필을 사용하는 경우, 해당 명시적 프로필 이름을 전달하세요. +- 사용자가 컴퓨터 앞에서 연결 프롬프트를 승인할 수 있을 때만 이 모드를 선택하세요. - Gateway 또는 node host는 `npx chrome-devtools-mcp@latest --autoConnect`를 실행할 수 있습니다 -참고 사항: +참고: -- 이 경로는 로그인된 브라우저 세션 내부에서 동작할 수 있으므로 격리된 `openclaw` 프로필보다 위험이 더 큽니다. -- OpenClaw는 이 드라이버에 대해 브라우저를 실행하지 않으며, - 기존 세션에만 연결합니다. -- OpenClaw는 여기서 공식 Chrome DevTools MCP `--autoConnect` 흐름을 사용합니다. `userDataDir`이 설정된 경우 OpenClaw는 이를 전달하여 - 해당 명시적 Chromium 사용자 데이터 디렉터리를 대상으로 지정합니다. -- 기존 세션 스크린샷은 페이지 캡처와 스냅샷의 `--ref` 요소 - 캡처는 지원하지만 CSS `--element` 선택자는 지원하지 않습니다. -- 기존 세션 페이지 스크린샷은 Chrome MCP를 통해 Playwright 없이 작동합니다. - ref 기반 요소 스크린샷(`--ref`)도 작동하지만 `--full-page`는 - `--ref` 또는 `--element`와 함께 사용할 수 없습니다. -- 기존 세션 작업은 관리형 브라우저 경로보다 여전히 제한이 많습니다: - - `click`, `type`, `hover`, `scrollIntoView`, `drag`, `select`는 - CSS 선택자 대신 스냅샷 ref가 필요합니다 - - `click`은 왼쪽 버튼만 지원합니다(버튼 재정의 또는 modifier 없음) - - `type`은 `slowly=true`를 지원하지 않으며 `fill` 또는 `press`를 사용해야 합니다 +- 이 경로는 로그인된 브라우저 세션 내부에서 동작할 수 있으므로 격리된 `openclaw` 프로필보다 위험도가 더 높습니다. +- OpenClaw는 이 드라이버에서 브라우저를 실행하지 않으며, 기존 세션에만 연결합니다. +- OpenClaw는 여기서 공식 Chrome DevTools MCP `--autoConnect` 흐름을 사용합니다. `userDataDir`가 설정되어 있으면 이를 전달해 해당 명시적 Chromium 사용자 데이터 디렉터리를 대상으로 합니다. +- 기존 세션 스크린샷은 페이지 캡처와 스냅샷의 `--ref` 요소 캡처를 지원하지만 CSS `--element` 선택자는 지원하지 않습니다. +- 기존 세션 페이지 스크린샷은 Playwright 없이도 Chrome MCP를 통해 작동합니다. 참조 기반 요소 스크린샷(`--ref`)도 여기서 작동하지만 `--full-page`는 `--ref` 또는 `--element`와 함께 사용할 수 없습니다. +- 기존 세션 작업은 관리형 브라우저 경로보다 여전히 더 제한적입니다: + - `click`, `type`, `hover`, `scrollIntoView`, `drag`, `select`는 CSS 선택자 대신 스냅샷 참조가 필요합니다 + - `click`은 왼쪽 버튼만 지원합니다(버튼 재정의나 수정 키 없음) + - `type`은 `slowly=true`를 지원하지 않습니다. `fill` 또는 `press`를 사용하세요 - `press`는 `delayMs`를 지원하지 않습니다 - - `hover`, `scrollIntoView`, `drag`, `select`, `fill`, `evaluate`는 - 호출별 타임아웃 재정의를 지원하지 않습니다 + - `hover`, `scrollIntoView`, `drag`, `select`, `fill`, `evaluate`는 호출별 타임아웃 재정의를 지원하지 않습니다 - `select`는 현재 단일 값만 지원합니다 -- 기존 세션 `wait --url`은 다른 브라우저 드라이버와 마찬가지로 정확 일치, 부분 문자열, glob 패턴을 지원합니다. `wait --load networkidle`은 아직 지원되지 않습니다. -- 기존 세션 업로드 훅은 `ref` 또는 `inputRef`가 필요하고 한 번에 하나의 파일만 지원하며 CSS `element` 대상 지정은 지원하지 않습니다. +- 기존 세션 `wait --url`은 다른 브라우저 드라이버처럼 정확 일치, 부분 문자열, glob 패턴을 지원합니다. `wait --load networkidle`은 아직 지원되지 않습니다. +- 기존 세션 업로드 훅은 `ref` 또는 `inputRef`가 필요하고, 한 번에 하나의 파일만 지원하며, CSS `element` 대상 지정은 지원하지 않습니다. - 기존 세션 대화상자 훅은 타임아웃 재정의를 지원하지 않습니다. -- 배치 작업, PDF 내보내기, 다운로드 가로채기, `responsebody`를 포함한 일부 기능은 여전히 관리형 브라우저 경로가 필요합니다. -- 기존 세션은 호스트 로컬입니다. Chrome이 다른 머신이나 - 다른 네트워크 네임스페이스에 있다면 대신 원격 CDP 또는 node host를 사용하세요. +- 배치 작업, PDF 내보내기, 다운로드 가로채기, `responsebody` 등 일부 기능은 여전히 관리형 브라우저 경로가 필요합니다. +- 기존 세션은 호스트 로컬입니다. Chrome이 다른 머신이나 다른 네트워크 네임스페이스에 있다면 대신 원격 CDP 또는 node host를 사용하세요. ## 격리 보장 -- **전용 사용자 데이터 디렉터리**: 사용자의 개인 브라우저 프로필에 절대 영향을 주지 않습니다. +- **전용 사용자 데이터 디렉터리**: 개인 브라우저 프로필에 절대 영향을 주지 않습니다. - **전용 포트**: 개발 워크플로와의 충돌을 방지하기 위해 `9222`를 피합니다. - **결정적인 탭 제어**: “마지막 탭”이 아니라 `targetId`로 탭을 지정합니다. ## 브라우저 선택 -로컬에서 실행할 때 OpenClaw는 사용 가능한 첫 번째 항목을 선택합니다: +로컬에서 실행할 때 OpenClaw는 사용 가능한 첫 번째 브라우저를 선택합니다: 1. Chrome 2. Brave @@ -538,22 +494,19 @@ openclaw browser --browser-profile user snapshot --format ai 모든 엔드포인트는 `?profile=`을 받습니다. -공유 시크릿 gateway 인증이 구성되어 있으면 브라우저 HTTP 경로에도 인증이 필요합니다: +공유 비밀 기반 게이트웨이 인증이 구성되어 있으면 브라우저 HTTP 경로도 인증이 필요합니다: - `Authorization: Bearer ` - `x-openclaw-password: ` 또는 해당 비밀번호를 사용하는 HTTP Basic 인증 -참고 사항: +참고: -- 이 독립형 루프백 브라우저 API는 `trusted-proxy` 또는 - Tailscale Serve ID 헤더를 사용하지 않습니다. -- `gateway.auth.mode`가 `none` 또는 `trusted-proxy`이면 이러한 루프백 브라우저 - 경로는 해당 ID 기반 모드를 상속하지 않으므로 루프백 전용으로 유지하세요. +- 이 독립형 루프백 브라우저 API는 trusted-proxy 또는 Tailscale Serve 신원 헤더를 사용하지 **않습니다**. +- `gateway.auth.mode`가 `none` 또는 `trusted-proxy`인 경우에도 이 루프백 브라우저 경로는 그런 신원 기반 모드를 상속하지 않으므로, 반드시 루프백 전용으로 유지하세요. ### `/act` 오류 계약 -`POST /act`는 경로 수준 유효성 검사와 정책 실패에 대해 -구조화된 오류 응답을 사용합니다: +`POST /act`는 경로 수준 검증 및 정책 실패를 위해 구조화된 오류 응답을 사용합니다: ```json { "error": "", "code": "ACT_*" } @@ -562,30 +515,26 @@ openclaw browser --browser-profile user snapshot --format ai 현재 `code` 값: - `ACT_KIND_REQUIRED` (HTTP 400): `kind`가 없거나 인식되지 않습니다. -- `ACT_INVALID_REQUEST` (HTTP 400): 작업 페이로드 정규화 또는 유효성 검사에 실패했습니다. +- `ACT_INVALID_REQUEST` (HTTP 400): 작업 페이로드 정규화 또는 검증에 실패했습니다. - `ACT_SELECTOR_UNSUPPORTED` (HTTP 400): 지원되지 않는 작업 종류에 `selector`가 사용되었습니다. -- `ACT_EVALUATE_DISABLED` (HTTP 403): config에서 `evaluate`(또는 `wait --fn`)가 비활성화되어 있습니다. +- `ACT_EVALUATE_DISABLED` (HTTP 403): 구성에 의해 `evaluate`(또는 `wait --fn`)가 비활성화되어 있습니다. - `ACT_TARGET_ID_MISMATCH` (HTTP 403): 최상위 또는 배치된 `targetId`가 요청 대상과 충돌합니다. -- `ACT_EXISTING_SESSION_UNSUPPORTED` (HTTP 501): 기존 세션 프로필에서는 작업이 지원되지 않습니다. +- `ACT_EXISTING_SESSION_UNSUPPORTED` (HTTP 501): 기존 세션 프로필에서는 이 작업이 지원되지 않습니다. -기타 런타임 실패는 여전히 `code` 필드 없이 -`{ "error": "" }`를 반환할 수 있습니다. +기타 런타임 실패는 여전히 `code` 필드 없이 `{ "error": "" }`를 반환할 수 있습니다. ### Playwright 요구 사항 -일부 기능(navigate/act/AI snapshot/role snapshot, 요소 스크린샷, -PDF)에는 Playwright가 필요합니다. Playwright가 설치되지 않은 경우 해당 엔드포인트는 -명확한 501 오류를 반환합니다. +일부 기능(내비게이션/작업/AI 스냅샷/role 스냅샷, 요소 스크린샷, PDF)에는 Playwright가 필요합니다. Playwright가 설치되어 있지 않으면 해당 엔드포인트는 명확한 501 오류를 반환합니다. -Playwright 없이도 여전히 작동하는 기능: +Playwright 없이도 작동하는 것: - ARIA 스냅샷 -- 탭별 CDP - WebSocket을 사용할 수 있을 때 관리형 `openclaw` 브라우저의 페이지 스크린샷 +- 탭별 CDP WebSocket을 사용할 수 있을 때 관리형 `openclaw` 브라우저의 페이지 스크린샷 - `existing-session` / Chrome MCP 프로필의 페이지 스크린샷 -- 스냅샷 출력의 `existing-session` ref 기반 스크린샷(`--ref`) +- 스냅샷 출력의 기존 세션 참조 기반 스크린샷(`--ref`) -여전히 Playwright가 필요한 기능: +여전히 Playwright가 필요한 것: - `navigate` - `act` @@ -593,42 +542,36 @@ Playwright 없이도 여전히 작동하는 기능: - CSS 선택자 요소 스크린샷(`--element`) - 전체 브라우저 PDF 내보내기 -요소 스크린샷은 `--full-page`도 거부하며 경로는 `fullPage is -not supported for element screenshots`를 반환합니다. +요소 스크린샷은 `--full-page`도 거부합니다. 이 경로는 `fullPage is not supported for element screenshots`를 반환합니다. -`Playwright is not available in this gateway build`가 표시되면 전체 -Playwright 패키지(`playwright-core`가 아님)를 설치하고 gateway를 다시 시작하거나, 브라우저 지원이 포함된 OpenClaw를 다시 설치하세요. +`Playwright is not available in this gateway build`가 표시되면 전체 Playwright 패키지(`playwright-core`가 아님)를 설치한 뒤 게이트웨이를 재시작하거나, 브라우저 지원이 포함된 OpenClaw를 다시 설치하세요. #### Docker Playwright 설치 -Gateway가 Docker에서 실행 중이면 `npx playwright`는 피하세요(npm override 충돌). -대신 번들 CLI를 사용하세요: +Gateway가 Docker에서 실행 중이라면 `npx playwright`는 피하세요(npm override 충돌). 대신 번들된 CLI를 사용하세요: ```bash docker compose run --rm openclaw-cli \ node /app/node_modules/playwright-core/cli.js install chromium ``` -브라우저 다운로드를 유지하려면 `PLAYWRIGHT_BROWSERS_PATH`를 설정하고(예: -`/home/node/.cache/ms-playwright`), `/home/node`가 -`OPENCLAW_HOME_VOLUME` 또는 bind mount를 통해 유지되도록 하세요. 자세한 내용은 [Docker](/ko/install/docker)를 참조하세요. +브라우저 다운로드를 유지하려면 `PLAYWRIGHT_BROWSERS_PATH`를 설정하고(예: `/home/node/.cache/ms-playwright`), `/home/node`가 `OPENCLAW_HOME_VOLUME` 또는 bind mount를 통해 유지되도록 하세요. 자세한 내용은 [Docker](/ko/install/docker)를 참조하세요. ## 작동 방식(내부) 상위 수준 흐름: - 작은 **제어 서버**가 HTTP 요청을 받습니다. -- **CDP**를 통해 Chromium 기반 브라우저(Chrome/Brave/Edge/Chromium)에 연결합니다. -- 고급 작업(클릭/입력/스냅샷/PDF)에는 CDP 위에서 **Playwright**를 사용합니다. +- 이 서버는 **CDP**를 통해 Chromium 기반 브라우저(Chrome/Brave/Edge/Chromium)에 연결합니다. +- 고급 작업(click/type/snapshot/PDF)에는 CDP 위에서 **Playwright**를 사용합니다. - Playwright가 없으면 Playwright 비의존 작업만 사용할 수 있습니다. -이 설계는 에이전트가 안정적이고 결정적인 인터페이스를 사용하도록 유지하면서도 -로컬/원격 브라우저와 프로필을 교체할 수 있게 합니다. +이 설계는 에이전트가 안정적이고 결정적인 인터페이스를 사용하도록 유지하면서, 로컬/원격 브라우저와 프로필을 교체할 수 있게 해줍니다. ## CLI 빠른 참조 -모든 명령은 특정 프로필을 대상으로 `--browser-profile `을 받을 수 있습니다. -모든 명령은 기계가 읽을 수 있는 출력(안정적인 페이로드)을 위해 `--json`도 받을 수 있습니다. +모든 명령은 특정 프로필을 지정하기 위해 `--browser-profile `을 받을 수 있습니다. +모든 명령은 기계가 읽을 수 있는 출력(안정적인 페이로드)을 위해 `--json`도 지원합니다. 기본: @@ -661,9 +604,7 @@ docker compose run --rm openclaw-cli \ 수명 주기 참고: -- attach-only 및 원격 CDP 프로필의 경우에도 테스트 후 정리 명령으로는 - `openclaw browser stop`이 올바릅니다. 이 명령은 실제 브라우저를 종료하는 대신 - 활성 제어 세션을 닫고 임시 에뮬레이션 재정의를 지웁니다. +- attach-only 및 원격 CDP 프로필의 경우에도 테스트 후 정리 명령으로는 여전히 `openclaw browser stop`이 적절합니다. 이 명령은 기본 브라우저를 종료하는 대신 활성 제어 세션을 닫고 임시 에뮬레이션 재정의 상태를 지웁니다. - `openclaw browser errors --clear` - `openclaw browser requests --filter api --clear` - `openclaw browser pdf` @@ -712,53 +653,52 @@ docker compose run --rm openclaw-cli \ - `openclaw browser set locale en-US` - `openclaw browser set device "iPhone 14"` -참고 사항: +참고: -- `upload`와 `dialog`는 **사전 준비** 호출입니다. 파일 선택기/대화상자를 - 트리거하는 클릭/키 입력 전에 실행하세요. +- `upload`와 `dialog`는 **사전 준비(arming)** 호출입니다. 파일 선택기/대화상자를 트리거하는 클릭/입력 전에 먼저 실행하세요. - 다운로드 및 trace 출력 경로는 OpenClaw 임시 루트로 제한됩니다: - - traces: `/tmp/openclaw` (대체 경로: `${os.tmpdir()}/openclaw`) - - downloads: `/tmp/openclaw/downloads` (대체 경로: `${os.tmpdir()}/openclaw/downloads`) -- 업로드 경로는 OpenClaw 임시 업로드 루트로 제한됩니다: - - uploads: `/tmp/openclaw/uploads` (대체 경로: `${os.tmpdir()}/openclaw/uploads`) + - traces: `/tmp/openclaw` (대체값: `${os.tmpdir()}/openclaw`) + - downloads: `/tmp/openclaw/downloads` (대체값: `${os.tmpdir()}/openclaw/downloads`) +- 업로드 경로는 OpenClaw 임시 uploads 루트로 제한됩니다: + - uploads: `/tmp/openclaw/uploads` (대체값: `${os.tmpdir()}/openclaw/uploads`) - `upload`는 `--input-ref` 또는 `--element`를 통해 파일 입력을 직접 설정할 수도 있습니다. - `snapshot`: - - `--format ai`(기본값, Playwright 설치 시): 숫자 ref(`aria-ref=""`)가 포함된 AI 스냅샷을 반환합니다. - - `--format aria`: 접근성 트리를 반환합니다(ref 없음, 검사 전용). - - `--efficient`(또는 `--mode efficient`): 간결한 role 스냅샷 프리셋(interactive + compact + depth + 낮은 maxChars)입니다. - - config 기본값(도구/CLI 전용): 호출자가 모드를 전달하지 않을 때 효율적인 스냅샷을 사용하려면 `browser.snapshotDefaults.mode: "efficient"`를 설정하세요([Gateway configuration](/ko/gateway/configuration-reference#browser) 참조). - - Role 스냅샷 옵션(`--interactive`, `--compact`, `--depth`, `--selector`)은 `ref=e12` 같은 ref가 있는 role 기반 스냅샷을 강제합니다. - - `--frame "