From f59e3251667a2640533c4ce08013535bebf40994 Mon Sep 17 00:00:00 2001 From: "openclaw-docs-i18n[bot]" Date: Mon, 4 May 2026 06:27:28 +0000 Subject: [PATCH] chore(i18n): refresh ko translations --- docs/ko/channels/telegram.md | 468 ++++++++------- docs/ko/ci.md | 490 ++++++++------- docs/ko/cli/plugins.md | 224 +++---- docs/ko/cli/proxy.md | 43 +- docs/ko/cli/sessions.md | 67 +-- docs/ko/concepts/mantis.md | 393 ++++++------ docs/ko/concepts/messages.md | 111 ++-- docs/ko/concepts/progress-drafts.md | 181 ++++-- docs/ko/concepts/qa-e2e-automation.md | 354 +++++------ docs/ko/concepts/streaming.md | 157 +++-- docs/ko/install/updating.md | 107 ++-- docs/ko/plugins/google-meet.md | 827 +++++++++++++++----------- docs/ko/plugins/voice-call.md | 326 +++++----- docs/ko/providers/elevenlabs.md | 81 +-- docs/ko/providers/google.md | 175 +++--- docs/ko/security/network-proxy.md | 103 ++-- docs/ko/tools/subagents.md | 358 ++++++----- docs/ko/web/control-ui.md | 280 ++++----- 18 files changed, 2549 insertions(+), 2196 deletions(-) diff --git a/docs/ko/channels/telegram.md b/docs/ko/channels/telegram.md index 21bbfed65..cc62cce8d 100644 --- a/docs/ko/channels/telegram.md +++ b/docs/ko/channels/telegram.md @@ -1,18 +1,18 @@ --- read_when: - Telegram 기능 또는 Webhook 작업하기 -summary: Telegram 봇 지원 상태, 기능 및 구성 +summary: Telegram 봇 지원 상태, 기능 및 설정 title: Telegram x-i18n: - generated_at: "2026-05-03T21:27:14Z" + generated_at: "2026-05-04T06:22:43Z" model: gpt-5.5 provider: openai - source_hash: 528ace9dae29eda22f98cc1436ec16146eb9d83edc73aa6db1ab8283f4f873c0 + source_hash: c7f49db5f3fe8fd724e53a2ae3d226446f248bf9d021fcc01c1cf816649381d2 source_path: channels/telegram.md workflow: 16 --- -프로덕션 준비가 된 bot DM 및 그룹 지원을 grammY를 통해 제공합니다. Long polling이 기본 모드이며, webhook 모드는 선택 사항입니다. +프로덕션에서 사용할 준비가 된 grammY 기반 봇 DM 및 그룹 지원입니다. 롱 폴링이 기본 모드이며, Webhook 모드는 선택 사항입니다. @@ -22,17 +22,17 @@ x-i18n: 채널 간 진단 및 복구 플레이북입니다. - 전체 채널 구성 패턴과 예제입니다. + 전체 채널 구성 패턴과 예시입니다. ## 빠른 설정 - - Telegram을 열고 **@BotFather**와 채팅하세요(핸들이 정확히 `@BotFather`인지 확인). + + Telegram을 열고 **@BotFather**와 채팅합니다(핸들이 정확히 `@BotFather`인지 확인). - `/newbot`을 실행하고 안내를 따른 뒤 토큰을 저장하세요. + `/newbot`을 실행하고 안내를 따른 뒤 토큰을 저장합니다. @@ -51,12 +51,12 @@ x-i18n: } ``` - Env 대체값: `TELEGRAM_BOT_TOKEN=...`(기본 계정에만 적용). - Telegram은 `openclaw channels login telegram`을 사용하지 **않습니다**. config/env에 토큰을 구성한 다음 gateway를 시작하세요. + 환경 변수 폴백: `TELEGRAM_BOT_TOKEN=...`(기본 계정만 해당). + Telegram은 `openclaw channels login telegram`을 사용하지 **않습니다**. config/env에 토큰을 구성한 다음 Gateway를 시작하세요. - + ```bash openclaw gateway @@ -68,115 +68,115 @@ openclaw pairing approve telegram - - bot을 그룹에 추가한 다음, 접근 모델에 맞게 `channels.telegram.groups`와 `groupPolicy`를 설정하세요. + + 그룹에 봇을 추가한 다음, 액세스 모델에 맞게 `channels.telegram.groups`와 `groupPolicy`를 설정합니다. -토큰 확인 순서는 계정을 인식합니다. 실제로는 config 값이 env 대체값보다 우선하며, `TELEGRAM_BOT_TOKEN`은 기본 계정에만 적용됩니다. +토큰 확인 순서는 계정을 인식합니다. 실제로는 구성 값이 환경 변수 폴백보다 우선하며, `TELEGRAM_BOT_TOKEN`은 기본 계정에만 적용됩니다. -## Telegram 측 설정 +## Telegram 쪽 설정 - - Telegram bot은 기본적으로 **Privacy Mode**를 사용하며, 이 모드는 bot이 수신하는 그룹 메시지를 제한합니다. + + Telegram 봇은 기본적으로 **개인정보 보호 모드**를 사용하며, 이 모드는 봇이 받을 수 있는 그룹 메시지를 제한합니다. - bot이 모든 그룹 메시지를 확인해야 하는 경우 다음 중 하나를 수행하세요. + 봇이 모든 그룹 메시지를 확인해야 한다면 다음 중 하나를 수행하세요. - - `/setprivacy`로 프라이버시 모드를 비활성화하거나 - - bot을 그룹 관리자로 만드세요. + - `/setprivacy`로 개인정보 보호 모드를 비활성화하거나 + - 봇을 그룹 관리자로 지정합니다. - 프라이버시 모드를 전환할 때는 Telegram이 변경 사항을 적용하도록 각 그룹에서 bot을 제거한 뒤 다시 추가하세요. + 개인정보 보호 모드를 전환할 때는 Telegram이 변경 사항을 적용하도록 각 그룹에서 봇을 제거한 뒤 다시 추가하세요. 관리자 상태는 Telegram 그룹 설정에서 제어됩니다. - 관리자 bot은 모든 그룹 메시지를 수신하므로, 항상 켜져 있는 그룹 동작에 유용합니다. + 관리자 봇은 모든 그룹 메시지를 받으므로, 상시 동작하는 그룹 동작에 유용합니다. - - 그룹 추가 허용/거부를 위한 `/setjoingroups` - - 그룹 표시 범위 동작을 위한 `/setprivacy` + - 그룹 추가를 허용/거부하는 `/setjoingroups` + - 그룹 가시성 동작을 위한 `/setprivacy` -## 접근 제어 및 활성화 +## 액세스 제어 및 활성화 - `channels.telegram.dmPolicy`는 직접 메시지 접근을 제어합니다. + `channels.telegram.dmPolicy`는 직접 메시지 액세스를 제어합니다. - `pairing`(기본값) - - `allowlist`(`allowFrom`에 보낸 사람 ID가 하나 이상 필요) + - `allowlist`(`allowFrom`에 하나 이상의 발신자 ID 필요) - `open`(`allowFrom`에 `"*"` 포함 필요) - `disabled` - `allowFrom: ["*"]`와 함께 `dmPolicy: "open"`을 사용하면 bot 사용자 이름을 찾거나 추측한 모든 Telegram 계정이 bot에 명령할 수 있습니다. 도구가 엄격히 제한된 의도적으로 공개된 bot에만 사용하세요. 단일 소유자 bot은 숫자 사용자 ID와 함께 `allowlist`를 사용해야 합니다. + `allowFrom: ["*"]`와 함께 `dmPolicy: "open"`을 사용하면 봇 사용자 이름을 찾거나 추측한 모든 Telegram 계정이 봇에 명령할 수 있습니다. 도구가 엄격히 제한된 의도적인 공개 봇에만 사용하세요. 단일 소유자 봇은 숫자 사용자 ID와 함께 `allowlist`를 사용해야 합니다. - `channels.telegram.allowFrom`은 숫자 Telegram 사용자 ID를 받습니다. `telegram:` / `tg:` 접두사는 허용되며 정규화됩니다. - 다중 계정 config에서는 제한적인 최상위 `channels.telegram.allowFrom`이 안전 경계로 처리됩니다. 계정 수준 `allowFrom: ["*"]` 항목은 병합 후 유효 계정 allowlist에 명시적 와일드카드가 계속 포함되어 있지 않는 한 해당 계정을 공개로 만들지 않습니다. - 빈 `allowFrom`과 함께 `dmPolicy: "allowlist"`를 사용하면 모든 DM이 차단되며 config 검증에서 거부됩니다. + `channels.telegram.allowFrom`은 숫자 Telegram 사용자 ID를 허용합니다. `telegram:` / `tg:` 접두사는 허용되며 정규화됩니다. + 다중 계정 구성에서는 제한적인 최상위 `channels.telegram.allowFrom`이 안전 경계로 처리됩니다. 병합 후 유효 계정 허용 목록에 명시적 와일드카드가 여전히 포함되어 있지 않으면, 계정 수준의 `allowFrom: ["*"]` 항목이 해당 계정을 공개로 만들지 않습니다. + 빈 `allowFrom`과 함께 `dmPolicy: "allowlist"`를 사용하면 모든 DM이 차단되며 구성 검증에서 거부됩니다. 설정은 숫자 사용자 ID만 요청합니다. - 업그레이드했으며 config에 `@username` allowlist 항목이 포함되어 있다면 `openclaw doctor --fix`를 실행해 해결하세요(최선의 시도 방식이며 Telegram bot 토큰 필요). - 이전에 pairing-store allowlist 파일에 의존했다면 `openclaw doctor --fix`가 allowlist 흐름에서 항목을 `channels.telegram.allowFrom`으로 복구할 수 있습니다(예: `dmPolicy: "allowlist"`에 아직 명시적 ID가 없는 경우). + 업그레이드 후 구성에 `@username` 허용 목록 항목이 포함되어 있다면 `openclaw doctor --fix`를 실행해 이를 확인하세요(최선의 시도이며, Telegram 봇 토큰 필요). + 이전에 페어링 저장소 허용 목록 파일에 의존했다면, `openclaw doctor --fix`가 allowlist 흐름에서 항목을 `channels.telegram.allowFrom`으로 복구할 수 있습니다(예: `dmPolicy: "allowlist"`에 아직 명시적 ID가 없는 경우). - 단일 소유자 bot의 경우 이전 페어링 승인에 의존하는 대신, 명시적 숫자 `allowFrom` ID와 함께 `dmPolicy: "allowlist"`를 사용해 접근 정책을 config에 지속적으로 유지하는 것을 권장합니다. + 단일 소유자 봇의 경우, 이전 페어링 승인에 의존하는 대신 액세스 정책이 구성에 지속되도록 명시적인 숫자 `allowFrom` ID와 함께 `dmPolicy: "allowlist"`를 사용하는 것이 좋습니다. - 흔한 혼동: DM 페어링 승인이 “이 보낸 사람이 어디서나 승인됨”을 의미하지는 않습니다. - 페어링은 DM 접근을 부여합니다. 아직 명령 소유자가 없으면, 처음 승인된 페어링은 소유자 전용 명령과 exec 승인이 명시적 운영자 계정을 갖도록 `commands.ownerAllowFrom`도 설정합니다. - 그룹 보낸 사람 승인은 여전히 명시적 config allowlist에서 옵니다. - “한 번 승인되면 DM과 그룹 명령이 모두 작동”하길 원한다면 숫자 Telegram 사용자 ID를 `channels.telegram.allowFrom`에 넣으세요. 소유자 전용 명령의 경우 `commands.ownerAllowFrom`에 `telegram:`가 포함되어 있는지 확인하세요. + 흔한 혼동: DM 페어링 승인은 "이 발신자가 모든 곳에서 승인되었다"는 뜻이 아닙니다. + 페어링은 DM 액세스를 부여합니다. 명령 소유자가 아직 없으면, 첫 승인된 페어링은 소유자 전용 명령과 실행 승인이 명시적인 운영자 계정을 갖도록 `commands.ownerAllowFrom`도 설정합니다. + 그룹 발신자 인증은 여전히 명시적인 구성 허용 목록에서 가져옵니다. + "한 번 승인되면 DM과 그룹 명령이 모두 작동"하기를 원한다면 숫자 Telegram 사용자 ID를 `channels.telegram.allowFrom`에 넣으세요. 소유자 전용 명령의 경우 `commands.ownerAllowFrom`에 `telegram:`가 포함되어 있는지 확인하세요. ### Telegram 사용자 ID 찾기 - 더 안전한 방법(타사 bot 없음): + 더 안전한 방법(서드파티 봇 없음): - 1. 내 bot에 DM을 보냅니다. + 1. 봇에 DM을 보냅니다. 2. `openclaw logs --follow`를 실행합니다. - 3. `from.id`를 읽습니다. + 3. `from.id`를 확인합니다. - 공식 Bot API 메서드: + 공식 Bot API 방법: ```bash curl "https://api.telegram.org/bot/getUpdates" ``` - 타사 방법(프라이버시가 더 낮음): `@userinfobot` 또는 `@getidsbot`. + 서드파티 방법(개인정보 보호 수준 낮음): `@userinfobot` 또는 `@getidsbot`. - - 두 제어가 함께 적용됩니다. + + 두 가지 제어가 함께 적용됩니다. 1. **허용되는 그룹**(`channels.telegram.groups`) - - `groups` config 없음: - - `groupPolicy: "open"` 사용: 모든 그룹이 그룹 ID 검사를 통과할 수 있음 - - `groupPolicy: "allowlist"`(기본값) 사용: `groups` 항목(또는 `"*"`)을 추가할 때까지 그룹이 차단됨 - - `groups` 구성됨: allowlist로 동작(명시적 ID 또는 `"*"`) + - `groups` 구성이 없음: + - `groupPolicy: "open"`인 경우: 모든 그룹이 그룹 ID 검사를 통과할 수 있음 + - `groupPolicy: "allowlist"`(기본값)인 경우: `groups` 항목(또는 `"*"`)을 추가할 때까지 그룹이 차단됨 + - `groups`가 구성됨: 허용 목록처럼 동작(명시적 ID 또는 `"*"`) - 2. **그룹에서 허용되는 보낸 사람**(`channels.telegram.groupPolicy`) + 2. **그룹에서 허용되는 발신자**(`channels.telegram.groupPolicy`) - `open` - `allowlist`(기본값) - `disabled` - `groupAllowFrom`은 그룹 보낸 사람 필터링에 사용됩니다. 설정되지 않으면 Telegram은 `allowFrom`으로 대체합니다. + `groupAllowFrom`은 그룹 발신자 필터링에 사용됩니다. 설정하지 않으면 Telegram은 `allowFrom`으로 폴백합니다. `groupAllowFrom` 항목은 숫자 Telegram 사용자 ID여야 합니다(`telegram:` / `tg:` 접두사는 정규화됨). Telegram 그룹 또는 슈퍼그룹 채팅 ID를 `groupAllowFrom`에 넣지 마세요. 음수 채팅 ID는 `channels.telegram.groups` 아래에 둡니다. - 숫자가 아닌 항목은 보낸 사람 승인에서 무시됩니다. - 보안 경계(`2026.2.25+`): 그룹 보낸 사람 인증은 DM pairing-store 승인을 상속하지 **않습니다**. - 페어링은 DM 전용으로 유지됩니다. 그룹의 경우 `groupAllowFrom` 또는 그룹별/토픽별 `allowFrom`을 설정하세요. - `groupAllowFrom`이 설정되지 않으면 Telegram은 pairing store가 아니라 config `allowFrom`으로 대체합니다. - 단일 소유자 bot의 실용적인 패턴: 사용자 ID를 `channels.telegram.allowFrom`에 설정하고, `groupAllowFrom`은 설정하지 않은 채 대상 그룹을 `channels.telegram.groups` 아래에서 허용하세요. - 런타임 참고: `channels.telegram`이 완전히 없으면, `channels.defaults.groupPolicy`가 명시적으로 설정되지 않은 한 런타임 기본값은 fail-closed `groupPolicy="allowlist"`입니다. + 숫자가 아닌 항목은 발신자 인증에서 무시됩니다. + 보안 경계(`2026.2.25+`): 그룹 발신자 인증은 DM 페어링 저장소 승인을 상속하지 **않습니다**. + 페어링은 DM 전용으로 유지됩니다. 그룹의 경우 `groupAllowFrom` 또는 그룹별/주제별 `allowFrom`을 설정하세요. + `groupAllowFrom`이 설정되지 않은 경우 Telegram은 페어링 저장소가 아니라 구성의 `allowFrom`으로 폴백합니다. + 단일 소유자 봇의 실용적인 패턴: 사용자 ID를 `channels.telegram.allowFrom`에 설정하고, `groupAllowFrom`은 설정하지 않은 채 대상 그룹을 `channels.telegram.groups` 아래에서 허용합니다. + 런타임 참고: `channels.telegram`이 완전히 누락된 경우, `channels.defaults.groupPolicy`가 명시적으로 설정되어 있지 않으면 런타임은 fail-closed `groupPolicy="allowlist"`를 기본값으로 사용합니다. - 예: 특정 그룹 하나에서 모든 멤버 허용: + 예시: 특정 그룹 하나의 모든 멤버 허용: ```json5 { @@ -193,7 +193,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 예: 특정 그룹 하나 안에서 특정 사용자만 허용: + 예시: 특정 그룹 하나 안에서 특정 사용자만 허용: ```json5 { @@ -211,18 +211,18 @@ curl "https://api.telegram.org/bot/getUpdates" ``` - 흔한 실수: `groupAllowFrom`은 Telegram 그룹 allowlist가 아닙니다. + 흔한 실수: `groupAllowFrom`은 Telegram 그룹 허용 목록이 아닙니다. - `-1001234567890` 같은 음수 Telegram 그룹 또는 슈퍼그룹 채팅 ID는 `channels.telegram.groups` 아래에 넣으세요. - - 허용된 그룹 안에서 어떤 사람이 bot을 트리거할 수 있는지 제한하려면 `8734062810` 같은 Telegram 사용자 ID를 `groupAllowFrom` 아래에 넣으세요. - - 허용된 그룹의 모든 멤버가 bot과 대화할 수 있게 하려는 경우에만 `groupAllowFrom: ["*"]`를 사용하세요. + - 허용된 그룹 안에서 어떤 사람이 봇을 트리거할 수 있는지 제한하려면 `8734062810` 같은 Telegram 사용자 ID를 `groupAllowFrom` 아래에 넣으세요. + - 허용된 그룹의 모든 멤버가 봇과 대화할 수 있게 하려는 경우에만 `groupAllowFrom: ["*"]`를 사용하세요. - 그룹 응답에는 기본적으로 멘션이 필요합니다. + 그룹 답장은 기본적으로 멘션이 필요합니다. 멘션은 다음에서 올 수 있습니다. @@ -236,9 +236,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `/activation always` - `/activation mention` - 이는 세션 상태만 업데이트합니다. 지속성에는 config를 사용하세요. + 이는 세션 상태만 업데이트합니다. 지속하려면 구성을 사용하세요. - 지속 config 예: + 지속 구성 예시: ```json5 { @@ -263,33 +263,33 @@ curl "https://api.telegram.org/bot/getUpdates" ## 런타임 동작 -- Telegram은 gateway 프로세스가 소유합니다. -- 라우팅은 결정적입니다. Telegram 인바운드는 Telegram으로 응답합니다(모델이 채널을 선택하지 않음). -- 인바운드 메시지는 응답 메타데이터와 미디어 플레이스홀더를 포함한 공유 채널 envelope으로 정규화됩니다. -- 그룹 세션은 그룹 ID로 격리됩니다. 포럼 토픽은 토픽 격리를 유지하기 위해 `:topic:`를 추가합니다. -- DM 메시지는 `message_thread_id`를 포함할 수 있습니다. OpenClaw는 응답을 위해 thread ID를 보존하지만, 기본적으로 DM은 평면 세션에 유지합니다. 의도적으로 DM 토픽 세션 격리를 원할 때는 `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct..threadReplies: "inbound"`, `requireTopic: true` 또는 일치하는 토픽 config를 구성하세요. -- Long polling은 채팅별/스레드별 순서를 갖춘 grammY runner를 사용합니다. 전체 runner sink 동시성은 `agents.defaults.maxConcurrent`를 사용합니다. -- Long polling은 각 gateway 프로세스 내부에서 보호되어, 한 번에 하나의 활성 poller만 bot 토큰을 사용할 수 있습니다. 여전히 `getUpdates` 409 충돌이 보이면 다른 OpenClaw gateway, 스크립트 또는 외부 poller가 같은 토큰을 사용 중일 가능성이 큽니다. -- Long-polling watchdog 재시작은 기본적으로 완료된 `getUpdates` liveness 없이 120초가 지나면 트리거됩니다. 배포 환경에서 장시간 실행 작업 중 잘못된 polling-stall 재시작이 계속 보이는 경우에만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 값은 밀리초 단위이며 `30000`부터 `600000`까지 허용됩니다. 계정별 override가 지원됩니다. +- Telegram은 Gateway 프로세스가 소유합니다. +- 라우팅은 결정적입니다. Telegram 인바운드는 Telegram으로 답장합니다(모델이 채널을 선택하지 않음). +- 인바운드 메시지는 답장 메타데이터와 미디어 플레이스홀더가 포함된 공유 채널 엔벌로프로 정규화됩니다. +- 그룹 세션은 그룹 ID로 격리됩니다. 포럼 주제는 주제를 격리하기 위해 `:topic:`를 추가합니다. +- DM 메시지는 `message_thread_id`를 포함할 수 있습니다. OpenClaw는 답장을 위해 스레드 ID를 보존하지만 기본적으로 DM은 플랫 세션에 유지합니다. 의도적으로 DM 주제 세션 격리를 원할 때는 `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct..threadReplies: "inbound"`, `requireTopic: true` 또는 일치하는 주제 구성을 설정하세요. +- 롱 폴링은 채팅별/스레드별 순서를 적용하는 grammY runner를 사용합니다. 전체 runner sink 동시성은 `agents.defaults.maxConcurrent`를 사용합니다. +- 롱 폴링은 각 Gateway 프로세스 내부에서 보호되므로 한 번에 하나의 활성 poller만 봇 토큰을 사용할 수 있습니다. 그래도 `getUpdates` 409 충돌이 보인다면 다른 OpenClaw Gateway, 스크립트 또는 외부 poller가 같은 토큰을 사용 중일 가능성이 큽니다. +- 롱 폴링 watchdog 재시작은 기본적으로 완료된 `getUpdates` 활성 신호가 120초 동안 없을 때 트리거됩니다. 배포 환경에서 장시간 실행 작업 중 잘못된 polling-stall 재시작이 계속 발생하는 경우에만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 값은 밀리초 단위이며 `30000`부터 `600000`까지 허용됩니다. 계정별 오버라이드가 지원됩니다. - Telegram Bot API는 읽음 확인을 지원하지 않습니다(`sendReadReceipts`는 적용되지 않음). -## 기능 참조 +## 기능 참고 - OpenClaw는 부분 응답을 실시간으로 스트리밍할 수 있습니다. + OpenClaw는 부분 답장을 실시간으로 스트리밍할 수 있습니다. - 직접 채팅: 미리보기 메시지 + `editMessageText` - - 그룹/토픽: 미리보기 메시지 + `editMessageText` + - 그룹/주제: 미리보기 메시지 + `editMessageText` 요구 사항: - - `channels.telegram.streaming`은 `off | partial | block | progress`입니다(기본값: `partial`). + - `channels.telegram.streaming`은 `off | partial | block | progress`입니다(기본값: `partial`) - `progress`는 편집 가능한 상태 초안 하나를 유지하고 최종 전달 전까지 도구 진행 상황으로 업데이트합니다. - - `streaming.preview.toolProgress`는 도구/진행 업데이트가 같은 편집된 미리보기 메시지를 재사용할지 제어합니다(기본값: 미리보기 스트리밍이 활성일 때 `true`). - - 레거시 `channels.telegram.streamMode`와 불리언 `streaming` 값은 감지됩니다. 이를 `channels.telegram.streaming.mode`로 마이그레이션하려면 `openclaw doctor --fix`를 실행하세요. + - `streaming.preview.toolProgress`는 도구/진행 상황 업데이트가 같은 편집된 미리보기 메시지를 재사용할지 제어합니다(기본값: 미리보기 스트리밍이 활성화된 경우 `true`). + - 기존 `channels.telegram.streamMode`와 불리언 `streaming` 값은 감지됩니다. `openclaw doctor --fix`를 실행해 `channels.telegram.streaming.mode`로 마이그레이션하세요. - 도구 진행 미리보기 업데이트는 도구가 실행되는 동안 표시되는 짧은 상태 줄입니다. 예를 들면 명령 실행, 파일 읽기, 계획 업데이트, 패치 요약입니다. Telegram은 `v2026.4.22` 이후의 릴리스된 OpenClaw 동작과 일치하도록 기본적으로 이를 활성화합니다. 답변 텍스트에 대해서는 편집된 미리보기를 유지하되 도구 진행 줄을 숨기려면 다음을 설정하세요. + 도구 진행 상황 미리보기 업데이트는 도구가 실행되는 동안 표시되는 짧은 상태 줄입니다. 예를 들어 명령 실행, 파일 읽기, 계획 업데이트 또는 패치 요약이 있습니다. Telegram은 `v2026.4.22` 및 이후 버전의 릴리스된 OpenClaw 동작과 일치하도록 기본적으로 이를 활성화합니다. 답변 텍스트용 편집 미리보기는 유지하되 도구 진행 상황 줄을 숨기려면 다음을 설정하세요. ```json { @@ -306,35 +306,36 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - `streaming.mode: "off"`는 최종 응답만 전달하려는 경우에만 사용하세요. Telegram 미리 보기 편집이 비활성화되고 일반적인 도구/진행 상황 대화는 독립 상태 메시지로 전송되지 않고 억제됩니다. 승인 프롬프트, 미디어 페이로드, 오류는 여전히 일반 최종 전달 경로로 라우팅됩니다. 도구 진행 상태 줄만 숨기고 답변 미리 보기 편집은 유지하려는 경우 `streaming.preview.toolProgress: false`를 사용하세요. + `streaming.mode: "off"`는 최종 응답만 전달하려는 경우에만 사용하세요. Telegram 미리 보기 편집이 비활성화되고, 일반 도구/진행 상황 잡담은 독립 상태 메시지로 전송되는 대신 억제됩니다. 승인 프롬프트, 미디어 페이로드, 오류는 여전히 일반 최종 전달 경로를 통해 라우팅됩니다. 도구 진행 상태 줄은 숨기면서 답변 미리 보기 편집만 유지하려면 `streaming.preview.toolProgress: false`를 사용하세요. - Telegram 선택된 인용 답장은 예외입니다. `replyToMode`가 `"first"`, `"all"` 또는 `"batched"`이고 수신 메시지에 선택된 인용 텍스트가 포함된 경우, OpenClaw는 답변 미리 보기를 편집하는 대신 Telegram의 기본 인용 답장 경로로 최종 답변을 보내므로 `streaming.preview.toolProgress`는 해당 턴의 짧은 상태 줄을 표시할 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답장은 여전히 미리 보기 스트리밍을 유지합니다. 도구 진행 상황 가시성이 기본 인용 답장보다 더 중요하면 `replyToMode: "off"`를 설정하거나, 절충을 인정하려면 `streaming.preview.toolProgress: false`를 설정하세요. + Telegram 선택 인용 답장은 예외입니다. `replyToMode`가 `"first"`, `"all"` 또는 `"batched"`이고 인바운드 메시지에 선택된 인용 텍스트가 포함된 경우, OpenClaw는 답변 미리 보기를 편집하는 대신 Telegram의 네이티브 인용 답장 경로를 통해 최종 답변을 전송하므로 `streaming.preview.toolProgress`는 해당 턴의 짧은 상태 줄을 표시할 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답장은 계속 미리 보기 스트리밍을 유지합니다. 도구 진행 상황 표시가 네이티브 인용 답장보다 더 중요하면 `replyToMode: "off"`를 설정하거나, 이 절충을 인정하려면 `streaming.preview.toolProgress: false`를 설정하세요. 텍스트 전용 답장의 경우: - - 짧은 DM/그룹/주제 미리 보기: OpenClaw는 동일한 미리 보기 메시지를 유지하고 그 자리에서 최종 편집을 수행합니다. 단, 미리 보기가 나타난 뒤 표시되는 비-미리 보기 메시지가 전송된 경우는 제외합니다. - - 미리 보기 뒤에 표시되는 비-미리 보기 출력이 이어지는 경우: OpenClaw는 완료된 답장을 새 최종 메시지로 보내고 이전 미리 보기를 정리하므로, 최종 답변이 중간 출력 뒤에 나타납니다. - - 약 1분보다 오래된 미리 보기: OpenClaw는 완료된 답장을 새 최종 메시지로 보낸 다음 미리 보기를 정리하므로, Telegram에 표시되는 타임스탬프는 미리 보기 생성 시간이 아니라 완료 시간을 반영합니다. + - 짧은 DM/그룹/토픽 미리 보기: 미리 보기가 나타난 뒤 보이는 비미리 보기 메시지가 전송되지 않은 한, OpenClaw는 같은 미리 보기 메시지를 유지하고 제자리에서 최종 편집을 수행합니다. + - 미리 보기 뒤에 보이는 비미리 보기 출력이 이어지는 경우: OpenClaw는 완료된 답장을 새 최종 메시지로 전송하고 이전 미리 보기를 정리하므로, 최종 답변은 중간 출력 뒤에 표시됩니다. + - 약 1분보다 오래된 미리 보기: OpenClaw는 완료된 답장을 새 최종 메시지로 전송한 다음 미리 보기를 정리하므로, Telegram의 표시 타임스탬프는 미리 보기 생성 시간이 아니라 완료 시간을 반영합니다. - 복잡한 답장(예: 미디어 페이로드)의 경우, OpenClaw는 일반 최종 전달로 대체한 다음 미리 보기 메시지를 정리합니다. + 복잡한 답장(예: 미디어 페이로드)의 경우, OpenClaw는 일반 최종 전달 방식으로 폴백한 다음 미리 보기 메시지를 정리합니다. - 미리 보기 스트리밍은 블록 스트리밍과 별개입니다. Telegram에 대해 블록 스트리밍이 명시적으로 활성화되면, OpenClaw는 중복 스트리밍을 피하기 위해 미리 보기 스트림을 건너뜁니다. + 미리 보기 스트리밍은 블록 스트리밍과 별개입니다. Telegram에서 블록 스트리밍이 명시적으로 활성화된 경우, OpenClaw는 이중 스트리밍을 피하기 위해 미리 보기 스트림을 건너뜁니다. Telegram 전용 추론 스트림: - - `/reasoning stream`은 생성 중에 추론을 실시간 미리 보기로 보냅니다. + - `/reasoning stream`은 생성 중 추론을 실시간 미리 보기에 전송합니다. + - 최종 전달 후 추론 미리 보기는 삭제됩니다. 추론을 계속 표시해야 하면 `/reasoning on`을 사용하세요. - 최종 답변은 추론 텍스트 없이 전송됩니다. - 발신 텍스트는 Telegram `parse_mode: "HTML"`을 사용합니다. + 아웃바운드 텍스트는 Telegram `parse_mode: "HTML"`을 사용합니다. - - Markdown 스타일 텍스트는 Telegram 안전 HTML로 렌더링됩니다. + - Markdown과 유사한 텍스트는 Telegram에 안전한 HTML로 렌더링됩니다. - 원시 모델 HTML은 Telegram 파싱 실패를 줄이기 위해 이스케이프됩니다. - - Telegram이 파싱된 HTML을 거부하면 OpenClaw는 일반 텍스트로 재시도합니다. + - Telegram이 파싱된 HTML을 거부하면 OpenClaw는 일반 텍스트로 다시 시도합니다. 링크 미리 보기는 기본적으로 활성화되며 `channels.telegram.linkPreview: false`로 비활성화할 수 있습니다. @@ -343,9 +344,9 @@ curl "https://api.telegram.org/bot/getUpdates" Telegram 명령 메뉴 등록은 시작 시 `setMyCommands`로 처리됩니다. - 기본 명령 기본값: + 네이티브 명령 기본값: - - `commands.native: "auto"`는 Telegram에 대해 기본 명령을 활성화합니다. + - `commands.native: "auto"`는 Telegram에서 네이티브 명령을 활성화합니다. 사용자 지정 명령 메뉴 항목 추가: @@ -364,47 +365,47 @@ curl "https://api.telegram.org/bot/getUpdates" 규칙: - - 이름은 정규화됩니다(앞의 `/` 제거, 소문자 변환). + - 이름은 정규화됩니다(앞의 `/` 제거, 소문자화). - 유효한 패턴: `a-z`, `0-9`, `_`, 길이 `1..32` - - 사용자 지정 명령은 기본 명령을 재정의할 수 없습니다. - - 충돌/중복은 건너뛰고 로그에 기록됩니다. + - 사용자 지정 명령은 네이티브 명령을 재정의할 수 없습니다. + - 충돌/중복은 건너뛰고 기록됩니다. 참고: - 사용자 지정 명령은 메뉴 항목일 뿐이며, 동작을 자동으로 구현하지 않습니다. - Plugin/skill 명령은 Telegram 메뉴에 표시되지 않더라도 입력하면 계속 작동할 수 있습니다. - 기본 명령이 비활성화되면 내장 명령이 제거됩니다. 사용자 지정/Plugin 명령은 구성된 경우 계속 등록될 수 있습니다. + 네이티브 명령이 비활성화된 경우, 기본 제공 명령은 제거됩니다. 구성된 경우 사용자 지정/Plugin 명령은 계속 등록될 수 있습니다. 일반적인 설정 실패: - - `setMyCommands failed`와 `BOT_COMMANDS_TOO_MUCH`가 함께 표시되면, 잘라낸 뒤에도 Telegram 메뉴가 여전히 넘쳤다는 뜻입니다. Plugin/skill/사용자 지정 명령을 줄이거나 `channels.telegram.commands.native`를 비활성화하세요. - - 직접 Bot API curl 명령은 작동하는데 `deleteWebhook`, `deleteMyCommands` 또는 `setMyCommands`가 `404: Not Found`로 실패하면 `channels.telegram.apiRoot`가 전체 `/bot` 엔드포인트로 설정되었을 수 있습니다. `apiRoot`는 Bot API 루트만이어야 하며, `openclaw doctor --fix`는 실수로 붙은 뒤쪽 `/bot`을 제거합니다. - - `getMe returned 401`은 Telegram이 구성된 봇 토큰을 거부했다는 뜻입니다. `botToken`, `tokenFile` 또는 `TELEGRAM_BOT_TOKEN`을 현재 BotFather 토큰으로 업데이트하세요. OpenClaw는 폴링 전에 중지되므로, 이 문제는 Webhook 정리 실패로 보고되지 않습니다. - - `setMyCommands failed`와 네트워크/fetch 오류가 함께 표시되면 일반적으로 `api.telegram.org`로 나가는 DNS/HTTPS가 차단되었다는 뜻입니다. + - `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`가 표시되면, 잘라낸 뒤에도 Telegram 메뉴가 여전히 넘쳤다는 뜻입니다. Plugin/skill/사용자 지정 명령을 줄이거나 `channels.telegram.commands.native`를 비활성화하세요. + - 직접 Bot API curl 명령은 작동하지만 `deleteWebhook`, `deleteMyCommands` 또는 `setMyCommands`가 `404: Not Found`로 실패하면 `channels.telegram.apiRoot`가 전체 `/bot` 엔드포인트로 설정되었을 수 있습니다. `apiRoot`는 Bot API 루트만이어야 하며, `openclaw doctor --fix`는 실수로 붙은 뒤쪽 `/bot`을 제거합니다. + - `getMe returned 401`은 Telegram이 구성된 봇 토큰을 거부했다는 뜻입니다. `botToken`, `tokenFile` 또는 `TELEGRAM_BOT_TOKEN`을 현재 BotFather 토큰으로 업데이트하세요. OpenClaw는 폴링 전에 중지하므로 이것은 Webhook 정리 실패로 보고되지 않습니다. + - 네트워크/페치 오류와 함께 `setMyCommands failed`가 표시되면 일반적으로 `api.telegram.org`로의 아웃바운드 DNS/HTTPS가 차단되었다는 뜻입니다. ### 기기 페어링 명령(`device-pair` Plugin) `device-pair` Plugin이 설치된 경우: - 1. `/pair`는 설정 코드를 생성합니다. + 1. `/pair`가 설정 코드를 생성합니다. 2. iOS 앱에 코드를 붙여넣습니다. - 3. `/pair pending`은 보류 중인 요청(역할/범위 포함)을 나열합니다. + 3. `/pair pending`은 대기 중인 요청(역할/스코프 포함)을 나열합니다. 4. 요청을 승인합니다. - - 명시적 승인의 경우 `/pair approve ` - - 보류 중인 요청이 하나뿐인 경우 `/pair approve` - - 가장 최근 요청의 경우 `/pair approve latest` + - 명시적 승인은 `/pair approve ` + - 대기 중인 요청이 하나뿐이면 `/pair approve` + - 가장 최근 요청은 `/pair approve latest` - 설정 코드는 수명이 짧은 부트스트랩 토큰을 전달합니다. 내장 부트스트랩 인계는 기본 노드 토큰을 `scopes: []`로 유지합니다. 인계된 운영자 토큰은 `operator.approvals`, `operator.read`, `operator.talk.secrets`, `operator.write`로 제한됩니다. 부트스트랩 범위 검사는 역할 접두사가 붙으므로, 해당 운영자 허용 목록은 운영자 요청만 충족합니다. 운영자가 아닌 역할은 여전히 자체 역할 접두사 아래의 범위가 필요합니다. + 설정 코드는 수명이 짧은 부트스트랩 토큰을 포함합니다. 기본 제공 부트스트랩 인계는 기본 Node 토큰을 `scopes: []`로 유지합니다. 인계된 모든 운영자 토큰은 `operator.approvals`, `operator.read`, `operator.talk.secrets`, `operator.write`로 제한됩니다. 부트스트랩 스코프 검사는 역할 접두사를 사용하므로 해당 운영자 허용 목록은 운영자 요청만 충족합니다. 비운영자 역할은 여전히 자체 역할 접두사 아래의 스코프가 필요합니다. - 기기가 인증 세부 정보(예: 역할/범위/공개 키)를 변경해 다시 시도하면, 이전 보류 요청은 대체되고 새 요청은 다른 `requestId`를 사용합니다. 승인하기 전에 `/pair pending`을 다시 실행하세요. + 기기가 변경된 인증 세부 정보(예: 역할/스코프/공개 키)로 다시 시도하면 이전 대기 요청은 대체되고 새 요청은 다른 `requestId`를 사용합니다. 승인하기 전에 `/pair pending`을 다시 실행하세요. 자세한 내용: [페어링](/ko/channels/pairing#pair-via-telegram-recommended-for-ios). - 인라인 키보드 범위 구성: + 인라인 키보드 스코프 구성: ```json5 { @@ -436,7 +437,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 범위: + 스코프: - `off` - `dm` @@ -446,7 +447,7 @@ curl "https://api.telegram.org/bot/getUpdates" 레거시 `capabilities: ["inlineButtons"]`는 `inlineButtons: "all"`로 매핑됩니다. - 메시지 액션 예시: + 메시지 작업 예시: ```json5 { @@ -464,13 +465,13 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 콜백 클릭은 텍스트로 agent에 전달됩니다. + 콜백 클릭은 텍스트로 에이전트에 전달됩니다. `callback_data: ` - Telegram 도구 액션에는 다음이 포함됩니다. + Telegram 도구 작업에는 다음이 포함됩니다. - `sendMessage`(`to`, `content`, 선택 사항 `mediaUrl`, `replyToMessageId`, `messageThreadId`) - `react`(`chatId`, `messageId`, `emoji`) @@ -478,9 +479,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `editMessage`(`chatId`, `messageId`, `content`) - `createForumTopic`(`chatId`, `name`, 선택 사항 `iconColor`, `iconCustomEmojiId`) - 채널 메시지 액션은 사용하기 쉬운 별칭(`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`)을 노출합니다. + 채널 메시지 작업은 인체공학적인 별칭(`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`)을 노출합니다. - 게이팅 제어: + 게이트 제어: - `channels.telegram.actions.sendMessage` - `channels.telegram.actions.deleteMessage` @@ -488,9 +489,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `channels.telegram.actions.sticker`(기본값: 비활성화) 참고: `edit`와 `topic-create`는 현재 기본적으로 활성화되어 있으며 별도의 `channels.telegram.actions.*` 토글이 없습니다. - 런타임 전송은 활성 구성/시크릿 스냅샷(시작/다시 로드)을 사용하므로, 액션 경로는 전송마다 임시 SecretRef 재해석을 수행하지 않습니다. + 런타임 전송은 활성 구성/시크릿 스냅샷(시작/다시 로드)을 사용하므로 작업 경로는 전송마다 임시 SecretRef 재해석을 수행하지 않습니다. - 리액션 제거 의미론: [/tools/reactions](/ko/tools/reactions) + 반응 제거 의미 체계: [/tools/reactions](/ko/tools/reactions) @@ -506,7 +507,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `first` - `all` - 답장 스레딩이 활성화되어 있고 원본 Telegram 텍스트 또는 캡션을 사용할 수 있으면, OpenClaw는 기본 Telegram 인용 발췌를 자동으로 포함합니다. Telegram은 기본 인용 텍스트를 1024 UTF-16 코드 단위로 제한하므로, 더 긴 메시지는 시작 부분부터 인용되며 Telegram이 인용을 거부하면 일반 답장으로 대체됩니다. + 답장 스레딩이 활성화되어 있고 원본 Telegram 텍스트 또는 캡션을 사용할 수 있으면, OpenClaw는 네이티브 Telegram 인용 발췌를 자동으로 포함합니다. Telegram은 네이티브 인용 텍스트를 1024 UTF-16 코드 단위로 제한하므로 더 긴 메시지는 시작 부분부터 인용되고 Telegram이 인용을 거부하면 일반 답장으로 폴백합니다. 참고: `off`는 암시적 답장 스레딩을 비활성화합니다. 명시적 `[[reply_to_*]]` 태그는 여전히 적용됩니다. @@ -515,20 +516,20 @@ curl "https://api.telegram.org/bot/getUpdates" 포럼 슈퍼그룹: - - 주제 세션 키는 `:topic:`를 덧붙입니다. - - 답장과 입력 표시가 주제 스레드를 대상으로 합니다. - - 주제 구성 경로: + - 토픽 세션 키는 `:topic:`를 추가합니다. + - 답장과 입력 중 표시는 토픽 스레드를 대상으로 합니다. + - 토픽 구성 경로: `channels.telegram.groups..topics.` - 일반 주제(`threadId=1`) 특수 사례: + 일반 토픽(`threadId=1`) 특수 사례: - - 메시지 전송은 `message_thread_id`를 생략합니다(Telegram은 `sendMessage(...thread_id=1)`을 거부합니다). - - 입력 표시 액션은 여전히 `message_thread_id`를 포함합니다. + - 메시지 전송은 `message_thread_id`를 생략합니다(Telegram은 `sendMessage(...thread_id=1)`를 거부함). + - 입력 중 작업은 여전히 `message_thread_id`를 포함합니다. - 주제 상속: 주제 항목은 재정의되지 않는 한 그룹 설정(`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`)을 상속합니다. - `agentId`는 주제 전용이며 그룹 기본값에서 상속되지 않습니다. + 토픽 상속: 토픽 항목은 재정의되지 않는 한 그룹 설정(`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`)을 상속합니다. + `agentId`는 토픽 전용이며 그룹 기본값에서 상속되지 않습니다. - **주제별 agent 라우팅**: 각 주제는 주제 구성에서 `agentId`를 설정해 다른 agent로 라우팅할 수 있습니다. 이렇게 하면 각 주제가 자체 격리된 워크스페이스, 메모리, 세션을 가집니다. 예시: + **토픽별 에이전트 라우팅**: 각 토픽은 토픽 구성에서 `agentId`를 설정하여 다른 에이전트로 라우팅할 수 있습니다. 이렇게 하면 각 토픽은 자체 격리된 워크스페이스, 메모리, 세션을 갖습니다. 예시: ```json5 { @@ -548,13 +549,13 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 그러면 각 주제는 자체 세션 키를 가집니다. `agent:zu:telegram:group:-1001234567890:topic:3` + 그러면 각 토픽은 자체 세션 키를 갖습니다. `agent:zu:telegram:group:-1001234567890:topic:3` - **영구 ACP 주제 바인딩**: 포럼 주제는 최상위 typed ACP 바인딩(`bindings[]`, `type: "acp"`, `match.channel: "telegram"`, `peer.kind: "group"`, 그리고 `-1001234567890:topic:42` 같은 주제 한정 id)을 통해 ACP 하네스 세션을 고정할 수 있습니다. 현재 그룹/슈퍼그룹의 포럼 주제로 범위가 제한됩니다. [ACP Agents](/ko/tools/acp-agents)를 참조하세요. + **영구 ACP 토픽 바인딩**: 포럼 토픽은 최상위 타입 지정 ACP 바인딩(`type: "acp"`와 `match.channel: "telegram"`, `peer.kind: "group"` 및 `-1001234567890:topic:42` 같은 토픽 한정 ID를 포함하는 `bindings[]`)을 통해 ACP 하네스 세션을 고정할 수 있습니다. 현재 그룹/슈퍼그룹의 포럼 토픽으로 범위가 제한됩니다. [ACP 에이전트](/ko/tools/acp-agents)를 참조하세요. - **채팅에서 스레드 바인딩 ACP 생성**: `/acp spawn --thread here|auto`는 현재 주제를 새 ACP 세션에 바인딩합니다. 후속 메시지는 그곳으로 직접 라우팅됩니다. OpenClaw는 생성 확인을 주제 안에 고정합니다. `channels.telegram.threadBindings.spawnSessions`가 계속 활성화되어 있어야 합니다(기본값: `true`). + **채팅에서 스레드 바인딩 ACP 생성**: `/acp spawn --thread here|auto`는 현재 토픽을 새 ACP 세션에 바인딩합니다. 후속 메시지는 해당 세션으로 직접 라우팅됩니다. OpenClaw는 생성 확인을 토픽 안에 고정합니다. `channels.telegram.threadBindings.spawnSessions`가 계속 활성화되어 있어야 합니다(기본값: `true`). - 템플릿 컨텍스트는 `MessageThreadId`와 `IsForum`을 노출합니다. `message_thread_id`가 있는 DM 채팅은 기본적으로 평면 세션에서 DM 라우팅과 답장 메타데이터를 유지합니다. `threadReplies: "inbound"`, `threadReplies: "always"`, `requireTopic: true` 또는 일치하는 주제 구성으로 설정된 경우에만 스레드 인식 세션 키를 사용합니다. 계정 기본값에는 최상위 `channels.telegram.dm.threadReplies`를 사용하거나, 특정 DM에는 `direct..threadReplies`를 사용하세요. + 템플릿 컨텍스트는 `MessageThreadId`와 `IsForum`을 노출합니다. `message_thread_id`가 있는 DM 채팅은 기본적으로 플랫 세션에서 DM 라우팅과 답장 메타데이터를 유지합니다. `threadReplies: "inbound"`, `threadReplies: "always"`, `requireTopic: true` 또는 일치하는 토픽 구성으로 설정된 경우에만 스레드 인식 세션 키를 사용합니다. 계정 기본값에는 최상위 `channels.telegram.dm.threadReplies`를 사용하거나, 단일 DM에는 `direct..threadReplies`를 사용하세요. @@ -564,12 +565,10 @@ curl "https://api.telegram.org/bot/getUpdates" Telegram은 음성 메모와 오디오 파일을 구분합니다. - 기본값: 오디오 파일 동작 - - 음성 메모 전송을 강제하려면 agent 답장에 `[[audio_as_voice]]` 태그를 사용하세요. - - 수신 음성 메모 전사는 agent 컨텍스트에서 기계 생성, - 신뢰할 수 없는 텍스트로 프레이밍됩니다. 멘션 감지는 여전히 원시 - 전사를 사용하므로 멘션 게이트가 적용된 음성 메시지가 계속 작동합니다. + - 음성 메모 전송을 강제하려면 에이전트 답장에 `[[audio_as_voice]]` 태그를 사용하세요. + - 인바운드 음성 메모 전사는 에이전트 컨텍스트에서 기계 생성의 신뢰할 수 없는 텍스트로 프레이밍됩니다. 멘션 감지는 여전히 원시 전사를 사용하므로 멘션 게이트 음성 메시지는 계속 작동합니다. - 메시지 액션 예시: + 메시지 작업 예시: ```json5 { @@ -581,11 +580,11 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - ### 비디오 메시지 + ### 동영상 메시지 Telegram은 동영상 파일과 동영상 노트를 구분합니다. - 메시지 액션 예시: + 메시지 작업 예시: ```json5 { @@ -603,7 +602,7 @@ curl "https://api.telegram.org/bot/getUpdates" 인바운드 스티커 처리: - - 정적 WEBP: 다운로드 및 처리됨(플레이스홀더 ``) + - 정적 WEBP: 다운로드 및 처리됨(자리표시자 ``) - 애니메이션 TGS: 건너뜀 - 동영상 WEBM: 건너뜀 @@ -619,9 +618,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `~/.openclaw/telegram/sticker-cache.json` - 스티커는 가능할 때 한 번 설명되고, 반복되는 비전 호출을 줄이기 위해 캐시됩니다. + 스티커는 가능한 경우 한 번 설명되고, 반복되는 비전 호출을 줄이기 위해 캐시됩니다. - 스티커 액션 활성화: + 스티커 작업 활성화: ```json5 { @@ -635,7 +634,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 스티커 액션 전송: + 스티커 작업 전송: ```json5 { @@ -666,44 +665,44 @@ curl "https://api.telegram.org/bot/getUpdates" - `Telegram reaction added: 👍 by Alice (@alice) on msg 42` - 구성: + 설정: - `channels.telegram.reactionNotifications`: `off | own | all`(기본값: `own`) - `channels.telegram.reactionLevel`: `off | ack | minimal | extensive`(기본값: `minimal`) 참고: - - `own`은 봇이 보낸 메시지에 대한 사용자 반응만 의미합니다(보낸 메시지 캐시를 통한 최선 노력 방식). - - 반응 이벤트도 Telegram 액세스 제어(`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`)를 그대로 따르며, 승인되지 않은 발신자는 삭제됩니다. - - Telegram은 반응 업데이트에 스레드 ID를 제공하지 않습니다. - - 비포럼 그룹은 그룹 채팅 세션으로 라우팅됩니다. - - 포럼 그룹은 정확한 원본 토픽이 아니라 그룹 일반 토픽 세션(`:topic:1`)으로 라우팅됩니다. + - `own`은 봇이 보낸 메시지에 대한 사용자 반응만 의미합니다(전송 메시지 캐시를 통한 최선의 처리). + - 반응 이벤트는 여전히 Telegram 접근 제어(`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`)를 따르며, 권한이 없는 발신자는 제외됩니다. + - Telegram은 반응 업데이트에서 스레드 ID를 제공하지 않습니다. + - 포럼이 아닌 그룹은 그룹 채팅 세션으로 라우팅됩니다. + - 포럼 그룹은 정확한 원래 토픽이 아니라 그룹 일반 토픽 세션(`:topic:1`)으로 라우팅됩니다. - 폴링/Webhook의 `allowed_updates`에는 `message_reaction`이 자동으로 포함됩니다. + 폴링/Webhook용 `allowed_updates`에는 `message_reaction`이 자동으로 포함됩니다. - - `ackReaction`은 OpenClaw가 인바운드 메시지를 처리하는 동안 승인 이모지를 보냅니다. + + `ackReaction`은 OpenClaw가 인바운드 메시지를 처리하는 동안 확인 이모지를 보냅니다. - 해석 순서: + 확인 순서: - `channels.telegram.accounts..ackReaction` - `channels.telegram.ackReaction` - `messages.ackReaction` - - 에이전트 아이덴티티 이모지 폴백(`agents.list[].identity.emoji`, 없으면 "👀") + - 에이전트 ID 이모지 폴백(`agents.list[].identity.emoji`, 없으면 "👀") 참고: - - Telegram은 유니코드 이모지를 예상합니다(예: "👀"). - - 채널 또는 계정의 반응을 비활성화하려면 `""`를 사용합니다. + - Telegram은 유니코드 이모지를 기대합니다(예: "👀"). + - 채널 또는 계정의 반응을 비활성화하려면 `""`를 사용하세요. - - 채널 구성 쓰기는 기본적으로 활성화됩니다(`configWrites !== false`). + + 채널 설정 쓰기는 기본적으로 활성화되어 있습니다(`configWrites !== false`). - Telegram에서 트리거되는 쓰기는 다음을 포함합니다. + Telegram으로 트리거되는 쓰기에는 다음이 포함됩니다. - `channels.telegram.groups`를 업데이트하기 위한 그룹 마이그레이션 이벤트(`migrate_to_chat_id`) - `/config set` 및 `/config unset`(명령 활성화 필요) @@ -722,30 +721,30 @@ curl "https://api.telegram.org/bot/getUpdates" - - 기본값은 긴 폴링입니다. Webhook 모드의 경우 `channels.telegram.webhookUrl`과 `channels.telegram.webhookSecret`을 설정합니다. 선택 사항으로 `webhookPath`, `webhookHost`, `webhookPort`가 있습니다(기본값 `/telegram-webhook`, `127.0.0.1`, `8787`). + + 기본값은 롱 폴링입니다. Webhook 모드의 경우 `channels.telegram.webhookUrl` 및 `channels.telegram.webhookSecret`을 설정하세요. 선택 사항은 `webhookPath`, `webhookHost`, `webhookPort`입니다(기본값 `/telegram-webhook`, `127.0.0.1`, `8787`). - 로컬 리스너는 `127.0.0.1:8787`에 바인딩됩니다. 공개 인그레스의 경우 로컬 포트 앞에 리버스 프록시를 두거나 의도적으로 `webhookHost: "0.0.0.0"`을 설정합니다. + 로컬 리스너는 `127.0.0.1:8787`에 바인딩됩니다. 공개 인그레스의 경우 로컬 포트 앞에 리버스 프록시를 두거나 의도적으로 `webhookHost: "0.0.0.0"`을 설정하세요. Webhook 모드는 Telegram에 `200`을 반환하기 전에 요청 가드, Telegram 비밀 토큰, JSON 본문을 검증합니다. - 그런 다음 OpenClaw는 긴 폴링에서 사용하는 것과 동일한 채팅별/토픽별 봇 레인을 통해 업데이트를 비동기적으로 처리하므로, 느린 에이전트 턴이 Telegram의 전달 ACK를 붙잡지 않습니다. + 그런 다음 OpenClaw는 롱 폴링에서 사용하는 것과 동일한 채팅별/토픽별 봇 레인을 통해 업데이트를 비동기적으로 처리하므로, 느린 에이전트 턴이 Telegram의 전달 ACK를 붙잡지 않습니다. - + - `channels.telegram.textChunkLimit` 기본값은 4000입니다. - - `channels.telegram.chunkMode="newline"`은 길이 분할 전에 문단 경계(빈 줄)를 우선합니다. + - `channels.telegram.chunkMode="newline"`은 길이 분할 전에 단락 경계(빈 줄)를 우선합니다. - `channels.telegram.mediaMaxMb`(기본값 100)는 인바운드 및 아웃바운드 Telegram 미디어 크기를 제한합니다. - - `channels.telegram.mediaGroupFlushMs`(기본값 500)는 Telegram 앨범/미디어 그룹을 OpenClaw가 하나의 인바운드 메시지로 디스패치하기 전에 얼마나 오래 버퍼링할지 제어합니다. 앨범 일부가 늦게 도착하면 늘리고, 앨범 답장 지연 시간을 줄이려면 줄입니다. - - `channels.telegram.timeoutSeconds`는 Telegram API 클라이언트 타임아웃을 재정의합니다(설정되지 않은 경우 grammY 기본값 적용). 봇 클라이언트는 구성된 값이 60초 아웃바운드 텍스트/입력 중 요청 가드보다 낮으면 해당 값으로 제한하여, OpenClaw의 전송 가드와 폴백이 실행되기 전에 grammY가 보이는 답장 전달을 중단하지 않도록 합니다. 긴 폴링은 여전히 45초 `getUpdates` 요청 가드를 사용하므로 유휴 폴링이 무기한 방치되지 않습니다. - - `channels.telegram.pollingStallThresholdMs`의 기본값은 `120000`입니다. 거짓 양성 폴링 중단 재시작에 대해서만 `30000`에서 `600000` 사이로 조정합니다. + - `channels.telegram.mediaGroupFlushMs`(기본값 500)는 OpenClaw가 Telegram 앨범/미디어 그룹을 하나의 인바운드 메시지로 디스패치하기 전에 버퍼링하는 시간을 제어합니다. 앨범 일부가 늦게 도착하면 늘리고, 앨범 답장 지연 시간을 줄이려면 줄이세요. + - `channels.telegram.timeoutSeconds`는 Telegram API 클라이언트 타임아웃을 재정의합니다(설정하지 않으면 grammY 기본값 적용). 봇 클라이언트는 설정된 값을 60초 아웃바운드 텍스트/타이핑 요청 가드보다 낮게 제한하여, OpenClaw의 전송 가드와 폴백이 실행되기 전에 grammY가 표시 가능한 답장 전달을 중단하지 않도록 합니다. 롱 폴링은 여전히 45초 `getUpdates` 요청 가드를 사용하므로 유휴 폴이 무기한 방치되지 않습니다. + - `channels.telegram.pollingStallThresholdMs`의 기본값은 `120000`입니다. 거짓 양성 폴링 정지 재시작에 대해서만 `30000`에서 `600000` 사이로 조정하세요. - 그룹 컨텍스트 기록은 `channels.telegram.historyLimit` 또는 `messages.groupChat.historyLimit`(기본값 50)을 사용합니다. `0`은 비활성화합니다. - 답장/인용/전달 보조 컨텍스트는 현재 수신된 그대로 전달됩니다. - - Telegram 허용 목록은 주로 에이전트를 트리거할 수 있는 사람을 제한하며, 전체 보조 컨텍스트 수정 경계가 아닙니다. + - Telegram 허용 목록은 주로 누가 에이전트를 트리거할 수 있는지를 제한하며, 완전한 보조 컨텍스트 삭제 경계는 아닙니다. - DM 기록 제어: - `channels.telegram.dmHistoryLimit` - `channels.telegram.dms[""].historyLimit` - - `channels.telegram.retry` 구성은 복구 가능한 아웃바운드 API 오류에 대해 Telegram 전송 헬퍼(CLI/도구/액션)에 적용됩니다. 인바운드 최종 답장 전달도 Telegram 사전 연결 실패에 대해 제한된 안전 전송 재시도를 사용하지만, 보이는 메시지를 중복시킬 수 있는 모호한 전송 후 네트워크 엔벌로프는 재시도하지 않습니다. + - `channels.telegram.retry` 설정은 복구 가능한 아웃바운드 API 오류에 대해 Telegram 전송 헬퍼(CLI/도구/작업)에 적용됩니다. 인바운드 최종 답장 전달도 Telegram 사전 연결 실패에 대해 제한된 안전 전송 재시도를 사용하지만, 표시 메시지를 중복할 수 있는 모호한 전송 후 네트워크 엔벌로프는 재시도하지 않습니다. CLI 전송 대상은 숫자 채팅 ID 또는 사용자 이름일 수 있습니다. @@ -773,48 +772,48 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ Telegram 전송은 다음도 지원합니다. - - `channels.telegram.capabilities.inlineButtons`가 허용할 때 인라인 키보드용 `buttons` 블록과 함께 `--presentation` + - `channels.telegram.capabilities.inlineButtons`가 허용하는 경우 인라인 키보드용 `buttons` 블록과 함께 `--presentation` - 봇이 해당 채팅에서 고정할 수 있을 때 고정 전달을 요청하는 `--pin` 또는 `--delivery '{"pin":true}'` - - 아웃바운드 이미지와 GIF를 압축 사진 또는 애니메이션 미디어 업로드 대신 문서로 보내는 `--force-document` + - 아웃바운드 이미지 및 GIF를 압축 사진 또는 애니메이션 미디어 업로드 대신 문서로 보내는 `--force-document` - 액션 게이팅: + 작업 게이팅: - `channels.telegram.actions.sendMessage=false`는 폴을 포함한 아웃바운드 Telegram 메시지를 비활성화합니다. - - `channels.telegram.actions.poll=false`는 일반 전송은 활성화한 채 Telegram 폴 생성을 비활성화합니다. + - `channels.telegram.actions.poll=false`는 일반 전송은 활성 상태로 둔 채 Telegram 폴 생성을 비활성화합니다. - - Telegram은 승인자 DM에서 exec 승인을 지원하며, 선택적으로 원본 채팅 또는 토픽에 프롬프트를 게시할 수 있습니다. 승인자는 숫자 Telegram 사용자 ID여야 합니다. + + Telegram은 승인자 DM에서 실행 승인을 지원하며, 선택적으로 원래 채팅 또는 토픽에 프롬프트를 게시할 수 있습니다. 승인자는 숫자 Telegram 사용자 ID여야 합니다. - 구성 경로: + 설정 경로: - - `channels.telegram.execApprovals.enabled`(하나 이상의 승인자를 해석할 수 있을 때 자동 활성화) + - `channels.telegram.execApprovals.enabled`(확인 가능한 승인자가 하나 이상 있으면 자동 활성화) - `channels.telegram.execApprovals.approvers`(`commands.ownerAllowFrom`의 숫자 소유자 ID로 폴백) - `channels.telegram.execApprovals.target`: `dm`(기본값) | `channel` | `both` - `agentFilter`, `sessionFilter` - `channels.telegram.allowFrom`, `groupAllowFrom`, `defaultTo`는 누가 봇과 대화할 수 있는지와 봇이 일반 답장을 어디로 보내는지를 제어합니다. 이들은 누군가를 exec 승인자로 만들지 않습니다. 아직 명령 소유자가 없을 때 첫 번째 승인된 DM 페어링이 `commands.ownerAllowFrom`을 부트스트랩하므로, 단일 소유자 설정은 `execApprovals.approvers` 아래에 ID를 중복하지 않아도 계속 작동합니다. + `channels.telegram.allowFrom`, `groupAllowFrom`, `defaultTo`는 누가 봇과 대화할 수 있는지와 봇이 일반 답장을 어디로 보내는지를 제어합니다. 이것들이 누군가를 실행 승인자로 만들지는 않습니다. 아직 명령 소유자가 없을 때 첫 번째 승인된 DM 페어링은 `commands.ownerAllowFrom`을 부트스트랩하므로, 단일 소유자 설정은 `execApprovals.approvers` 아래에 ID를 중복하지 않아도 계속 작동합니다. - 채널 전달은 채팅에 명령 텍스트를 표시합니다. 신뢰할 수 있는 그룹/토픽에서만 `channel` 또는 `both`를 활성화하세요. 프롬프트가 포럼 토픽에 도착하면 OpenClaw는 승인 프롬프트와 후속 메시지에 대해 해당 토픽을 보존합니다. exec 승인은 기본적으로 30분 후 만료됩니다. + 채널 전달은 채팅에 명령 텍스트를 표시합니다. 신뢰할 수 있는 그룹/토픽에서만 `channel` 또는 `both`를 활성화하세요. 프롬프트가 포럼 토픽에 도착하면 OpenClaw는 승인 프롬프트와 후속 조치에 해당 토픽을 유지합니다. 실행 승인은 기본적으로 30분 후 만료됩니다. - 인라인 승인 버튼도 `channels.telegram.capabilities.inlineButtons`가 대상 표면(`dm`, `group` 또는 `all`)을 허용해야 합니다. `plugin:` 접두사가 붙은 승인 ID는 Plugin 승인을 통해 해석되고, 그 외는 exec 승인을 먼저 통해 해석됩니다. + 인라인 승인 버튼도 `channels.telegram.capabilities.inlineButtons`가 대상 표면(`dm`, `group` 또는 `all`)을 허용해야 합니다. `plugin:` 접두사가 붙은 승인 ID는 Plugin 승인을 통해 확인되고, 그 외에는 먼저 실행 승인을 통해 확인됩니다. - [Exec 승인](/ko/tools/exec-approvals)을 참조하세요. + [실행 승인](/ko/tools/exec-approvals)을 참조하세요. ## 오류 답장 제어 -에이전트가 전달 또는 공급자 오류를 만나면 Telegram은 오류 텍스트로 답장하거나 이를 억제할 수 있습니다. 두 구성 키가 이 동작을 제어합니다. +에이전트가 전달 또는 제공자 오류를 만나면 Telegram은 오류 텍스트로 답장하거나 이를 억제할 수 있습니다. 두 설정 키가 이 동작을 제어합니다. -| 키 | 값 | 기본값 | 설명 | +| 키 | 값 | 기본값 | 설명 | | ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- | -| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply`는 채팅에 친절한 오류 메시지를 보냅니다. `silent`는 오류 답장을 완전히 억제합니다. | -| `channels.telegram.errorCooldownMs` | 숫자(ms) | `60000` | 같은 채팅에 오류 답장을 보내는 최소 간격입니다. 중단 중 오류 스팸을 방지합니다. | +| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply`는 채팅에 친절한 오류 메시지를 보냅니다. `silent`는 오류 답장을 완전히 억제합니다. | +| `channels.telegram.errorCooldownMs` | 숫자(ms) | `60000` | 같은 채팅에 대한 오류 답장 간 최소 시간입니다. 장애 중 오류 스팸을 방지합니다. | -계정별, 그룹별, 토픽별 재정의가 지원됩니다(다른 Telegram 구성 키와 동일한 상속). +계정별, 그룹별, 토픽별 재정의가 지원됩니다(다른 Telegram 설정 키와 동일한 상속). ```json5 { @@ -824,7 +823,7 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ errorCooldownMs: 120000, groups: { "-1001234567890": { - errorPolicy: "silent", // suppress errors in this group + errorPolicy: "silent", // 이 그룹에서 오류 억제 }, }, }, @@ -835,12 +834,12 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ ## 문제 해결 - + - - `requireMention=false`인 경우 Telegram 개인정보 보호 모드는 전체 가시성을 허용해야 합니다. + - `requireMention=false`인 경우 Telegram 개인정보 보호 모드가 전체 가시성을 허용해야 합니다. - BotFather: `/setprivacy` -> 비활성화 - - 그런 다음 그룹에서 봇을 제거하고 다시 추가합니다. - - 구성이 멘션 없는 그룹 메시지를 예상할 때 `openclaw channels status`가 경고합니다. + - 그런 다음 그룹에서 봇을 제거하고 다시 추가 + - 설정이 멘션 없는 그룹 메시지를 기대할 때 `openclaw channels status`가 경고합니다. - `openclaw channels status --probe`는 명시적인 숫자 그룹 ID를 확인할 수 있습니다. 와일드카드 `"*"`는 멤버십 프로브가 불가능합니다. - 빠른 세션 테스트: `/activation always`. @@ -849,42 +848,42 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ - `channels.telegram.groups`가 있으면 그룹이 목록에 있어야 합니다(또는 `"*"` 포함). - - 그룹의 봇 멤버십을 확인합니다. - - 건너뛴 이유는 로그에서 검토합니다: `openclaw logs --follow` + - 그룹 내 봇 멤버십 확인 + - 건너뛰기 이유는 로그 검토: `openclaw logs --follow` - - 발신자 아이덴티티를 승인합니다(페어링 및/또는 숫자 `allowFrom`). - - 그룹 정책이 `open`이어도 명령 승인은 계속 적용됩니다. - - `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`가 표시되면 네이티브 메뉴 항목이 너무 많다는 뜻입니다. Plugin/Skill/사용자 지정 명령을 줄이거나 네이티브 메뉴를 비활성화하세요. - - `deleteMyCommands` / `setMyCommands` 시작 호출 및 `sendChatAction` 입력 중 호출은 제한되며 요청 타임아웃 시 Telegram의 전송 폴백을 통해 한 번 재시도됩니다. 지속적인 네트워크/fetch 오류는 일반적으로 `api.telegram.org`에 대한 DNS/HTTPS 도달성 문제를 나타냅니다. + - 발신자 ID 승인(페어링 및/또는 숫자 `allowFrom`) + - 그룹 정책이 `open`이어도 명령 권한 부여는 계속 적용됩니다. + - `BOT_COMMANDS_TOO_MUCH`와 함께 `setMyCommands failed`가 표시되면 네이티브 메뉴에 항목이 너무 많다는 뜻입니다. Plugin/Skill/사용자 지정 명령을 줄이거나 네이티브 메뉴를 비활성화하세요. + - `deleteMyCommands` / `setMyCommands` 시작 호출과 `sendChatAction` 타이핑 호출은 제한되며 요청 타임아웃 시 Telegram의 전송 폴백을 통해 한 번 재시도됩니다. 지속적인 네트워크/페치 오류는 보통 `api.telegram.org`에 대한 DNS/HTTPS 도달성 문제를 나타냅니다. - + - `getMe returned 401`은 구성된 봇 토큰에 대한 Telegram 인증 실패입니다. - - BotFather에서 봇 토큰을 다시 복사하거나 재생성한 다음 기본 계정의 `channels.telegram.botToken`, `channels.telegram.tokenFile`, `channels.telegram.accounts..botToken` 또는 `TELEGRAM_BOT_TOKEN`을 업데이트하세요. - - 시작 중 `deleteWebhook 401 Unauthorized`도 인증 실패입니다. 이를 "웹훅이 없음"으로 처리하면 동일한 잘못된 토큰 실패가 이후 API 호출로 미뤄질 뿐입니다. + - BotFather에서 봇 토큰을 다시 복사하거나 재생성한 다음, 기본 계정의 `channels.telegram.botToken`, `channels.telegram.tokenFile`, `channels.telegram.accounts..botToken` 또는 `TELEGRAM_BOT_TOKEN`을 업데이트하세요. + - 시작 중 `deleteWebhook 401 Unauthorized`도 인증 실패입니다. 이를 "webhook이 없음"으로 처리하면 동일한 잘못된 토큰 실패가 이후 API 호출로 미뤄질 뿐입니다. - Node 22+와 사용자 지정 fetch/proxy는 AbortSignal 타입이 일치하지 않으면 즉시 중단 동작을 유발할 수 있습니다. - - 일부 호스트는 `api.telegram.org`를 IPv6로 먼저 해석합니다. 손상된 IPv6 송신은 간헐적인 Telegram API 실패를 일으킬 수 있습니다. + - 일부 호스트는 `api.telegram.org`를 IPv6로 먼저 확인합니다. IPv6 송신이 손상되어 있으면 간헐적인 Telegram API 실패가 발생할 수 있습니다. - 로그에 `TypeError: fetch failed` 또는 `Network request for 'getUpdates' failed!`가 포함되면 OpenClaw는 이제 이를 복구 가능한 네트워크 오류로 재시도합니다. - - 폴링 시작 중 OpenClaw는 성공한 시작 `getMe` 프로브를 grammY에 재사용하므로 실행기가 첫 번째 `getUpdates` 전에 두 번째 `getMe`를 필요로 하지 않습니다. - - 폴링 시작 중 `deleteWebhook`이 일시적인 네트워크 오류로 실패하면 OpenClaw는 또 다른 사전 폴링 제어 평면 호출을 하지 않고 long polling으로 계속 진행합니다. 여전히 활성 상태인 Webhook은 `getUpdates` 충돌로 드러납니다. 그러면 OpenClaw가 Telegram 전송을 다시 빌드하고 Webhook 정리를 재시도합니다. - - Telegram 소켓이 짧은 고정 주기로 재활용된다면 낮은 `channels.telegram.timeoutSeconds` 값을 확인하세요. 봇 클라이언트는 송신 및 `getUpdates` 요청 보호값보다 낮게 구성된 값을 제한하지만, 이전 릴리스에서는 이 값이 해당 보호값보다 낮게 설정되면 모든 폴링 또는 응답이 중단될 수 있었습니다. - - 로그에 `Polling stall detected`가 포함되면 OpenClaw는 기본적으로 120초 동안 완료된 long-poll 활성 상태가 없을 때 폴링을 다시 시작하고 Telegram 전송을 다시 빌드합니다. - - `openclaw channels status --probe`와 `openclaw doctor`는 실행 중인 폴링 계정이 시작 유예 시간 후 `getUpdates`를 완료하지 않았거나, 실행 중인 Webhook 계정이 시작 유예 시간 후 `setWebhook`을 완료하지 않았거나, 마지막으로 성공한 폴링 전송 활동이 오래된 경우 경고합니다. - - 오래 실행되는 `getUpdates` 호출은 정상인데도 호스트가 잘못된 폴링 정지 재시작을 계속 보고할 때만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 지속적인 정지는 보통 호스트와 `api.telegram.org` 사이의 프록시, DNS, IPv6 또는 TLS 송신 문제를 가리킵니다. - - Telegram은 Bot API 전송에 대해 `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` 및 각각의 소문자 변형을 포함한 프로세스 프록시 환경 변수도 따릅니다. `NO_PROXY` / `no_proxy`는 여전히 `api.telegram.org`를 우회할 수 있습니다. - - 서비스 환경에서 OpenClaw 관리 프록시가 `OPENCLAW_PROXY_URL`을 통해 구성되어 있고 표준 프록시 환경 변수가 없으면 Telegram도 Bot API 전송에 해당 URL을 사용합니다. - - 직접 송신/TLS가 불안정한 VPS 호스트에서는 Telegram API 호출을 `channels.telegram.proxy`를 통해 라우팅하세요. + - 폴링 시작 중 OpenClaw는 grammY에 성공한 시작 `getMe` 프로브를 재사용하므로, 러너가 첫 `getUpdates` 전에 두 번째 `getMe`를 수행할 필요가 없습니다. + - 폴링 시작 중 일시적인 네트워크 오류로 `deleteWebhook`이 실패하면 OpenClaw는 다른 사전 폴링 제어 평면 호출을 만들지 않고 롱 폴링으로 계속 진행합니다. 아직 활성 상태인 webhook은 `getUpdates` 충돌로 나타납니다. 그러면 OpenClaw는 Telegram 전송을 다시 빌드하고 webhook 정리를 재시도합니다. + - Telegram 소켓이 짧은 고정 주기로 재활용된다면 낮은 `channels.telegram.timeoutSeconds` 값을 확인하세요. 봇 클라이언트는 구성된 값이 송신 및 `getUpdates` 요청 가드보다 낮으면 이를 제한하지만, 이전 릴리스에서는 이 값이 해당 가드보다 낮게 설정된 경우 모든 폴링이나 응답이 중단될 수 있었습니다. + - 로그에 `Polling stall detected`가 포함되면 OpenClaw는 기본적으로 완료된 롱 폴 활성 상태 없이 120초가 지난 뒤 폴링을 다시 시작하고 Telegram 전송을 다시 빌드합니다. + - `openclaw channels status --probe` 및 `openclaw doctor`는 실행 중인 폴링 계정이 시작 유예 후 `getUpdates`를 완료하지 않았거나, 실행 중인 webhook 계정이 시작 유예 후 `setWebhook`을 완료하지 않았거나, 마지막으로 성공한 폴링 전송 활동이 오래된 경우 경고합니다. + - 장시간 실행되는 `getUpdates` 호출은 정상인데도 호스트가 잘못된 폴링 중단 재시작을 계속 보고하는 경우에만 `channels.telegram.pollingStallThresholdMs`를 늘리세요. 지속적인 중단은 일반적으로 호스트와 `api.telegram.org` 사이의 proxy, DNS, IPv6 또는 TLS 송신 문제를 가리킵니다. + - Telegram은 Bot API 전송에 대해 `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` 및 이들의 소문자 변형을 포함한 프로세스 proxy 환경 변수도 따릅니다. `NO_PROXY` / `no_proxy`는 여전히 `api.telegram.org`를 우회할 수 있습니다. + - 서비스 환경에서 OpenClaw 관리 proxy가 `OPENCLAW_PROXY_URL`을 통해 구성되어 있고 표준 proxy 환경 변수가 없으면, Telegram도 Bot API 전송에 해당 URL을 사용합니다. + - 직접 송신/TLS가 불안정한 VPS 호스트에서는 `channels.telegram.proxy`를 통해 Telegram API 호출을 라우팅하세요. ```yaml channels: @@ -892,8 +891,8 @@ channels: proxy: socks5://:@proxy-host:1080 ``` - - Node 22+는 기본적으로 `autoSelectFamily=true`입니다(WSL2 제외). Telegram DNS 결과 순서는 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`, 그다음 `channels.telegram.network.dnsResultOrder`, 그다음 `NODE_OPTIONS=--dns-result-order=ipv4first` 같은 프로세스 기본값을 따릅니다. 적용되는 값이 없으면 Node 22+는 `ipv4first`로 폴백합니다. - - 호스트가 WSL2이거나 IPv4 전용 동작이 명시적으로 더 잘 작동한다면 패밀리 선택을 강제하세요. + - Node 22+는 기본적으로 `autoSelectFamily=true`입니다(WSL2 제외). Telegram DNS 결과 순서는 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`, 그다음 `channels.telegram.network.dnsResultOrder`, 그다음 `NODE_OPTIONS=--dns-result-order=ipv4first` 같은 프로세스 기본값을 따릅니다. 아무것도 적용되지 않으면 Node 22+는 `ipv4first`로 폴백합니다. + - 호스트가 WSL2이거나 IPv4 전용 동작에서 명시적으로 더 잘 작동한다면 패밀리 선택을 강제하세요. ```yaml channels: @@ -902,7 +901,7 @@ channels: autoSelectFamily: false ``` - - RFC 2544 벤치마크 범위 응답(`198.18.0.0/15`)은 기본적으로 이미 Telegram 미디어 다운로드에 허용됩니다. 신뢰할 수 있는 fake-IP 또는 투명 프록시가 미디어 다운로드 중 `api.telegram.org`를 다른 private/internal/special-use 주소로 다시 작성한다면 Telegram 전용 우회를 선택적으로 활성화할 수 있습니다. + - RFC 2544 벤치마크 범위 응답(`198.18.0.0/15`)은 기본적으로 Telegram 미디어 다운로드에 이미 허용됩니다. 신뢰할 수 있는 가짜 IP 또는 투명 proxy가 미디어 다운로드 중 `api.telegram.org`를 다른 private/internal/special-use 주소로 다시 쓰는 경우, Telegram 전용 우회를 선택할 수 있습니다. ```yaml channels: @@ -911,23 +910,22 @@ channels: dangerouslyAllowPrivateNetwork: true ``` - - 계정별로도 동일한 옵트인이 - `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork`에서 제공됩니다. - - 프록시가 Telegram 미디어 호스트를 `198.18.x.x`로 해석한다면 먼저 위험 플래그를 꺼 둔 상태로 유지하세요. Telegram 미디어는 기본적으로 이미 RFC 2544 벤치마크 범위를 허용합니다. + - 동일한 옵트인은 계정별로 + `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork`에서도 사용할 수 있습니다. + - proxy가 Telegram 미디어 호스트를 `198.18.x.x`로 확인한다면, 먼저 위험한 플래그를 꺼 둔 상태로 두세요. Telegram 미디어는 기본적으로 RFC 2544 벤치마크 범위를 이미 허용합니다. `channels.telegram.network.dangerouslyAllowPrivateNetwork`는 Telegram - 미디어 SSRF 보호를 약화합니다. Clash, Mihomo, Surge fake-IP 라우팅처럼 - RFC 2544 벤치마크 범위 밖의 private 또는 special-use 응답을 합성하는 - 신뢰할 수 있는 운영자 제어 프록시 환경에서만 사용하세요. 일반 공용 인터넷 - Telegram 접근에는 꺼 둔 상태로 두세요. + 미디어 SSRF 보호를 약화합니다. Clash, Mihomo 또는 Surge 가짜 IP 라우팅처럼 신뢰할 수 있는 운영자 제어 proxy + 환경에서 RFC 2544 벤치마크 범위 밖의 private 또는 special-use 응답을 합성하는 경우에만 사용하세요. + 일반 공용 인터넷 Telegram 액세스에는 꺼 두세요. - 환경 재정의(임시): - `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first` - - DNS 응답을 검증하세요. + - DNS 응답 검증: ```bash dig +short api.telegram.org A @@ -943,18 +941,18 @@ dig +short api.telegram.org AAAA 기본 참조: [구성 참조 - Telegram](/ko/gateway/config-channels#telegram). - + -- 시작/인증: `enabled`, `botToken`, `tokenFile`, `accounts.*`(`tokenFile`은 일반 파일을 가리켜야 하며 심볼릭 링크는 거부됨) -- 접근 제어: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, 최상위 `bindings[]`(`type: "acp"`) -- 실행 승인: `execApprovals`, `accounts.*.execApprovals` +- 시작/인증: `enabled`, `botToken`, `tokenFile`, `accounts.*` (`tokenFile`은 일반 파일을 가리켜야 하며, 심볼릭 링크는 거부됩니다) +- 액세스 제어: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, 최상위 `bindings[]` (`type: "acp"`) +- exec 승인: `execApprovals`, `accounts.*.execApprovals` - 명령/메뉴: `commands.native`, `commands.nativeSkills`, `customCommands` -- 스레드/응답: `replyToMode`, `dm.threadReplies`, `direct.*.threadReplies` -- 스트리밍: `streaming`(미리보기), `streaming.preview.toolProgress`, `blockStreaming` -- 형식 지정/전송: `textChunkLimit`, `chunkMode`, `linkPreview`, `responsePrefix` +- 스레딩/응답: `replyToMode`, `dm.threadReplies`, `direct.*.threadReplies` +- 스트리밍: `streaming`(미리 보기), `streaming.preview.toolProgress`, `blockStreaming` +- 형식/전달: `textChunkLimit`, `chunkMode`, `linkPreview`, `responsePrefix` - 미디어/네트워크: `mediaMaxMb`, `mediaGroupFlushMs`, `timeoutSeconds`, `pollingStallThresholdMs`, `retry`, `network.autoSelectFamily`, `network.dangerouslyAllowPrivateNetwork`, `proxy` - 사용자 지정 API 루트: `apiRoot`(Bot API 루트만 해당, `/bot`을 포함하지 마세요) -- Webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost` +- webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost` - 작업/기능: `capabilities.inlineButtons`, `actions.sendMessage|editMessage|deleteMessage|reactions|sticker` - 반응: `reactionNotifications`, `reactionLevel` - 오류: `errorPolicy`, `errorCooldownMs` @@ -963,7 +961,7 @@ dig +short api.telegram.org AAAA -다중 계정 우선순위: 두 개 이상의 계정 ID가 구성된 경우 기본 라우팅을 명시하려면 `channels.telegram.defaultAccount`를 설정하거나 `channels.telegram.accounts.default`를 포함하세요. 그렇지 않으면 OpenClaw는 첫 번째 정규화된 계정 ID로 폴백하고 `openclaw doctor`가 경고합니다. 이름이 지정된 계정은 `channels.telegram.allowFrom` / `groupAllowFrom`을 상속하지만 `accounts.default.*` 값은 상속하지 않습니다. +다중 계정 우선순위: 두 개 이상의 계정 ID가 구성된 경우 기본 라우팅을 명시하려면 `channels.telegram.defaultAccount`를 설정하세요(또는 `channels.telegram.accounts.default`를 포함하세요). 그렇지 않으면 OpenClaw는 첫 번째 정규화된 계정 ID로 폴백하고 `openclaw doctor`가 경고합니다. 이름 있는 계정은 `channels.telegram.allowFrom` / `groupAllowFrom`을 상속하지만 `accounts.default.*` 값은 상속하지 않습니다. ## 관련 항목 @@ -973,18 +971,18 @@ dig +short api.telegram.org AAAA Telegram 사용자를 Gateway에 페어링합니다. - 그룹 및 주제 허용 목록 동작입니다. + 그룹 및 토픽 허용 목록 동작. - 수신 메시지를 에이전트로 라우팅합니다. + 인바운드 메시지를 에이전트로 라우팅합니다. - 위협 모델 및 강화입니다. + 위협 모델과 강화. - 그룹과 주제를 에이전트에 매핑합니다. + 그룹과 토픽을 에이전트에 매핑합니다. - 채널 간 진단입니다. + 교차 채널 진단. diff --git a/docs/ko/ci.md b/docs/ko/ci.md index a6ed9ccd8..af96abf07 100644 --- a/docs/ko/ci.md +++ b/docs/ko/ci.md @@ -1,94 +1,94 @@ --- read_when: - - CI 작업이 실행되었거나 실행되지 않은 이유를 파악해야 합니다 + - CI 작업이 실행되었거나 실행되지 않은 이유를 이해해야 합니다 - 실패한 GitHub Actions 검사를 디버깅하고 있습니다 - - 릴리스 검증 실행 또는 재실행을 조율하고 있습니다 + - 릴리스 검증 실행 또는 재실행을 조정하고 있습니다 - ClawSweeper 디스패치 또는 GitHub 활동 전달을 변경하고 있습니다 -summary: CI 작업 그래프, 범위 게이트, 릴리스 통합 게이트 및 로컬 명령어 대응 항목 +summary: CI 작업 그래프, 범위 게이트, 릴리스 포괄 항목 및 로컬 명령 대응 항목 title: CI 파이프라인 x-i18n: - generated_at: "2026-05-03T21:27:39Z" + generated_at: "2026-05-04T06:23:13Z" model: gpt-5.5 provider: openai - source_hash: e07fc44aa844cb66ce529c570cbbbbf502a61bcbcbc3d9488557abb459ef7678 + source_hash: 72959d0feaf1339f01c9da263153fd89cc4727da6f928933819931991222714d source_path: ci.md workflow: 16 --- -OpenClaw CI는 `main`에 대한 모든 푸시와 모든 pull request에서 실행됩니다. `preflight` 작업은 diff를 분류하고 관련 없는 영역만 변경된 경우 비용이 큰 lane을 끕니다. 수동 `workflow_dispatch` 실행은 의도적으로 스마트 범위 지정을 우회하고 릴리스 후보와 광범위한 검증을 위해 전체 그래프로 확장됩니다. Android lane은 `include_android`를 통해 계속 선택 사항으로 유지됩니다. 릴리스 전용 Plugin 커버리지는 별도의 [`Plugin 사전 릴리스`](#plugin-prerelease) 워크플로에 있으며, [`전체 릴리스 검증`](#full-release-validation) 또는 명시적인 수동 dispatch에서만 실행됩니다. +OpenClaw CI는 `main`에 푸시할 때마다, 그리고 모든 풀 리퀘스트에서 실행됩니다. `preflight` 작업은 diff를 분류하고 관련 없는 영역만 변경된 경우 비용이 큰 레인을 끕니다. 수동 `workflow_dispatch` 실행은 의도적으로 스마트 범위 지정을 우회하며, 릴리스 후보와 광범위한 검증을 위해 전체 그래프를 펼칩니다. Android 레인은 `include_android`를 통해 계속 옵트인 방식으로 유지됩니다. 릴리스 전용 Plugin 커버리지는 별도의 [`Plugin Prerelease`](#plugin-prerelease) 워크플로에 있으며, [`Full Release Validation`](#full-release-validation) 또는 명시적인 수동 디스패치에서만 실행됩니다. ## 파이프라인 개요 | 작업 | 목적 | 실행 시점 | | -------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| `preflight` | 문서 전용 변경, 변경된 범위, 변경된 extension을 감지하고 CI manifest를 빌드 | draft가 아닌 푸시와 PR에서 항상 | -| `security-scm-fast` | `zizmor`를 통한 비공개 키 감지 및 워크플로 감사 | draft가 아닌 푸시와 PR에서 항상 | -| `security-dependency-audit` | npm 권고에 대해 dependency-free production lockfile 감사 | draft가 아닌 푸시와 PR에서 항상 | -| `security-fast` | 빠른 보안 작업의 필수 aggregate | draft가 아닌 푸시와 PR에서 항상 | -| `check-dependencies` | production Knip dependency-only pass와 unused-file allowlist guard | Node 관련 변경 | -| `build-artifacts` | `dist/`, Control UI, 빌드된 artifact 검사, 재사용 가능한 downstream artifact 빌드 | Node 관련 변경 | -| `checks-fast-core` | bundled/plugin-contract/protocol 검사 같은 빠른 Linux 정확성 lane | Node 관련 변경 | -| `checks-fast-contracts-channels` | 안정적인 aggregate 검사 결과가 있는 sharded channel contract 검사 | Node 관련 변경 | -| `checks-node-core-test` | channel, bundled, contract, extension lane을 제외한 core Node 테스트 shard | Node 관련 변경 | -| `check` | sharded main local gate에 해당: prod types, lint, guard, test types, strict smoke | Node 관련 변경 | -| `check-additional` | architecture, sharded boundary/prompt drift, extension guard, package boundary, gateway watch | Node 관련 변경 | -| `build-smoke` | 빌드된 CLI smoke test와 startup-memory smoke | Node 관련 변경 | -| `checks` | 빌드된 artifact channel 테스트의 verifier | Node 관련 변경 | -| `checks-node-compat-node22` | Node 22 호환성 빌드 및 smoke lane | 릴리스용 수동 CI dispatch | -| `check-docs` | 문서 formatting, lint, broken-link 검사 | 문서 변경 | -| `skills-python` | Python 기반 Skills용 Ruff + pytest | Python-skill 관련 변경 | -| `checks-windows` | Windows별 process/path 테스트와 공유 runtime import specifier regression | Windows 관련 변경 | -| `macos-node` | 공유 빌드 artifact를 사용하는 macOS TypeScript 테스트 lane | macOS 관련 변경 | -| `macos-swift` | macOS 앱용 Swift lint, build, test | macOS 관련 변경 | -| `android` | 두 flavor의 Android unit test와 debug APK 빌드 하나 | Android 관련 변경 | -| `test-performance-agent` | 신뢰된 활동 이후 일일 Codex slow-test 최적화 | Main CI 성공 또는 수동 dispatch | -| `openclaw-performance` | mock-provider, deep-profile, GPT 5.4 live lane이 포함된 일일/주문형 Kova runtime performance report | 예약 및 수동 dispatch | +| `preflight` | 문서 전용 변경, 변경된 범위, 변경된 확장, CI 매니페스트 빌드를 감지 | draft가 아닌 푸시와 PR에서 항상 | +| `security-scm-fast` | `zizmor`를 통한 개인 키 감지 및 워크플로 감사 | draft가 아닌 푸시와 PR에서 항상 | +| `security-dependency-audit` | npm 권고에 대한 의존성 없는 프로덕션 lockfile 감사 | draft가 아닌 푸시와 PR에서 항상 | +| `security-fast` | 빠른 보안 작업의 필수 집계 | draft가 아닌 푸시와 PR에서 항상 | +| `check-dependencies` | 프로덕션 Knip 의존성 전용 패스와 미사용 파일 허용 목록 가드 | Node 관련 변경 | +| `build-artifacts` | `dist/`, Control UI, 빌드된 아티팩트 검사, 재사용 가능한 downstream 아티팩트 빌드 | Node 관련 변경 | +| `checks-fast-core` | 번들/Plugin 계약/프로토콜 검사 같은 빠른 Linux 정확성 레인 | Node 관련 변경 | +| `checks-fast-contracts-channels` | 안정적인 집계 검사 결과가 있는 샤딩된 채널 계약 검사 | Node 관련 변경 | +| `checks-node-core-test` | 채널, 번들, 계약, 확장 레인을 제외한 코어 Node 테스트 샤드 | Node 관련 변경 | +| `check` | 샤딩된 주요 로컬 게이트와 동등한 검사: 프로덕션 타입, 린트, 가드, 테스트 타입, 엄격한 smoke | Node 관련 변경 | +| `check-additional` | 아키텍처, 샤딩된 경계/프롬프트 드리프트, 확장 가드, 패키지 경계, Gateway watch | Node 관련 변경 | +| `build-smoke` | 빌드된 CLI smoke 테스트와 시작 메모리 smoke | Node 관련 변경 | +| `checks` | 빌드된 아티팩트 채널 테스트 검증기 | Node 관련 변경 | +| `checks-node-compat-node22` | Node 22 호환성 빌드 및 smoke 레인 | 릴리스용 수동 CI 디스패치 | +| `check-docs` | 문서 포맷팅, 린트, 깨진 링크 검사 | 문서 변경 | +| `skills-python` | Python 기반 Skills를 위한 Ruff + pytest | Python Skills 관련 변경 | +| `checks-windows` | Windows 전용 프로세스/경로 테스트와 공유 런타임 import 지정자 회귀 검사 | Windows 관련 변경 | +| `macos-node` | 공유 빌드 아티팩트를 사용하는 macOS TypeScript 테스트 레인 | macOS 관련 변경 | +| `macos-swift` | macOS 앱의 Swift 린트, 빌드, 테스트 | macOS 관련 변경 | +| `android` | 두 flavor의 Android 단위 테스트와 하나의 debug APK 빌드 | Android 관련 변경 | +| `test-performance-agent` | 신뢰된 활동 이후의 일일 Codex 느린 테스트 최적화 | main CI 성공 또는 수동 디스패치 | +| `openclaw-performance` | mock-provider, deep-profile, GPT 5.4 라이브 레인을 포함한 일일/온디맨드 Kova 런타임 성능 보고서 | 예약 실행 및 수동 디스패치 | ## 빠른 실패 순서 -1. `preflight`는 어떤 lane이 존재할지 결정합니다. `docs-scope`와 `changed-scope` 로직은 독립 작업이 아니라 이 작업 안의 step입니다. -2. `security-scm-fast`, `security-dependency-audit`, `security-fast`, `check`, `check-additional`, `check-docs`, `skills-python`은 더 무거운 artifact 및 platform matrix 작업을 기다리지 않고 빠르게 실패합니다. -3. `build-artifacts`는 빠른 Linux lane과 겹쳐 실행되므로 공유 빌드가 준비되는 즉시 downstream consumer가 시작할 수 있습니다. -4. 그 후 더 무거운 platform 및 runtime lane이 확장됩니다: `checks-fast-core`, `checks-fast-contracts-channels`, `checks-node-core-test`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, `android`. +1. `preflight`가 어떤 레인이 존재할지 결정합니다. `docs-scope`와 `changed-scope` 로직은 이 작업 내부의 단계이며, 독립 실행 작업이 아닙니다. +2. `security-scm-fast`, `security-dependency-audit`, `security-fast`, `check`, `check-additional`, `check-docs`, `skills-python`은 더 무거운 아티팩트 및 플랫폼 매트릭스 작업을 기다리지 않고 빠르게 실패합니다. +3. `build-artifacts`는 빠른 Linux 레인과 겹쳐 실행되어 공유 빌드가 준비되는 즉시 downstream 소비자가 시작할 수 있게 합니다. +4. 그다음 더 무거운 플랫폼 및 런타임 레인이 펼쳐집니다: `checks-fast-core`, `checks-fast-contracts-channels`, `checks-node-core-test`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, `android`. -같은 PR 또는 `main` ref에 더 새로운 푸시가 올라오면 GitHub가 대체된 작업을 `cancelled`로 표시할 수 있습니다. 같은 ref의 최신 실행도 실패하지 않는 한 이를 CI 잡음으로 취급하세요. Aggregate shard 검사는 `!cancelled() && always()`를 사용하므로 일반 shard 실패는 계속 보고하지만 전체 워크플로가 이미 대체된 뒤에는 queue에 넣지 않습니다. 자동 CI concurrency key는 versioned(`CI-v7-*`)되어 있어 GitHub 쪽의 이전 queue group zombie가 더 새로운 main 실행을 무기한 차단할 수 없습니다. 수동 full-suite 실행은 `CI-manual-v1-*`를 사용하며 진행 중인 실행을 취소하지 않습니다. +같은 PR 또는 `main` ref에 새 푸시가 올라오면 GitHub가 대체된 작업을 `cancelled`로 표시할 수 있습니다. 같은 ref의 최신 실행도 실패 중인 경우가 아니라면 이를 CI 잡음으로 간주하세요. 집계 샤드 검사는 `!cancelled() && always()`를 사용하므로 일반적인 샤드 실패는 계속 보고하지만, 전체 워크플로가 이미 대체된 뒤에는 큐에 들어가지 않습니다. 자동 CI 동시성 키는 버전이 지정되어 있으므로(`CI-v7-*`) 오래된 큐 그룹의 GitHub 측 좀비가 더 새로운 main 실행을 무기한 막을 수 없습니다. 수동 전체 스위트 실행은 `CI-manual-v1-*`를 사용하며 진행 중인 실행을 취소하지 않습니다. -## 범위와 라우팅 +## 범위 및 라우팅 -Scope 로직은 `scripts/ci-changed-scope.mjs`에 있으며 `src/scripts/ci-changed-scope.test.ts`의 unit test로 다룹니다. 수동 dispatch는 changed-scope 감지를 건너뛰고 preflight manifest가 모든 scoped area가 변경된 것처럼 동작하게 합니다. +범위 로직은 `scripts/ci-changed-scope.mjs`에 있으며, `src/scripts/ci-changed-scope.test.ts`의 단위 테스트로 커버됩니다. 수동 디스패치는 changed-scope 감지를 건너뛰고 preflight 매니페스트가 모든 범위 영역이 변경된 것처럼 동작하게 합니다. -- **CI 워크플로 편집**은 Node CI 그래프와 workflow linting을 검증하지만, 그 자체만으로 Windows, Android, macOS native build를 강제하지 않습니다. 해당 platform lane은 platform source 변경으로 범위가 유지됩니다. -- **CI routing-only 편집, 선택된 저비용 core-test fixture 편집, 좁은 plugin contract helper/test-routing 편집**은 빠른 Node 전용 manifest 경로를 사용합니다: `preflight`, security, 단일 `checks-fast-core` 작업. 이 경로는 변경이 빠른 작업이 직접 실행하는 routing 또는 helper surface로 제한될 때 build artifacts, Node 22 compatibility, channel contracts, full core shards, bundled-plugin shards, additional guard matrix를 건너뜁니다. -- **Windows Node 검사**는 Windows별 process/path wrapper, npm/pnpm/UI runner helper, package manager config, 해당 lane을 실행하는 CI workflow surface로 범위가 지정됩니다. 관련 없는 source, Plugin, install-smoke, test-only 변경은 Linux Node lane에 남습니다. +- **CI 워크플로 편집**은 Node CI 그래프와 워크플로 린팅을 검증하지만, 그 자체로 Windows, Android, macOS 네이티브 빌드를 강제하지는 않습니다. 해당 플랫폼 레인은 플랫폼 소스 변경으로 계속 범위가 지정됩니다. +- **CI 라우팅 전용 편집, 선택된 저비용 코어 테스트 fixture 편집, 좁은 Plugin 계약 helper/test-routing 편집**은 빠른 Node 전용 매니페스트 경로를 사용합니다: `preflight`, 보안, 단일 `checks-fast-core` 작업. 변경이 빠른 작업이 직접 실행하는 라우팅 또는 helper 표면에 제한된 경우 이 경로는 빌드 아티팩트, Node 22 호환성, 채널 계약, 전체 코어 샤드, 번들 Plugin 샤드, 추가 가드 매트릭스를 건너뜁니다. +- **Windows Node 검사**는 Windows 전용 프로세스/경로 wrapper, npm/pnpm/UI runner helper, 패키지 관리자 설정, 해당 레인을 실행하는 CI 워크플로 표면으로 범위가 지정됩니다. 관련 없는 소스, Plugin, install-smoke, 테스트 전용 변경은 Linux Node 레인에 남습니다. -가장 느린 Node test family는 각 작업이 runner를 과도하게 예약하지 않고 작게 유지되도록 분할되거나 균형 조정됩니다. channel contract는 세 개의 weighted shard로 실행되고, core unit fast/support lane은 별도로 실행되며, core runtime infra는 state shard와 process/config shard로 나뉘고, auto-reply는 balanced worker로 실행됩니다(reply subtree는 agent-runner, dispatch, commands/state-routing shard로 분할). agentic gateway/server config는 built artifact를 기다리는 대신 chat/auth/model/http-plugin/runtime/startup lane으로 나뉩니다. 광범위한 browser, QA, media, miscellaneous Plugin 테스트는 공유 Plugin catch-all 대신 전용 Vitest config를 사용합니다. Include-pattern shard는 CI shard 이름을 사용해 timing entry를 기록하므로 `.artifacts/vitest-shard-timings.json`이 전체 config와 filtered shard를 구분할 수 있습니다. `check-additional`은 package-boundary compile/canary 작업을 함께 유지하고 runtime topology architecture를 gateway watch coverage와 분리합니다. boundary guard list는 네 개의 matrix shard에 나뉘며, 각 shard는 선택된 독립 guard를 동시에 실행하고 `pnpm prompt:snapshots:check`를 포함한 check별 timing을 출력하여 Codex runtime happy-path prompt drift가 이를 일으킨 PR에 고정되게 합니다. Gateway watch, channel test, core support-boundary shard는 `dist/`와 `dist-runtime/`가 이미 빌드된 뒤 `build-artifacts` 안에서 동시에 실행됩니다. +가장 느린 Node 테스트 계열은 각 작업이 runner를 과도하게 예약하지 않으면서 작게 유지되도록 분할되거나 균형 조정됩니다. 채널 계약은 가중치가 적용된 세 샤드로 실행되고, 코어 단위 fast/support 레인은 별도로 실행되며, 코어 런타임 인프라는 state와 process/config 샤드로 나뉘고, auto-reply는 균형 잡힌 worker로 실행됩니다. reply 하위 트리는 agent-runner, dispatch, commands/state-routing 샤드로 분할됩니다. agentic gateway/server 설정은 빌드 아티팩트를 기다리는 대신 chat/auth/model/http-plugin/runtime/startup 레인 전반에 분할됩니다. 광범위한 browser, QA, media, 기타 Plugin 테스트는 공유 Plugin catch-all 대신 전용 Vitest 설정을 사용합니다. include-pattern 샤드는 CI 샤드 이름을 사용해 timing 항목을 기록하므로 `.artifacts/vitest-shard-timings.json`이 전체 설정과 필터링된 샤드를 구분할 수 있습니다. `check-additional`은 package-boundary compile/canary 작업을 함께 유지하고 런타임 토폴로지 아키텍처를 Gateway watch 커버리지와 분리합니다. boundary 가드 목록은 네 개의 매트릭스 샤드에 나뉘며, 각 샤드는 선택된 독립 가드를 동시에 실행하고 `pnpm prompt:snapshots:check`를 포함한 검사별 timing을 출력하므로 Codex 런타임 happy-path 프롬프트 드리프트가 이를 유발한 PR에 고정됩니다. Gateway watch, 채널 테스트, 코어 support-boundary 샤드는 `dist/`와 `dist-runtime/`가 이미 빌드된 뒤 `build-artifacts` 내부에서 동시에 실행됩니다. -Android CI는 `testPlayDebugUnitTest`와 `testThirdPartyDebugUnitTest`를 모두 실행한 다음 Play debug APK를 빌드합니다. third-party flavor에는 별도 source set이나 manifest가 없습니다. unit-test lane은 여전히 SMS/call-log BuildConfig flag로 flavor를 컴파일하지만, Android 관련 푸시마다 중복 debug APK packaging 작업은 피합니다. +Android CI는 `testPlayDebugUnitTest`와 `testThirdPartyDebugUnitTest`를 모두 실행한 뒤 Play debug APK를 빌드합니다. third-party flavor에는 별도의 소스 세트나 매니페스트가 없습니다. 해당 단위 테스트 레인은 여전히 SMS/call-log BuildConfig 플래그로 flavor를 컴파일하면서, Android 관련 푸시마다 중복 debug APK 패키징 작업을 피합니다. -`check-dependencies` shard는 `pnpm deadcode:dependencies`(최신 Knip version에 고정되고 `dlx` install을 위해 pnpm의 minimum release age가 비활성화된 production Knip dependency-only pass)와 `pnpm deadcode:unused-files`를 실행합니다. 후자는 Knip의 production unused-file finding을 `scripts/deadcode-unused-files.allowlist.mjs`와 비교합니다. unused-file guard는 PR이 검토되지 않은 새 unused file을 추가하거나 오래된 allowlist entry를 남기면 실패하면서도 Knip이 정적으로 해석할 수 없는 의도적인 dynamic Plugin, generated, build, live-test, package bridge surface는 보존합니다. +`check-dependencies` 샤드는 `pnpm deadcode:dependencies`(최신 Knip 버전에 고정되고 `dlx` 설치를 위해 pnpm의 최소 릴리스 나이가 비활성화된 프로덕션 Knip 의존성 전용 패스)와 `pnpm deadcode:unused-files`를 실행합니다. 후자는 Knip의 프로덕션 미사용 파일 결과를 `scripts/deadcode-unused-files.allowlist.mjs`와 비교합니다. 미사용 파일 가드는 PR이 검토되지 않은 새 미사용 파일을 추가하거나 오래된 허용 목록 항목을 남겨두면 실패하며, Knip이 정적으로 해석할 수 없는 의도적인 동적 Plugin, generated, build, live-test, package bridge 표면은 보존합니다. ## ClawSweeper 활동 전달 -`.github/workflows/clawsweeper-dispatch.yml`은 OpenClaw repository activity를 ClawSweeper로 보내는 대상 측 bridge입니다. 신뢰할 수 없는 pull request 코드를 checkout하거나 실행하지 않습니다. 이 워크플로는 `CLAWSWEEPER_APP_PRIVATE_KEY`에서 GitHub App token을 만든 다음 compact `repository_dispatch` payload를 `openclaw/clawsweeper`로 dispatch합니다. +`.github/workflows/clawsweeper-dispatch.yml`은 OpenClaw 저장소 활동을 ClawSweeper로 전달하는 대상 측 bridge입니다. 신뢰할 수 없는 풀 리퀘스트 코드를 checkout하거나 실행하지 않습니다. 이 워크플로는 `CLAWSWEEPER_APP_PRIVATE_KEY`에서 GitHub App 토큰을 만든 다음, 간결한 `repository_dispatch` 페이로드를 `openclaw/clawsweeper`로 디스패치합니다. -이 워크플로에는 네 개의 lane이 있습니다. +이 워크플로에는 네 개의 레인이 있습니다. -- 정확한 issue 및 pull request review 요청을 위한 `clawsweeper_item`; -- issue comment의 명시적 ClawSweeper 명령을 위한 `clawsweeper_comment`; -- `main` 푸시의 commit-level review 요청을 위한 `clawsweeper_commit_review`; -- ClawSweeper agent가 검사할 수 있는 일반 GitHub activity를 위한 `github_activity`. +- 정확한 이슈 및 풀 리퀘스트 리뷰 요청을 위한 `clawsweeper_item`; +- 이슈 댓글의 명시적 ClawSweeper 명령을 위한 `clawsweeper_comment`; +- `main` 푸시의 커밋 수준 리뷰 요청을 위한 `clawsweeper_commit_review`; +- ClawSweeper agent가 검사할 수 있는 일반 GitHub 활동을 위한 `github_activity`. -`github_activity` lane은 event type, action, actor, repository, item number, URL, title, state, comment 또는 review가 있을 때의 짧은 excerpt 같은 정규화된 metadata만 전달합니다. 의도적으로 전체 webhook body를 전달하지 않습니다. `openclaw/clawsweeper`의 수신 워크플로는 `.github/workflows/github-activity.yml`이며, 정규화된 event를 ClawSweeper agent용 OpenClaw Gateway hook에 게시합니다. +`github_activity` 레인은 정규화된 메타데이터만 전달합니다: 이벤트 타입, 액션, actor, 저장소, item 번호, URL, 제목, 상태, 그리고 댓글이나 리뷰가 있는 경우 짧은 발췌. 전체 Webhook 본문 전달은 의도적으로 피합니다. `openclaw/clawsweeper`의 수신 워크플로는 `.github/workflows/github-activity.yml`이며, 정규화된 이벤트를 ClawSweeper agent용 OpenClaw Gateway hook에 게시합니다. -일반 activity는 관찰이며 기본 전달이 아닙니다. ClawSweeper agent는 prompt에서 Discord target을 받으며, event가 놀랍거나, 실행 가능하거나, 위험하거나, 운영상 유용할 때만 `#clawsweeper`에 게시해야 합니다. 일상적인 open, edit, bot churn, 중복 webhook noise, 일반 review traffic은 `NO_REPLY`가 되어야 합니다. +일반 활동은 관찰이며, 기본 전달이 아닙니다. ClawSweeper agent는 프롬프트에서 Discord 대상을 받으며, 이벤트가 놀랍거나, 실행 가능하거나, 위험하거나, 운영상 유용한 경우에만 `#clawsweeper`에 게시해야 합니다. 일상적인 열기, 편집, bot churn, 중복 Webhook 잡음, 일반 리뷰 트래픽은 `NO_REPLY`로 이어져야 합니다. -이 경로 전체에서 GitHub title, comment, body, review text, branch name, commit message를 신뢰할 수 없는 data로 취급하세요. 이들은 요약과 triage의 input이지, workflow나 agent runtime에 대한 instruction이 아닙니다. +이 경로 전체에서 GitHub 제목, 댓글, 본문, 리뷰 텍스트, 브랜치 이름, 커밋 메시지를 신뢰할 수 없는 데이터로 취급하세요. 이들은 요약과 triage를 위한 입력이지, 워크플로 또는 agent 런타임을 위한 지시가 아닙니다. -## 수동 dispatch +## 수동 디스패치 -수동 CI 디스패치는 일반 CI와 동일한 작업 그래프를 실행하지만 Android가 아닌 모든 범위 지정 lane을 강제로 켭니다. Linux Node 샤드, 번들 Plugin 샤드, 채널 계약, Node 22 호환성, `check`, `check-additional`, 빌드 스모크, 문서 검사, Python skills, Windows, macOS, Control UI i18n이 포함됩니다. 독립 실행형 수동 CI 디스패치는 `include_android=true`로 Android만 실행합니다. 전체 릴리스 umbrella는 `include_android=true`를 전달하여 Android를 활성화합니다. Plugin 프리릴리스 정적 검사, 릴리스 전용 `agentic-plugins` 샤드, 전체 확장 배치 스윕, Plugin 프리릴리스 Docker lane은 CI에서 제외됩니다. Docker 프리릴리스 제품군은 `Full Release Validation`이 릴리스 검증 게이트를 활성화한 상태로 별도의 `Plugin Prerelease` 워크플로를 디스패치할 때만 실행됩니다. +수동 CI 디스패치는 일반 CI와 동일한 작업 그래프를 실행하지만 Android 범위가 아닌 모든 lane을 강제로 켭니다. Linux Node shard, 번들 Plugin shard, 채널 contract, Node 22 호환성, `check`, `check-additional`, 빌드 smoke, 문서 검사, Python Skills, Windows, macOS, Control UI i18n입니다. 독립 실행형 수동 CI 디스패치는 `include_android=true`일 때 Android만 실행합니다. 전체 릴리스 umbrella는 `include_android=true`를 전달해 Android를 활성화합니다. Plugin 프리릴리스 정적 검사, 릴리스 전용 `agentic-plugins` shard, 전체 확장 batch sweep, Plugin 프리릴리스 Docker lane은 CI에서 제외됩니다. Docker 프리릴리스 suite는 `Full Release Validation`이 릴리스 검증 gate를 활성화한 별도의 `Plugin Prerelease` workflow를 디스패치할 때만 실행됩니다. -수동 실행은 고유한 동시성 그룹을 사용하므로 릴리스 후보 전체 제품군이 같은 ref의 다른 push 또는 PR 실행 때문에 취소되지 않습니다. 선택적 `target_ref` 입력을 사용하면 신뢰할 수 있는 호출자가 선택한 디스패치 ref의 워크플로 파일을 사용하면서 브랜치, 태그 또는 전체 커밋 SHA를 대상으로 해당 그래프를 실행할 수 있습니다. +수동 실행은 고유한 concurrency group을 사용하므로 릴리스 후보 전체 suite가 같은 ref의 다른 push 또는 PR 실행으로 취소되지 않습니다. 선택적 `target_ref` 입력을 사용하면 신뢰할 수 있는 호출자가 선택한 dispatch ref의 workflow 파일을 사용하면서 branch, tag 또는 전체 commit SHA에 대해 해당 그래프를 실행할 수 있습니다. ```bash gh workflow run ci.yml --ref release/YYYY.M.D @@ -96,17 +96,17 @@ gh workflow run ci.yml --ref main -f target_ref= -f include_andro gh workflow run full-release-validation.yml --ref main -f ref= ``` -## 러너 +## Runner -| 러너 | 작업 | +| Runner | 작업 | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | `preflight`, 빠른 보안 작업 및 집계(`security-scm-fast`, `security-dependency-audit`, `security-fast`), 빠른 프로토콜/계약/번들 검사, 샤딩된 채널 계약 검사, lint를 제외한 `check` 샤드, `check-additional` 샤드 및 집계, Node 테스트 집계 검증기, 문서 검사, Python skills, workflow-sanity, labeler, auto-response; install-smoke preflight도 GitHub 호스팅 Ubuntu를 사용하므로 Blacksmith 매트릭스가 더 일찍 대기열에 들어갈 수 있습니다 | -| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, 더 가벼운 확장 샤드, `checks-fast-core`, `checks-node-compat-node22`, `check-prod-types`, `check-test-types` | -| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`, build-smoke, Linux Node 테스트 샤드, 번들 Plugin 테스트 샤드, `android` | -| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(CPU에 민감하여 8 vCPU는 절약한 것보다 비용이 더 컸습니다); install-smoke Docker 빌드(32-vCPU 대기열 시간은 절약한 것보다 비용이 더 컸습니다) | +| `ubuntu-24.04` | `preflight`, 빠른 security 작업 및 aggregate(`security-scm-fast`, `security-dependency-audit`, `security-fast`), 빠른 protocol/contract/번들 검사, shard된 채널 contract 검사, lint를 제외한 `check` shard, `check-additional` shard 및 aggregate, Node test aggregate verifier, 문서 검사, Python Skills, workflow-sanity, labeler, auto-response. install-smoke preflight도 GitHub-hosted Ubuntu를 사용하므로 Blacksmith matrix가 더 일찍 queue될 수 있습니다 | +| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, 더 가벼운 확장 shard, `checks-fast-core`, `checks-node-compat-node22`, `check-prod-types`, `check-test-types` | +| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`, build-smoke, Linux Node test shard, 번들 Plugin test shard, `android` | +| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(CPU에 충분히 민감해 8 vCPU가 절약한 것보다 더 많은 비용이 들었습니다), install-smoke Docker build(32-vCPU queue 시간 비용이 절약한 것보다 더 컸습니다) | | `blacksmith-16vcpu-windows-2025` | `checks-windows` | -| `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw`의 `macos-node`; 포크는 `macos-latest`로 폴백합니다 | -| `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw`의 `macos-swift`; 포크는 `macos-latest`로 폴백합니다 | +| `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw`의 `macos-node`; fork는 `macos-latest`로 fallback합니다 | +| `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw`의 `macos-swift`; fork는 `macos-latest`로 fallback합니다 | ## 로컬 대응 명령 @@ -135,9 +135,9 @@ pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifac pnpm perf:kova:summary --report .artifacts/kova/reports/mock-provider/report.json --output .artifacts/kova/summary.md ``` -## OpenClaw 성능 +## OpenClaw Performance -`OpenClaw Performance`는 제품/런타임 성능 워크플로입니다. 매일 `main`에서 실행되며 수동으로 디스패치할 수 있습니다. +`OpenClaw Performance`는 제품/runtime 성능 workflow입니다. `main`에서 매일 실행되며 수동으로도 디스패치할 수 있습니다. ```bash gh workflow run openclaw-performance.yml --ref main -f profile=diagnostic -f repeat=3 @@ -145,32 +145,26 @@ gh workflow run openclaw-performance.yml --ref main -f profile=smoke -f repeat=1 gh workflow run openclaw-performance.yml --ref main -f target_ref=v2026.5.2 -f profile=diagnostic -f repeat=3 ``` -수동 디스패치는 일반적으로 워크플로 ref를 벤치마크합니다. 현재 워크플로 구현으로 릴리스 태그나 다른 브랜치를 벤치마크하려면 `target_ref`를 설정하세요. 게시된 보고서 경로와 최신 포인터는 테스트된 ref를 기준으로 키가 지정되며, 각 `index.md`는 테스트된 ref/SHA, 워크플로 ref/SHA, Kova ref, 프로필, lane 인증 모드, 모델, 반복 횟수, 시나리오 필터를 기록합니다. +수동 디스패치는 일반적으로 workflow ref를 benchmark합니다. 현재 workflow 구현으로 릴리스 tag 또는 다른 branch를 benchmark하려면 `target_ref`를 설정하세요. 게시된 report path와 latest pointer는 테스트된 ref를 기준으로 key가 지정되며, 각 `index.md`에는 테스트된 ref/SHA, workflow ref/SHA, Kova ref, profile, lane auth mode, model, repeat count, scenario filter가 기록됩니다. -워크플로는 고정된 릴리스에서 OCM을 설치하고, 고정된 `kova_ref` 입력의 `openclaw/Kova`에서 Kova를 설치한 다음 세 개의 lane을 실행합니다. +workflow는 고정된 릴리스에서 OCM을 설치하고 고정된 `kova_ref` 입력의 `openclaw/Kova`에서 Kova를 설치한 다음 세 가지 lane을 실행합니다. -- `mock-provider`: 결정적 가짜 OpenAI 호환 인증이 있는 로컬 빌드 런타임을 대상으로 하는 Kova 진단 시나리오입니다. -- `mock-deep-profile`: 시작, Gateway, agent-turn 핫스팟에 대한 CPU/힙/트레이스 프로파일링입니다. -- `live-gpt54`: 실제 OpenAI `openai/gpt-5.4` 에이전트 turn이며, `OPENAI_API_KEY`를 사용할 수 없으면 건너뜁니다. +- `mock-provider`: 결정적인 fake OpenAI 호환 auth를 사용하는 local-build runtime에 대한 Kova diagnostic scenario입니다. +- `mock-deep-profile`: startup, Gateway, agent-turn hotspot에 대한 CPU/heap/trace profiling입니다. +- `live-gpt54`: 실제 OpenAI `openai/gpt-5.4` agent turn이며, `OPENAI_API_KEY`를 사용할 수 없으면 건너뜁니다. -mock-provider lane은 Kova 통과 후 OpenClaw 네이티브 소스 프로브도 실행합니다. 기본, hook, 50-Plugin 시작 사례 전반의 Gateway 부팅 타이밍과 메모리, 반복 mock-OpenAI `channel-chat-baseline` hello 루프, 부팅된 Gateway를 대상으로 하는 CLI 시작 명령이 포함됩니다. 소스 프로브 Markdown 요약은 보고서 번들의 `source/index.md`에 있으며, 원시 JSON은 그 옆에 있습니다. +mock-provider lane은 Kova pass 후 OpenClaw native source probe도 실행합니다. 기본, hook, 50-Plugin startup case의 Gateway boot timing 및 memory, 반복 mock-OpenAI `channel-chat-baseline` hello loop, boot된 Gateway에 대한 CLI startup command입니다. source probe Markdown summary는 report bundle의 `source/index.md`에 있으며, raw JSON은 그 옆에 있습니다. -모든 lane은 GitHub 아티팩트를 업로드합니다. `CLAWGRIT_REPORTS_TOKEN`이 구성된 경우 워크플로는 `report.json`, `report.md`, 번들, `index.md`, 소스 프로브 아티팩트도 `openclaw-performance//-//` 아래의 `openclaw/clawgrit-reports`에 커밋합니다. 현재 테스트된 ref 포인터는 `openclaw-performance//latest-.json`으로 기록됩니다. +모든 lane은 GitHub artifact를 업로드합니다. `CLAWGRIT_REPORTS_TOKEN`이 구성된 경우 workflow는 `report.json`, `report.md`, bundle, `index.md`, source-probe artifact도 `openclaw-performance//-//` 아래의 `openclaw/clawgrit-reports`에 commit합니다. 현재 tested-ref pointer는 `openclaw-performance//latest-.json`으로 작성됩니다. ## 전체 릴리스 검증 -`Full Release Validation`은 "릴리스 전에 모든 것을 실행"하기 위한 수동 umbrella 워크플로입니다. 브랜치, 태그 또는 전체 커밋 SHA를 받아 해당 대상을 사용해 수동 `CI` 워크플로를 디스패치하고, 릴리스 전용 Plugin/패키지/정적/Docker 증거를 위해 `Plugin Prerelease`를 디스패치하며, 설치 스모크, 패키지 수락, Docker 릴리스 경로 제품군, live/E2E, OpenWebUI, QA Lab parity, Matrix, Telegram lane을 위해 `OpenClaw Release Checks`를 디스패치합니다. `rerun_group=all` 및 `release_profile=full`을 사용하면 릴리스 검사에서 나온 `release-package-under-test` 아티팩트를 대상으로 `NPM Telegram Beta E2E`도 실행합니다. 게시 후에는 게시된 npm 패키지를 대상으로 동일한 Telegram 패키지 lane을 다시 실행하려면 `npm_telegram_package_spec`을 전달하세요. +`Full Release Validation`은 "릴리스 전에 모든 것을 실행"하기 위한 수동 umbrella workflow입니다. branch, tag 또는 전체 commit SHA를 입력받아 해당 target으로 수동 `CI` workflow를 디스패치하고, 릴리스 전용 Plugin/package/static/Docker proof를 위해 `Plugin Prerelease`를 디스패치하며, install smoke, package acceptance, Docker release-path suite, live/E2E, OpenWebUI, QA Lab parity, Matrix, Telegram lane을 위해 `OpenClaw Release Checks`를 디스패치합니다. `rerun_group=all` 및 `release_profile=full`을 사용하면 release checks의 `release-package-under-test` artifact에 대해 `NPM Telegram Beta E2E`도 실행합니다. 게시 후에는 `npm_telegram_package_spec`을 전달해 게시된 npm 패키지에 대해 동일한 Telegram package lane을 다시 실행하세요. -단계 매트릭스, 정확한 워크플로 작업 이름, 프로필 차이, 아티팩트, -집중 재실행 핸들은 [전체 릴리스 검증](/ko/reference/full-release-validation)을 -참조하세요. +stage matrix, 정확한 workflow job name, profile 차이, artifact, 집중 rerun handle은 +[전체 릴리스 검증](/ko/reference/full-release-validation)을 참조하세요. -`OpenClaw Release Publish`는 변경을 수행하는 수동 릴리스 워크플로입니다. -릴리스 태그가 존재하고 OpenClaw npm preflight가 성공한 뒤 `release/YYYY.M.D` -또는 `main`에서 디스패치하세요. 이 워크플로는 `pnpm plugins:sync:check`를 -검증하고, 게시 가능한 모든 Plugin 패키지에 대해 `Plugin NPM Release`를 -디스패치하며, 같은 릴리스 SHA에 대해 `Plugin ClawHub Release`를 디스패치한 -다음에만 저장된 `preflight_run_id`로 `OpenClaw NPM Release`를 디스패치합니다. +`OpenClaw Release Publish`는 변경을 수행하는 수동 릴리스 workflow입니다. 릴리스 tag가 존재하고 OpenClaw npm preflight가 성공한 뒤 `release/YYYY.M.D` 또는 `main`에서 디스패치하세요. 이 workflow는 `pnpm plugins:sync:check`를 검증하고, 게시 가능한 모든 Plugin package에 대해 `Plugin NPM Release`를 디스패치하며, 동일한 릴리스 SHA에 대해 `Plugin ClawHub Release`를 디스패치한 다음에만 저장된 `preflight_run_id`로 `OpenClaw NPM Release`를 디스패치합니다. ```bash gh workflow run openclaw-release-publish.yml \ @@ -180,41 +174,36 @@ gh workflow run openclaw-release-publish.yml \ -f npm_dist_tag=beta ``` -빠르게 움직이는 브랜치에서 고정된 커밋 증거가 필요하면 +빠르게 움직이는 branch에서 고정된 commit proof가 필요하면 `gh workflow run ... --ref main -f ref=` 대신 helper를 사용하세요. ```bash pnpm ci:full-release --sha ``` -GitHub 워크플로 디스패치 ref는 원시 커밋 SHA가 아니라 브랜치 또는 태그여야 합니다. -helper는 대상 SHA에 임시 `release-ci/-...` 브랜치를 push하고, -해당 고정 ref에서 `Full Release Validation`을 디스패치하며, 모든 하위 -워크플로의 `headSha`가 대상과 일치하는지 검증하고, 실행이 완료되면 임시 -브랜치를 삭제합니다. umbrella 검증기는 하위 워크플로가 다른 SHA에서 실행된 -경우에도 실패합니다. +GitHub workflow dispatch ref는 branch 또는 tag여야 하며 raw commit SHA가 될 수 없습니다. 이 helper는 target SHA에 임시 `release-ci/-...` branch를 push하고, 해당 고정 ref에서 `Full Release Validation`을 디스패치하며, 모든 child workflow의 `headSha`가 target과 일치하는지 검증하고, 실행이 완료되면 임시 branch를 삭제합니다. umbrella verifier는 child workflow가 다른 SHA에서 실행된 경우에도 실패합니다. -`release_profile`은 릴리스 검사에 전달되는 live/provider 범위를 제어합니다. 수동 릴리스 워크플로는 기본값으로 `stable`을 사용합니다. 광범위한 advisory provider/media 매트릭스를 의도적으로 원할 때만 `full`을 사용하세요. +`release_profile`은 릴리스 검사에 전달되는 라이브/공급자 범위를 제어합니다. 수동 릴리스 워크플로의 기본값은 `stable`입니다. 광범위한 권고 공급자/미디어 매트릭스를 의도적으로 원할 때만 `full`을 사용하세요. -- `minimum`은 가장 빠른 OpenAI/핵심 릴리스 필수 lane을 유지합니다. -- `stable`은 stable provider/backend 세트를 추가합니다. -- `full`은 광범위한 advisory provider/media 매트릭스를 실행합니다. +- `minimum`은 가장 빠른 OpenAI/코어 릴리스 필수 레인만 유지합니다. +- `stable`은 안정 공급자/백엔드 세트를 추가합니다. +- `full`은 광범위한 권고 공급자/미디어 매트릭스를 실행합니다. -상위 워크플로는 디스패치된 하위 실행 ID를 기록하며, 마지막 `Verify full validation` 작업은 현재 하위 실행 결론을 다시 확인하고 각 하위 실행의 가장 느린 작업 표를 덧붙입니다. 하위 워크플로를 다시 실행해 녹색으로 바뀌면, 상위 검증 작업만 다시 실행해 상위 결과와 타이밍 요약을 새로 고치세요. +상위 워크플로는 디스패치된 하위 실행 ID를 기록하고, 최종 `Verify full validation` 작업은 현재 하위 실행 결론을 다시 확인한 뒤 각 하위 실행의 가장 느린 작업 표를 추가합니다. 하위 워크플로를 다시 실행해 녹색이 되면, 상위 검증 작업만 다시 실행해 상위 결과와 시간 요약을 새로 고치세요. -복구를 위해 `Full Release Validation`과 `OpenClaw Release Checks`는 모두 `rerun_group`을 허용합니다. 릴리스 후보에는 `all`, 일반 full CI 하위 항목만에는 `ci`, Plugin prerelease 하위 항목만에는 `plugin-prerelease`, 모든 릴리스 하위 항목에는 `release-checks`, 또는 상위 워크플로에서 더 좁은 그룹인 `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, `npm-telegram`을 사용하세요. 이렇게 하면 집중 수정 후 실패한 릴리스 박스 재실행 범위를 제한할 수 있습니다. +복구를 위해 `Full Release Validation`과 `OpenClaw Release Checks`는 모두 `rerun_group`을 허용합니다. 릴리스 후보에는 `all`, 일반 전체 CI 하위만에는 `ci`, Plugin 프리릴리스 하위만에는 `plugin-prerelease`, 모든 릴리스 하위에는 `release-checks`, 또는 상위 워크플로에서 더 좁은 그룹인 `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, `npm-telegram`을 사용하세요. 이렇게 하면 집중 수정 후 실패한 릴리스 박스 재실행 범위를 제한할 수 있습니다. -`OpenClaw Release Checks`는 신뢰된 워크플로 ref를 사용해 선택된 ref를 한 번 `release-package-under-test` tarball로 확인한 다음, 해당 artifact를 live/E2E 릴리스 경로 Docker 워크플로와 package acceptance 샤드 모두에 전달합니다. 이렇게 하면 릴리스 박스 전반에서 package 바이트가 일관되게 유지되고, 여러 하위 작업에서 같은 후보를 다시 패킹하지 않아도 됩니다. +`OpenClaw Release Checks`는 신뢰된 워크플로 ref를 사용해 선택된 ref를 한 번 `release-package-under-test` tarball로 해석한 뒤, 그 아티팩트를 라이브/E2E 릴리스 경로 Docker 워크플로와 패키지 수락 샤드 모두에 전달합니다. 이렇게 하면 릴리스 박스 전반에서 패키지 바이트가 일관되게 유지되고, 여러 하위 작업에서 같은 후보를 다시 패키징하지 않아도 됩니다. -`ref=main` 및 `rerun_group=all`에 대한 중복 `Full Release Validation` 실행은 더 오래된 상위 워크플로를 대체합니다. 상위 모니터는 상위가 취소될 때 이미 디스패치한 모든 하위 워크플로를 취소하므로, 새 main 검증이 오래된 두 시간짜리 release-check 실행 뒤에 대기하지 않습니다. 릴리스 브랜치/태그 검증과 집중 재실행 그룹은 `cancel-in-progress: false`를 유지합니다. +`ref=main` 및 `rerun_group=all`에 대한 중복 `Full Release Validation` 실행은 더 오래된 상위 워크플로를 대체합니다. 상위 모니터는 상위 워크플로가 취소될 때 이미 디스패치한 모든 하위 워크플로를 취소하므로, 새 main 검증이 오래된 2시간짜리 릴리스 검사 실행 뒤에서 대기하지 않습니다. 릴리스 브랜치/태그 검증과 집중 재실행 그룹은 `cancel-in-progress: false`를 유지합니다. -## Live 및 E2E 샤드 +## 라이브 및 E2E 샤드 -릴리스 live/E2E 하위 항목은 광범위한 네이티브 `pnpm test:live` 커버리지를 유지하지만, 하나의 직렬 작업 대신 `scripts/test-live-shard.mjs`를 통해 이름 있는 샤드로 실행합니다. +릴리스 라이브/E2E 하위 워크플로는 광범위한 네이티브 `pnpm test:live` 범위를 유지하지만, 하나의 직렬 작업 대신 `scripts/test-live-shard.mjs`를 통해 이름 있는 샤드로 실행합니다. - `native-live-src-agents` - `native-live-src-gateway-core` -- provider로 필터링된 `native-live-src-gateway-profiles` 작업 +- 공급자 필터링된 `native-live-src-gateway-profiles` 작업 - `native-live-src-gateway-backends` - `native-live-test` - `native-live-extensions-a-k` @@ -222,59 +211,59 @@ helper는 대상 SHA에 임시 `release-ci/-...` 브랜치를 push하고, - `native-live-extensions-openai` - `native-live-extensions-o-z-other` - `native-live-extensions-xai` -- 분할된 media audio/video 샤드 및 provider로 필터링된 music 샤드 +- 분리된 미디어 오디오/비디오 샤드 및 공급자 필터링된 음악 샤드 -이렇게 하면 같은 파일 커버리지를 유지하면서 느린 live provider 실패를 더 쉽게 재실행하고 진단할 수 있습니다. 집계 `native-live-extensions-o-z`, `native-live-extensions-media`, `native-live-extensions-media-music` 샤드 이름은 수동 일회성 재실행에도 계속 유효합니다. +이렇게 하면 동일한 파일 범위를 유지하면서 느린 라이브 공급자 실패를 더 쉽게 재실행하고 진단할 수 있습니다. 집계 `native-live-extensions-o-z`, `native-live-extensions-media`, `native-live-extensions-media-music` 샤드 이름은 수동 단발 재실행에서도 계속 유효합니다. -네이티브 live media 샤드는 `Live Media Runner Image` 워크플로가 빌드한 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`에서 실행됩니다. 해당 이미지는 `ffmpeg`와 `ffprobe`를 미리 설치합니다. media 작업은 설정 전에 바이너리만 확인합니다. Docker 기반 live 스위트는 일반 Blacksmith 러너에 유지하세요. 컨테이너 작업은 중첩 Docker 테스트를 시작하기에 적절한 위치가 아닙니다. +네이티브 라이브 미디어 샤드는 `Live Media Runner Image` 워크플로가 빌드한 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`에서 실행됩니다. 이 이미지는 `ffmpeg`와 `ffprobe`를 미리 설치합니다. 미디어 작업은 설정 전에 바이너리만 확인합니다. Docker 기반 라이브 제품군은 일반 Blacksmith 러너에 유지하세요. 컨테이너 작업은 중첩 Docker 테스트를 시작하기에 적합하지 않습니다. -Docker 기반 live model/backend 샤드는 선택된 커밋마다 별도의 공유 `ghcr.io/openclaw/openclaw-live-test:` 이미지를 사용합니다. live 릴리스 워크플로는 해당 이미지를 한 번 빌드하고 푸시한 다음, Docker live model, provider로 샤딩된 Gateway, CLI backend, ACP bind, Codex harness 샤드를 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 실행합니다. Gateway Docker 샤드는 워크플로 작업 제한 시간보다 낮은 명시적인 스크립트 수준 `timeout` 상한을 가지고 있어, 멈춘 컨테이너나 cleanup 경로가 전체 release-check 예산을 소비하는 대신 빠르게 실패합니다. 이러한 샤드가 전체 source Docker target을 독립적으로 다시 빌드한다면 릴리스 실행이 잘못 구성된 것이며, 중복 이미지 빌드로 wall clock을 낭비하게 됩니다. +Docker 기반 라이브 모델/백엔드 샤드는 선택된 커밋마다 별도의 공유 `ghcr.io/openclaw/openclaw-live-test:` 이미지를 사용합니다. 라이브 릴리스 워크플로는 해당 이미지를 한 번 빌드하고 푸시한 뒤, Docker 라이브 모델, 공급자 샤딩 Gateway, CLI 백엔드, ACP 바인드, Codex 하네스 샤드를 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 실행합니다. Gateway Docker 샤드는 워크플로 작업 제한 시간보다 낮은 명시적 스크립트 수준 `timeout` 상한을 가지므로, 멈춘 컨테이너나 정리 경로가 전체 릴리스 검사 예산을 소모하는 대신 빠르게 실패합니다. 이러한 샤드가 전체 소스 Docker 대상을 독립적으로 다시 빌드한다면 릴리스 실행이 잘못 구성된 것이며, 중복 이미지 빌드로 실제 시간이 낭비됩니다. -## Package Acceptance +## 패키지 수락 -“이 설치 가능한 OpenClaw package가 제품으로서 작동하는가?”가 질문이라면 `Package Acceptance`를 사용하세요. 이는 일반 CI와 다릅니다. 일반 CI는 source tree를 검증하지만, package acceptance는 설치 또는 업데이트 후 사용자가 실행하는 것과 같은 Docker E2E harness를 통해 단일 tarball을 검증합니다. +질문이 "이 설치 가능한 OpenClaw 패키지가 제품으로 동작하는가?"일 때 `Package Acceptance`를 사용하세요. 이는 일반 CI와 다릅니다. 일반 CI는 소스 트리를 검증하지만, 패키지 수락은 설치 또는 업데이트 후 사용자가 실행하는 것과 동일한 Docker E2E 하네스를 통해 단일 tarball을 검증합니다. ### 작업 -1. `resolve_package`는 `workflow_ref`를 체크아웃하고, 하나의 package 후보를 확인하고, `.artifacts/docker-e2e-package/openclaw-current.tgz`를 쓰고, `.artifacts/docker-e2e-package/package-candidate.json`을 쓰고, 둘 다 `package-under-test` artifact로 업로드하며, GitHub 단계 요약에 source, workflow ref, package ref, version, SHA-256, profile을 출력합니다. -2. `docker_acceptance`는 `ref=workflow_ref` 및 `package_artifact_name=package-under-test`로 `openclaw-live-and-e2e-checks-reusable.yml`을 호출합니다. 재사용 가능한 워크플로는 해당 artifact를 다운로드하고, tarball inventory를 검증하고, 필요할 때 package-digest Docker 이미지를 준비하며, workflow checkout을 패킹하는 대신 해당 package를 대상으로 선택된 Docker lane을 실행합니다. profile이 여러 targeted `docker_lanes`를 선택하면, 재사용 가능한 워크플로는 package와 공유 이미지를 한 번 준비한 다음, 해당 lane들을 고유 artifact를 가진 병렬 targeted Docker 작업으로 fan out합니다. -3. `package_telegram`은 선택적으로 `NPM Telegram Beta E2E`를 호출합니다. `telegram_mode`가 `none`이 아닐 때 실행되며, Package Acceptance가 하나를 확인한 경우 같은 `package-under-test` artifact를 설치합니다. 독립 실행형 Telegram dispatch는 여전히 게시된 npm spec을 설치할 수 있습니다. -4. `summary`는 package resolution, Docker acceptance 또는 선택적 Telegram lane이 실패한 경우 워크플로를 실패시킵니다. +1. `resolve_package`는 `workflow_ref`를 체크아웃하고, 하나의 패키지 후보를 해석하고, `.artifacts/docker-e2e-package/openclaw-current.tgz`를 쓰고, `.artifacts/docker-e2e-package/package-candidate.json`을 쓰고, 둘 다 `package-under-test` 아티팩트로 업로드한 뒤, GitHub 단계 요약에 소스, 워크플로 ref, 패키지 ref, 버전, SHA-256, 프로필을 출력합니다. +2. `docker_acceptance`는 `ref=workflow_ref` 및 `package_artifact_name=package-under-test`로 `openclaw-live-and-e2e-checks-reusable.yml`을 호출합니다. 재사용 워크플로는 해당 아티팩트를 다운로드하고, tarball 인벤토리를 검증하고, 필요할 때 패키지 다이제스트 Docker 이미지를 준비하며, 워크플로 체크아웃을 패킹하는 대신 해당 패키지를 대상으로 선택된 Docker 레인을 실행합니다. 프로필이 여러 대상 `docker_lanes`를 선택하면, 재사용 워크플로는 패키지와 공유 이미지를 한 번 준비한 뒤 해당 레인들을 고유한 아티팩트를 가진 병렬 대상 Docker 작업으로 전개합니다. +3. `package_telegram`은 선택적으로 `NPM Telegram Beta E2E`를 호출합니다. `telegram_mode`가 `none`이 아닐 때 실행되며, Package Acceptance가 하나를 해석한 경우 동일한 `package-under-test` 아티팩트를 설치합니다. 독립형 Telegram 디스패치는 여전히 게시된 npm spec을 설치할 수 있습니다. +4. `summary`는 패키지 해석, Docker 수락 또는 선택적 Telegram 레인이 실패하면 워크플로를 실패 처리합니다. ### 후보 소스 -- `source=npm`은 `openclaw@beta`, `openclaw@latest`, 또는 `openclaw@2026.4.27-beta.2` 같은 정확한 OpenClaw 릴리스 버전만 허용합니다. 게시된 prerelease/stable acceptance에 이것을 사용하세요. -- `source=ref`는 신뢰된 `package_ref` 브랜치, 태그 또는 전체 커밋 SHA를 패킹합니다. resolver는 OpenClaw 브랜치/태그를 가져오고, 선택된 커밋이 저장소 브랜치 히스토리 또는 릴리스 태그에서 도달 가능한지 검증하고, detached worktree에 deps를 설치한 뒤 `scripts/package-openclaw-for-docker.mjs`로 패킹합니다. -- `source=url`은 HTTPS `.tgz`를 다운로드합니다. `package_sha256`이 필요합니다. -- `source=artifact`는 `artifact_run_id`와 `artifact_name`에서 하나의 `.tgz`를 다운로드합니다. `package_sha256`은 선택 사항이지만 외부 공유 artifact에는 제공해야 합니다. +- `source=npm`은 `openclaw@beta`, `openclaw@latest` 또는 `openclaw@2026.4.27-beta.2` 같은 정확한 OpenClaw 릴리스 버전만 허용합니다. 게시된 프리릴리스/안정 수락에 사용하세요. +- `source=ref`는 신뢰된 `package_ref` 브랜치, 태그 또는 전체 커밋 SHA를 패킹합니다. 해석기는 OpenClaw 브랜치/태그를 가져오고, 선택된 커밋이 저장소 브랜치 히스토리 또는 릴리스 태그에서 도달 가능한지 확인하고, 분리된 worktree에 의존성을 설치한 뒤 `scripts/package-openclaw-for-docker.mjs`로 패킹합니다. +- `source=url`은 HTTPS `.tgz`를 다운로드합니다. `package_sha256`은 필수입니다. +- `source=artifact`는 `artifact_run_id` 및 `artifact_name`에서 하나의 `.tgz`를 다운로드합니다. `package_sha256`은 선택 사항이지만 외부 공유 아티팩트에는 제공해야 합니다. -`workflow_ref`와 `package_ref`를 분리해 유지하세요. `workflow_ref`는 테스트를 실행하는 신뢰된 워크플로/harness 코드입니다. `package_ref`는 `source=ref`일 때 패킹되는 source commit입니다. 이를 통해 현재 테스트 harness가 오래된 워크플로 로직을 실행하지 않고도 오래된 신뢰된 source commit을 검증할 수 있습니다. +`workflow_ref`와 `package_ref`를 분리해 유지하세요. `workflow_ref`는 테스트를 실행하는 신뢰된 워크플로/하네스 코드입니다. `package_ref`는 `source=ref`일 때 패킹되는 소스 커밋입니다. 이를 통해 현재 테스트 하네스가 오래된 워크플로 로직을 실행하지 않고도 더 오래된 신뢰된 소스 커밋을 검증할 수 있습니다. -### 스위트 프로필 +### 제품군 프로필 - `smoke` — `npm-onboard-channel-agent`, `gateway-network`, `config-reload` - `package` — `npm-onboard-channel-agent`, `doctor-switch`, `update-channel-switch`, `upgrade-survivor`, `published-upgrade-survivor`, `plugins-offline`, `plugin-update` - `product` — `package`에 `mcp-channels`, `cron-mcp-cleanup`, `openai-web-search-minimal`, `openwebui` 추가 -- `full` — OpenWebUI가 포함된 전체 Docker 릴리스 경로 chunk -- `custom` — 정확한 `docker_lanes`; `suite_profile=custom`일 때 필요 +- `full` — OpenWebUI가 포함된 전체 Docker 릴리스 경로 청크 +- `custom` — 정확한 `docker_lanes`; `suite_profile=custom`일 때 필수 -`package` profile은 offline Plugin 커버리지를 사용하므로 게시된 package 검증이 live ClawHub 가용성에 묶이지 않습니다. 선택적 Telegram lane은 `NPM Telegram Beta E2E`에서 `package-under-test` artifact를 재사용하며, 게시된 npm spec 경로는 독립 실행형 dispatch용으로 유지됩니다. +`package` 프로필은 오프라인 Plugin 범위를 사용하므로 게시된 패키지 검증이 라이브 ClawHub 가용성에 의해 차단되지 않습니다. 선택적 Telegram 레인은 `NPM Telegram Beta E2E`에서 `package-under-test` 아티팩트를 재사용하며, 게시된 npm spec 경로는 독립형 디스패치를 위해 유지됩니다. -전용 업데이트 및 Plugin 테스트 정책, local commands, Docker lanes, Package Acceptance inputs, release defaults, failure triage는 [업데이트 및 Plugin 테스트](/ko/help/testing-updates-plugins)를 참조하세요. +로컬 명령, Docker 레인, Package Acceptance 입력, 릴리스 기본값, 실패 분류를 포함한 전용 업데이트 및 Plugin 테스트 정책은 [업데이트 및 Plugin 테스트](/ko/help/testing-updates-plugins)를 참조하세요. -릴리스 검사는 준비된 릴리스 package artifact, `suite_profile=custom`, `docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues`, `telegram_mode=mock-openai`와 함께 `source=artifact`로 Package Acceptance를 호출합니다. 이렇게 하면 package migration, update, stale-plugin-dependency cleanup, configured-plugin install repair, offline Plugin, plugin-update, Telegram proof가 같은 확인된 package tarball에서 유지됩니다. SHA로 빌드한 artifact 대신 배포된 npm package를 대상으로 같은 매트릭스를 실행하려면 Full Release Validation 또는 OpenClaw Release Checks에서 `package_acceptance_package_spec`을 설정하세요. Cross-OS 릴리스 검사는 여전히 OS별 onboarding, installer, platform behavior를 다룹니다. package/update 제품 검증은 Package Acceptance에서 시작해야 합니다. `published-upgrade-survivor` Docker lane은 실행당 하나의 게시된 package baseline을 검증합니다. Package Acceptance에서 확인된 `package-under-test` tarball은 항상 후보이며, `published_upgrade_survivor_baseline`은 fallback published baseline을 선택하고 기본값은 `openclaw@latest`입니다. failed-lane rerun command는 해당 baseline을 보존합니다. `published_upgrade_survivor_baselines=all-since-2026.4.23`을 설정하면 Full Release CI가 `2026.4.23`부터 `latest`까지 모든 stable npm release 전반으로 확장됩니다. 더 오래된 pre-date anchor를 사용한 수동 광범위 샘플링에는 `release-history`가 계속 제공됩니다. `published_upgrade_survivor_scenarios=reported-issues`를 설정하면 Feishu config, 보존된 bootstrap/persona 파일, 구성된 OpenClaw Plugin 설치, tilde log path, 오래된 legacy Plugin dependency root에 대한 issue-shaped fixture 전반으로 같은 baseline이 확장됩니다. 별도의 `Update Migration` 워크플로는 질문이 일반 Full Release CI 범위가 아니라 철저한 게시된 update cleanup일 때 `all-since-2026.4.23` 및 `plugin-deps-cleanup`과 함께 `update-migration` Docker lane을 사용합니다. 로컬 집계 실행은 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS`로 정확한 package spec을 전달하거나, `openclaw@2026.4.15` 같은 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC`으로 단일 lane을 유지하거나, scenario matrix용으로 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS`를 설정할 수 있습니다. 게시된 lane은 baked `openclaw config set` command recipe로 baseline을 구성하고, recipe step을 `summary.json`에 기록하며, Gateway 시작 후 `/healthz`, `/readyz`와 RPC status를 probe합니다. Windows packaged 및 installer fresh lane도 설치된 package가 raw absolute Windows path에서 browser-control override를 import할 수 있는지 확인합니다. OpenAI cross-OS agent-turn smoke는 설정된 경우 기본값으로 `OPENCLAW_CROSS_OS_OPENAI_MODEL`을 사용하고, 그렇지 않으면 `openai/gpt-5.4`를 사용하므로, install 및 Gateway proof가 GPT-4.x 기본값을 피하면서 GPT-5 test model에 유지됩니다. +릴리스 검사는 준비된 릴리스 패키지 아티팩트, `suite_profile=custom`, `docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'`, `published_upgrade_survivor_baselines=all-since-2026.4.23`, `published_upgrade_survivor_scenarios=reported-issues`, `telegram_mode=mock-openai`와 함께 `source=artifact`로 Package Acceptance를 호출합니다. 이렇게 하면 패키지 마이그레이션, 업데이트, 오래된 Plugin 의존성 정리, 구성된 Plugin 설치 복구, 오프라인 Plugin, Plugin 업데이트, Telegram 증명이 동일한 해석된 패키지 tarball에서 유지됩니다. Full Release Validation 또는 OpenClaw Release Checks에서 `package_acceptance_package_spec`을 설정하면 SHA로 빌드한 아티팩트 대신 출시된 npm 패키지를 대상으로 동일한 매트릭스를 실행합니다. Cross-OS 릴리스 검사는 여전히 OS별 온보딩, 설치 관리자, 플랫폼 동작을 다룹니다. 패키지/업데이트 제품 검증은 Package Acceptance로 시작해야 합니다. `published-upgrade-survivor` Docker 레인은 실행당 하나의 게시된 패키지 기준선을 검증합니다. Package Acceptance에서 해석된 `package-under-test` tarball은 항상 후보이고, `published_upgrade_survivor_baseline`은 폴백 게시 기준선을 선택하며 기본값은 `openclaw@latest`입니다. 실패한 레인 재실행 명령은 해당 기준선을 보존합니다. `published_upgrade_survivor_baselines=all-since-2026.4.23`을 설정하면 Full Release CI가 `2026.4.23`부터 `latest`까지의 모든 안정 npm 릴리스로 확장됩니다. `release-history`는 더 오래된 기준 날짜 앵커를 사용하는 수동 광범위 샘플링에 계속 사용할 수 있습니다. `published_upgrade_survivor_scenarios=reported-issues`를 설정하면 동일한 기준선을 Feishu 구성, 보존된 bootstrap/persona 파일, 구성된 OpenClaw Plugin 설치, 물결표 로그 경로, 오래된 레거시 Plugin 의존성 루트에 대한 이슈 형태의 fixture 전반으로 확장합니다. 별도의 `Update Migration` 워크플로는 질문이 일반 Full Release CI 범위가 아니라 게시된 업데이트 정리에 대한 철저한 검증일 때 `all-since-2026.4.23` 및 `plugin-deps-cleanup`과 함께 `update-migration` Docker 레인을 사용합니다. 로컬 집계 실행은 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS`로 정확한 패키지 spec을 전달하거나, `openclaw@2026.4.15` 같은 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC`으로 단일 레인을 유지하거나, 시나리오 매트릭스에 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS`를 설정할 수 있습니다. 게시된 레인은 내장된 `openclaw config set` 명령 레시피로 기준선을 구성하고, 레시피 단계를 `summary.json`에 기록하며, Gateway 시작 후 `/healthz`, `/readyz` 및 RPC 상태를 조사합니다. Windows 패키지 및 설치 관리자 신규 레인도 설치된 패키지가 원시 절대 Windows 경로에서 browser-control override를 가져올 수 있는지 확인합니다. OpenAI Cross-OS agent-turn smoke는 `OPENCLAW_CROSS_OS_OPENAI_MODEL`이 설정된 경우 이를 기본값으로 사용하고, 그렇지 않으면 `openai/gpt-5.4`를 사용하므로, GPT-4.x 기본값을 피하면서 설치 및 Gateway 증명이 GPT-5 테스트 모델에 유지됩니다. -### Legacy compatibility window +### 레거시 호환성 기간 -Package Acceptance에는 이미 게시된 package를 위한 제한된 legacy compatibility window가 있습니다. `2026.4.25-beta.*`를 포함해 `2026.4.25`까지의 package는 compatibility path를 사용할 수 있습니다. +Package Acceptance에는 이미 게시된 패키지를 위한 제한된 레거시 호환성 기간이 있습니다. `2026.4.25-beta.*`를 포함해 `2026.4.25`까지의 패키지는 호환성 경로를 사용할 수 있습니다. -- `dist/postinstall-inventory.json`의 알려진 private QA entry는 tarball에서 생략된 파일을 가리킬 수 있습니다. -- package가 해당 flag를 노출하지 않는 경우 `doctor-switch`는 `gateway install --wrapper` persistence subcase를 건너뛸 수 있습니다. -- `update-channel-switch`는 tarball에서 파생된 fake git fixture에서 누락된 `pnpm.patchedDependencies`를 prune할 수 있으며, 누락된 persisted `update.channel`을 log할 수 있습니다. -- Plugin smoke는 legacy install-record 위치를 읽거나 누락된 marketplace install-record persistence를 허용할 수 있습니다. -- `plugin-update`는 install record와 no-reinstall behavior가 변경되지 않은 상태를 계속 요구하면서 config metadata migration을 허용할 수 있습니다. +- `dist/postinstall-inventory.json`의 알려진 비공개 QA 항목은 tarball에서 생략된 파일을 가리킬 수 있습니다. +- 패키지가 해당 플래그를 노출하지 않는 경우 `doctor-switch`는 `gateway install --wrapper` 지속성 하위 사례를 건너뛸 수 있습니다. +- `update-channel-switch`는 tarball에서 파생된 가짜 git fixture에서 누락된 `pnpm.patchedDependencies`를 제거할 수 있으며, 누락된 지속 `update.channel`을 로그로 남길 수 있습니다. +- Plugin smoke는 레거시 설치 기록 위치를 읽거나 누락된 marketplace 설치 기록 지속성을 허용할 수 있습니다. +- `plugin-update`는 설치 기록과 무재설치 동작이 변경되지 않은 상태로 유지되어야 한다는 요구사항은 유지하면서 구성 메타데이터 마이그레이션을 허용할 수 있습니다. -게시된 `2026.4.26` package도 이미 배포된 local build metadata stamp file에 대해 warn할 수 있습니다. 이후 package는 modern contract를 충족해야 합니다. 같은 조건은 warn 또는 skip 대신 실패합니다. +게시된 `2026.4.26` 패키지는 이미 출시된 로컬 빌드 메타데이터 스탬프 파일에 대해서도 경고할 수 있습니다. 이후 패키지는 최신 계약을 충족해야 합니다. 동일한 조건은 경고 또는 건너뛰기 대신 실패합니다. ### 예시 @@ -317,60 +306,60 @@ gh workflow run package-acceptance.yml \ -f docker_lanes='install-e2e plugin-update' ``` -실패한 패키지 수락 실행을 디버깅할 때는 `resolve_package` 요약에서 시작해 패키지 소스, 버전, SHA-256을 확인하세요. 그런 다음 `docker_acceptance` 하위 실행과 해당 Docker 아티팩트를 검사하세요: `.artifacts/docker-tests/**/summary.json`, `failures.json`, 레인 로그, 단계별 타이밍, 재실행 명령. 전체 릴리스 검증을 다시 실행하는 대신 실패한 패키지 프로필이나 정확한 Docker 레인을 다시 실행하는 것을 선호하세요. +실패한 패키지 승인 실행을 디버깅할 때는 `resolve_package` 요약에서 시작해 패키지 소스, 버전, SHA-256을 확인하세요. 그런 다음 `docker_acceptance` 하위 실행과 해당 Docker 아티팩트인 `.artifacts/docker-tests/**/summary.json`, `failures.json`, 레인 로그, 단계 타이밍, 재실행 명령을 검사하세요. 전체 릴리스 검증을 다시 실행하는 대신 실패한 패키지 프로필 또는 정확한 Docker 레인을 다시 실행하는 것을 선호하세요. ## 설치 스모크 -별도의 `Install Smoke` 워크플로는 자체 `preflight` 작업을 통해 같은 범위 스크립트를 재사용합니다. 스모크 커버리지를 `run_fast_install_smoke`와 `run_full_install_smoke`로 나눕니다. +별도의 `Install Smoke` 워크플로는 자체 `preflight` 작업을 통해 같은 범위 스크립트를 재사용합니다. 스모크 범위를 `run_fast_install_smoke`와 `run_full_install_smoke`로 나눕니다. -- **빠른 경로**는 Docker/패키지 표면, 번들된 Plugin 패키지/매니페스트 변경, 또는 Docker 스모크 작업이 실행하는 코어 Plugin/채널/Gateway/Plugin SDK 표면을 건드리는 풀 리퀘스트에서 실행됩니다. 소스 전용 번들 Plugin 변경, 테스트 전용 편집, 문서 전용 편집은 Docker 워커를 예약하지 않습니다. 빠른 경로는 루트 Dockerfile 이미지를 한 번 빌드하고, CLI를 확인하고, 에이전트 삭제 공유 워크스페이스 CLI 스모크를 실행하고, 컨테이너 gateway-network e2e를 실행하고, 번들된 확장 빌드 인수를 검증하며, 240초 집계 명령 타임아웃 아래에서 제한된 번들 Plugin Docker 프로필을 실행합니다(각 시나리오의 Docker 실행은 별도로 제한됨). -- **전체 경로**는 야간 예약 실행, 수동 디스패치, workflow-call 릴리스 검사, 그리고 실제로 설치 프로그램/패키지/Docker 표면을 건드리는 풀 리퀘스트를 위해 QR 패키지 설치 및 설치 프로그램 Docker/update 커버리지를 유지합니다. 전체 모드에서 install-smoke는 하나의 대상 SHA GHCR 루트 Dockerfile 스모크 이미지를 준비하거나 재사용한 다음, 설치 프로그램 작업이 루트 이미지 스모크 뒤에서 기다리지 않도록 QR 패키지 설치, 루트 Dockerfile/Gateway 스모크, 설치 프로그램/update 스모크, 빠른 번들 Plugin Docker E2E를 별도 작업으로 실행합니다. +- **빠른 경로**는 Docker/패키지 표면, 번들 Plugin 패키지/매니페스트 변경, 또는 Docker 스모크 작업이 실행하는 핵심 Plugin/채널/Gateway/Plugin SDK 표면을 건드리는 풀 리퀘스트에서 실행됩니다. 소스만 변경된 번들 Plugin 변경, 테스트 전용 편집, 문서 전용 편집은 Docker 워커를 예약하지 않습니다. 빠른 경로는 루트 Dockerfile 이미지를 한 번 빌드하고, CLI를 확인하며, 에이전트 삭제 공유 워크스페이스 CLI 스모크를 실행하고, 컨테이너 Gateway 네트워크 e2e를 실행하며, 번들 확장 빌드 인자를 검증하고, 240초 집계 명령 제한 시간 안에서 제한된 번들 Plugin Docker 프로필을 실행합니다. 각 시나리오의 Docker 실행은 별도로 제한됩니다. +- **전체 경로**는 야간 예약 실행, 수동 디스패치, workflow-call 릴리스 검사, 그리고 실제로 설치 프로그램/패키지/Docker 표면을 건드리는 풀 리퀘스트를 위해 QR 패키지 설치와 설치 프로그램 Docker/update 범위를 유지합니다. 전체 모드에서 install-smoke는 대상 SHA GHCR 루트 Dockerfile 스모크 이미지를 하나 준비하거나 재사용한 다음, QR 패키지 설치, 루트 Dockerfile/Gateway 스모크, 설치 프로그램/update 스모크, 빠른 번들 Plugin Docker E2E를 별도 작업으로 실행하여 설치 프로그램 작업이 루트 이미지 스모크 뒤에서 대기하지 않게 합니다. -`main` 푸시(머지 커밋 포함)는 전체 경로를 강제하지 않습니다. 변경 범위 로직이 푸시에서 전체 커버리지를 요청하더라도 워크플로는 빠른 Docker 스모크를 유지하고 전체 설치 스모크는 야간 또는 릴리스 검증에 맡깁니다. +`main` 푸시(머지 커밋 포함)는 전체 경로를 강제하지 않습니다. 변경 범위 로직이 푸시에서 전체 범위를 요청하더라도 워크플로는 빠른 Docker 스모크를 유지하고 전체 설치 스모크는 야간 또는 릴리스 검증에 맡깁니다. -느린 Bun 전역 설치 image-provider 스모크는 `run_bun_global_install_smoke`로 별도 게이트됩니다. 야간 일정과 릴리스 검사 워크플로에서 실행되며, 수동 `Install Smoke` 디스패치는 이를 선택할 수 있지만 풀 리퀘스트와 `main` 푸시에서는 실행되지 않습니다. QR 및 설치 프로그램 Docker 테스트는 각각 설치 중심 Dockerfile을 유지합니다. +느린 Bun 전역 설치 이미지 제공자 스모크는 `run_bun_global_install_smoke`로 별도 게이트됩니다. 이 검사는 야간 일정과 릴리스 검사 워크플로에서 실행되며, 수동 `Install Smoke` 디스패치는 이를 선택할 수 있지만 풀 리퀘스트와 `main` 푸시는 실행하지 않습니다. QR 및 설치 프로그램 Docker 테스트는 각자의 설치 중심 Dockerfile을 유지합니다. ## 로컬 Docker E2E -`pnpm test:docker:all`은 하나의 공유 라이브 테스트 이미지를 미리 빌드하고, OpenClaw를 npm tarball로 한 번 패킹하며, 두 개의 공유 `scripts/e2e/Dockerfile` 이미지를 빌드합니다. +`pnpm test:docker:all`은 공유 live-test 이미지 하나를 미리 빌드하고, OpenClaw를 npm tarball로 한 번 패킹하며, 공유 `scripts/e2e/Dockerfile` 이미지 두 개를 빌드합니다. -- 설치 프로그램/update/Plugin 의존성 레인을 위한 기본 Node/Git 러너 +- 설치 프로그램/update/Plugin 의존성 레인용 기본 Node/Git 러너 - 일반 기능 레인을 위해 같은 tarball을 `/app`에 설치하는 기능 이미지 Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, 플래너 로직은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, 러너는 선택된 계획만 실행합니다. 스케줄러는 `OPENCLAW_DOCKER_E2E_BARE_IMAGE`와 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`로 레인별 이미지를 선택한 다음 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 레인을 실행합니다. -### 조정 가능 항목 +### 조정 가능한 항목 | 변수 | 기본값 | 목적 | | -------------------------------------- | ------- | --------------------------------------------------------------------------------------------- | -| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 일반 레인의 메인 풀 슬롯 수. | -| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 프로바이더 민감 tail 풀 슬롯 수. | -| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 프로바이더가 스로틀링하지 않도록 하는 동시 라이브 레인 상한. | -| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 동시 npm 설치 레인 상한. | -| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 동시 다중 서비스 레인 상한. | -| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | Docker 데몬 생성 폭주를 피하기 위한 레인 시작 간격. 간격을 없애려면 `0`으로 설정하세요. | -| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 레인별 폴백 타임아웃(120분). 선택된 라이브/tail 레인은 더 엄격한 상한을 사용합니다. | +| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 일반 레인의 메인 풀 슬롯 수입니다. | +| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 제공자에 민감한 테일 풀 슬롯 수입니다. | +| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 제공자가 스로틀링하지 않도록 하는 동시 라이브 레인 상한입니다. | +| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 동시 npm 설치 레인 상한입니다. | +| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 동시 다중 서비스 레인 상한입니다. | +| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | Docker 데몬 생성 폭주를 피하기 위한 레인 시작 간격입니다. 간격을 없애려면 `0`으로 설정하세요. | +| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 레인별 폴백 제한 시간(120분)입니다. 선택된 live/tail 레인은 더 엄격한 상한을 사용합니다. | | `OPENCLAW_DOCKER_ALL_DRY_RUN` | unset | `1`은 레인을 실행하지 않고 스케줄러 계획을 출력합니다. | -| `OPENCLAW_DOCKER_ALL_LANES` | unset | 쉼표로 구분된 정확한 레인 목록. 에이전트가 실패한 단일 레인을 재현할 수 있도록 정리 스모크를 건너뜁니다. | +| `OPENCLAW_DOCKER_ALL_LANES` | unset | 쉼표로 구분된 정확한 레인 목록입니다. 에이전트가 실패한 레인 하나를 재현할 수 있도록 정리 스모크를 건너뜁니다. | -실효 상한보다 무거운 레인도 비어 있는 풀에서 시작할 수 있으며, 이후 용량을 해제할 때까지 단독으로 실행됩니다. 로컬 집계는 Docker를 사전 점검하고, 오래된 OpenClaw E2E 컨테이너를 제거하고, 활성 레인 상태를 내보내고, 가장 긴 것부터 정렬하기 위해 레인 타이밍을 저장하며, 기본적으로 첫 번째 실패 이후 새 pooled 레인 스케줄링을 중지합니다. +유효 상한보다 무거운 레인도 빈 풀에서는 시작할 수 있으며, 이후 용량을 해제할 때까지 단독으로 실행됩니다. 로컬 집계는 Docker를 사전 점검하고, 오래된 OpenClaw E2E 컨테이너를 제거하며, 활성 레인 상태를 내보내고, longest-first 순서를 위해 레인 타이밍을 저장하며, 기본적으로 첫 실패 이후 새 풀 레인 예약을 중단합니다. ### 재사용 가능한 라이브/E2E 워크플로 -재사용 가능한 라이브/E2E 워크플로는 필요한 패키지, 이미지 종류, 라이브 이미지, 레인, 자격 증명 커버리지를 `scripts/test-docker-all.mjs --plan-json`에 묻습니다. 그런 다음 `scripts/docker-e2e.mjs`가 그 계획을 GitHub 출력과 요약으로 변환합니다. 이 워크플로는 `scripts/package-openclaw-for-docker.mjs`를 통해 OpenClaw를 패킹하거나, 현재 실행의 패키지 아티팩트를 다운로드하거나, `package_artifact_run_id`에서 패키지 아티팩트를 다운로드합니다. 또한 tarball 인벤토리를 검증하고, 계획에 패키지 설치 레인이 필요할 때 Blacksmith의 Docker 레이어 캐시를 통해 패키지 다이제스트 태그가 붙은 bare/functional GHCR Docker E2E 이미지를 빌드하고 푸시하며, 재빌드 대신 제공된 `docker_e2e_bare_image`/`docker_e2e_functional_image` 입력 또는 기존 패키지 다이제스트 이미지를 재사용합니다. Docker 이미지 pull은 제한된 시도당 180초 타임아웃으로 재시도되므로, 멈춘 레지스트리/캐시 스트림이 CI 핵심 경로의 대부분을 소비하는 대신 빠르게 재시도됩니다. +재사용 가능한 라이브/E2E 워크플로는 `scripts/test-docker-all.mjs --plan-json`에 필요한 패키지, 이미지 종류, 라이브 이미지, 레인, 자격 증명 범위를 질의합니다. 그런 다음 `scripts/docker-e2e.mjs`가 해당 계획을 GitHub 출력 및 요약으로 변환합니다. 이 워크플로는 `scripts/package-openclaw-for-docker.mjs`를 통해 OpenClaw를 패킹하거나, 현재 실행 패키지 아티팩트를 다운로드하거나, `package_artifact_run_id`에서 패키지 아티팩트를 다운로드합니다. tarball 인벤토리를 검증하고, 계획에 패키지 설치 레인이 필요한 경우 Blacksmith의 Docker 레이어 캐시를 통해 패키지 다이제스트 태그가 붙은 bare/functional GHCR Docker E2E 이미지를 빌드하고 푸시하며, 다시 빌드하는 대신 제공된 `docker_e2e_bare_image`/`docker_e2e_functional_image` 입력 또는 기존 패키지 다이제스트 이미지를 재사용합니다. Docker 이미지 풀은 시도당 180초로 제한된 제한 시간 안에서 재시도되므로, 멈춘 레지스트리/캐시 스트림이 CI 중요 경로 대부분을 소비하는 대신 빠르게 재시도됩니다. ### 릴리스 경로 청크 -릴리스 Docker 커버리지는 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 더 작은 청크 작업을 실행하므로 각 청크는 필요한 이미지 종류만 pull하고 같은 가중치 기반 스케줄러를 통해 여러 레인을 실행합니다. +릴리스 Docker 범위는 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 더 작은 청크 작업을 실행하여 각 청크가 필요한 이미지 종류만 가져오고 같은 가중치 스케줄러를 통해 여러 레인을 실행하게 합니다. - `OPENCLAW_DOCKER_ALL_PROFILE=release-path` - `OPENCLAW_DOCKER_ALL_CHUNK=core | package-update-openai | package-update-anthropic | package-update-core | plugins-runtime-plugins | plugins-runtime-services | plugins-runtime-install-a..h` -현재 릴리스 Docker 청크는 `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services`, 그리고 `plugins-runtime-install-a`부터 `plugins-runtime-install-h`까지입니다. `plugins-runtime-core`, `plugins-runtime`, `plugins-integrations`는 집계 Plugin/runtime 별칭으로 남아 있습니다. `install-e2e` 레인 별칭은 두 프로바이더 설치 프로그램 레인 모두에 대한 집계 수동 재실행 별칭으로 남아 있습니다. +현재 릴리스 Docker 청크는 `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services`, 그리고 `plugins-runtime-install-a`부터 `plugins-runtime-install-h`까지입니다. `plugins-runtime-core`, `plugins-runtime`, `plugins-integrations`는 집계 Plugin/runtime 별칭으로 남습니다. `install-e2e` 레인 별칭은 두 제공자 설치 프로그램 레인 모두에 대한 집계 수동 재실행 별칭으로 남습니다. -전체 release-path 커버리지가 요청할 때 OpenWebUI는 `plugins-runtime-services`에 포함되며, OpenWebUI 전용 디스패치에만 독립 실행형 `openwebui` 청크를 유지합니다. 번들 채널 update 레인은 일시적인 npm 네트워크 실패에 대해 한 번 재시도합니다. +전체 release-path 범위가 요청할 때 OpenWebUI는 `plugins-runtime-services`에 포함되며, OpenWebUI 전용 디스패치에만 독립 실행형 `openwebui` 청크를 유지합니다. 번들 채널 update 레인은 일시적인 npm 네트워크 실패에 대해 한 번 재시도합니다. -각 청크는 레인 로그, 타이밍, `summary.json`, `failures.json`, 단계별 타이밍, 스케줄러 계획 JSON, 느린 레인 테이블, 레인별 재실행 명령을 포함한 `.artifacts/docker-tests/`를 업로드합니다. 워크플로 `docker_lanes` 입력은 청크 작업 대신 준비된 이미지를 대상으로 선택된 레인을 실행합니다. 이를 통해 실패한 레인 디버깅을 하나의 대상 Docker 작업으로 제한하고, 해당 실행을 위한 패키지 아티팩트를 준비, 다운로드 또는 재사용합니다. 선택된 레인이 라이브 Docker 레인인 경우, 대상 작업은 해당 재실행을 위해 라이브 테스트 이미지를 로컬에서 빌드합니다. 생성된 레인별 GitHub 재실행 명령에는 해당 값이 존재할 때 `package_artifact_run_id`, `package_artifact_name`, 준비된 이미지 입력이 포함되므로, 실패한 레인이 실패한 실행의 정확한 패키지와 이미지를 재사용할 수 있습니다. +각 청크는 레인 로그, 타이밍, `summary.json`, `failures.json`, 단계 타이밍, 스케줄러 계획 JSON, 느린 레인 표, 레인별 재실행 명령이 포함된 `.artifacts/docker-tests/`를 업로드합니다. 워크플로 `docker_lanes` 입력은 청크 작업 대신 준비된 이미지에 대해 선택된 레인을 실행합니다. 이렇게 하면 실패 레인 디버깅이 하나의 대상 Docker 작업으로 제한되고, 해당 실행을 위해 패키지 아티팩트를 준비, 다운로드 또는 재사용합니다. 선택한 레인이 라이브 Docker 레인이면 대상 작업은 해당 재실행을 위해 live-test 이미지를 로컬에서 빌드합니다. 생성된 레인별 GitHub 재실행 명령에는 값이 존재할 때 `package_artifact_run_id`, `package_artifact_name`, 준비된 이미지 입력이 포함되므로, 실패한 레인이 실패한 실행의 정확한 패키지와 이미지를 재사용할 수 있습니다. ```bash pnpm test:docker:rerun # download Docker artifacts and print combined/per-lane targeted rerun commands @@ -379,48 +368,48 @@ pnpm test:docker:timings # slow-lane and phase critical-path summari 예약된 라이브/E2E 워크플로는 전체 release-path Docker 제품군을 매일 실행합니다. -## Plugin 프리릴리스 +## Plugin 사전 릴리스 -`Plugin Prerelease`는 더 비용이 큰 제품/패키지 커버리지이므로 `Full Release Validation`이나 명시적 운영자가 디스패치하는 별도 워크플로입니다. 일반 풀 리퀘스트, `main` 푸시, 독립 실행형 수동 CI 디스패치는 이 제품군을 꺼 둡니다. 이 워크플로는 번들 Plugin 테스트를 여덟 개 확장 워커에 균등 배분합니다. 해당 확장 샤드 작업은 한 번에 최대 두 개의 Plugin 구성 그룹을 실행하며, 그룹당 하나의 Vitest 워커와 더 큰 Node 힙을 사용하므로 import가 많은 Plugin 배치가 추가 CI 작업을 만들지 않습니다. 릴리스 전용 Docker 프리릴리스 경로는 하나에서 세 분짜리 작업을 위해 수십 개의 러너를 예약하지 않도록 대상 Docker 레인을 작은 그룹으로 배치합니다. +`Plugin Prerelease`는 더 비용이 큰 제품/패키지 범위이므로 `Full Release Validation` 또는 명시적 운영자가 디스패치하는 별도 워크플로입니다. 일반 풀 리퀘스트, `main` 푸시, 독립 실행형 수동 CI 디스패치는 이 제품군을 꺼 둡니다. 이 워크플로는 번들 Plugin 테스트를 8개의 확장 워커에 균등하게 분산합니다. 해당 확장 샤드 작업은 한 번에 최대 두 개의 Plugin 구성 그룹을 실행하며, 그룹당 Vitest 워커 하나와 더 큰 Node 힙을 사용해 import가 많은 Plugin 배치가 추가 CI 작업을 만들지 않게 합니다. 릴리스 전용 Docker 사전 릴리스 경로는 수십 개의 러너를 1~3분짜리 작업에 예약하지 않도록 대상 Docker 레인을 작은 그룹으로 배치 처리합니다. ## QA Lab -QA Lab에는 기본 스마트 범위 워크플로 외부에 전용 CI 레인이 있습니다. 에이전트 parity는 독립 실행형 PR 워크플로가 아니라 광범위한 QA 및 릴리스 하니스 아래에 중첩됩니다. parity를 광범위한 검증 실행과 함께 태워야 할 때는 `rerun_group=qa-parity`와 함께 `Full Release Validation`을 사용하세요. +QA Lab에는 기본 스마트 범위 워크플로 밖에 전용 CI 레인이 있습니다. 에이전트 패리티는 넓은 QA 및 릴리스 하네스 아래에 중첩되며, 독립 실행형 PR 워크플로가 아닙니다. 패리티가 넓은 검증 실행과 함께 가야 할 때는 `rerun_group=qa-parity`와 함께 `Full Release Validation`을 사용하세요. -- `QA-Lab - All Lanes` 워크플로는 매일 밤 `main`에서 그리고 수동 디스패치 시 실행됩니다. mock parity 레인, 라이브 Matrix 레인, 라이브 Telegram 및 Discord 레인을 병렬 작업으로 팬아웃합니다. 라이브 작업은 `qa-live-shared` 환경을 사용하며, Telegram/Discord는 Convex lease를 사용합니다. +- `QA-Lab - All Lanes` 워크플로는 `main`에서 야간에, 그리고 수동 디스패치에서 실행됩니다. mock 패리티 레인, live Matrix 레인, live Telegram 및 Discord 레인을 병렬 작업으로 확장합니다. live 작업은 `qa-live-shared` 환경을 사용하고, Telegram/Discord는 Convex 임대를 사용합니다. -릴리스 검사는 결정론적 mock 프로바이더와 mock-qualified 모델(`mock-openai/gpt-5.5` 및 `mock-openai/gpt-5.5-alt`)로 Matrix 및 Telegram 라이브 전송 레인을 실행하므로, 채널 계약이 라이브 모델 지연 시간과 일반 프로바이더 Plugin 시작에서 격리됩니다. 라이브 전송 Gateway는 메모리 검색을 비활성화합니다. QA parity가 메모리 동작을 별도로 다루기 때문입니다. 프로바이더 연결성은 별도의 라이브 모델, 네이티브 프로바이더, Docker 프로바이더 제품군에서 다룹니다. +릴리스 검사는 결정적 mock 제공자와 mock 한정 모델(`mock-openai/gpt-5.5` 및 `mock-openai/gpt-5.5-alt`)로 Matrix 및 Telegram live 전송 레인을 실행하여, 채널 계약을 live 모델 지연 시간과 일반 제공자 Plugin 시작에서 분리합니다. live 전송 Gateway는 QA 패리티가 메모리 동작을 별도로 다루기 때문에 메모리 검색을 비활성화합니다. 제공자 연결성은 별도의 live 모델, 네이티브 제공자, Docker 제공자 제품군에서 다룹니다. -Matrix는 예약 및 릴리스 게이트에 `--profile fast`를 사용하며, 체크아웃된 CLI가 지원할 때만 `--fail-fast`를 추가합니다. CLI 기본값과 수동 워크플로 입력은 `all`로 유지됩니다. 수동 `matrix_profile=all` 디스패치는 항상 전체 Matrix 커버리지를 `transport`, `media`, `e2ee-smoke`, `e2ee-deep`, `e2ee-cli` 작업으로 샤딩합니다. +Matrix는 예약 및 릴리스 게이트에 `--profile fast`를 사용하며, 체크아웃된 CLI가 지원할 때만 `--fail-fast`를 추가합니다. CLI 기본값과 수동 워크플로 입력은 `all`로 유지됩니다. 수동 `matrix_profile=all` 디스패치는 항상 전체 Matrix 범위를 `transport`, `media`, `e2ee-smoke`, `e2ee-deep`, `e2ee-cli` 작업으로 샤딩합니다. -`OpenClaw Release Checks`도 릴리스 승인 전에 릴리스에 중요한 QA Lab 레인을 실행합니다. QA parity 게이트는 candidate 및 baseline 팩을 병렬 레인 작업으로 실행한 다음, 최종 parity 비교를 위해 두 아티팩트를 작은 보고서 작업으로 다운로드합니다. +`OpenClaw Release Checks`도 릴리스 승인 전에 릴리스에 중요한 QA Lab 레인을 실행합니다. QA 패리티 게이트는 후보 팩과 기준선 팩을 병렬 레인 작업으로 실행한 다음, 최종 패리티 비교를 위해 두 아티팩트를 작은 보고서 작업으로 다운로드합니다. -일반 PR에서는 parity를 필수 상태로 취급하는 대신 범위 지정된 CI/check 증거를 따르세요. +일반 PR의 경우 패리티를 필수 상태로 취급하는 대신 범위가 지정된 CI/check 증거를 따르세요. ## CodeQL -`CodeQL` 워크플로는 전체 저장소 스윕이 아니라 의도적으로 좁은 1차 보안 스캐너입니다. 일일, 수동, 비초안 pull request 가드 실행은 Actions 워크플로 코드와 가장 위험도가 높은 JavaScript/TypeScript 표면을 스캔하며, high/critical `security-severity`로 필터링된 높은 신뢰도의 보안 쿼리를 사용합니다. +`CodeQL` 워크플로는 전체 리포지토리 스윕이 아니라 의도적으로 좁은 1차 보안 스캐너입니다. 일일, 수동, 그리고 초안이 아닌 풀 리퀘스트 가드 실행은 Actions 워크플로 코드와 함께 가장 위험도가 높은 JavaScript/TypeScript 표면을 스캔하며, high/critical `security-severity`로 필터링된 높은 신뢰도의 보안 쿼리를 사용합니다. -pull request 가드는 가볍게 유지됩니다. `.github/actions`, `.github/codeql`, `.github/workflows`, `packages`, 또는 `src` 아래 변경에 대해서만 시작되며, 예약 워크플로와 동일한 높은 신뢰도의 보안 매트릭스를 실행합니다. Android 및 macOS CodeQL은 PR 기본값에서 제외됩니다. +풀 리퀘스트 가드는 가볍게 유지됩니다. `.github/actions`, `.github/codeql`, `.github/workflows`, `packages`, 또는 `src` 아래 변경에 대해서만 시작되며, 예약 워크플로와 동일한 높은 신뢰도의 보안 매트릭스를 실행합니다. Android 및 macOS CodeQL은 PR 기본값에서 제외됩니다. -### 보안 범주 +### 보안 카테고리 -| 범주 | 표면 | +| 카테고리 | 표면 | | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `/codeql-security-high/core-auth-secrets` | 인증, 비밀, 샌드박스, Cron, Gateway 기준선 | -| `/codeql-security-high/channel-runtime-boundary` | 핵심 채널 구현 계약과 채널 Plugin 런타임, Gateway, Plugin SDK, 비밀, 감사 접점 | -| `/codeql-security-high/network-ssrf-boundary` | 핵심 SSRF, IP 파싱, 네트워크 가드, 웹 가져오기, Plugin SDK SSRF 정책 표면 | -| `/codeql-security-high/mcp-process-tool-boundary` | MCP 서버, 프로세스 실행 헬퍼, 아웃바운드 전달, 에이전트 도구 실행 게이트 | -| `/codeql-security-high/plugin-trust-boundary` | Plugin 설치, 로더, 매니페스트, 레지스트리, 패키지 관리자 설치, 소스 로딩, Plugin SDK 패키지 계약 신뢰 표면 | +| `/codeql-security-high/core-auth-secrets` | 인증, 시크릿, 샌드박스, cron, 그리고 gateway 기준선 | +| `/codeql-security-high/channel-runtime-boundary` | 핵심 채널 구현 계약과 채널 plugin 런타임, gateway, Plugin SDK, 시크릿, 감사 접점 | +| `/codeql-security-high/network-ssrf-boundary` | 핵심 SSRF, IP 파싱, 네트워크 가드, 웹 가져오기, 그리고 Plugin SDK SSRF 정책 표면 | +| `/codeql-security-high/mcp-process-tool-boundary` | MCP 서버, 프로세스 실행 헬퍼, 아웃바운드 전달, 그리고 에이전트 도구 실행 게이트 | +| `/codeql-security-high/plugin-trust-boundary` | Plugin 설치, 로더, 매니페스트, 레지스트리, 패키지 관리자 설치, 소스 로딩, 그리고 Plugin SDK 패키지 계약 신뢰 표면 | ### 플랫폼별 보안 샤드 -- `CodeQL Android Critical Security` — 예약된 Android 보안 샤드입니다. 워크플로 정상성 검사에서 허용하는 가장 작은 Blacksmith Linux 러너에서 CodeQL을 위해 Android 앱을 수동으로 빌드합니다. `/codeql-critical-security/android` 아래에 업로드합니다. -- `CodeQL macOS Critical Security` — 주간/수동 macOS 보안 샤드입니다. Blacksmith macOS에서 CodeQL을 위해 macOS 앱을 수동으로 빌드하고, 업로드된 SARIF에서 의존성 빌드 결과를 필터링하며, `/codeql-critical-security/macos` 아래에 업로드합니다. macOS 빌드가 깨끗할 때도 런타임을 지배하므로 일일 기본값 밖에 유지됩니다. +- `CodeQL Android Critical Security` — 예약된 Android 보안 샤드입니다. 워크플로 정상성 검사에서 허용하는 가장 작은 Blacksmith Linux 러너에서 CodeQL용 Android 앱을 수동으로 빌드합니다. `/codeql-critical-security/android` 아래에 업로드합니다. +- `CodeQL macOS Critical Security` — 주간/수동 macOS 보안 샤드입니다. Blacksmith macOS에서 CodeQL용 macOS 앱을 수동으로 빌드하고, 업로드된 SARIF에서 의존성 빌드 결과를 필터링한 뒤 `/codeql-critical-security/macos` 아래에 업로드합니다. macOS 빌드가 깨끗한 경우에도 런타임 대부분을 차지하므로 일일 기본값에서는 제외됩니다. -### 중요 품질 범주 +### 중요 품질 카테고리 -`CodeQL Critical Quality`는 이에 대응하는 비보안 샤드입니다. 더 작은 Blacksmith Linux 러너에서 좁고 가치가 높은 표면에 대해 error 심각도, 비보안 JavaScript/TypeScript 품질 쿼리만 실행합니다. 이 pull request 가드는 예약 프로필보다 의도적으로 더 작습니다. 비초안 PR은 에이전트 명령/모델/도구 실행 및 답장 디스패치 코드, 설정 스키마/마이그레이션/IO 코드, 인증/비밀/샌드박스/보안 코드, 핵심 채널 및 번들 채널 Plugin 런타임, Gateway 프로토콜/서버 메서드, 메모리 런타임/SDK 글루, MCP/프로세스/아웃바운드 전달, 프로바이더 런타임/모델 카탈로그, 세션 진단/전달 큐, Plugin 로더, Plugin SDK/패키지 계약, 또는 Plugin SDK 답장 런타임 변경에 대해 일치하는 `agent-runtime-boundary`, `config-boundary`, `core-auth-secrets`, `channel-runtime-boundary`, `gateway-runtime-boundary`, `memory-runtime-boundary`, `mcp-process-runtime-boundary`, `provider-runtime-boundary`, `session-diagnostics-boundary`, `plugin-boundary`, `plugin-sdk-package-contract`, `plugin-sdk-reply-runtime` 샤드만 실행합니다. CodeQL 설정 및 품질 워크플로 변경은 12개의 PR 품질 샤드를 모두 실행합니다. +`CodeQL Critical Quality`는 이에 대응하는 비보안 샤드입니다. 더 작은 Blacksmith Linux 러너에서 좁고 가치가 높은 표면에 대해 오류 심각도만 있는 비보안 JavaScript/TypeScript 품질 쿼리만 실행합니다. 이 풀 리퀘스트 가드는 예약 프로필보다 의도적으로 더 작습니다. 초안이 아닌 PR은 에이전트 명령/모델/도구 실행 및 답장 디스패치 코드, 구성 스키마/마이그레이션/IO 코드, 인증/시크릿/샌드박스/보안 코드, 핵심 채널 및 번들 채널 plugin 런타임, gateway 프로토콜/서버 메서드, 메모리 런타임/SDK 접착 코드, MCP/프로세스/아웃바운드 전달, provider 런타임/모델 카탈로그, 세션 진단/전달 큐, plugin 로더, Plugin SDK/패키지 계약, 또는 Plugin SDK 답장 런타임 변경에 대해 일치하는 `agent-runtime-boundary`, `config-boundary`, `core-auth-secrets`, `channel-runtime-boundary`, `gateway-runtime-boundary`, `memory-runtime-boundary`, `mcp-process-runtime-boundary`, `provider-runtime-boundary`, `session-diagnostics-boundary`, `plugin-boundary`, `plugin-sdk-package-contract`, 그리고 `plugin-sdk-reply-runtime` 샤드만 실행합니다. CodeQL 구성 및 품질 워크플로 변경은 12개 PR 품질 샤드를 모두 실행합니다. 수동 디스패치는 다음을 허용합니다. @@ -428,40 +417,40 @@ pull request 가드는 가볍게 유지됩니다. `.github/actions`, `.github/co profile=all|agent-runtime-boundary|config-boundary|core-auth-secrets|channel-runtime-boundary|gateway-runtime-boundary|memory-runtime-boundary|mcp-process-runtime-boundary|plugin-boundary|plugin-sdk-package-contract|plugin-sdk-reply-runtime|provider-runtime-boundary|session-diagnostics-boundary ``` -좁은 프로필은 하나의 품질 샤드를 격리해서 실행하기 위한 학습/반복 훅입니다. +좁은 프로필은 하나의 품질 샤드를 격리해서 실행하기 위한 교육/반복 훅입니다. -| 범주 | 표면 | +| 카테고리 | 표면 | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `/codeql-critical-quality/core-auth-secrets` | 인증, 비밀, 샌드박스, Cron, Gateway 보안 경계 코드 | -| `/codeql-critical-quality/config-boundary` | 설정 스키마, 마이그레이션, 정규화, IO 계약 | -| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 프로토콜 스키마 및 서버 메서드 계약 | -| `/codeql-critical-quality/channel-runtime-boundary` | 핵심 채널 및 번들 채널 Plugin 구현 계약 | -| `/codeql-critical-quality/agent-runtime-boundary` | 명령 실행, 모델/프로바이더 디스패치, 자동 답장 디스패치 및 큐, ACP 제어 플레인 런타임 계약 | -| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 서버 및 도구 브리지, 프로세스 감독 헬퍼, 아웃바운드 전달 계약 | -| `/codeql-critical-quality/memory-runtime-boundary` | 메모리 호스트 SDK, 메모리 런타임 파사드, 메모리 Plugin SDK 별칭, 메모리 런타임 활성화 글루, 메모리 doctor 명령 | -| `/codeql-critical-quality/session-diagnostics-boundary` | 답장 큐 내부, 세션 전달 큐, 아웃바운드 세션 바인딩/전달 헬퍼, 진단 이벤트/로그 번들 표면, 세션 doctor CLI 계약 | -| `/codeql-critical-quality/plugin-sdk-reply-runtime` | Plugin SDK 인바운드 답장 디스패치, 답장 페이로드/청킹/런타임 헬퍼, 채널 답장 옵션, 전달 큐, 세션/스레드 바인딩 헬퍼 | -| `/codeql-critical-quality/provider-runtime-boundary` | 모델 카탈로그 정규화, 프로바이더 인증 및 발견, 프로바이더 런타임 등록, 프로바이더 기본값/카탈로그, 웹/검색/가져오기/임베딩 레지스트리 | -| `/codeql-critical-quality/ui-control-plane` | 제어 UI 부트스트랩, 로컬 지속성, Gateway 제어 흐름, 작업 제어 플레인 런타임 계약 | -| `/codeql-critical-quality/web-media-runtime-boundary` | 핵심 웹 가져오기/검색, 미디어 IO, 미디어 이해, 이미지 생성, 미디어 생성 런타임 계약 | -| `/codeql-critical-quality/plugin-boundary` | 로더, 레지스트리, 공개 표면, Plugin SDK 진입점 계약 | -| `/codeql-critical-quality/plugin-sdk-package-contract` | 게시된 패키지 측 Plugin SDK 소스 및 Plugin 패키지 계약 헬퍼 | +| `/codeql-critical-quality/core-auth-secrets` | 인증, 시크릿, 샌드박스, cron, 그리고 gateway 보안 경계 코드 | +| `/codeql-critical-quality/config-boundary` | 구성 스키마, 마이그레이션, 정규화, 그리고 IO 계약 | +| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 프로토콜 스키마 및 서버 메서드 계약 | +| `/codeql-critical-quality/channel-runtime-boundary` | 핵심 채널 및 번들 채널 plugin 구현 계약 | +| `/codeql-critical-quality/agent-runtime-boundary` | 명령 실행, 모델/provider 디스패치, 자동 답장 디스패치 및 큐, 그리고 ACP 제어 플레인 런타임 계약 | +| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 서버 및 도구 브리지, 프로세스 감독 헬퍼, 그리고 아웃바운드 전달 계약 | +| `/codeql-critical-quality/memory-runtime-boundary` | 메모리 호스트 SDK, 메모리 런타임 파사드, 메모리 Plugin SDK 별칭, 메모리 런타임 활성화 접착 코드, 그리고 메모리 doctor 명령 | +| `/codeql-critical-quality/session-diagnostics-boundary` | 답장 큐 내부 구조, 세션 전달 큐, 아웃바운드 세션 바인딩/전달 헬퍼, 진단 이벤트/로그 번들 표면, 그리고 세션 doctor CLI 계약 | +| `/codeql-critical-quality/plugin-sdk-reply-runtime` | Plugin SDK 인바운드 답장 디스패치, 답장 페이로드/청킹/런타임 헬퍼, 채널 답장 옵션, 전달 큐, 그리고 세션/스레드 바인딩 헬퍼 | +| `/codeql-critical-quality/provider-runtime-boundary` | 모델 카탈로그 정규화, provider 인증 및 검색, provider 런타임 등록, provider 기본값/카탈로그, 그리고 웹/검색/가져오기/임베딩 레지스트리 | +| `/codeql-critical-quality/ui-control-plane` | 제어 UI 부트스트랩, 로컬 영속성, gateway 제어 흐름, 그리고 작업 제어 플레인 런타임 계약 | +| `/codeql-critical-quality/web-media-runtime-boundary` | 핵심 웹 가져오기/검색, 미디어 IO, 미디어 이해, 이미지 생성, 그리고 미디어 생성 런타임 계약 | +| `/codeql-critical-quality/plugin-boundary` | 로더, 레지스트리, 공개 표면, 그리고 Plugin SDK 진입점 계약 | +| `/codeql-critical-quality/plugin-sdk-package-contract` | 게시된 패키지 측 Plugin SDK 소스 및 plugin 패키지 계약 헬퍼 | -품질은 보안과 분리되어 유지되므로 품질 발견 사항을 보안 신호를 흐리지 않고 예약, 측정, 비활성화 또는 확장할 수 있습니다. Swift, Python, 번들 Plugin CodeQL 확장은 좁은 프로필의 런타임과 신호가 안정된 뒤에만 범위가 지정되거나 샤딩된 후속 작업으로 다시 추가해야 합니다. +품질은 보안과 분리되어 유지되므로, 품질 발견 사항을 보안 신호를 흐리지 않고 예약, 측정, 비활성화, 또는 확장할 수 있습니다. Swift, Python, 그리고 번들 plugin CodeQL 확장은 좁은 프로필의 런타임과 신호가 안정된 뒤에만 범위가 지정되거나 샤딩된 후속 작업으로 다시 추가해야 합니다. -## 유지관리 워크플로 +## 유지보수 워크플로 -### 문서 에이전트 +### Docs Agent -`Docs Agent` 워크플로는 최근 랜딩된 변경과 기존 문서를 정렬하기 위한 이벤트 기반 Codex 유지관리 레인입니다. 순수한 일정은 없습니다. `main`에서 성공한 비봇 push CI 실행이 이를 트리거할 수 있고, 수동 디스패치로 직접 실행할 수 있습니다. Workflow-run 호출은 `main`이 이동했거나 지난 한 시간 안에 다른 건너뛰지 않은 Docs Agent 실행이 생성된 경우 건너뜁니다. 실행될 때는 이전 건너뛰지 않은 Docs Agent 소스 SHA부터 현재 `main`까지의 커밋 범위를 검토하므로, 한 시간마다 한 번 실행해도 마지막 문서 패스 이후 누적된 모든 main 변경을 다룰 수 있습니다. +`Docs Agent` 워크플로는 최근 랜딩된 변경과 기존 문서를 일치시키기 위한 이벤트 기반 Codex 유지보수 레인입니다. 순수 일정은 없습니다. `main`에서 성공한 비봇 push CI 실행이 이를 트리거할 수 있으며, 수동 디스패치로 직접 실행할 수 있습니다. 워크플로 실행 호출은 `main`이 이동했거나 지난 1시간 안에 건너뛰지 않은 다른 Docs Agent 실행이 생성된 경우 건너뜁니다. 실행될 때는 이전에 건너뛰지 않은 Docs Agent 소스 SHA부터 현재 `main`까지의 커밋 범위를 검토하므로, 한 번의 시간당 실행으로 마지막 문서 패스 이후 누적된 모든 main 변경을 처리할 수 있습니다. -### 테스트 성능 에이전트 +### Test Performance Agent -`Test Performance Agent` 워크플로는 느린 테스트를 위한 이벤트 기반 Codex 유지관리 레인입니다. 순수한 일정은 없습니다. `main`에서 성공한 비봇 push CI 실행이 이를 트리거할 수 있지만, 같은 UTC 날짜에 다른 workflow-run 호출이 이미 실행되었거나 실행 중이면 건너뜁니다. 수동 디스패치는 해당 일일 활동 게이트를 우회합니다. 이 레인은 전체 스위트 그룹화 Vitest 성능 보고서를 빌드하고, Codex가 광범위한 리팩터링 대신 커버리지를 보존하는 작은 테스트 성능 수정만 만들게 한 뒤, 전체 스위트 보고서를 다시 실행하고 통과 기준 테스트 수를 줄이는 변경을 거부합니다. 기준선에 실패 테스트가 있으면 Codex는 명백한 실패만 고칠 수 있고, 에이전트 이후 전체 스위트 보고서는 커밋되기 전에 반드시 통과해야 합니다. 봇 push가 랜딩되기 전에 `main`이 진행되면, 이 레인은 검증된 패치를 리베이스하고 `pnpm check:changed`를 다시 실행한 뒤 push를 재시도합니다. 충돌하는 오래된 패치는 건너뜁니다. Codex 액션이 문서 에이전트와 동일한 drop-sudo 안전 태세를 유지할 수 있도록 GitHub 호스팅 Ubuntu를 사용합니다. +`Test Performance Agent` 워크플로는 느린 테스트를 위한 이벤트 기반 Codex 유지보수 레인입니다. 순수 일정은 없습니다. `main`에서 성공한 비봇 push CI 실행이 이를 트리거할 수 있지만, 해당 UTC 날짜에 다른 워크플로 실행 호출이 이미 실행되었거나 실행 중이면 건너뜁니다. 수동 디스패치는 그 일일 활동 게이트를 우회합니다. 이 레인은 전체 스위트 그룹화 Vitest 성능 보고서를 빌드하고, Codex가 광범위한 리팩터링 대신 커버리지를 보존하는 작은 테스트 성능 수정만 수행하도록 한 다음, 전체 스위트 보고서를 다시 실행하고 통과 기준 테스트 수를 줄이는 변경을 거부합니다. 기준선에 실패하는 테스트가 있으면 Codex는 명백한 실패만 고칠 수 있으며, 에이전트 이후 전체 스위트 보고서가 통과해야만 커밋됩니다. 봇 push가 랜딩되기 전에 `main`이 전진하면 레인은 검증된 패치를 리베이스하고, `pnpm check:changed`를 다시 실행한 뒤 push를 재시도합니다. 충돌하는 오래된 패치는 건너뜁니다. Codex 액션이 docs agent와 동일한 drop-sudo 안전 태세를 유지할 수 있도록 GitHub 호스팅 Ubuntu를 사용합니다. ### 병합 후 중복 PR -`Duplicate PRs After Merge` 워크플로는 랜딩 후 중복 정리를 위한 수동 유지관리자 워크플로입니다. 기본값은 dry-run이며 `apply=true`일 때 명시적으로 나열된 PR만 닫습니다. GitHub를 변경하기 전에, 랜딩된 PR이 병합되었고 각 중복 항목에 공유 참조 이슈 또는 겹치는 변경 헝크가 있는지 확인합니다. +`Duplicate PRs After Merge` 워크플로는 랜딩 후 중복 정리를 위한 수동 maintainer 워크플로입니다. 기본값은 dry-run이며, `apply=true`일 때 명시적으로 나열된 PR만 닫습니다. GitHub를 변경하기 전에 랜딩된 PR이 병합되었고 각 중복 항목에 공유된 참조 이슈 또는 겹치는 변경 헝크가 있는지 확인합니다. ```bash gh workflow run duplicate-after-merge.yml \ @@ -472,36 +461,113 @@ gh workflow run duplicate-after-merge.yml \ ## 로컬 검사 게이트 및 변경 라우팅 -로컬 changed-lane 로직은 `scripts/changed-lanes.mjs`에 있으며 `scripts/check-changed.mjs`가 실행합니다. 이 로컬 검사 게이트는 넓은 CI 플랫폼 범위보다 아키텍처 경계에 대해 더 엄격합니다. +로컬 변경 레인 로직은 `scripts/changed-lanes.mjs`에 있으며 `scripts/check-changed.mjs`가 실행합니다. 이 로컬 검사 게이트는 넓은 CI 플랫폼 범위보다 아키텍처 경계에 더 엄격합니다. -- 핵심 프로덕션 변경은 핵심 prod 및 핵심 test 타입체크와 핵심 lint/가드를 실행합니다. -- 핵심 테스트 전용 변경은 핵심 test 타입체크와 핵심 lint만 실행합니다. -- extension 프로덕션 변경은 extension prod 및 extension test 타입체크와 extension lint를 실행합니다. -- extension 테스트 전용 변경은 extension test 타입체크와 extension lint를 실행합니다. -- 공개 Plugin SDK 또는 Plugin 계약 변경은 extension이 해당 핵심 계약에 의존하므로 extension 타입체크로 확장됩니다(Vitest extension 스윕은 명시적인 테스트 작업으로 유지됩니다). -- release 메타데이터 전용 버전 범프는 대상 버전/설정/루트 의존성 검사를 실행합니다. -- 알 수 없는 루트/설정 변경은 안전하게 모든 검사 레인으로 실패합니다. +- 핵심 프로덕션 변경은 core prod 및 core test 타입체크와 core lint/guards를 실행합니다. +- 핵심 테스트 전용 변경은 core test 타입체크와 core lint만 실행합니다. +- 확장 프로덕션 변경은 extension prod 및 extension test 타입체크와 extension lint를 실행합니다. +- 확장 테스트 전용 변경은 extension test 타입체크와 extension lint를 실행합니다. +- 공개 Plugin SDK 또는 plugin 계약 변경은 확장이 해당 핵심 계약에 의존하므로 extension 타입체크로 확장됩니다. Vitest 확장 스윕은 명시적 테스트 작업으로 유지됩니다. +- 릴리스 메타데이터 전용 버전 범프는 대상 버전/구성/루트 의존성 검사를 실행합니다. +- 알 수 없는 루트/구성 변경은 모든 검사 레인으로 안전하게 실패합니다. -로컬 changed-test 라우팅은 `scripts/test-projects.test-support.mjs`에 있으며 의도적으로 `check:changed`보다 저렴합니다. 직접 테스트 편집은 자기 자신을 실행하고, 소스 편집은 명시적 매핑을 우선한 뒤 형제 테스트와 import 그래프 의존 항목을 사용합니다. 공유 group-room 전달 설정은 명시적 매핑 중 하나입니다. 그룹 visible-reply 설정, 소스 답장 전달 모드, 또는 message-tool 시스템 프롬프트 변경은 핵심 답장 테스트와 Discord 및 Slack 전달 회귀를 통해 라우팅되어, 공유 기본값 변경이 첫 PR push 전에 실패하게 합니다. 변경이 하네스 전반에 걸쳐 있어 저렴한 매핑 세트를 신뢰할 수 있는 대리로 보기 어려울 때만 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 사용하세요. +로컬 변경 테스트 라우팅은 `scripts/test-projects.test-support.mjs`에 있으며, 의도적으로 `check:changed`보다 저렴합니다. 직접 테스트 편집은 해당 테스트 자체를 실행하고, 소스 편집은 명시적 매핑을 우선한 뒤 형제 테스트와 import 그래프 의존 항목을 사용합니다. 공유 그룹 룸 전달 구성은 명시적 매핑 중 하나입니다. 그룹 가시 답장 구성, 소스 답장 전달 모드, 또는 message-tool 시스템 프롬프트 변경은 core reply 테스트와 Discord 및 Slack 전달 회귀를 거치므로, 공유 기본값 변경은 첫 PR push 전에 실패합니다. 변경이 하네스 전반에 걸쳐 있어 저렴하게 매핑된 집합을 신뢰할 수 있는 대리 지표로 볼 수 없을 때만 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 사용하세요. ## Testbox 검증 -리포지토리 루트에서 Testbox를 실행하고, 광범위한 증명을 위해서는 새로 예열한 박스를 선호하세요. 재사용되었거나 만료되었거나 방금 예상보다 큰 동기화를 보고한 박스에서 느린 게이트를 실행하기 전에, 먼저 박스 안에서 `pnpm testbox:sanity`를 실행하세요. +리포지토리 루트에서 Testbox를 실행하고, 광범위한 검증에는 새로 예열된 박스를 우선 사용하세요. 재사용되었거나 만료되었거나 방금 예상보다 큰 동기화를 보고한 박스에서 느린 게이트를 실행하기 전에, 먼저 박스 내부에서 `pnpm testbox:sanity`를 실행하세요. -정상성 검사는 `pnpm-lock.yaml` 같은 필수 루트 파일이 사라졌거나 `git status --short`가 추적 중인 삭제를 200개 이상 표시할 때 빠르게 실패합니다. 이는 보통 원격 동기화 상태가 PR의 신뢰할 수 있는 복사본이 아니라는 뜻입니다. 제품 테스트 실패를 디버깅하는 대신 해당 박스를 중지하고 새 박스를 예열하세요. 의도적인 대량 삭제 PR의 경우 해당 정상성 실행에 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`을 설정하세요. +정상성 검사는 `pnpm-lock.yaml` 같은 필수 루트 파일이 사라졌거나 `git status --short`가 추적 중인 삭제를 200개 이상 표시하면 빠르게 실패합니다. 이는 대개 원격 동기화 상태가 PR의 신뢰할 수 있는 복사본이 아니라는 뜻입니다. 제품 테스트 실패를 디버깅하는 대신 해당 박스를 중지하고 새 박스를 예열하세요. 의도적으로 대량 삭제가 포함된 PR의 경우 해당 정상성 실행에 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`을 설정하세요. -`pnpm testbox:run`은 사후 동기화 출력 없이 동기화 단계에 5분 넘게 머무르는 로컬 Blacksmith CLI 호출도 종료합니다. 해당 보호 장치를 비활성화하려면 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0`을 설정하거나, 비정상적으로 큰 로컬 diff에는 더 큰 밀리초 값을 사용하세요. +`pnpm testbox:run`은 동기화 이후 출력 없이 동기화 단계에 5분 넘게 머무르는 로컬 Blacksmith CLI 호출도 종료합니다. 이 보호 장치를 비활성화하려면 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0`을 설정하거나, 비정상적으로 큰 로컬 diff에는 더 큰 밀리초 값을 사용하세요. -Crabbox는 Blacksmith를 사용할 수 없거나 소유한 클라우드 용량이 더 적합할 때 Linux 증명을 위한 리포지토리 소유의 두 번째 원격 박스 경로입니다. 박스를 예열하고, 프로젝트 워크플로를 통해 하이드레이트한 다음, Crabbox CLI를 통해 명령을 실행하세요. +Crabbox는 유지관리자 Linux 검증을 위한 리포지토리 소유 원격 박스 래퍼입니다. 검사가 로컬 편집 루프에 비해 너무 광범위하거나, CI 동등성이 중요하거나, 검증에 시크릿, Docker, 패키지 레인, 재사용 가능한 박스 또는 원격 로그가 필요할 때 사용하세요. 일반 OpenClaw 백엔드는 `blacksmith-testbox`입니다. 소유 AWS/Hetzner 용량은 Blacksmith 장애, 할당량 문제 또는 명시적인 소유 용량 테스트를 위한 대체 수단입니다. + +처음 실행하기 전에 리포지토리 루트에서 래퍼를 확인하세요. ```bash -pnpm crabbox:warmup -- --idle-timeout 90m -pnpm crabbox:hydrate -- --id -pnpm crabbox:run -- --id --shell "OPENCLAW_TESTBOX=1 pnpm check:changed" -pnpm crabbox:stop -- +pnpm crabbox:run -- --help | sed -n '1,120p' ``` -`.crabbox.yaml`은 공급자, 동기화, GitHub Actions 하이드레이션 기본값을 소유합니다. 하이드레이션된 Actions 체크아웃이 유지 관리자 로컬 원격과 오브젝트 저장소를 동기화하는 대신 자체 원격 Git 메타데이터를 유지하도록 로컬 `.git`을 제외하며, 절대 전송되어서는 안 되는 로컬 런타임/빌드 산출물도 제외합니다. `.github/workflows/crabbox-hydrate.yml`은 체크아웃, Node/pnpm 설정, `origin/main` 가져오기, 그리고 이후 `crabbox run --id ` 명령이 소스로 사용하는 비밀이 아닌 환경 인계를 소유합니다. +리포지토리 래퍼는 `blacksmith-testbox`를 알리지 않는 오래된 Crabbox 바이너리를 거부합니다. `.crabbox.yaml`에 소유 클라우드 기본값이 있더라도 공급자를 명시적으로 전달하세요. + +변경 게이트: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox \ + --blacksmith-org openclaw \ + --blacksmith-workflow .github/workflows/ci-check-testbox.yml \ + --blacksmith-job check \ + --blacksmith-ref main \ + --idle-timeout 90m \ + --ttl 240m \ + --timing-json \ + --shell -- \ + "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changed" +``` + +집중 테스트 재실행: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox \ + --blacksmith-org openclaw \ + --blacksmith-workflow .github/workflows/ci-check-testbox.yml \ + --blacksmith-job check \ + --blacksmith-ref main \ + --idle-timeout 90m \ + --ttl 240m \ + --timing-json \ + --shell -- \ + "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test " +``` + +전체 제품군: + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox \ + --blacksmith-org openclaw \ + --blacksmith-workflow .github/workflows/ci-check-testbox.yml \ + --blacksmith-job check \ + --blacksmith-ref main \ + --idle-timeout 90m \ + --ttl 240m \ + --timing-json \ + --shell -- \ + "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test" +``` + +최종 JSON 요약을 읽으세요. 유용한 필드는 `provider`, `leaseId`, `syncDelegated`, `exitCode`, `commandMs`, `totalMs`입니다. 일회성 Blacksmith 기반 Crabbox 실행은 Testbox를 자동으로 중지해야 합니다. 실행이 중단되었거나 정리가 불분명하면 활성 박스를 검사하고 직접 만든 박스만 중지하세요. + +```bash +blacksmith testbox list +blacksmith testbox stop --id +``` + +동일하게 준비된 박스에서 여러 명령이 의도적으로 필요할 때만 재사용하세요. + +```bash +pnpm crabbox:run -- --provider blacksmith-testbox --id --no-sync --timing-json --shell -- "pnpm test " +pnpm crabbox:stop -- +``` + +Crabbox 계층만 고장 났고 Blacksmith 자체는 작동한다면, 좁은 대체 수단으로 직접 Blacksmith를 사용하세요. + +```bash +blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90 +blacksmith testbox run --id "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changed" +blacksmith testbox stop --id +``` + +Blacksmith가 다운되었거나, 할당량 제한이 있거나, 필요한 환경이 없거나, 소유 용량이 명시적인 목표일 때만 소유 Crabbox 용량으로 에스컬레이션하세요. + +```bash +pnpm crabbox:warmup -- --provider aws --class beast --market on-demand --idle-timeout 90m +pnpm crabbox:hydrate -- --id +pnpm crabbox:run -- --id --timing-json --shell -- "env NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm check:changed" +pnpm crabbox:stop -- +``` + +`.crabbox.yaml`은 소유 클라우드 레인의 공급자, 동기화, GitHub Actions 준비 기본값을 소유합니다. 이 파일은 로컬 `.git`을 제외하므로, 준비된 Actions checkout이 유지관리자 로컬 원격 저장소와 객체 저장소를 동기화하는 대신 자체 원격 Git 메타데이터를 유지합니다. 또한 전송되어서는 안 되는 로컬 런타임/빌드 아티팩트도 제외합니다. `.github/workflows/crabbox-hydrate.yml`은 소유 클라우드 `crabbox run --id ` 명령을 위한 checkout, Node/pnpm 설정, `origin/main` 가져오기, 비시크릿 환경 전달을 소유합니다. ## 관련 diff --git a/docs/ko/cli/plugins.md b/docs/ko/cli/plugins.md index 749d466a0..29399fe8b 100644 --- a/docs/ko/cli/plugins.md +++ b/docs/ko/cli/plugins.md @@ -3,34 +3,34 @@ read_when: - Gateway Plugin 또는 호환 번들을 설치하거나 관리하려는 경우 - Plugin 로드 실패를 디버그하려는 경우 sidebarTitle: Plugins -summary: 'CLI 참조: `openclaw plugins`(목록, 설치, 마켓플레이스, 제거, 활성화/비활성화, doctor)' -title: Plugin +summary: '`openclaw plugins`에 대한 CLI 참조(list, install, marketplace, uninstall, enable/disable, doctor)' +title: Plugins x-i18n: - generated_at: "2026-05-03T21:29:19Z" + generated_at: "2026-05-04T06:23:03Z" model: gpt-5.5 provider: openai - source_hash: d854d052b0a012a86f9c775775676a9a8fe8ae86b2c38a18118f1abf0732174c + source_hash: 36ae7edb12986ead7e126f25e0761bf312b2644b35017181b674082105886776 source_path: cli/plugins.md workflow: 16 --- -Gateway Plugin, 훅 팩 및 호환 번들을 관리합니다. +Gateway Plugin, 훅 팩, 호환 번들을 관리합니다. - - Plugin 설치, 활성화 및 문제 해결을 위한 최종 사용자 가이드입니다. + + Plugin 설치, 활성화 및 문제 해결을 위한 최종 사용자 가이드. - - 설치, 목록 보기, 업데이트, 제거 및 게시를 위한 빠른 예시입니다. + + 설치, 목록 보기, 업데이트, 제거, 게시를 위한 빠른 예시. - - 번들 호환성 모델입니다. + + 번들 호환성 모델. - - 매니페스트 필드 및 구성 스키마입니다. + + 매니페스트 필드와 구성 스키마. - - Plugin 설치를 위한 보안 강화입니다. + + Plugin 설치를 위한 보안 강화. @@ -62,16 +62,16 @@ openclaw plugins marketplace list openclaw plugins marketplace list --json ``` -느린 설치, 검사, 제거 또는 레지스트리 새로 고침을 조사하려면 -`OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1`과 함께 명령을 실행하세요. 추적은 단계별 소요 시간을 -stderr에 기록하며 JSON 출력을 파싱 가능한 상태로 유지합니다. [디버깅](/ko/help/debugging#plugin-lifecycle-trace)을 참고하세요. +설치, 검사, 제거 또는 레지스트리 새로 고침이 느린 문제를 조사하려면 +`OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1`로 명령을 실행하세요. 이 추적은 단계별 타이밍을 +stderr에 기록하고 JSON 출력을 파싱 가능한 상태로 유지합니다. [디버깅](/ko/help/debugging#plugin-lifecycle-trace)을 참고하세요. -번들 Plugin은 OpenClaw와 함께 제공됩니다. 일부는 기본적으로 활성화되어 있으며(예: 번들 모델 제공자, 번들 음성 제공자, 번들 브라우저 Plugin), 다른 항목은 `plugins enable`이 필요합니다. +번들된 Plugin은 OpenClaw와 함께 제공됩니다. 일부는 기본적으로 활성화되어 있습니다(예: 번들된 모델 제공자, 번들된 음성 제공자, 번들된 브라우저 Plugin). 나머지는 `plugins enable`이 필요합니다. -네이티브 OpenClaw Plugin은 인라인 JSON Schema(`configSchema`, 비어 있더라도)를 포함한 `openclaw.plugin.json`을 제공해야 합니다. 호환 번들은 대신 자체 번들 매니페스트를 사용합니다. +네이티브 OpenClaw Plugin은 인라인 JSON 스키마(`configSchema`, 비어 있더라도 포함)와 함께 `openclaw.plugin.json`을 제공해야 합니다. 호환 번들은 대신 자체 번들 매니페스트를 사용합니다. -`plugins list`는 `Format: openclaw` 또는 `Format: bundle`을 표시합니다. 자세한 목록/정보 출력에는 감지된 번들 기능과 함께 번들 하위 유형(`codex`, `claude` 또는 `cursor`)도 표시됩니다. +`plugins list`는 `Format: openclaw` 또는 `Format: bundle`을 표시합니다. 상세 list/info 출력에는 번들 하위 유형(`codex`, `claude`, 또는 `cursor`)과 감지된 번들 기능도 표시됩니다. ### 설치 @@ -93,83 +93,83 @@ openclaw plugins install --marketplace https://github.com// -출시 전환 기간에는 단순 패키지 이름이 기본적으로 npm에서 설치됩니다. ClawHub에는 `clawhub:`를 사용하세요. Plugin 설치는 코드를 실행하는 것처럼 취급하세요. 고정된 버전을 사용하는 것이 좋습니다. +출시 전환 기간에는 접두사가 없는 패키지 이름이 기본적으로 npm에서 설치됩니다. ClawHub에는 `clawhub:`를 사용하세요. Plugin 설치는 코드를 실행하는 것처럼 취급하세요. 고정된 버전을 선호하세요. `plugins search`는 ClawHub에서 설치 가능한 Plugin 패키지를 조회하고 -설치 준비가 된 패키지 이름을 출력합니다. 이는 code-plugin 및 bundle-plugin 패키지를 검색하며, +바로 설치할 수 있는 패키지 이름을 출력합니다. 코드 Plugin 및 번들 Plugin 패키지를 검색하며, Skills는 검색하지 않습니다. ClawHub Skills에는 `openclaw skills search`를 사용하세요. -ClawHub는 대부분의 Plugin을 위한 기본 배포 및 검색 표면입니다. npm은 -지원되는 대체 경로이자 직접 설치 경로로 남아 있습니다. OpenClaw 소유 -`@openclaw/*` Plugin 패키지는 다시 npm에 게시됩니다. 현재 목록은 +ClawHub는 대부분의 Plugin에 대한 기본 배포 및 검색 표면입니다. npm은 +지원되는 대체 수단이자 직접 설치 경로로 남아 있습니다. OpenClaw 소유 +`@openclaw/*` Plugin 패키지는 npm에 다시 게시됩니다. 현재 목록은 [npmjs.com/org/openclaw](https://www.npmjs.com/org/openclaw) 또는 -[Plugin 인벤토리](/ko/plugins/plugin-inventory)를 참고하세요. 안정 설치는 `latest`를 사용합니다. -베타 채널 설치 및 업데이트는 해당 태그가 사용 가능할 때 npm `beta` dist-tag를 우선 사용하고, -그다음 `latest`로 대체합니다. +[Plugin 인벤토리](/ko/plugins/plugin-inventory)를 참고하세요. 안정판 설치는 `latest`를 사용합니다. +베타 채널 설치 및 업데이트는 해당 태그가 있을 때 npm `beta` dist-tag를 +우선 사용한 다음 `latest`로 폴백합니다. - - `plugins` 섹션이 단일 파일 `$include`로 뒷받침되는 경우 `plugins install/update/enable/disable/uninstall`은 포함된 해당 파일에 기록하고 `openclaw.json`은 건드리지 않습니다. 루트 include, include 배열, 형제 재정의가 있는 include는 평탄화하는 대신 닫힌 상태로 실패합니다. 지원되는 형태는 [구성 include](/ko/gateway/configuration)를 참고하세요. + + `plugins` 섹션이 단일 파일 `$include`로 뒷받침되는 경우, `plugins install/update/enable/disable/uninstall`은 포함된 해당 파일에 직접 기록하고 `openclaw.json`은 건드리지 않습니다. 루트 include, include 배열, 형제 override가 있는 include는 평탄화하지 않고 안전하게 실패하여 중단됩니다. 지원되는 형태는 [구성 include](/ko/gateway/configuration)를 참고하세요. - 설치 중 구성이 유효하지 않으면 `plugins install`은 일반적으로 닫힌 상태로 실패하고 먼저 `openclaw doctor --fix`를 실행하라고 안내합니다. Gateway 시작 및 핫 리로드 중에는 유효하지 않은 Plugin 구성이 다른 유효하지 않은 구성과 마찬가지로 닫힌 상태로 실패합니다. `openclaw doctor --fix`는 유효하지 않은 Plugin 항목을 격리할 수 있습니다. 문서화된 유일한 설치 시점 예외는 `openclaw.install.allowInvalidConfigRecovery`를 명시적으로 선택한 Plugin을 위한 좁은 범위의 번들 Plugin 복구 경로입니다. + 설치 중 구성이 잘못된 경우, `plugins install`은 일반적으로 안전하게 실패하여 중단하고 먼저 `openclaw doctor --fix`를 실행하라고 안내합니다. Gateway 시작 및 핫 리로드 중에는 잘못된 Plugin 구성도 다른 잘못된 구성과 마찬가지로 안전하게 실패하여 중단됩니다. `openclaw doctor --fix`는 잘못된 Plugin 항목을 격리할 수 있습니다. 문서화된 유일한 설치 시점 예외는 명시적으로 `openclaw.install.allowInvalidConfigRecovery`를 선택한 Plugin을 위한 좁은 범위의 번들된 Plugin 복구 경로입니다. - - `--force`는 기존 설치 대상을 재사용하고 이미 설치된 Plugin 또는 훅 팩을 제자리에서 덮어씁니다. 같은 id를 새 로컬 경로, 아카이브, ClawHub 패키지 또는 npm 아티팩트에서 의도적으로 다시 설치할 때 사용하세요. 이미 추적 중인 npm Plugin의 일반 업그레이드에는 `openclaw plugins update `를 사용하는 것이 좋습니다. + + `--force`는 기존 설치 대상을 재사용하고 이미 설치된 Plugin 또는 훅 팩을 그 자리에서 덮어씁니다. 새 로컬 경로, 아카이브, ClawHub 패키지 또는 npm 아티팩트에서 동일한 ID를 의도적으로 재설치할 때 사용하세요. 이미 추적 중인 npm Plugin의 일반적인 업그레이드에는 `openclaw plugins update `를 선호하세요. - 이미 설치된 Plugin id에 대해 `plugins install`을 실행하면 OpenClaw는 중단하고 일반 업그레이드에는 `plugins update `를, 현재 설치를 다른 소스에서 실제로 덮어쓰려는 경우에는 `plugins install --force`를 사용하라고 안내합니다. + 이미 설치된 Plugin ID에 대해 `plugins install`을 실행하면 OpenClaw는 중단하고 일반 업그레이드에는 `plugins update `를 안내하거나, 현재 설치를 다른 소스에서 정말로 덮어쓰려는 경우에는 `plugins install --force`를 안내합니다. - - `--pin`은 npm 설치에만 적용됩니다. `git:` 설치에서는 지원되지 않습니다. 고정된 소스를 원할 때는 `git:github.com/acme/plugin@v1.2.3`처럼 명시적 git ref를 사용하세요. `--marketplace`와도 함께 사용할 수 없습니다. marketplace 설치는 npm spec 대신 marketplace 소스 메타데이터를 유지하기 때문입니다. + + `--pin`은 npm 설치에만 적용됩니다. `git:` 설치에서는 지원되지 않습니다. 소스를 고정하려면 `git:github.com/acme/plugin@v1.2.3`처럼 명시적인 git ref를 사용하세요. `--marketplace`와 함께 사용할 수 없습니다. 마켓플레이스 설치는 npm 명세 대신 마켓플레이스 소스 메타데이터를 유지하기 때문입니다. - `--dangerously-force-unsafe-install`은 내장 위험 코드 스캐너의 오탐에 대응하기 위한 비상 옵션입니다. 내장 스캐너가 `critical` 발견 사항을 보고해도 설치를 계속할 수 있게 하지만, Plugin `before_install` 훅 정책 차단을 우회하지 않으며 스캔 실패도 우회하지 않습니다. + `--dangerously-force-unsafe-install`은 내장 위험 코드 스캐너의 오탐을 위한 비상용 옵션입니다. 내장 스캐너가 `critical` 탐지 결과를 보고해도 설치를 계속할 수 있게 하지만, Plugin `before_install` 훅 정책 차단을 우회하지 **않으며** 스캔 실패도 우회하지 **않습니다**. - 이 CLI 플래그는 Plugin 설치/업데이트 흐름에 적용됩니다. Gateway 기반 skill 의존성 설치는 대응되는 `dangerouslyForceUnsafeInstall` 요청 재정의를 사용하며, `openclaw skills install`은 별도의 ClawHub skill 다운로드/설치 흐름으로 유지됩니다. + 이 CLI 플래그는 Plugin 설치/업데이트 흐름에 적용됩니다. Gateway 기반 Skills 의존성 설치는 대응되는 `dangerouslyForceUnsafeInstall` 요청 override를 사용하며, `openclaw skills install`은 별도의 ClawHub Skills 다운로드/설치 흐름으로 남아 있습니다. - ClawHub에 게시한 Plugin이 레지스트리 스캔으로 차단되는 경우 [ClawHub](/ko/tools/clawhub)의 게시자 절차를 사용하세요. + ClawHub에 게시한 Plugin이 레지스트리 스캔으로 차단되면 [ClawHub](/ko/tools/clawhub)의 게시자 단계를 사용하세요. - - `plugins install`은 `package.json`에서 `openclaw.hooks`를 노출하는 훅 팩의 설치 표면이기도 합니다. 패키지 설치가 아니라 필터링된 훅 표시 및 훅별 활성화에는 `openclaw hooks`를 사용하세요. + + `plugins install`은 `package.json`에서 `openclaw.hooks`를 노출하는 훅 팩의 설치 진입점이기도 합니다. 패키지 설치가 아니라 필터링된 훅 표시 및 훅별 활성화에는 `openclaw hooks`를 사용하세요. - npm spec은 **레지스트리 전용**입니다(패키지 이름 + 선택적 **정확한 버전** 또는 **dist-tag**). Git/URL/file spec 및 semver 범위는 거부됩니다. 의존성 설치는 셸에 전역 npm 설치 설정이 있더라도 안전을 위해 `--ignore-scripts`와 함께 프로젝트 로컬에서 실행됩니다. + npm 명세는 **레지스트리 전용**입니다(패키지 이름 + 선택적 **정확한 버전** 또는 **dist-tag**). Git/URL/file 명세와 semver 범위는 거부됩니다. 의존성 설치는 안전을 위해 셸에 전역 npm 설치 설정이 있더라도 `--ignore-scripts`로 프로젝트 로컬에서 실행됩니다. - npm 해석을 명시적으로 만들고 싶을 때는 `npm:`를 사용하세요. 단순 패키지 spec도 출시 전환 기간에는 npm에서 직접 설치됩니다. + npm 해석을 명시적으로 만들고 싶을 때는 `npm:`를 사용하세요. 접두사가 없는 패키지 명세도 출시 전환 기간에는 npm에서 직접 설치됩니다. - 단순 spec 및 `@latest`는 안정 트랙에 유지됩니다. npm이 이 중 하나를 프리릴리스로 해석하면 OpenClaw는 중단하고 `@beta`/`@rc` 같은 프리릴리스 태그 또는 `@1.2.3-beta.4` 같은 정확한 프리릴리스 버전으로 명시적으로 선택하라고 요청합니다. + 접두사가 없는 명세와 `@latest`는 안정판 트랙에 머무릅니다. `2026.5.3-1` 같은 OpenClaw 날짜 스탬프 수정 버전은 이 검사에서 안정판 릴리스입니다. npm이 둘 중 하나를 사전 릴리스로 해석하면 OpenClaw는 중단하고 `@beta`/`@rc` 같은 사전 릴리스 태그 또는 `@1.2.3-beta.4` 같은 정확한 사전 릴리스 버전으로 명시적으로 선택하라고 요청합니다. - 단순 설치 spec이 공식 Plugin id와 일치하는 경우(예: `diffs`) OpenClaw는 카탈로그 항목을 직접 설치합니다. 같은 이름의 npm 패키지를 설치하려면 명시적 scoped spec을 사용하세요(예: `@scope/diffs`). + 접두사가 없는 설치 명세가 공식 Plugin ID와 일치하면(예: `diffs`) OpenClaw는 카탈로그 항목을 직접 설치합니다. 같은 이름의 npm 패키지를 설치하려면 명시적인 스코프 명세(예: `@scope/diffs`)를 사용하세요. - - git 저장소에서 직접 설치하려면 `git:`를 사용하세요. 지원되는 형식에는 `git:github.com/owner/repo`, `git:owner/repo`, 전체 `https://`, `ssh://`, `git://`, `file://`, `git@host:owner/repo.git` clone URL이 포함됩니다. 설치 전에 브랜치, 태그 또는 커밋을 체크아웃하려면 `@` 또는 `#`를 추가하세요. + + git 저장소에서 직접 설치하려면 `git:`를 사용하세요. 지원되는 형식에는 `git:github.com/owner/repo`, `git:owner/repo`, 전체 `https://`, `ssh://`, `git://`, `file://`, `git@host:owner/repo.git` 클론 URL이 포함됩니다. 설치 전에 브랜치, 태그 또는 커밋을 체크아웃하려면 `@` 또는 `#`를 추가하세요. - Git 설치는 임시 디렉터리에 clone하고, 요청된 ref가 있으면 체크아웃한 다음, 일반 Plugin 디렉터리 설치 프로그램을 사용합니다. 즉 매니페스트 검증, 위험 코드 스캔, 패키지 관리자 설치 작업 및 설치 기록은 npm 설치처럼 동작합니다. 기록된 git 설치에는 소스 URL/ref와 해석된 커밋이 포함되어 `openclaw plugins update`가 나중에 소스를 다시 해석할 수 있습니다. + Git 설치는 임시 디렉터리로 클론하고, 요청된 ref가 있으면 체크아웃한 다음, 일반 Plugin 디렉터리 설치기를 사용합니다. 즉 매니페스트 검증, 위험 코드 스캔, 패키지 관리자 설치 작업 및 설치 기록이 npm 설치처럼 동작합니다. 기록된 git 설치에는 소스 URL/ref와 해석된 커밋이 포함되므로 `openclaw plugins update`가 나중에 소스를 다시 해석할 수 있습니다. - git에서 설치한 뒤에는 `openclaw plugins inspect --runtime --json`을 사용해 gateway 메서드 및 CLI 명령 같은 런타임 등록을 확인하세요. Plugin이 `api.registerCli`로 CLI 루트를 등록했다면 OpenClaw 루트 CLI를 통해 해당 명령을 직접 실행하세요. 예: `openclaw demo-plugin ping`. + git에서 설치한 후에는 `openclaw plugins inspect --runtime --json`을 사용하여 Gateway 메서드 및 CLI 명령 같은 런타임 등록을 확인하세요. Plugin이 `api.registerCli`로 CLI 루트를 등록했다면 해당 명령을 OpenClaw 루트 CLI를 통해 직접 실행하세요. 예: `openclaw demo-plugin ping`. - - 지원되는 아카이브: `.zip`, `.tgz`, `.tar.gz`, `.tar`. 네이티브 OpenClaw Plugin 아카이브는 추출된 Plugin 루트에 유효한 `openclaw.plugin.json`을 포함해야 합니다. `package.json`만 포함하는 아카이브는 OpenClaw가 설치 기록을 쓰기 전에 거부됩니다. + + 지원되는 아카이브: `.zip`, `.tgz`, `.tar.gz`, `.tar`. 네이티브 OpenClaw Plugin 아카이브에는 압축 해제된 Plugin 루트에 유효한 `openclaw.plugin.json`이 있어야 합니다. `package.json`만 포함한 아카이브는 OpenClaw가 설치 기록을 쓰기 전에 거부됩니다. - Claude marketplace 설치도 지원됩니다. + Claude 마켓플레이스 설치도 지원됩니다. -ClawHub 설치는 명시적 `clawhub:` 로케이터를 사용합니다. +ClawHub 설치는 명시적인 `clawhub:` locator를 사용합니다. ```bash openclaw plugins install clawhub:openclaw-codex-app-server openclaw plugins install clawhub:openclaw-codex-app-server@1.2.3 ``` -출시 전환 기간에는 단순 npm 안전 Plugin spec이 기본적으로 npm에서 설치됩니다. +접두사가 없는 npm-safe Plugin 명세는 출시 전환 기간 동안 기본적으로 npm에서 설치됩니다. ```bash openclaw plugins install openclaw-codex-app-server @@ -182,19 +182,19 @@ openclaw plugins install npm:openclaw-codex-app-server openclaw plugins install npm:@scope/plugin-name@1.0.1 ``` -OpenClaw는 설치 전에 광고된 Plugin API / 최소 gateway 호환성을 확인합니다. 선택한 ClawHub 버전이 ClawPack 아티팩트를 게시한 경우 OpenClaw는 버전이 지정된 npm-pack `.tgz`를 다운로드하고, ClawHub digest 헤더와 아티팩트 digest를 검증한 다음, 일반 아카이브 경로를 통해 설치합니다. ClawPack 메타데이터가 없는 이전 ClawHub 버전은 여전히 레거시 패키지 아카이브 검증 경로를 통해 설치됩니다. 기록된 설치는 나중 업데이트를 위해 ClawHub 소스 메타데이터, 아티팩트 종류, npm integrity, npm shasum, tarball 이름 및 ClawPack digest 정보를 유지합니다. -버전이 지정되지 않은 ClawHub 설치는 `openclaw plugins update`가 더 새로운 ClawHub 릴리스를 따라갈 수 있도록 버전 없는 기록 spec을 유지합니다. `clawhub:pkg@1.2.3` 및 `clawhub:pkg@beta` 같은 명시적 버전 또는 태그 선택자는 해당 선택자에 고정된 상태로 유지됩니다. +OpenClaw는 설치 전에 게시된 Plugin API / 최소 Gateway 호환성을 확인합니다. 선택한 ClawHub 버전이 ClawPack 아티팩트를 게시하면 OpenClaw는 버전이 지정된 npm-pack `.tgz`를 다운로드하고, ClawHub digest 헤더와 아티팩트 digest를 검증한 다음, 일반 아카이브 경로를 통해 설치합니다. ClawPack 메타데이터가 없는 이전 ClawHub 버전은 여전히 레거시 패키지 아카이브 검증 경로를 통해 설치됩니다. 기록된 설치는 이후 업데이트를 위해 ClawHub 소스 메타데이터, 아티팩트 종류, npm integrity, npm shasum, tarball 이름 및 ClawPack digest 사실을 보관합니다. +버전이 지정되지 않은 ClawHub 설치는 버전이 없는 기록된 명세를 유지하므로 `openclaw plugins update`가 더 새로운 ClawHub 릴리스를 따라갈 수 있습니다. `clawhub:pkg@1.2.3` 및 `clawhub:pkg@beta` 같은 명시적 버전 또는 태그 선택자는 해당 선택자에 고정된 상태로 유지됩니다. -#### Marketplace 약식 표기 +#### 마켓플레이스 축약형 -marketplace 이름이 Claude의 로컬 레지스트리 캐시 `~/.claude/plugins/known_marketplaces.json`에 존재할 때 `plugin@marketplace` 약식 표기를 사용하세요. +Claude의 로컬 레지스트리 캐시 `~/.claude/plugins/known_marketplaces.json`에 마켓플레이스 이름이 있을 때 `plugin@marketplace` 축약형을 사용하세요. ```bash openclaw plugins marketplace list openclaw plugins install @ ``` -marketplace 소스를 명시적으로 전달하려면 `--marketplace`를 사용하세요. +마켓플레이스 소스를 명시적으로 전달하려면 `--marketplace`를 사용하세요. ```bash openclaw plugins install --marketplace @@ -204,28 +204,28 @@ openclaw plugins install --marketplace ./my-marketplace ``` - - - `~/.claude/plugins/known_marketplaces.json`에 있는 Claude의 알려진 마켓플레이스 이름 + + - `~/.claude/plugins/known_marketplaces.json`의 Claude 알려진 마켓플레이스 이름 - 로컬 마켓플레이스 루트 또는 `marketplace.json` 경로 - - `owner/repo` 같은 GitHub 저장소 축약 표기 + - `owner/repo` 같은 GitHub 저장소 축약형 - `https://github.com/owner/repo` 같은 GitHub 저장소 URL - git URL - - GitHub 또는 git에서 로드한 원격 마켓플레이스의 경우, Plugin 항목은 클론된 마켓플레이스 저장소 안에 있어야 합니다. OpenClaw는 해당 저장소의 상대 경로 소스를 허용하며, 원격 manifest의 HTTP(S), 절대 경로, git, GitHub 및 기타 경로가 아닌 Plugin 소스를 거부합니다. + + GitHub 또는 git에서 로드된 원격 마켓플레이스의 경우, Plugin 항목은 복제된 마켓플레이스 저장소 안에 있어야 합니다. OpenClaw는 해당 저장소의 상대 경로 소스를 허용하고, 원격 매니페스트의 HTTP(S), 절대 경로, git, GitHub 및 기타 경로가 아닌 Plugin 소스를 거부합니다. -로컬 경로와 아카이브의 경우 OpenClaw는 다음을 자동 감지합니다. +로컬 경로와 아카이브의 경우, OpenClaw는 다음을 자동 감지합니다. - 네이티브 OpenClaw Plugin(`openclaw.plugin.json`) - Codex 호환 번들(`.codex-plugin/plugin.json`) -- Claude 호환 번들(`.claude-plugin/plugin.json` 또는 기본 Claude 구성 요소 레이아웃) +- Claude 호환 번들(`.claude-plugin/plugin.json` 또는 기본 Claude 컴포넌트 레이아웃) - Cursor 호환 번들(`.cursor-plugin/plugin.json`) -호환 번들은 일반 Plugin 루트에 설치되며 동일한 list/info/enable/disable 흐름에 참여합니다. 현재는 번들 Skills, Claude 명령-Skills, Claude `settings.json` 기본값, Claude `.lsp.json` / manifest에 선언된 `lspServers` 기본값, Cursor 명령-Skills, 호환 Codex hook 디렉터리가 지원됩니다. 감지된 다른 번들 기능은 진단/info에 표시되지만 아직 런타임 실행에는 연결되지 않았습니다. +호환 번들은 일반 Plugin 루트에 설치되며 동일한 목록/정보/활성화/비활성화 흐름에 참여합니다. 현재는 번들 Skills, Claude command-skills, Claude `settings.json` 기본값, Claude `.lsp.json` / 매니페스트에 선언된 `lspServers` 기본값, Cursor command-skills, 호환 Codex 훅 디렉터리가 지원됩니다. 감지된 다른 번들 기능은 진단/정보에 표시되지만 아직 런타임 실행에는 연결되지 않았습니다. ### 목록 @@ -244,27 +244,27 @@ openclaw plugins search --json 활성화된 Plugin만 표시합니다. - 테이블 보기에서 Plugin별 세부 줄로 전환하여 소스/출처/버전/활성화 메타데이터를 표시합니다. + 테이블 보기에서 Plugin별 소스/출처/버전/활성화 메타데이터가 있는 세부 줄로 전환합니다. - 머신이 읽을 수 있는 인벤터리와 registry 진단 및 package 의존성 설치 상태입니다. + 기계 판독 가능 인벤터리와 레지스트리 진단 및 패키지 의존성 설치 상태입니다. -`plugins list`는 먼저 영속화된 로컬 Plugin registry를 읽고, registry가 없거나 유효하지 않으면 manifest만으로 파생한 대체 정보를 사용합니다. 이는 Plugin이 설치, 활성화되어 있고 cold startup planning에 표시되는지 확인하는 데 유용하지만, 이미 실행 중인 Gateway 프로세스의 live runtime probe는 아닙니다. Plugin 코드, 활성화 상태, hook 정책 또는 `plugins.load.paths`를 변경한 뒤에는 새 `register(api)` 코드나 hook이 실행되기를 기대하기 전에 채널을 제공하는 Gateway를 다시 시작하세요. 원격/컨테이너 배포에서는 wrapper 프로세스만이 아니라 실제 `openclaw gateway run` 자식을 다시 시작하는지 확인하세요. +`plugins list`는 먼저 영구 저장된 로컬 Plugin 레지스트리를 읽고, 레지스트리가 없거나 유효하지 않으면 매니페스트 전용 파생 폴백을 사용합니다. Plugin이 설치되고 활성화되었으며 콜드 스타트업 계획에 표시되는지 확인하는 데 유용하지만, 이미 실행 중인 Gateway 프로세스의 라이브 런타임 프로브는 아닙니다. Plugin 코드, 활성화 상태, 훅 정책 또는 `plugins.load.paths`를 변경한 뒤에는 새 `register(api)` 코드 또는 훅이 실행되기를 기대하기 전에 채널을 제공하는 Gateway를 다시 시작하세요. 원격/컨테이너 배포에서는 래퍼 프로세스만이 아니라 실제 `openclaw gateway run` 하위 프로세스를 다시 시작하는지 확인하세요. -`plugins list --json`에는 각 Plugin의 `package.json` `dependencies`와 `optionalDependencies`에서 가져온 `dependencyStatus`가 포함됩니다. OpenClaw는 해당 package 이름이 Plugin의 일반적인 Node `node_modules` lookup path에 존재하는지 확인합니다. Plugin 런타임 코드를 import하거나, package manager를 실행하거나, 누락된 의존성을 복구하지 않습니다. +`plugins list --json`에는 `package.json`의 `dependencies` 및 `optionalDependencies`에서 가져온 각 Plugin의 `dependencyStatus`가 포함됩니다. OpenClaw는 해당 패키지 이름이 Plugin의 일반 Node `node_modules` 조회 경로에 있는지 확인합니다. Plugin 런타임 코드를 가져오거나, 패키지 관리자를 실행하거나, 누락된 의존성을 복구하지 않습니다. -`plugins search`는 원격 ClawHub 카탈로그 lookup입니다. 로컬 상태를 검사하거나, config를 변경하거나, package를 설치하거나, Plugin 런타임 코드를 로드하지 않습니다. 검색 결과에는 ClawHub package 이름, family, channel, version, summary와 `openclaw plugins install clawhub:` 같은 설치 힌트가 포함됩니다. +`plugins search`는 원격 ClawHub 카탈로그 조회입니다. 로컬 상태를 검사하거나, 구성을 변경하거나, 패키지를 설치하거나, Plugin 런타임 코드를 로드하지 않습니다. 검색 결과에는 ClawHub 패키지 이름, 패밀리, 채널, 버전, 요약 및 `openclaw plugins install clawhub:` 같은 설치 힌트가 포함됩니다. -패키징된 Docker 이미지 안에서 번들 Plugin 작업을 할 때는 `/app/extensions/synology-chat` 같은 일치하는 패키징된 소스 경로 위에 Plugin 소스 디렉터리를 bind-mount하세요. OpenClaw는 `/app/dist/extensions/synology-chat`보다 먼저 해당 mount된 소스 overlay를 발견합니다. 단순히 복사된 소스 디렉터리는 비활성 상태로 남으므로 일반 패키징 설치는 계속 컴파일된 dist를 사용합니다. +패키징된 Docker 이미지 안에서 번들 Plugin 작업을 할 때는 `/app/extensions/synology-chat` 같은 일치하는 패키징된 소스 경로 위에 Plugin 소스 디렉터리를 바인드 마운트하세요. OpenClaw는 `/app/dist/extensions/synology-chat`보다 먼저 해당 마운트된 소스 오버레이를 발견합니다. 단순히 복사된 소스 디렉터리는 비활성 상태로 남으므로 일반 패키징 설치는 계속 컴파일된 dist를 사용합니다. -런타임 hook 디버깅의 경우: +런타임 훅 디버깅의 경우: -- `openclaw plugins inspect --runtime --json`은 모듈 로드 검사 pass에서 등록된 hook과 진단을 표시합니다. 런타임 검사는 의존성을 설치하지 않습니다. 레거시 의존성 상태를 정리하거나 누락된 구성된 다운로드 가능 Plugin을 설치하려면 `openclaw doctor --fix`를 사용하세요. -- `openclaw gateway status --deep --require-rpc`는 도달 가능한 Gateway, service/process 힌트, config 경로 및 RPC 상태를 확인합니다. -- 번들되지 않은 대화 hook(`llm_input`, `llm_output`, `before_agent_finalize`, `agent_end`)에는 `plugins.entries..hooks.allowConversationAccess=true`가 필요합니다. +- `openclaw plugins inspect --runtime --json`은 모듈 로드 검사 패스에서 등록된 훅과 진단을 표시합니다. 런타임 검사는 의존성을 설치하지 않습니다. 레거시 의존성 상태를 정리하거나 누락된 구성된 다운로드 가능 Plugin을 설치하려면 `openclaw doctor --fix`를 사용하세요. +- `openclaw gateway status --deep --require-rpc`는 연결 가능한 Gateway, 서비스/프로세스 힌트, 구성 경로 및 RPC 상태를 확인합니다. +- 번들되지 않은 대화 훅(`llm_input`, `llm_output`, `before_agent_finalize`, `agent_end`)에는 `plugins.entries..hooks.allowConversationAccess=true`가 필요합니다. 로컬 디렉터리 복사를 피하려면 `--link`를 사용하세요(`plugins.load.paths`에 추가됨). @@ -273,16 +273,16 @@ openclaw plugins install -l ./my-plugin ``` -연결된 설치는 관리형 설치 대상 위에 복사하는 대신 소스 경로를 재사용하므로 `--force`는 `--link`와 함께 지원되지 않습니다. +링크 설치는 관리되는 설치 대상 위에 복사하는 대신 소스 경로를 재사용하므로 `--force`는 `--link`와 함께 지원되지 않습니다. -npm 설치에서 `--pin`을 사용하면 기본 동작은 고정하지 않은 상태로 유지하면서, 확인된 정확한 spec(`name@version`)을 관리형 Plugin 인덱스에 저장합니다. +npm 설치에서 `--pin`을 사용하면 기본 동작은 고정하지 않은 상태로 유지하면서, 확인된 정확한 사양(`name@version`)을 관리되는 Plugin 인덱스에 저장합니다. ### Plugin 인덱스 -Plugin 설치 메타데이터는 사용자의 config가 아니라 머신이 관리하는 상태입니다. 설치와 업데이트는 활성 OpenClaw state 디렉터리 아래의 `plugins/installs.json`에 이를 기록합니다. 최상위 `installRecords` map은 손상되었거나 누락된 Plugin manifest에 대한 record를 포함해 설치 메타데이터의 durable source입니다. `plugins` 배열은 manifest에서 파생된 cold registry cache입니다. 이 파일에는 편집 금지 경고가 포함되며 `openclaw plugins update`, 제거, 진단 및 cold Plugin registry에서 사용됩니다. +Plugin 설치 메타데이터는 사용자 구성이 아니라 기계가 관리하는 상태입니다. 설치 및 업데이트는 활성 OpenClaw 상태 디렉터리 아래의 `plugins/installs.json`에 이를 기록합니다. 최상위 `installRecords` 맵은 손상되었거나 누락된 Plugin 매니페스트의 기록을 포함해 설치 메타데이터의 지속적인 원본입니다. `plugins` 배열은 매니페스트에서 파생된 콜드 레지스트리 캐시입니다. 이 파일에는 편집 금지 경고가 포함되어 있으며 `openclaw plugins update`, 제거, 진단 및 콜드 Plugin 레지스트리에서 사용됩니다. -OpenClaw가 config에서 제공된 레거시 `plugins.installs` record를 발견하면 이를 Plugin 인덱스로 이동하고 config key를 제거합니다. 어느 한쪽 쓰기가 실패하면 설치 메타데이터가 손실되지 않도록 config record를 유지합니다. +OpenClaw가 구성에서 제공된 레거시 `plugins.installs` 레코드를 발견하면, 이를 Plugin 인덱스로 이동하고 구성 키를 제거합니다. 어느 한쪽 쓰기가 실패하면 설치 메타데이터가 손실되지 않도록 구성 레코드를 유지합니다. ### 제거 @@ -292,10 +292,10 @@ openclaw plugins uninstall --dry-run openclaw plugins uninstall --keep-files ``` -`uninstall`은 적용 가능한 경우 `plugins.entries`, 영속화된 Plugin 인덱스, Plugin allow/deny list 항목, 연결된 `plugins.load.paths` 항목에서 Plugin record를 제거합니다. `--keep-files`가 설정되지 않은 한, 제거는 추적 중인 관리형 설치 디렉터리가 OpenClaw의 Plugin extensions 루트 안에 있을 때 해당 디렉터리도 제거합니다. Active Memory Plugin의 경우 memory slot이 `memory-core`로 재설정됩니다. +`uninstall`은 해당하는 경우 `plugins.entries`, 영구 저장된 Plugin 인덱스, Plugin 허용/거부 목록 항목 및 연결된 `plugins.load.paths` 항목에서 Plugin 레코드를 제거합니다. `--keep-files`가 설정되지 않은 한, 제거는 OpenClaw의 Plugin 확장 루트 안에 있는 추적된 관리 설치 디렉터리도 제거합니다. Active Memory Plugin의 경우 메모리 슬롯이 `memory-core`로 재설정됩니다. -`--keep-config`는 더 이상 권장되지 않는 `--keep-files`의 alias로 지원됩니다. +`--keep-config`는 `--keep-files`의 더 이상 권장되지 않는 별칭으로 지원됩니다. ### 업데이트 @@ -308,29 +308,29 @@ openclaw plugins update @openclaw/voice-call openclaw plugins update openclaw-codex-app-server --dangerously-force-unsafe-install ``` -업데이트는 관리형 Plugin 인덱스에서 추적되는 Plugin 설치와 `hooks.internal.installs`에서 추적되는 hook-pack 설치에 적용됩니다. +업데이트는 관리되는 Plugin 인덱스의 추적된 Plugin 설치와 `hooks.internal.installs`의 추적된 훅 팩 설치에 적용됩니다. - - Plugin id를 전달하면 OpenClaw는 해당 Plugin에 기록된 설치 spec을 재사용합니다. 즉 이전에 저장된 `@beta` 같은 dist-tag와 정확히 고정된 버전이 이후 `update ` 실행에서도 계속 사용됩니다. + + Plugin ID를 전달하면 OpenClaw는 해당 Plugin에 기록된 설치 사양을 재사용합니다. 즉, `@beta` 같은 이전에 저장된 dist-tag와 정확히 고정된 버전이 이후 `update ` 실행에서도 계속 사용됩니다. - npm 설치의 경우 dist-tag 또는 정확한 버전이 포함된 명시적 npm package spec도 전달할 수 있습니다. OpenClaw는 해당 package 이름을 추적 중인 Plugin record로 다시 해석하고, 설치된 해당 Plugin을 업데이트한 뒤, 향후 id 기반 업데이트를 위해 새 npm spec을 기록합니다. + npm 설치의 경우 dist-tag 또는 정확한 버전이 포함된 명시적인 npm 패키지 사양을 전달할 수도 있습니다. OpenClaw는 해당 패키지 이름을 추적된 Plugin 레코드로 다시 해석하고, 설치된 해당 Plugin을 업데이트하며, 향후 ID 기반 업데이트를 위해 새 npm 사양을 기록합니다. - 버전이나 tag 없이 npm package 이름을 전달해도 추적 중인 Plugin record로 다시 해석됩니다. Plugin이 정확한 버전에 고정되어 있었고 registry의 기본 release line으로 되돌리고 싶을 때 이를 사용하세요. + 버전 또는 태그 없이 npm 패키지 이름을 전달해도 추적된 Plugin 레코드로 다시 해석됩니다. Plugin이 정확한 버전으로 고정되어 있었고 이를 레지스트리의 기본 릴리스 라인으로 되돌리고 싶을 때 사용하세요. - - `openclaw plugins update`는 새 spec을 전달하지 않는 한 추적 중인 Plugin spec을 재사용합니다. `openclaw update`는 추가로 활성 OpenClaw 업데이트 channel을 알고 있습니다. beta channel에서는 default-line npm 및 ClawHub Plugin record가 먼저 `@beta`를 시도한 뒤, Plugin beta release가 없으면 기록된 default/latest spec으로 fallback합니다. 정확한 버전과 명시적 tag는 해당 selector에 계속 고정됩니다. + + `openclaw plugins update`는 새 사양을 전달하지 않는 한 추적된 Plugin 사양을 재사용합니다. `openclaw update`는 추가로 활성 OpenClaw 업데이트 채널을 알고 있습니다. 베타 채널에서는 기본 라인의 npm 및 ClawHub Plugin 레코드가 먼저 `@beta`를 시도한 다음, Plugin 베타 릴리스가 없으면 기록된 default/latest 사양으로 폴백합니다. 정확한 버전과 명시적 태그는 해당 선택자에 계속 고정됩니다. - - live npm 업데이트 전에 OpenClaw는 설치된 package version을 npm registry metadata와 대조합니다. 설치된 version과 기록된 artifact identity가 이미 확인된 target과 일치하면 다운로드, 재설치 또는 `openclaw.json` 재작성 없이 업데이트를 건너뜁니다. + + 라이브 npm 업데이트 전에 OpenClaw는 설치된 패키지 버전을 npm 레지스트리 메타데이터와 비교합니다. 설치된 버전과 기록된 아티팩트 ID가 이미 확인된 대상과 일치하면 다운로드, 재설치 또는 `openclaw.json` 재작성 없이 업데이트를 건너뜁니다. - 저장된 integrity hash가 있고 가져온 artifact hash가 변경되면 OpenClaw는 이를 npm artifact drift로 처리합니다. 대화형 `openclaw plugins update` 명령은 예상 hash와 실제 hash를 출력하고 계속하기 전에 확인을 요청합니다. 비대화형 업데이트 helper는 호출자가 명시적 continuation policy를 제공하지 않는 한 fail closed합니다. + 저장된 무결성 해시가 있고 가져온 아티팩트 해시가 변경되면 OpenClaw는 이를 npm 아티팩트 드리프트로 처리합니다. 대화형 `openclaw plugins update` 명령은 예상 해시와 실제 해시를 출력하고 진행하기 전에 확인을 요청합니다. 비대화형 업데이트 헬퍼는 호출자가 명시적인 계속 정책을 제공하지 않는 한 닫힌 상태로 실패합니다. - - `--dangerously-force-unsafe-install`는 Plugin 업데이트 중 내장 dangerous-code scan의 false positive에 대한 break-glass override로 `plugins update`에서도 사용할 수 있습니다. 그래도 Plugin `before_install` 정책 차단이나 scan-failure 차단은 우회하지 않으며, hook-pack 업데이트가 아닌 Plugin 업데이트에만 적용됩니다. + + `--dangerously-force-unsafe-install`은 Plugin 업데이트 중 내장 위험 코드 스캔의 오탐에 대한 비상 우회로 `plugins update`에서도 사용할 수 있습니다. 그래도 Plugin `before_install` 정책 차단 또는 스캔 실패 차단은 우회하지 않으며, 훅 팩 업데이트가 아니라 Plugin 업데이트에만 적용됩니다. @@ -342,21 +342,21 @@ openclaw plugins inspect --runtime openclaw plugins inspect --json ``` -Inspect는 기본적으로 Plugin 런타임을 import하지 않고 identity, load status, source, manifest capabilities, policy flags, diagnostics, install metadata, bundle capabilities, 감지된 MCP 또는 LSP server 지원을 표시합니다. `--runtime`를 추가하면 Plugin 모듈을 로드하고 등록된 hook, tool, command, service, gateway method 및 HTTP route를 포함합니다. 런타임 검사는 누락된 Plugin 의존성을 직접 보고합니다. 설치와 복구는 `openclaw plugins install`, `openclaw plugins update`, `openclaw doctor --fix`에 남아 있습니다. +검사는 기본적으로 Plugin 런타임을 가져오지 않고 ID, 로드 상태, 소스, 매니페스트 기능, 정책 플래그, 진단, 설치 메타데이터, 번들 기능 및 감지된 MCP 또는 LSP 서버 지원을 표시합니다. Plugin 모듈을 로드하고 등록된 훅, 도구, 명령, 서비스, Gateway 메서드 및 HTTP 라우트를 포함하려면 `--runtime`을 추가하세요. 런타임 검사는 누락된 Plugin 의존성을 직접 보고합니다. 설치와 복구는 `openclaw plugins install`, `openclaw plugins update`, `openclaw doctor --fix`에 남아 있습니다. -Plugin 소유 CLI 명령은 루트 `openclaw` command group으로 설치됩니다. `inspect --runtime`이 `cliCommands` 아래에 command를 표시한 뒤에는 `openclaw ...`로 실행하세요. 예를 들어 `demo-git`를 등록하는 Plugin은 `openclaw demo-git ping`으로 검증할 수 있습니다. +Plugin 소유 CLI 명령은 루트 `openclaw` 명령 그룹으로 설치됩니다. `inspect --runtime`이 `cliCommands` 아래에 명령을 표시한 뒤에는 `openclaw ...`로 실행하세요. 예를 들어 `demo-git`를 등록하는 Plugin은 `openclaw demo-git ping`으로 확인할 수 있습니다. 각 Plugin은 런타임에 실제로 등록하는 항목에 따라 분류됩니다. -- **plain-capability** — 하나의 capability type(예: provider 전용 Plugin) -- **hybrid-capability** — 여러 capability type(예: text + speech + images) -- **hook-only** — hook만 있고 capabilities 또는 surface는 없음 -- **non-capability** — tools/commands/services는 있지만 capabilities는 없음 +- **plain-capability** — 하나의 기능 유형(예: provider 전용 Plugin) +- **hybrid-capability** — 여러 기능 유형(예: 텍스트 + 음성 + 이미지) +- **hook-only** — 훅만 있고 기능 또는 표면 없음 +- **non-capability** — 도구/명령/서비스가 있지만 기능 없음 -capability model에 대한 자세한 내용은 [Plugin shapes](/ko/plugins/architecture#plugin-shapes)를 참조하세요. +기능 모델에 대한 자세한 내용은 [Plugin 형태](/ko/plugins/architecture#plugin-shapes)를 참조하세요. -`--json` flag는 스크립팅과 감사에 적합한 머신이 읽을 수 있는 report를 출력합니다. `inspect --all`은 shape, capability kinds, compatibility notices, bundle capabilities 및 hook summary 열이 포함된 fleet-wide table을 렌더링합니다. `info`는 `inspect`의 alias입니다. +`--json` 플래그는 스크립팅 및 감사에 적합한 기계 판독 가능 보고서를 출력합니다. `inspect --all`은 형태, 기능 종류, 호환성 알림, 번들 기능 및 훅 요약 열이 있는 전체 플릿 테이블을 렌더링합니다. `info`는 `inspect`의 별칭입니다. ### Doctor @@ -365,13 +365,13 @@ capability model에 대한 자세한 내용은 [Plugin shapes](/ko/plugins/archi openclaw plugins doctor ``` -`doctor`는 Plugin load error, manifest/discovery diagnostics, compatibility notices를 보고합니다. 모든 것이 깨끗하면 `No plugin issues detected.`를 출력합니다. +`doctor`는 Plugin 로드 오류, 매니페스트/발견 진단 및 호환성 알림을 보고합니다. 모든 것이 깨끗하면 `No plugin issues detected.`를 출력합니다. -구성된 Plugin이 디스크에 있지만 loader의 path-safety checks에 의해 차단된 경우, config validation은 Plugin 항목을 유지하고 이를 `present but blocked`로 보고합니다. `plugins.entries.` 또는 `plugins.allow` config를 제거하는 대신, path ownership 또는 world-writable permissions 같은 앞선 blocked-plugin diagnostic을 수정하세요. +구성된 Plugin이 디스크에 있지만 로더의 경로 안전 검사에 의해 차단된 경우, 구성 검증은 Plugin 항목을 유지하고 이를 `present but blocked`로 보고합니다. `plugins.entries.` 또는 `plugins.allow` 구성을 제거하지 말고, 경로 소유권 또는 전역 쓰기 가능 권한 같은 앞선 차단된 Plugin 진단을 수정하세요. -`register`/`activate` export 누락 같은 module-shape failure의 경우 `OPENCLAW_PLUGIN_LOAD_DEBUG=1`로 다시 실행하면 diagnostic output에 간결한 export-shape summary가 포함됩니다. +`register`/`activate` 내보내기 누락 같은 모듈 형태 실패의 경우, 진단 출력에 간결한 내보내기 형태 요약을 포함하려면 `OPENCLAW_PLUGIN_LOAD_DEBUG=1`로 다시 실행하세요. -### Registry +### 레지스트리 ```bash openclaw plugins registry @@ -379,12 +379,12 @@ openclaw plugins registry --refresh openclaw plugins registry --json ``` -로컬 Plugin registry는 설치된 Plugin identity, enablement, source metadata 및 contribution ownership에 대한 OpenClaw의 영속화된 cold read model입니다. 일반 startup, provider owner lookup, channel setup classification 및 Plugin inventory는 Plugin 런타임 모듈을 import하지 않고 이를 읽을 수 있습니다. +로컬 Plugin 레지스트리는 설치된 Plugin ID, 활성화 상태, 소스 메타데이터 및 기여 소유권에 대한 OpenClaw의 영구 저장된 콜드 읽기 모델입니다. 일반 시작, provider 소유자 조회, 채널 설정 분류 및 Plugin 인벤터리는 Plugin 런타임 모듈을 가져오지 않고 이를 읽을 수 있습니다. -`plugins registry`를 사용하여 지속된 레지스트리가 있는지, 최신인지, 오래되었는지 검사합니다. `--refresh`를 사용하면 지속된 Plugin 인덱스, 구성 정책, 매니페스트/패키지 메타데이터에서 이를 다시 빌드합니다. 이는 복구 경로이며, 런타임 활성화 경로가 아닙니다. +`plugins registry`를 사용하여 영구 저장된 레지스트리가 있는지, 최신 상태인지, 오래되었는지 검사하세요. `--refresh`를 사용하여 영구 저장된 Plugin 인덱스, 구성 정책, 매니페스트/패키지 메타데이터에서 다시 빌드하세요. 이는 복구 경로이며, 런타임 활성화 경로가 아닙니다. -`OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY=1`은 레지스트리 읽기 실패를 위한 더 이상 권장되지 않는 비상 호환성 스위치입니다. `plugins registry --refresh` 또는 `openclaw doctor --fix`를 우선 사용하세요. env 폴백은 마이그레이션이 배포되는 동안 긴급 시작 복구에만 사용해야 합니다. +`OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY=1`은 레지스트리 읽기 실패에 대한 더 이상 권장되지 않는 비상 호환성 스위치입니다. `plugins registry --refresh` 또는 `openclaw doctor --fix`를 사용하는 것이 좋습니다. 환경 변수 대체 방식은 마이그레이션이 배포되는 동안 긴급 시작 복구용으로만 사용하세요. ### 마켓플레이스 @@ -394,7 +394,7 @@ openclaw plugins marketplace list openclaw plugins marketplace list --json ``` -마켓플레이스 목록은 로컬 마켓플레이스 경로, `marketplace.json` 경로, `owner/repo` 같은 GitHub 축약형, GitHub 리포지토리 URL 또는 git URL을 허용합니다. `--json`은 확인된 소스 레이블과 파싱된 마켓플레이스 매니페스트 및 Plugin 항목을 출력합니다. +마켓플레이스 목록은 로컬 마켓플레이스 경로, `marketplace.json` 경로, `owner/repo` 같은 GitHub 축약 표기, GitHub 리포지토리 URL 또는 git URL을 허용합니다. `--json`은 확인된 소스 레이블과 파싱된 마켓플레이스 매니페스트 및 Plugin 항목을 출력합니다. ## 관련 항목 diff --git a/docs/ko/cli/proxy.md b/docs/ko/cli/proxy.md index dbbf5af22..576a51ce5 100644 --- a/docs/ko/cli/proxy.md +++ b/docs/ko/cli/proxy.md @@ -1,29 +1,24 @@ --- read_when: - 배포 전에 운영자가 관리하는 프록시 라우팅을 검증해야 합니다 - - 디버깅을 위해 OpenClaw 전송 트래픽을 로컬에서 캡처해야 합니다 - - 디버그 프록시 세션, 블롭 또는 내장 쿼리 프리셋을 검사하려는 경우 -summary: '`openclaw proxy`에 대한 CLI 참조. 운영자 관리 프록시 검증 및 로컬 디버그 프록시 캡처 검사기 포함' + - 디버깅을 위해 로컬에서 OpenClaw 전송 트래픽을 캡처해야 합니다 + - 디버그 프록시 세션, 블롭 또는 기본 제공 쿼리 프리셋을 검사하려는 경우 +summary: '`openclaw proxy`에 대한 CLI 참조, 운영자 관리 프록시 검증 및 로컬 디버그 프록시 캡처 검사기 포함' title: 프록시 x-i18n: - generated_at: "2026-05-01T06:23:21Z" + generated_at: "2026-05-04T06:23:07Z" model: gpt-5.5 provider: openai - source_hash: e0820de861bfe1ec14e0c1624d636d6474b5fedd317e3ba1baaa61f6530e06e9 + source_hash: 9589bedafb97c31bcb6536a04307cd0c6550e1f307693bd4401785d79f34a1eb source_path: cli/proxy.md workflow: 16 --- # `openclaw proxy` -운영자 관리형 프록시 라우팅을 검증하거나 로컬 명시적 디버그 프록시를 실행하고 -캡처된 트래픽을 검사합니다. +운영자가 관리하는 프록시 라우팅을 검증하거나, 로컬 명시적 디버그 프록시를 실행하고 캡처된 트래픽을 검사합니다. -OpenClaw 프록시 라우팅을 활성화하기 전에 `validate`를 사용해 운영자 관리형 -포워드 프록시를 사전 점검하세요. 다른 명령은 전송 수준 조사를 위한 디버깅 -도구입니다. 로컬 프록시를 시작하고, 캡처를 활성화한 상태로 자식 명령을 실행하고, -캡처 세션을 나열하고, 일반적인 트래픽 패턴을 쿼리하고, 캡처된 블롭을 읽고, -로컬 캡처 데이터를 삭제할 수 있습니다. +OpenClaw 프록시 라우팅을 활성화하기 전에 운영자가 관리하는 전달 프록시를 사전 점검하려면 `validate`를 사용하세요. 다른 명령은 전송 수준 조사를 위한 디버깅 도구입니다. 로컬 프록시를 시작하고, 캡처를 활성화한 상태로 자식 명령을 실행하고, 캡처 세션을 나열하고, 일반적인 트래픽 패턴을 쿼리하고, 캡처된 blob을 읽고, 로컬 캡처 데이터를 삭제할 수 있습니다. ## 명령 @@ -40,24 +35,17 @@ openclaw proxy purge ## 검증 -`openclaw proxy validate`는 `--proxy-url`, 구성 또는 `OPENCLAW_PROXY_URL`에서 -유효한 운영자 관리형 프록시 URL을 확인합니다. 프록시가 활성화 및 구성되어 있지 -않으면 구성 문제를 보고합니다. 구성을 변경하기 전에 일회성 사전 점검에는 -`--proxy-url`을 사용하세요. 기본적으로 공용 대상이 프록시를 통해 성공하는지, -그리고 프록시가 임시 루프백 카나리아에 도달할 수 없는지 검증합니다. -사용자 지정 거부 대상은 실패 시 차단 방식입니다. 배포별 거부 신호를 별도로 -검증할 수 없는 한 HTTP 응답과 모호한 전송 실패가 모두 실패로 처리됩니다. +`openclaw proxy validate`는 `--proxy-url`, 구성 또는 `OPENCLAW_PROXY_URL`에서 적용되는 운영자 관리 프록시 URL을 확인합니다. 활성화되고 구성된 프록시가 없으면 구성 문제를 보고합니다. 구성을 변경하기 전에 일회성 사전 점검을 하려면 `--proxy-url`을 사용하세요. 기본적으로 공용 대상이 프록시를 통해 성공하는지, 프록시가 임시 루프백 카나리에 접근할 수 없는지 확인합니다. 사용자 지정 거부 대상은 실패 시 닫힘 방식입니다. 배포별 거부 신호를 별도로 확인할 수 없는 한 HTTP 응답과 모호한 전송 실패는 모두 실패로 처리됩니다. 옵션: - `--json`: 기계가 읽을 수 있는 JSON을 출력합니다. - `--proxy-url `: 구성 또는 환경 변수 대신 이 프록시 URL을 검증합니다. -- `--allowed-url `: 프록시를 통해 성공해야 하는 대상을 추가합니다. 여러 대상을 확인하려면 반복합니다. -- `--denied-url `: 프록시에서 차단해야 하는 대상을 추가합니다. 여러 대상을 확인하려면 반복합니다. -- `--timeout-ms `: 요청당 제한 시간(밀리초)입니다. +- `--allowed-url `: 프록시를 통해 성공해야 하는 대상을 추가합니다. 여러 대상을 확인하려면 반복해서 지정하세요. +- `--denied-url `: 프록시에서 차단해야 하는 대상을 추가합니다. 여러 대상을 확인하려면 반복해서 지정하세요. +- `--timeout-ms `: 요청별 제한 시간(밀리초)입니다. -배포 지침과 거부 의미 체계는 [네트워크 프록시](/ko/security/network-proxy)를 -참조하세요. +배포 지침과 거부 의미 체계는 [네트워크 프록시](/ko/security/network-proxy)를 참조하세요. ## 쿼리 프리셋 @@ -70,14 +58,15 @@ openclaw proxy purge - `missing-ack` - `error-bursts` -## 참고 사항 +## 참고 -- `--host`가 설정되지 않으면 `start`는 기본적으로 `127.0.0.1`을 사용합니다. +- `start`는 `--host`가 설정되지 않은 경우 기본값으로 `127.0.0.1`을 사용합니다. - `run`은 로컬 디버그 프록시를 시작한 다음 `--` 뒤의 명령을 실행합니다. +- 디버그 프록시의 직접 업스트림 전달은 진단을 위해 업스트림 소켓을 엽니다. OpenClaw 관리형 프록시 모드가 활성화되면 프록시 요청 및 CONNECT 터널에 대한 직접 전달은 기본적으로 비활성화됩니다. 승인된 로컬 진단에만 `OPENCLAW_DEBUG_PROXY_ALLOW_DIRECT_CONNECT_WITH_MANAGED_PROXY=1`을 설정하세요. - `validate`는 프록시 구성 또는 대상 확인이 실패하면 코드 1로 종료됩니다. - 캡처는 로컬 디버깅 데이터입니다. 완료되면 `openclaw proxy purge`를 사용하세요. -## 관련 문서 +## 관련 항목 - [CLI 참조](/ko/cli) - [네트워크 프록시](/ko/security/network-proxy) diff --git a/docs/ko/cli/sessions.md b/docs/ko/cli/sessions.md index 778a67086..4350cfd40 100644 --- a/docs/ko/cli/sessions.md +++ b/docs/ko/cli/sessions.md @@ -1,13 +1,13 @@ --- read_when: - - 저장된 세션 목록을 보고 최근 활동을 확인하려는 경우 -summary: '`openclaw sessions`의 CLI 참조(저장된 세션 목록 + 사용법)' + - 저장된 세션을 나열하고 최근 활동을 확인하려는 경우 +summary: '`openclaw sessions`용 CLI 참조(저장된 세션 목록 + 사용법)' title: 세션 x-i18n: - generated_at: "2026-05-02T20:46:34Z" + generated_at: "2026-05-04T06:22:57Z" model: gpt-5.5 provider: openai - source_hash: 5c9ec3ca55f7c5b6217b481e9da62f5416df73e69405a0dc15e77d2afeac723f + source_hash: 8dc90344f40c53513bd6db3696bc709279155f26e7c3b6ea27e81a07a2f9f15e source_path: cli/sessions.md workflow: 16 --- @@ -16,12 +16,17 @@ x-i18n: 저장된 대화 세션을 나열합니다. -세션 목록은 채널/제공자의 활성 상태 확인이 아닙니다. 세션 저장소에 유지된 -대화 행을 보여줍니다. 조용한 Discord, Slack, Telegram 또는 -다른 채널은 메시지가 처리될 때까지 새 세션 행을 만들지 않고도 -성공적으로 다시 연결될 수 있습니다. 실시간 채널 연결이 필요할 때는 -`openclaw channels status --probe`, `openclaw status --deep` 또는 -`openclaw health --verbose`를 사용하세요. +세션 목록은 채널/Provider 활성 상태 확인이 아닙니다. 세션 저장소에 유지된 +대화 행을 보여줍니다. 조용한 Discord, Slack, Telegram 또는 기타 채널은 +메시지가 처리되어 새 세션 행이 생성되기 전까지도 성공적으로 다시 연결될 수 +있습니다. 실시간 채널 연결이 필요할 때는 `openclaw channels status --probe`, +`openclaw status --deep` 또는 `openclaw health --verbose`를 사용하세요. + +Gateway `sessions.list` 응답은 기본적으로 제한되어 있으므로, 크고 오래 유지되는 +저장소가 Gateway 이벤트 루프를 독점할 수 없습니다. RPC 클라이언트에서 다른 결과 +범위가 필요할 때는 명시적인 양수 `limit`를 전달하세요. 호출자가 더 많은 행이 +있다는 것을 표시해야 하는 경우 응답에는 `totalCount`, `limitApplied`, +`hasMore`가 포함됩니다. ```bash openclaw sessions @@ -36,28 +41,22 @@ openclaw sessions --json - 기본값: 구성된 기본 에이전트 저장소 - `--verbose`: 자세한 로깅 -- `--agent `: 구성된 에이전트 저장소 하나 +- `--agent `: 구성된 단일 에이전트 저장소 - `--all-agents`: 구성된 모든 에이전트 저장소 집계 - `--store `: 명시적 저장소 경로(`--agent` 또는 `--all-agents`와 함께 사용할 수 없음) -저장된 세션의 트래젝터리 번들을 내보냅니다. +저장된 세션의 trajectory 번들을 내보냅니다. ```bash openclaw sessions export-trajectory --session-key "agent:main:telegram:direct:123" --workspace . openclaw sessions export-trajectory --session-key "agent:main:telegram:direct:123" --output bug-123 --json ``` -이 명령 경로는 소유자가 실행 요청을 승인한 뒤 `/export-trajectory` 슬래시 명령에서 -사용됩니다. 출력 디렉터리는 항상 선택한 워크스페이스 아래의 -`.openclaw/trajectory-exports/` 내부로 해석됩니다. +이 명령 경로는 소유자가 exec 요청을 승인한 뒤 `/export-trajectory` 슬래시 명령에서 사용됩니다. 출력 디렉터리는 항상 선택한 작업 영역 아래의 `.openclaw/trajectory-exports/` 안으로 해석됩니다. -`openclaw sessions --all-agents`는 구성된 에이전트 저장소를 읽습니다. Gateway 및 ACP -세션 검색은 더 넓습니다. 기본 `agents/` 루트 또는 템플릿화된 `session.store` 루트 -아래에서 발견된 디스크 전용 저장소도 포함합니다. 이렇게 검색된 저장소는 -에이전트 루트 내부의 일반 `sessions.json` 파일로 해석되어야 하며, -심볼릭 링크와 루트 밖 경로는 건너뜁니다. +`openclaw sessions --all-agents`는 구성된 에이전트 저장소를 읽습니다. Gateway와 ACP 세션 검색은 더 넓습니다. 기본 `agents/` 루트 또는 템플릿화된 `session.store` 루트 아래에서 찾은 디스크 전용 저장소도 포함합니다. 이러한 발견된 저장소는 에이전트 루트 내부의 일반 `sessions.json` 파일로 해석되어야 하며, 심볼릭 링크와 루트 밖 경로는 건너뜁니다. -JSON 예: +JSON 예시: `openclaw sessions --all-agents --json`: @@ -78,9 +77,9 @@ JSON 예: } ``` -## 정리 유지 관리 +## 정리 유지관리 -다음 쓰기 주기를 기다리지 않고 지금 유지 관리를 실행합니다. +다음 쓰기 주기를 기다리지 않고 지금 유지관리를 실행합니다. ```bash openclaw sessions cleanup --dry-run @@ -93,21 +92,19 @@ openclaw sessions cleanup --json `openclaw sessions cleanup`은 구성의 `session.maintenance` 설정을 사용합니다. -- 범위 참고: `openclaw sessions cleanup`은 세션 저장소, 트랜스크립트, 트래젝터리 사이드카를 유지 관리합니다. `cron/runs/.jsonl` Cron 실행 로그는 정리하지 않습니다. 이 로그는 [Cron 구성](/ko/automation/cron-jobs#configuration)의 `cron.runLog.maxBytes` 및 `cron.runLog.keepLines`로 관리되며 [Cron 유지 관리](/ko/automation/cron-jobs#maintenance)에 설명되어 있습니다. +- 범위 참고: `openclaw sessions cleanup`은 세션 저장소, transcript, trajectory sidecar를 유지관리합니다. Cron 실행 로그(`cron/runs/.jsonl`)는 정리하지 않습니다. 이 로그는 [Cron 구성](/ko/automation/cron-jobs#configuration)의 `cron.runLog.maxBytes`와 `cron.runLog.keepLines`로 관리되며 [Cron 유지관리](/ko/automation/cron-jobs#maintenance)에 설명되어 있습니다. -- `--dry-run`: 쓰기 없이 몇 개 항목이 정리/상한 처리될지 미리 봅니다. - - 텍스트 모드에서 드라이런은 세션별 작업 표(`Action`, `Key`, `Age`, `Model`, `Flags`)를 출력하므로 무엇이 유지되고 제거될지 확인할 수 있습니다. -- `--enforce`: `session.maintenance.mode`가 `warn`인 경우에도 유지 관리를 적용합니다. -- `--fix-missing`: 아직 일반적으로 나이/개수 기준에 걸리지 않더라도 트랜스크립트 파일이 누락된 항목을 제거합니다. -- `--active-key `: 특정 활성 키를 디스크 예산 기반 제거에서 보호합니다. 그룹 세션 및 스레드 범위 채팅 세션 같은 지속 외부 대화 포인터도 나이/개수/디스크 예산 유지 관리에서 보존됩니다. -- `--agent `: 구성된 에이전트 저장소 하나에 대해 정리를 실행합니다. +- `--dry-run`: 쓰기 없이 정리/제한될 항목 수를 미리 봅니다. + - 텍스트 모드에서 dry-run은 세션별 작업 표(`Action`, `Key`, `Age`, `Model`, `Flags`)를 출력하므로 무엇이 유지되고 무엇이 제거될지 확인할 수 있습니다. +- `--enforce`: `session.maintenance.mode`가 `warn`이어도 유지관리를 적용합니다. +- `--fix-missing`: transcript 파일이 없는 항목을 제거합니다. 아직 일반적인 age/count 기준에 따라 제거되지 않을 항목도 포함됩니다. +- `--active-key `: 특정 활성 키를 디스크 예산 기반 제거에서 보호합니다. 그룹 세션과 스레드 범위 채팅 세션 같은 내구성 있는 외부 대화 포인터도 age/count/disk-budget 유지관리에서 보존됩니다. +- `--agent `: 구성된 단일 에이전트 저장소에 대해 정리를 실행합니다. - `--all-agents`: 구성된 모든 에이전트 저장소에 대해 정리를 실행합니다. -- `--store `: 특정 `sessions.json` 파일에 대해 실행합니다. -- `--json`: JSON 요약을 출력합니다. `--all-agents`와 함께 사용하면 출력에 저장소별 요약이 포함됩니다. +- `--store `: 특정 `sessions.json` 파일을 대상으로 실행합니다. +- `--json`: JSON 요약을 출력합니다. `--all-agents`를 사용하면 출력에 저장소별 요약이 하나씩 포함됩니다. -Gateway에 연결할 수 있으면, 구성된 에이전트 저장소에 대한 비드라이런 정리는 -Gateway를 통해 전송되어 런타임 트래픽과 동일한 세션 저장소 작성기를 공유합니다. -저장소 파일의 명시적 오프라인 복구에는 `--store `를 사용하세요. +Gateway에 연결할 수 있으면, 구성된 에이전트 저장소의 non-dry-run 정리는 Gateway를 통해 전송되어 런타임 트래픽과 동일한 세션 저장소 writer를 공유합니다. 저장소 파일의 명시적 오프라인 복구에는 `--store `를 사용하세요. `openclaw sessions cleanup --all-agents --dry-run --json`: diff --git a/docs/ko/concepts/mantis.md b/docs/ko/concepts/mantis.md index 7d1c42685..985761b21 100644 --- a/docs/ko/concepts/mantis.md +++ b/docs/ko/concepts/mantis.md @@ -1,73 +1,65 @@ --- read_when: - - OpenClaw 버그에 대한 실시간 시각적 QA 빌드 또는 실행 - - 풀 리퀘스트에 대한 전후 검증 추가하기 - - Discord, Slack, WhatsApp 또는 기타 라이브 전송 시나리오 추가 + - OpenClaw 버그를 위한 라이브 시각적 QA 빌드 또는 실행 + - 풀 리퀘스트에 대한 전후 검증 추가 + - Discord, Slack, WhatsApp 또는 기타 실시간 전송 시나리오 추가 - 스크린샷, 브라우저 자동화 또는 VNC 액세스가 필요한 QA 실행 디버깅 -summary: Mantis는 실시간 전송 수단에서 OpenClaw 버그를 재현하고, 전후 증거를 캡처하며, 아티팩트를 풀 리퀘스트에 첨부하기 위한 시각적 엔드투엔드 검증 시스템입니다. +summary: Mantis는 실제 전송 채널에서 OpenClaw 버그를 재현하고, 수정 전후 증거를 캡처하며, 아티팩트를 PR에 첨부하기 위한 시각적 엔드 투 엔드 검증 시스템입니다. title: 사마귀 x-i18n: - generated_at: "2026-05-04T02:22:55Z" + generated_at: "2026-05-04T06:23:13Z" model: gpt-5.5 provider: openai - source_hash: 5a86ab4bc876d1c53ada1c30580034165f028194a072f559eb54a898a369211d + source_hash: 9d3f3fa3db111b1b5c85f8efeccd749fbd5885cee6b7843ca4c8d049acfd9164 source_path: concepts/mantis.md workflow: 16 --- -Mantis는 실제 runtime, 실제 transport, 그리고 눈에 보이는 증거가 필요한 버그를 위한 OpenClaw 종단 간 검증 시스템입니다. 알려진 -나쁜 ref에 대해 시나리오를 실행하고, 증거를 캡처한 뒤, candidate ref에 대해 -같은 시나리오를 실행하고, maintainer가 PR 또는 로컬 명령에서 검사할 수 있는 -artifact로 비교 결과를 게시합니다. +Mantis는 실제 런타임, 실제 전송 수단, 그리고 눈에 보이는 증거가 필요한 버그를 위한 OpenClaw 엔드투엔드 검증 시스템입니다. 알려진 불량 ref에 대해 시나리오를 실행하고, 증거를 캡처한 다음, 후보 ref에 대해 같은 시나리오를 실행하고, maintainer가 PR 또는 로컬 명령에서 검사할 수 있는 아티팩트로 비교 결과를 게시합니다. -Mantis는 Discord부터 시작합니다. Discord는 가치가 높은 첫 lane을 제공하기 때문입니다: -실제 bot auth, 실제 guild channel, reaction, thread, native command, 그리고 -사람이 transport가 보여 준 내용을 시각적으로 확인할 수 있는 browser UI입니다. +Mantis는 Discord에서 시작합니다. Discord는 실제 봇 인증, 실제 길드 채널, 반응, 스레드, 네이티브 명령, 그리고 사람이 전송 수단에 표시된 내용을 시각적으로 확인할 수 있는 브라우저 UI라는 가치 높은 첫 번째 레인을 제공하기 때문입니다. ## 목표 -- GitHub issue 또는 PR의 버그를 사용자가 보는 것과 같은 transport 형태로 재현합니다. -- fix를 적용하기 전에 baseline ref에서 **before** artifact를 캡처합니다. -- fix를 적용한 뒤 candidate ref에서 **after** artifact를 캡처합니다. -- 가능하면 Discord REST reaction 읽기 또는 channel transcript 확인 같은 결정적 oracle을 사용합니다. -- 버그에 보이는 UI 표면이 있을 때 screenshot을 캡처합니다. -- agent가 제어하는 CLI에서 로컬로, 그리고 GitHub에서 원격으로 실행합니다. -- login, browser automation, provider auth가 막혔을 때 VNC rescue에 필요한 충분한 machine state를 보존합니다. -- 실행이 차단되었거나, 수동 VNC 도움이 필요하거나, 완료되었을 때 operator Discord channel에 간결한 status를 게시합니다. +- 사용자가 보는 것과 같은 전송 형태로 GitHub 이슈 또는 PR의 버그를 재현합니다. +- 수정 적용 전에 baseline ref에서 **before** 아티팩트를 캡처합니다. +- 수정 적용 후 candidate ref에서 **after** 아티팩트를 캡처합니다. +- 가능한 경우 Discord REST 반응 읽기 또는 채널 transcript 확인 같은 결정적 oracle을 사용합니다. +- 버그에 눈에 보이는 UI 표면이 있는 경우 스크린샷을 캡처합니다. +- 에이전트가 제어하는 CLI에서 로컬로, 그리고 GitHub에서 원격으로 실행합니다. +- 로그인, 브라우저 자동화, provider 인증이 멈췄을 때 VNC 복구에 충분한 머신 상태를 보존합니다. +- 실행이 차단되었거나, 수동 VNC 도움이 필요하거나, 완료되었을 때 operator Discord 채널에 간결한 상태를 게시합니다. ## 비목표 -- Mantis는 unit test를 대체하지 않습니다. Mantis 실행은 보통 fix가 이해된 뒤 더 작은 regression test가 되어야 합니다. -- Mantis는 일반적인 빠른 CI gate가 아닙니다. 더 느리고, live credential을 사용하며, - live environment가 중요한 버그를 위해 예약됩니다. -- Mantis는 정상 동작에 사람을 요구해서는 안 됩니다. 수동 VNC는 rescue path이지 happy path가 아닙니다. -- Mantis는 raw secret을 artifact, log, screenshot, Markdown report, PR comment에 저장하지 않습니다. +- Mantis는 단위 테스트를 대체하지 않습니다. Mantis 실행은 일반적으로 수정 사항을 이해한 뒤 더 작은 회귀 테스트가 되어야 합니다. +- Mantis는 일반적인 빠른 CI gate가 아닙니다. 더 느리고, live credentials를 사용하며, live 환경이 중요한 버그에만 사용됩니다. +- Mantis는 정상 동작에 사람이 필요해서는 안 됩니다. 수동 VNC는 복구 경로이지 정상 경로가 아닙니다. +- Mantis는 원시 secret을 아티팩트, 로그, 스크린샷, Markdown 보고서 또는 PR 댓글에 저장하지 않습니다. ## 소유권 -Mantis는 OpenClaw QA stack에 속합니다. +Mantis는 OpenClaw QA 스택에 속합니다. -- OpenClaw는 `pnpm openclaw qa mantis` 아래의 scenario runtime, transport adapter, evidence schema, local CLI를 소유합니다. -- QA Lab은 live transport harness 구성 요소, browser capture helper, artifact writer를 소유합니다. -- Crabbox는 remote VM이 필요할 때 warmed Linux machine을 소유합니다. -- GitHub Actions는 remote workflow entrypoint와 artifact retention을 소유합니다. -- ClawSweeper는 maintainer command parsing, workflow dispatch, 최종 PR comment 게시 같은 GitHub comment routing을 소유합니다. -- OpenClaw agent는 시나리오에 agentic setup, debugging, stuck-state reporting이 필요할 때 Codex를 통해 Mantis를 구동합니다. +- OpenClaw는 `pnpm openclaw qa mantis` 아래의 시나리오 런타임, 전송 adapter, 증거 schema, 로컬 CLI를 소유합니다. +- QA Lab은 live 전송 harness 구성 요소, 브라우저 캡처 helper, 아티팩트 writer를 소유합니다. +- Crabbox는 원격 VM이 필요할 때 예열된 Linux 머신을 소유합니다. +- GitHub Actions는 원격 workflow entrypoint와 아티팩트 보존을 소유합니다. +- ClawSweeper는 GitHub 댓글 routing을 소유합니다. maintainer 명령을 파싱하고, workflow를 dispatch하며, 최종 PR 댓글을 게시합니다. +- OpenClaw agent는 시나리오에 agentic 설정, 디버깅 또는 stuck-state 보고가 필요할 때 Codex를 통해 Mantis를 구동합니다. -이 경계는 transport knowledge를 OpenClaw에, machine scheduling을 -Crabbox에, maintainer workflow glue를 ClawSweeper에 유지합니다. +이 경계는 전송 지식을 OpenClaw에, 머신 scheduling을 Crabbox에, maintainer workflow glue를 ClawSweeper에 둡니다. -## 명령 형식 +## 명령 형태 -첫 로컬 명령은 Discord bot, guild, channel, message send, -reaction send, artifact path를 검증합니다: +첫 번째 로컬 명령은 Discord 봇, 길드, 채널, 메시지 전송, 반응 전송, 아티팩트 경로를 검증합니다. ```bash pnpm openclaw qa mantis discord-smoke \ --output-dir .artifacts/qa-e2e/mantis/discord-smoke ``` -로컬 before/after runner는 이 형식을 받습니다: +로컬 before 및 after runner는 이 형태를 받습니다. ```bash pnpm openclaw qa mantis run \ @@ -78,112 +70,122 @@ pnpm openclaw qa mantis run \ --output-dir .artifacts/qa-e2e/mantis/local-discord-status-reactions ``` -runner는 output directory 아래에 detached baseline 및 candidate worktree를 만들고, -dependency를 설치하고, 각 ref를 build하고, `--allow-failures`로 시나리오를 실행한 뒤 -`baseline/`, `candidate/`, `comparison.json`, `mantis-report.md`를 씁니다. 첫 Discord 시나리오에서 성공적인 검증은 -baseline status가 `fail`이고 candidate status가 `pass`임을 의미합니다. +runner는 output 디렉터리 아래에 분리된 baseline 및 candidate worktree를 만들고, dependencies를 설치하고, 각 ref를 build하고, `--allow-failures`로 시나리오를 실행한 다음 `baseline/`, `candidate/`, `comparison.json`, `mantis-report.md`를 작성합니다. 첫 번째 Discord 시나리오에서 성공적인 검증은 baseline status가 `fail`이고 candidate status가 `pass`임을 의미합니다. -첫 VM/browser primitive는 desktop smoke입니다: +첫 번째 VM/browser primitive는 desktop smoke입니다. ```bash pnpm openclaw qa mantis desktop-browser-smoke \ --output-dir .artifacts/qa-e2e/mantis/desktop-browser ``` -이 명령은 Crabbox desktop machine을 lease하거나 재사용하고, VNC session 안에서 보이는 browser를 시작하고, -desktop을 캡처하고, artifact를 local output directory로 다시 가져오며, -reconnect command를 report에 씁니다. 이 명령은 Hetzner provider를 기본값으로 사용합니다. -Mantis lane에서 작동하는 desktop/VNC coverage를 가진 첫 provider이기 때문입니다. -다른 Crabbox fleet에 대해 실행할 때는 `--provider`, `--crabbox-bin`, 또는 -`OPENCLAW_MANTIS_CRABBOX_PROVIDER`로 재정의하세요. +이 명령은 Crabbox desktop 머신을 임대하거나 재사용하고, VNC 세션 안에서 보이는 브라우저를 시작하고, desktop을 캡처하고, 아티팩트를 로컬 output 디렉터리로 가져오며, 보고서에 재연결 명령을 작성합니다. 이 명령은 Mantis 레인에서 desktop/VNC coverage가 동작하는 첫 provider이기 때문에 기본적으로 Hetzner provider를 사용합니다. 다른 Crabbox fleet에 대해 실행할 때는 `--provider`, `--crabbox-bin` 또는 `OPENCLAW_MANTIS_CRABBOX_PROVIDER`로 override합니다. 유용한 desktop smoke flag: -- `--lease-id ` 또는 `OPENCLAW_MANTIS_CRABBOX_LEASE_ID`는 warmed desktop을 재사용합니다. -- `--browser-url `은 보이는 browser에서 여는 page를 변경합니다. -- `--html-file `는 repo-local HTML artifact를 보이는 browser에서 렌더링합니다. Mantis는 실제 Crabbox desktop을 통해 생성된 Discord status-reaction timeline을 캡처하는 데 이것을 사용합니다. -- `--keep-lease` 또는 `OPENCLAW_MANTIS_KEEP_VM=1`은 새로 만든 passing lease를 VNC inspection을 위해 열린 상태로 유지합니다. 실패한 실행은 lease가 생성된 경우 operator가 reconnect할 수 있도록 기본적으로 lease를 유지합니다. -- `--class`, `--idle-timeout`, `--ttl`은 machine size와 lease lifetime을 조정합니다. +- `--lease-id ` 또는 `OPENCLAW_MANTIS_CRABBOX_LEASE_ID`는 예열된 desktop을 재사용합니다. +- `--browser-url `은 보이는 브라우저에서 열 페이지를 변경합니다. +- `--html-file `는 repo-local HTML 아티팩트를 보이는 브라우저에 렌더링합니다. Mantis는 이를 사용해 생성된 Discord status-reaction timeline을 실제 Crabbox desktop을 통해 캡처합니다. +- `--keep-lease` 또는 `OPENCLAW_MANTIS_KEEP_VM=1`은 새로 생성된 passing lease를 VNC 검사용으로 열어 둡니다. 실패한 실행은 operator가 다시 연결할 수 있도록 lease가 생성된 경우 기본적으로 lease를 유지합니다. +- `--class`, `--idle-timeout`, `--ttl`은 머신 크기와 lease 수명을 조정합니다. -GitHub smoke workflow는 `Mantis Discord Smoke`입니다. 첫 실제 시나리오의 before/after GitHub -workflow는 `Mantis Discord Status Reactions`입니다. 이 workflow는 다음을 받습니다: +첫 번째 전체 desktop 전송 primitive는 Slack desktop smoke입니다. -- `baseline_ref`: queued-only behavior를 재현할 것으로 예상되는 ref. -- `candidate_ref`: `queued -> thinking -> done`을 보여 줄 것으로 예상되는 ref. +```bash +pnpm openclaw qa mantis slack-desktop-smoke \ + --output-dir .artifacts/qa-e2e/mantis/slack-desktop \ + --gateway-setup \ + --scenario slack-canary \ + --keep-lease +``` -이 workflow는 workflow harness ref를 checkout하고, 별도의 baseline 및 candidate -worktree를 build하고, 각 worktree에 대해 `discord-status-reactions-tool-only`를 실행한 뒤, -`baseline/`, `candidate/`, `comparison.json`, `mantis-report.md`를 -Actions artifact로 업로드합니다. 또한 각 lane의 timeline HTML을 Crabbox -desktop browser에서 렌더링하고, PR comment의 결정적 -timeline PNG 옆에 해당 VNC screenshot을 게시합니다. 이 workflow는 -다음 Crabbox binary release가 만들어지기 전에 현재 desktop/browser lease flag를 사용할 수 있도록 -`openclaw/crabbox` main에서 Crabbox CLI를 build합니다. +이 명령은 Crabbox desktop 머신을 임대하거나 재사용하고, 현재 checkout을 VM으로 sync하고, 해당 VM 안에서 `pnpm openclaw qa slack`을 실행하고, VNC 브라우저에서 Slack Web을 열고, 보이는 desktop을 캡처하며, Slack QA 아티팩트와 VNC 스크린샷을 모두 로컬 output 디렉터리로 복사합니다. 이는 SUT OpenClaw gateway와 브라우저가 모두 같은 Linux desktop VM 안에 존재하는 첫 번째 Mantis 형태입니다. -PR comment에서 status-reactions 실행을 직접 trigger할 수도 있습니다: +`--gateway-setup`을 사용하면 명령은 `$HOME/.openclaw-mantis/slack-openclaw`에 지속성 있는 일회용 OpenClaw home을 준비하고, 선택한 채널에 맞게 Slack Socket Mode 구성을 patch하고, port `38973`에서 `openclaw gateway run`을 시작하며, VNC 세션에서 Chrome이 계속 실행되도록 유지합니다. 이는 "Slack과 실행 중인 claw가 있는 Linux desktop을 남겨 달라" 모드입니다. `--gateway-setup`을 생략하면 bot-to-bot Slack QA 레인이 기본값으로 유지됩니다. + +`--credential-source env`에 필요한 입력: + +- `OPENCLAW_QA_SLACK_CHANNEL_ID` +- `OPENCLAW_QA_SLACK_DRIVER_BOT_TOKEN` +- `OPENCLAW_QA_SLACK_SUT_BOT_TOKEN` +- `OPENCLAW_QA_SLACK_SUT_APP_TOKEN` +- remote model 레인용 `OPENCLAW_LIVE_OPENAI_KEY`. 로컬에 `OPENAI_API_KEY`만 설정된 경우, Mantis는 Crabbox를 호출하기 전에 이를 `OPENCLAW_LIVE_OPENAI_KEY`로 매핑하여 Crabbox의 `OPENCLAW_*` env forwarding이 VM 안으로 전달할 수 있게 합니다. + +유용한 Slack desktop flag: + +- `--lease-id `는 operator가 이미 VNC를 통해 Slack Web에 로그인한 머신에 대해 다시 실행합니다. +- `--gateway-setup`은 bot-to-bot QA 레인만 실행하는 대신 VM에서 지속성 있는 OpenClaw Slack gateway를 시작합니다. +- `--slack-url `은 특정 Slack Web URL을 엽니다. 없으면 SUT bot token을 사용할 수 있을 때 Mantis가 Slack `auth.test`에서 `https://app.slack.com/client//`을 파생합니다. +- `--slack-channel-id `는 gateway setup에서 사용하는 Slack 채널 allowlist를 제어합니다. +- `OPENCLAW_MANTIS_SLACK_BROWSER_PROFILE_DIR`는 VM 안의 지속성 있는 Chrome profile을 제어합니다. 기본값은 `$HOME/.config/openclaw-mantis/slack-chrome-profile`이므로 같은 lease에서 수동 Slack Web 로그인이 rerun 후에도 유지됩니다. +- `--credential-source convex --credential-role ci`는 직접 Slack env token 대신 공유 credential pool을 사용합니다. +- `--provider-mode`, `--model`, `--alt-model`, `--fast`는 Slack live 레인으로 전달됩니다. + +GitHub smoke workflow는 `Mantis Discord Smoke`입니다. 첫 번째 실제 시나리오를 위한 before 및 after GitHub workflow는 `Mantis Discord Status Reactions`입니다. 다음을 받습니다. + +- `baseline_ref`: queued-only 동작을 재현할 것으로 예상되는 ref입니다. +- `candidate_ref`: `queued -> thinking -> done`을 표시할 것으로 예상되는 ref입니다. + +이 workflow는 workflow harness ref를 checkout하고, 별도의 baseline 및 candidate worktree를 build하고, 각 worktree에 대해 `discord-status-reactions-tool-only`를 실행하며, `baseline/`, `candidate/`, `comparison.json`, `mantis-report.md`를 Actions 아티팩트로 업로드합니다. 또한 각 레인의 timeline HTML을 Crabbox desktop 브라우저에서 렌더링하고, 결정적 timeline PNG 옆에 해당 VNC 스크린샷을 PR 댓글에 게시합니다. workflow는 다음 Crabbox binary release가 나오기 전에 현재 desktop/browser lease flag를 사용할 수 있도록 `openclaw/crabbox` main에서 Crabbox CLI를 build합니다. + +PR 댓글에서 status-reactions 실행을 직접 trigger할 수도 있습니다. ```text @Mantis discord status reactions ``` -comment trigger는 의도적으로 좁습니다. write, maintain, admin access가 있는 사용자의 pull request -comment에서만 실행되며, Discord status-reaction request만 인식합니다. 기본적으로 알려진 나쁜 baseline ref와 -현재 PR head SHA를 candidate로 사용합니다. Maintainer는 어느 ref든 재정의할 수 있습니다: +댓글 trigger는 의도적으로 좁습니다. write, maintain 또는 admin access가 있는 사용자의 pull request 댓글에서만 실행되며, Discord status-reaction 요청만 인식합니다. 기본적으로 알려진 bad baseline ref와 현재 PR head SHA를 candidate로 사용합니다. Maintainer는 어느 ref든 override할 수 있습니다. ```text @Mantis discord status reactions baseline=origin/main candidate=HEAD ``` -ClawSweeper command example: +ClawSweeper 명령 예시: ```text @clawsweeper mantis discord discord-status-reactions-tool-only @clawsweeper verify e2e discord ``` -첫 명령은 명시적이며 scenario-focused입니다. 두 번째 명령은 나중에 label, changed file, -ClawSweeper review finding을 바탕으로 PR 또는 issue를 추천 Mantis scenario에 매핑할 수 있습니다. +첫 번째 명령은 명시적이고 시나리오 중심입니다. 두 번째 명령은 나중에 label, 변경된 file, ClawSweeper review finding을 바탕으로 PR 또는 이슈를 권장 Mantis 시나리오에 매핑할 수 있습니다. -## 실행 수명 주기 +## 실행 생명주기 1. credential을 획득합니다. 2. VM을 할당하거나 재사용합니다. -3. scenario에 UI evidence가 필요할 때 desktop/browser profile을 준비합니다. -4. baseline ref의 clean checkout을 준비합니다. -5. dependency를 설치하고 scenario에 필요한 것만 build합니다. -6. isolated state directory로 child OpenClaw Gateway를 시작합니다. -7. live transport, provider, model, browser profile을 구성합니다. -8. scenario를 실행하고 baseline evidence를 캡처합니다. -9. gateway를 중지하고 log를 보존합니다. +3. 시나리오에 UI 증거가 필요한 경우 desktop/browser profile을 준비합니다. +4. baseline ref를 위한 깨끗한 checkout을 준비합니다. +5. dependencies를 설치하고 시나리오에 필요한 것만 build합니다. +6. 격리된 state 디렉터리로 child OpenClaw Gateway를 시작합니다. +7. live 전송, provider, model, browser profile을 구성합니다. +8. 시나리오를 실행하고 baseline 증거를 캡처합니다. +9. gateway를 중지하고 로그를 보존합니다. 10. 같은 VM에서 candidate ref를 준비합니다. -11. 같은 scenario를 실행하고 candidate evidence를 캡처합니다. -12. oracle result와 visual evidence를 비교합니다. -13. Markdown, JSON, log, screenshot, optional trace artifact를 씁니다. -14. GitHub Actions artifact를 업로드합니다. -15. 간결한 PR 또는 Discord status message를 게시합니다. +11. 같은 시나리오를 실행하고 candidate 증거를 캡처합니다. +12. oracle 결과와 시각적 증거를 비교합니다. +13. Markdown, JSON, 로그, 스크린샷, 선택적 trace 아티팩트를 작성합니다. +14. GitHub Actions 아티팩트를 업로드합니다. +15. 간결한 PR 또는 Discord 상태 메시지를 게시합니다. -scenario는 서로 다른 두 방식으로 실패할 수 있어야 합니다: +시나리오는 두 가지 방식으로 실패할 수 있어야 합니다. -- **버그 재현됨**: baseline이 예상한 방식으로 실패했습니다. -- **Harness failure**: bug oracle이 의미 있기 전에 environment setup, credential, Discord API, browser, 또는 - provider가 실패했습니다. +- **버그 재현됨**: baseline이 예상된 방식으로 실패했습니다. +- **Harness 실패**: bug oracle이 의미를 갖기 전에 환경 설정, credential, Discord API, 브라우저 또는 provider가 실패했습니다. -최종 report는 maintainer가 flaky environment와 product behavior를 혼동하지 않도록 -이 case들을 분리해야 합니다. +최종 보고서는 maintainer가 불안정한 환경을 product 동작과 혼동하지 않도록 이러한 사례를 분리해야 합니다. ## Discord MVP -첫 scenario는 source reply delivery mode가 `message_tool_only`인 guild channel의 Discord status reaction을 대상으로 해야 합니다. +첫 번째 시나리오는 source reply delivery mode가 `message_tool_only`인 guild channel의 Discord status reaction을 대상으로 해야 합니다. 좋은 Mantis seed인 이유: -- triggering message의 reaction으로 Discord에 보입니다. +- triggering message의 반응으로 Discord에 표시됩니다. - Discord message reaction state를 통한 강력한 REST oracle이 있습니다. -- 실제 OpenClaw Gateway, Discord bot auth, message dispatch, - source reply delivery mode, status reaction state, model turn lifecycle을 실행합니다. -- 첫 구현이 명확하게 유지될 만큼 범위가 좁습니다. +- 실제 OpenClaw Gateway, Discord bot auth, message dispatch, source reply delivery mode, status reaction state, model turn lifecycle을 exercise합니다. +- 첫 구현을 정직하게 유지할 만큼 범위가 좁습니다. -예상 scenario 형식: +예상 시나리오 형태: ```yaml id: discord-status-reactions-tool-only @@ -214,11 +216,9 @@ evidence: screenshotMessageRow: true ``` -Baseline evidence는 queued acknowledgement reaction은 보이지만 tool-only mode에서 lifecycle transition은 없음을 보여야 합니다. -Candidate evidence는 `messages.statusReactions.enabled`가 명시적으로 true일 때 lifecycle -status reaction이 실행됨을 보여야 합니다. +Baseline 증거는 queued acknowledgement reaction은 보이지만 tool-only mode에서 lifecycle transition은 없음을 보여야 합니다. Candidate 증거는 `messages.statusReactions.enabled`가 명시적으로 `true`일 때 lifecycle status reaction이 실행됨을 보여야 합니다. -실행 가능한 첫 slice는 opt-in Discord live QA scenario입니다: +실행 가능한 첫 번째 slice는 opt-in Discord live QA 시나리오입니다. ```bash pnpm openclaw qa discord \ @@ -230,30 +230,31 @@ pnpm openclaw qa discord \ --output-dir .artifacts/qa-e2e/mantis/discord-status-reactions-candidate ``` -이 명령은 SUT를 always-on guild handling, `visibleReplies: -"message_tool"`, `ackReaction: "👀"`, explicit status reaction으로 구성합니다. oracle은 -실제 Discord triggering message를 poll하고 관찰된 sequence -`👀 -> 🤔 -> 👍`를 기대합니다. Artifact에는 `discord-qa-reaction-timelines.json`, -`discord-status-reactions-tool-only-timeline.html`, 그리고 +항상 켜진 길드 처리, `visibleReplies: +"message_tool"`, `ackReaction: "👀"`, 명시적 상태 반응으로 SUT를 구성합니다. 오라클은 +실제 Discord 트리거 메시지를 폴링하고 관찰된 시퀀스 +`👀 -> 🤔 -> 👍`을 기대합니다. 아티팩트에는 `discord-qa-reaction-timelines.json`, +`discord-status-reactions-tool-only-timeline.html`, `discord-status-reactions-tool-only-timeline.png`가 포함됩니다. ## 기존 QA 구성 요소 -Mantis는 처음부터 시작하는 대신 기존 private QA stack을 기반으로 해야 합니다: +Mantis는 처음부터 시작하는 대신 기존 비공개 QA 스택을 기반으로 해야 합니다. -- `pnpm openclaw qa discord`는 이미 driver 및 SUT bot으로 live Discord lane을 실행합니다. -- live transport runner는 이미 `.artifacts/qa-e2e/` 아래에 report와 observed-message artifact를 씁니다. -- Convex credential lease는 이미 shared live transport credential에 대한 exclusive access를 제공합니다. -- browser control service는 이미 screenshot, snapshot, - headless managed profile, remote CDP profile을 지원합니다. -- QA Lab은 이미 transport-shaped testing을 위한 debugger UI와 bus를 갖고 있습니다. +- `pnpm openclaw qa discord`는 이미 드라이버 및 SUT 봇으로 라이브 Discord 레인을 실행합니다. +- 라이브 전송 러너는 이미 `.artifacts/qa-e2e/` 아래에 보고서와 관찰된 메시지 + 아티팩트를 씁니다. +- Convex 자격 증명 임대는 이미 공유 라이브 전송 자격 증명에 대한 독점 접근을 제공합니다. +- 브라우저 제어 서비스는 이미 스크린샷, 스냅샷, + 헤드리스 관리 프로필, 원격 CDP 프로필을 지원합니다. +- QA Lab에는 이미 전송 형태 테스트를 위한 디버거 UI와 버스가 있습니다. -첫 Mantis 구현은 이러한 구성 요소 위에 얇은 before/after runner와 -하나의 visual evidence layer를 더한 형태일 수 있습니다. +첫 번째 Mantis 구현은 이러한 구성 요소 위의 얇은 전/후 러너와 +하나의 시각적 증거 레이어일 수 있습니다. -## Evidence Model +## 증거 모델 -모든 실행은 stable artifact directory를 씁니다: +모든 실행은 안정적인 아티팩트 디렉터리를 씁니다. ```text .artifacts/qa-e2e/mantis// @@ -273,68 +274,77 @@ Mantis는 처음부터 시작하는 대신 기존 private QA stack을 기반으 run.log ``` -`mantis-summary.json`은 machine-readable source of truth여야 합니다. -Markdown report는 PR comment와 human review를 위한 것입니다. +`mantis-summary.json`은 기계가 읽을 수 있는 단일 진실 공급원이어야 합니다. +Markdown 보고서는 PR 댓글과 사람의 검토를 위한 것입니다. -summary에는 다음이 포함되어야 합니다: +요약에는 다음이 포함되어야 합니다. - 테스트한 ref와 SHA -- transport와 scenario id -- machine provider와 machine id 또는 lease id -- secret value 없는 credential source -- baseline result -- candidate result -- baseline에서 버그가 재현되었는지 여부 -- candidate가 이를 수정했는지 여부 -- artifact path -- sanitized setup 또는 cleanup issue +- 전송 및 시나리오 id +- 머신 제공자 및 머신 id 또는 임대 id +- 비밀 값이 없는 자격 증명 출처 +- 기준 결과 +- 후보 결과 +- 버그가 기준에서 재현되었는지 여부 +- 후보가 이를 수정했는지 여부 +- 아티팩트 경로 +- 삭제 처리된 설정 또는 정리 문제 -Screenshot은 evidence이지 secret이 아닙니다. 그래도 redaction discipline이 필요합니다: -private channel name, user name, message content가 나타날 수 있습니다. public PR에서는 -redaction story가 더 강해질 때까지 inline image보다 GitHub Actions artifact link를 선호하세요. +스크린샷은 증거이지 비밀이 아닙니다. 그래도 삭제 규율이 필요합니다. +비공개 채널 이름, 사용자 이름 또는 메시지 내용이 나타날 수 있습니다. 공개 PR의 경우, +삭제 스토리가 더 강해질 때까지 인라인 이미지보다 GitHub Actions 아티팩트 링크를 +선호하세요. -## Browser 및 VNC +## 브라우저 및 VNC -browser lane에는 두 가지 mode가 있습니다: +브라우저 레인에는 두 가지 모드가 있습니다. -- **Headless automation**: CI의 기본값입니다. Chrome은 CDP가 활성화된 상태로 실행되고, - Playwright 또는 OpenClaw browser control이 screenshot을 캡처합니다. -- **VNC rescue**: login, MFA, Discord anti-automation, - 또는 visual debugging에 사람이 필요할 때 같은 VM에서 활성화됩니다. +- **헤드리스 자동화**: CI의 기본값입니다. Chrome은 CDP가 활성화된 상태로 실행되며, + Playwright 또는 OpenClaw 브라우저 제어가 스크린샷을 캡처합니다. +- **VNC 구조**: 로그인, MFA, Discord 자동화 방지 또는 시각적 디버깅에 사람이 + 필요할 때 같은 VM에서 활성화됩니다. -Discord 옵저버 브라우저 프로필은 매 실행마다 로그인하지 않아도 될 만큼 지속되어야 하지만, 개인 브라우저 상태와는 격리되어야 합니다. 프로필은 개발자 노트북이 아니라 Mantis 머신 풀에 속합니다. +Discord 관찰자 브라우저 프로필은 매 실행마다 로그인하지 않아도 될 만큼 +지속적이어야 하지만, 개인 브라우저 상태와는 격리되어야 합니다. 프로필은 +개발자 노트북이 아니라 Mantis 머신 풀에 속합니다. -Mantis가 멈추면 다음 내용을 포함한 Discord 상태 메시지를 게시합니다. +Mantis가 막히면 다음이 포함된 Discord 상태 메시지를 게시합니다. -- 실행 ID -- 시나리오 ID +- 실행 id +- 시나리오 id - 머신 제공자 - 아티팩트 디렉터리 - 사용 가능한 경우 VNC 또는 noVNC 연결 지침 -- 짧은 차단 원인 텍스트 +- 짧은 차단 사유 텍스트 -첫 번째 비공개 배포는 이러한 메시지를 기존 운영자 채널에 게시하고, 나중에 전용 Mantis 채널로 이동할 수 있습니다. +첫 번째 비공개 배포는 이러한 메시지를 기존 운영자 채널에 게시하고, +나중에 전용 Mantis 채널로 이동할 수 있습니다. ## 머신 -Mantis는 첫 번째 원격 구현에서 Crabbox를 통한 AWS를 우선 사용해야 합니다. Crabbox는 준비된 머신, 임대 추적, 하이드레이션, 로그, 결과, 정리를 제공합니다. AWS 용량이 너무 느리거나 사용할 수 없으면 동일한 머신 인터페이스 뒤에 Hetzner 제공자를 추가하세요. +Mantis는 첫 번째 원격 구현에서 Crabbox를 통한 AWS를 선호해야 합니다. +Crabbox는 예열된 머신, 임대 추적, 수화, 로그, 결과, 정리를 제공합니다. +AWS 용량이 너무 느리거나 사용할 수 없는 경우, 같은 머신 인터페이스 뒤에 +Hetzner 제공자를 추가하세요. 최소 VM 요구 사항: -- 데스크톱 사용이 가능한 Chrome 또는 Chromium 설치가 있는 Linux -- 브라우저 자동화를 위한 CDP 액세스 -- 복구를 위한 VNC 또는 noVNC +- 데스크톱 가능한 Chrome 또는 Chromium 설치가 있는 Linux +- 브라우저 자동화를 위한 CDP 접근 +- 구조용 VNC 또는 noVNC - Node 22 및 pnpm - OpenClaw 체크아웃 및 의존성 캐시 -- Playwright를 사용하는 경우 Playwright Chromium 브라우저 캐시 -- OpenClaw Gateway 하나, 브라우저 하나, 모델 실행 하나를 감당할 충분한 CPU 및 메모리 -- Discord, GitHub, 모델 제공자, 자격 증명 브로커에 대한 아웃바운드 액세스 +- Playwright를 사용할 때 Playwright Chromium 브라우저 캐시 +- 하나의 OpenClaw Gateway, 하나의 브라우저, 하나의 모델 실행을 위한 충분한 CPU와 메모리 +- Discord, GitHub, 모델 제공자, 자격 증명 브로커로의 아웃바운드 접근 -VM은 예상된 자격 증명 또는 브라우저 프로필 저장소 밖에 장기 보관되는 원시 비밀을 유지해서는 안 됩니다. +VM은 예상되는 자격 증명 또는 브라우저 프로필 저장소 밖에 장기 원시 비밀을 +보관해서는 안 됩니다. ## 비밀 -비밀은 원격 실행의 경우 GitHub 조직 또는 저장소 비밀에, 로컬 실행의 경우 로컬 운영자가 제어하는 비밀 파일에 둡니다. +비밀은 원격 실행의 경우 GitHub 조직 또는 저장소 비밀에, 로컬 실행의 경우 +로컬 운영자가 제어하는 비밀 파일에 있습니다. 권장 비밀 이름: @@ -344,15 +354,19 @@ VM은 예상된 자격 증명 또는 브라우저 프로필 저장소 밖에 장 - `OPENCLAW_QA_DISCORD_GUILD_ID` - `OPENCLAW_QA_DISCORD_CHANNEL_ID` - `OPENCLAW_QA_DISCORD_NOTIFY_CHANNEL_ID` -- 공개 GitHub 아티팩트 업로드를 위한 `OPENCLAW_QA_REDACT_PUBLIC_METADATA=1` +- 공개 GitHub 아티팩트 업로드의 경우 `OPENCLAW_QA_REDACT_PUBLIC_METADATA=1` - `OPENCLAW_QA_CONVEX_SITE_URL` - `OPENCLAW_QA_CONVEX_SECRET_CI` - `OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR` - `OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN` -장기적으로 Convex 자격 증명 풀은 라이브 전송 자격 증명의 일반 소스로 유지되어야 합니다. GitHub 비밀은 브로커와 폴백 레인을 부트스트랩합니다. Discord 상태 반응 워크플로는 Mantis Crabbox 비밀을 Crabbox CLI가 기대하는 `CRABBOX_COORDINATOR` 및 `CRABBOX_COORDINATOR_TOKEN` 환경 변수로 다시 매핑합니다. 일반 `CRABBOX_*` GitHub 비밀 이름은 호환성 폴백으로 계속 허용됩니다. +장기적으로 Convex 자격 증명 풀은 라이브 전송 자격 증명의 일반적인 출처로 +남아야 합니다. GitHub 비밀은 브로커와 폴백 레인을 부트스트랩합니다. +Discord 상태 반응 워크플로는 Mantis Crabbox 비밀을 Crabbox CLI가 기대하는 +`CRABBOX_COORDINATOR` 및 `CRABBOX_COORDINATOR_TOKEN` 환경 변수로 다시 매핑합니다. +일반 `CRABBOX_*` GitHub 비밀 이름은 호환성 폴백으로 계속 허용됩니다. -Mantis 러너는 절대로 다음을 출력해서는 안 됩니다. +Mantis 러너는 다음을 절대 출력해서는 안 됩니다. - Discord 봇 토큰 - 제공자 API 키 @@ -361,15 +375,27 @@ Mantis 러너는 절대로 다음을 출력해서는 안 됩니다. - VNC 비밀번호 - 원시 자격 증명 페이로드 -공개 아티팩트 업로드는 봇, 길드, 채널, 메시지 ID 같은 Discord 대상 메타데이터도 삭제해야 합니다. GitHub 스모크 워크플로는 이러한 이유로 `OPENCLAW_QA_REDACT_PUBLIC_METADATA=1`을 활성화합니다. +공개 아티팩트 업로드는 봇, 길드, 채널, 메시지 id 같은 Discord 대상 메타데이터도 +삭제해야 합니다. GitHub 스모크 워크플로는 이러한 이유로 +`OPENCLAW_QA_REDACT_PUBLIC_METADATA=1`을 활성화합니다. -토큰이 실수로 이슈, PR, 채팅, 로그에 붙여넣어진 경우 새 비밀을 저장한 뒤 해당 토큰을 교체하세요. +토큰이 실수로 이슈, PR, 채팅 또는 로그에 붙여넣어진 경우, 새 비밀이 저장된 뒤 +이를 교체하세요. ## GitHub 아티팩트 및 PR 댓글 -Mantis 워크플로는 전체 증거 번들을 수명이 짧은 Actions 아티팩트로 업로드해야 합니다. 워크플로가 버그 보고서 또는 수정 PR에 대해 실행될 때는 삭제 처리된 PNG 스크린샷도 `qa-artifacts` 브랜치에 게시하고, 해당 버그 또는 수정 PR에 전후 스크린샷을 인라인으로 포함한 댓글을 upsert해야 합니다. 기본 증거를 일반 QA 자동화 PR에만 게시하지 마세요. 원시 로그, 관찰된 메시지, 기타 큰 증거는 Actions 아티팩트에 남겨 둡니다. +Mantis 워크플로는 전체 증거 번들을 수명이 짧은 Actions 아티팩트로 업로드해야 합니다. +버그 보고서 또는 수정 PR에 대해 워크플로가 실행될 때는 삭제 처리된 PNG 스크린샷도 +`qa-artifacts` 브랜치에 게시하고, 해당 버그 또는 수정 PR에 전/후 스크린샷을 +인라인으로 포함한 댓글을 upsert해야 합니다. 일반 QA 자동화 PR에만 주요 증명을 +게시하지 마세요. 원시 로그, 관찰된 메시지, 기타 큰 증거는 Actions 아티팩트에 +남겨 둡니다. -프로덕션 워크플로는 `github-actions[bot]`이 아니라 Mantis GitHub App으로 해당 댓글을 게시해야 합니다. 앱 ID와 비공개 키를 `MANTIS_GITHUB_APP_ID` 및 `MANTIS_GITHUB_APP_PRIVATE_KEY` GitHub Actions 비밀로 저장하세요. 워크플로는 숨김 마커를 upsert 키로 사용하고, 토큰이 편집할 수 있으면 해당 댓글을 업데이트하며, 이전 봇 소유 마커를 편집할 수 없으면 Mantis 소유 댓글을 새로 만듭니다. +프로덕션 워크플로는 `github-actions[bot]`가 아니라 Mantis GitHub App으로 해당 댓글을 +게시해야 합니다. 앱 id와 비공개 키를 `MANTIS_GITHUB_APP_ID` 및 +`MANTIS_GITHUB_APP_PRIVATE_KEY` GitHub Actions 비밀로 저장하세요. 워크플로는 숨겨진 +마커를 upsert 키로 사용하고, 토큰이 편집할 수 있으면 해당 댓글을 업데이트하며, +이전 bot 소유 마커를 편집할 수 없으면 새 Mantis 소유 댓글을 생성합니다. PR 댓글은 짧고 시각적이어야 합니다. @@ -391,21 +417,25 @@ candidate showed the expected queued -> thinking -> done sequence. | | | ``` -하네스 실패로 실행이 실패한 경우, 댓글은 후보가 실패했다는 뜻을 암시하지 말고 그 사실을 명시해야 합니다. +하네스 실패로 실행이 실패한 경우, 댓글은 후보가 실패했다고 암시하는 대신 +그 사실을 말해야 합니다. ## 비공개 배포 참고 사항 -비공개 배포에는 이미 Mantis Discord 애플리케이션이 있을 수 있습니다. 올바른 봇 권한이 있고 안전하게 교체할 수 있다면 다른 앱을 만들지 말고 해당 애플리케이션을 재사용하세요. +비공개 배포에는 이미 Mantis Discord 애플리케이션이 있을 수 있습니다. 해당 애플리케이션이 +올바른 봇 권한을 가지고 안전하게 교체될 수 있다면, 다른 앱을 만들지 말고 이를 재사용하세요. -초기 운영자 알림 채널은 비밀 또는 배포 구성으로 설정하세요. 처음에는 기존 유지관리자 또는 운영 채널을 가리키고, 전용 Mantis 채널이 생기면 그쪽으로 이동할 수 있습니다. +초기 운영자 알림 채널은 비밀 또는 배포 구성을 통해 설정하세요. 처음에는 기존 +관리자 또는 운영 채널을 가리키고, 전용 Mantis 채널이 생긴 뒤 그곳으로 이동할 수 있습니다. -이 문서에 길드 ID, 채널 ID, 봇 토큰, 브라우저 쿠키, VNC 비밀번호를 넣지 마세요. GitHub 비밀, 자격 증명 브로커 또는 운영자의 로컬 비밀 저장소에 저장하세요. +길드 id, 채널 id, 봇 토큰, 브라우저 쿠키 또는 VNC 비밀번호를 이 문서에 넣지 마세요. +GitHub 비밀, 자격 증명 브로커 또는 운영자의 로컬 비밀 저장소에 저장하세요. ## 시나리오 추가 Mantis 시나리오는 다음을 선언해야 합니다. -- ID 및 제목 +- id 및 제목 - 전송 - 필요한 자격 증명 - 기준 ref 정책 @@ -424,27 +454,30 @@ Mantis 시나리오는 다음을 선언해야 합니다. - 반응 버그의 경우 Discord 반응 상태 - 스레딩 버그의 경우 Discord 메시지 참조 - Slack 버그의 경우 Slack 스레드 ts 및 반응 API 상태 -- 이메일 버그의 경우 이메일 메시지 ID 및 헤더 -- UI가 유일하게 신뢰할 수 있는 관찰 대상인 경우 브라우저 스크린샷 +- 이메일 버그의 경우 이메일 메시지 id 및 헤더 +- UI가 유일하게 신뢰할 수 있는 관찰 대상일 때 브라우저 스크린샷 -비전 검사는 추가적인 성격이어야 합니다. 플랫폼 API가 버그를 증명할 수 있다면 API를 통과/실패 오라클로 사용하고, 스크린샷은 사람이 확인할 신뢰도를 위해 유지하세요. +비전 검사는 추가적이어야 합니다. 플랫폼 API가 버그를 증명할 수 있다면, +API를 통과/실패 오라클로 사용하고 스크린샷은 사람의 확신을 위해 유지하세요. ## 제공자 확장 -Discord 이후 동일한 러너는 다음을 추가할 수 있습니다. +Discord 이후 같은 러너는 다음을 추가할 수 있습니다. - Slack: 반응, 스레드, 앱 멘션, 모달, 파일 업로드. -- 이메일: 커넥터만으로 충분하지 않은 경우 `gog`를 사용한 Gmail 인증 및 메시지 스레딩. +- 이메일: 커넥터만으로 충분하지 않은 경우 `gog`를 사용하는 Gmail 인증 및 메시지 스레딩. - WhatsApp: QR 로그인, 재식별, 메시지 전달, 미디어, 반응. -- Telegram: 사용 가능한 경우 그룹 멘션 게이팅, 명령, 반응. -- Matrix: 암호화된 룸, 스레드 또는 답장 관계, 재시작 재개. +- Telegram: 그룹 멘션 게이팅, 명령, 사용 가능한 경우 반응. +- Matrix: 암호화된 방, 스레드 또는 답장 관계, 재시작 재개. -각 전송에는 저렴한 스모크 시나리오 하나와 하나 이상의 버그 클래스 시나리오가 있어야 합니다. 비용이 큰 시각적 시나리오는 옵트인으로 유지해야 합니다. +각 전송에는 하나의 저렴한 스모크 시나리오와 하나 이상의 버그 클래스 시나리오가 +있어야 합니다. 비용이 큰 시각적 시나리오는 옵트인으로 유지해야 합니다. ## 열린 질문 -- 기존 Mantis 봇을 재사용할 때 어떤 Discord 봇을 드라이버로, 어떤 봇을 SUT로 사용해야 합니까? -- 옵저버 브라우저 로그인은 첫 단계에서 사람 Discord 계정, 테스트 계정 또는 봇이 읽을 수 있는 REST 증거만 사용해야 합니까? -- GitHub는 PR용 Mantis 아티팩트를 얼마나 오래 보관해야 합니까? -- ClawSweeper는 유지관리자 명령을 기다리는 대신 언제 Mantis를 자동으로 권장해야 합니까? -- 공개 PR에 업로드하기 전에 스크린샷을 삭제 처리하거나 자르기 해야 합니까? +- 기존 Mantis 봇을 재사용할 때 어떤 Discord 봇이 드라이버이고 어떤 봇이 SUT여야 하나요? +- 관찰자 브라우저 로그인은 첫 단계에서 사람 Discord 계정, 테스트 계정 또는 + bot이 읽을 수 있는 REST 증거만 사용해야 하나요? +- GitHub는 PR용 Mantis 아티팩트를 얼마나 오래 보존해야 하나요? +- ClawSweeper는 언제 관리자 명령을 기다리는 대신 Mantis를 자동으로 권장해야 하나요? +- 공개 PR에 업로드하기 전에 스크린샷을 삭제 처리하거나 잘라내야 하나요? diff --git a/docs/ko/concepts/messages.md b/docs/ko/concepts/messages.md index bafa5e9af..ee8d1272d 100644 --- a/docs/ko/concepts/messages.md +++ b/docs/ko/concepts/messages.md @@ -1,20 +1,20 @@ --- read_when: - - 수신 메시지가 응답으로 변환되는 방식 설명 - - 세션, 대기열 모드 또는 스트리밍 동작 명확히 하기 - - 추론 가시성과 사용 영향 문서화 -summary: 메시지 흐름, 세션, 대기열 처리, 추론 가시성 + - 인바운드 메시지가 답장으로 전환되는 방식 설명 + - 세션, 큐잉 모드 또는 스트리밍 동작 명확히 하기 + - 추론 가시성 및 사용상의 영향 문서화 +summary: 메시지 흐름, 세션, 큐 처리 및 추론 가시성 title: 메시지 x-i18n: - generated_at: "2026-04-30T16:27:52Z" + generated_at: "2026-05-04T06:23:04Z" model: gpt-5.5 provider: openai - source_hash: fdeee014d92767a725501691fbe0c4ee6b631acc9a2ab5cbbcf321bfee9679b9 + source_hash: 15242e21fd17a9f2013561003e108d197204d834caf51bbcdc53ffb3f118b14f source_path: concepts/messages.md workflow: 16 --- -OpenClaw는 세션 해석, 큐잉, 스트리밍, 도구 실행, 추론 가시성의 파이프라인을 통해 인바운드 메시지를 처리합니다. 이 페이지는 인바운드 메시지에서 응답까지의 경로를 설명합니다. +OpenClaw는 세션 확인, 큐잉, 스트리밍, 도구 실행, 추론 가시성의 파이프라인을 통해 인바운드 메시지를 처리합니다. 이 페이지는 인바운드 메시지에서 답장까지의 경로를 설명합니다. ## 메시지 흐름(상위 수준) @@ -26,21 +26,21 @@ Inbound message -> outbound replies (channel limits + chunking) ``` -주요 조정 항목은 구성에 있습니다. +핵심 조정값은 구성에 있습니다. -- 접두사, 큐잉, 그룹 동작은 `messages.*`. -- 블록 스트리밍 및 청킹 기본값은 `agents.defaults.*`. -- 한도와 스트리밍 토글은 채널 재정의(`channels.whatsapp.*`, `channels.telegram.*` 등). +- `messages.*`: 접두사, 큐잉, 그룹 동작. +- `agents.defaults.*`: 블록 스트리밍 및 청킹 기본값. +- 채널 재정의(`channels.whatsapp.*`, `channels.telegram.*` 등): 제한 및 스트리밍 토글. -전체 스키마는 [구성](/ko/gateway/configuration)을 참조하세요. +전체 스키마는 [구성](/ko/gateway/configuration)을 참고하세요. ## 인바운드 중복 제거 -채널은 재연결 후 같은 메시지를 다시 전달할 수 있습니다. OpenClaw는 채널/계정/피어/세션/메시지 ID를 키로 하는 단기 캐시를 유지하여 중복 전달이 또 다른 에이전트 실행을 트리거하지 않도록 합니다. +채널은 재연결 후 같은 메시지를 다시 전달할 수 있습니다. OpenClaw는 채널/계정/피어/세션/메시지 ID를 키로 하는 수명이 짧은 캐시를 유지하여 중복 전달이 다른 에이전트 실행을 트리거하지 않도록 합니다. ## 인바운드 디바운싱 -**같은 발신자**의 빠른 연속 메시지는 `messages.inbound`를 통해 단일 에이전트 턴으로 묶을 수 있습니다. 디바운싱은 채널 + 대화별로 범위가 지정되며, 응답 스레딩/ID에는 가장 최근 메시지를 사용합니다. +**동일한 발신자**의 빠른 연속 메시지는 `messages.inbound`를 통해 단일 에이전트 턴으로 일괄 처리될 수 있습니다. 디바운싱은 채널 + 대화별로 범위가 지정되며, 답장 스레딩/ID에는 가장 최근 메시지를 사용합니다. 구성(전역 기본값 + 채널별 재정의): @@ -62,17 +62,17 @@ Inbound message 참고: - 디바운스는 **텍스트 전용** 메시지에 적용됩니다. 미디어/첨부 파일은 즉시 플러시됩니다. -- 제어 명령은 독립적으로 유지되도록 디바운싱을 우회합니다. 단, 채널이 같은 발신자 DM 병합을 명시적으로 선택한 경우는 **예외**입니다(예: [BlueBubbles `coalesceSameSenderDms`](/ko/channels/bluebubbles#coalescing-split-send-dms-command--url-in-one-composition)). 이 경우 분할 전송 페이로드가 같은 에이전트 턴에 합류할 수 있도록 DM 명령은 디바운스 창 안에서 대기합니다. +- 제어 명령은 디바운싱을 우회하여 독립적으로 유지됩니다. 단, 채널이 동일 발신자 DM 병합을 명시적으로 선택한 경우는 **예외**입니다(예: [BlueBubbles `coalesceSameSenderDms`](/ko/channels/bluebubbles#coalescing-split-send-dms-command--url-in-one-composition)). 이 경우 DM 명령은 분할 전송 페이로드가 같은 에이전트 턴에 합류할 수 있도록 디바운스 창 안에서 대기합니다. -## 세션과 기기 +## 세션 및 기기 세션은 클라이언트가 아니라 Gateway가 소유합니다. -- 직접 채팅은 에이전트 기본 세션 키로 통합됩니다. +- 직접 채팅은 에이전트 기본 세션 키로 합쳐집니다. - 그룹/채널은 자체 세션 키를 갖습니다. - 세션 저장소와 트랜스크립트는 Gateway 호스트에 있습니다. -여러 기기/채널이 같은 세션에 매핑될 수 있지만, 기록이 모든 클라이언트로 완전히 동기화되지는 않습니다. 권장 사항: 긴 대화에서는 컨텍스트가 갈라지는 것을 피하기 위해 하나의 기본 기기를 사용하세요. Control UI와 TUI는 항상 Gateway 기반 세션 트랜스크립트를 표시하므로, 이것이 신뢰할 수 있는 원본입니다. +여러 기기/채널이 같은 세션에 매핑될 수 있지만, 기록이 모든 클라이언트로 완전히 다시 동기화되지는 않습니다. 권장 사항: 긴 대화에서는 컨텍스트가 갈라지는 것을 피하기 위해 하나의 주 기기를 사용하세요. Control UI와 TUI는 항상 Gateway 기반 세션 트랜스크립트를 표시하므로, 이것이 신뢰할 수 있는 원본입니다. 자세한 내용: [세션 관리](/ko/concepts/session). @@ -80,18 +80,18 @@ Inbound message 도구 결과 `content`는 모델에 표시되는 결과입니다. 도구 결과 `details`는 UI 렌더링, 진단, 미디어 전달, Plugin을 위한 런타임 메타데이터입니다. -OpenClaw는 이 경계를 명시적으로 유지합니다. +OpenClaw는 이 경계를 명확히 유지합니다. -- `toolResult.details`는 provider 재생 및 Compaction 입력 전에 제거됩니다. +- `toolResult.details`는 공급자 재생 및 Compaction 입력 전에 제거됩니다. - 영구 저장된 세션 트랜스크립트는 제한된 `details`만 유지합니다. 너무 큰 메타데이터는 `persistedDetailsTruncated: true`로 표시된 간결한 요약으로 대체됩니다. -- Plugin과 도구는 모델이 읽어야 하는 텍스트를 `details`에만 두지 말고 `content`에 넣어야 합니다. +- Plugin과 도구는 모델이 읽어야 하는 텍스트를 `details`에만 넣지 말고 `content`에 넣어야 합니다. -## 인바운드 본문과 기록 컨텍스트 +## 인바운드 본문 및 기록 컨텍스트 OpenClaw는 **프롬프트 본문**과 **명령 본문**을 분리합니다. -- `BodyForAgent`: 현재 메시지의 기본 모델 대상 텍스트입니다. 채널 Plugin은 발신자의 현재 프롬프트 포함 텍스트에 집중되도록 유지해야 합니다. -- `Body`: 레거시 프롬프트 대체값입니다. 채널 봉투와 선택적 기록 래퍼를 포함할 수 있지만, 현재 채널은 `BodyForAgent`를 사용할 수 있을 때 이를 기본 모델 입력으로 의존해서는 안 됩니다. +- `BodyForAgent`: 현재 메시지의 기본 모델 대상 텍스트입니다. 채널 Plugin은 이를 발신자의 현재 프롬프트 포함 텍스트에 집중되도록 유지해야 합니다. +- `Body`: 레거시 프롬프트 폴백입니다. 여기에는 채널 봉투와 선택적 기록 래퍼가 포함될 수 있지만, 현재 채널은 `BodyForAgent`를 사용할 수 있을 때 이를 기본 모델 입력으로 의존해서는 안 됩니다. - `CommandBody`: 지시문/명령 파싱을 위한 원시 사용자 텍스트입니다. - `RawBody`: `CommandBody`의 레거시 별칭입니다(호환성을 위해 유지됨). @@ -100,77 +100,76 @@ OpenClaw는 **프롬프트 본문**과 **명령 본문**을 분리합니다. - `[Chat messages since your last reply - for context]` - `[Current message - respond to this]` -**비직접 채팅**(그룹/채널/룸)의 경우 **현재 메시지 본문**에는 발신자 레이블이 접두사로 붙습니다(기록 항목에 사용되는 것과 같은 스타일). 이렇게 하면 에이전트 프롬프트에서 실시간 메시지와 큐/기록 메시지가 일관되게 유지됩니다. +**비직접 채팅**(그룹/채널/룸)의 경우, **현재 메시지 본문**에는 발신자 레이블이 접두사로 붙습니다(기록 항목에 사용되는 것과 같은 스타일). 이렇게 하면 에이전트 프롬프트에서 실시간 메시지와 큐/기록 메시지가 일관되게 유지됩니다. -기록 버퍼는 **대기 중 항목 전용**입니다. 실행을 트리거하지 _않은_ 그룹 메시지(예: 멘션 게이트 메시지)를 포함하고, 세션 트랜스크립트에 이미 있는 메시지는 **제외**합니다. +기록 버퍼는 **대기 중인 항목 전용**입니다. 실행을 트리거하지 _않은_ 그룹 메시지(예: 멘션 게이트 메시지)를 포함하고, 세션 트랜스크립트에 이미 있는 메시지는 **제외**합니다. -지시문 제거는 **현재 메시지** 섹션에만 적용되므로 기록은 그대로 유지됩니다. 기록을 래핑하는 채널은 `CommandBody`(또는 `RawBody`)를 원래 메시지 텍스트로 설정하고 `Body`는 결합된 프롬프트로 유지해야 합니다. 구조화된 기록, 응답, 전달됨, 채널 메타데이터는 프롬프트 조립 중 사용자 역할의 신뢰할 수 없는 컨텍스트 블록으로 렌더링됩니다. -기록 버퍼는 `messages.groupChat.historyLimit`(전역 기본값) 및 `channels.slack.historyLimit` 또는 `channels.telegram.accounts..historyLimit` 같은 채널별 재정의로 구성할 수 있습니다(비활성화하려면 `0`으로 설정). +지시문 제거는 **현재 메시지** 섹션에만 적용되어 기록이 그대로 유지됩니다. 기록을 래핑하는 채널은 `CommandBody`(또는 `RawBody`)를 원래 메시지 텍스트로 설정하고, `Body`는 결합된 프롬프트로 유지해야 합니다. 구조화된 기록, 답장, 전달된 메시지, 채널 메타데이터는 프롬프트 조립 중 사용자 역할의 신뢰되지 않은 컨텍스트 블록으로 렌더링됩니다. +기록 버퍼는 `messages.groupChat.historyLimit`(전역 기본값) 및 `channels.slack.historyLimit` 또는 `channels.telegram.accounts..historyLimit` 같은 채널별 재정의로 구성할 수 있습니다(`0`으로 설정하면 비활성화). -## 큐잉과 후속 처리 +## 큐잉 및 후속 처리 -실행이 이미 활성 상태인 경우, 인바운드 메시지는 큐에 넣거나, 현재 실행으로 유도하거나, 후속 턴을 위해 수집할 수 있습니다. +실행이 이미 활성 상태라면, 인바운드 메시지는 큐에 들어가거나, 현재 실행으로 조향되거나, 후속 턴을 위해 수집될 수 있습니다. - `messages.queue`(및 `messages.queue.byChannel`)를 통해 구성합니다. -- 기본 모드는 `steer`이며, 유도가 큐에 넣은 후속 전달로 폴백될 때 500ms 후속 디바운스가 적용됩니다. +- 기본 모드는 `steer`이며, 조향이 큐 기반 후속 전달로 폴백될 때 500ms 후속 디바운스를 사용합니다. - 모드: `steer`, `followup`, `collect`, `steer-backlog`, `interrupt`, 그리고 레거시 한 번에 하나씩 처리하는 `queue` 모드. -자세한 내용: [명령 큐](/ko/concepts/queue) 및 [Steering 큐](/ko/concepts/queue-steering). +자세한 내용: [명령 큐](/ko/concepts/queue) 및 [조향 큐](/ko/concepts/queue-steering). ## 채널 실행 소유권 -채널 Plugin은 메시지가 세션 큐에 들어가기 전에 순서 보존, 입력 디바운스, 전송 백프레셔 적용을 수행할 수 있습니다. 에이전트 턴 자체에 별도의 타임아웃을 부과해서는 안 됩니다. 메시지가 세션으로 라우팅되면 장시간 실행 작업은 세션, 도구, 런타임 수명 주기에 의해 관리되므로 모든 채널이 느린 턴을 일관되게 보고하고 복구합니다. +채널 Plugin은 메시지가 세션 큐에 들어가기 전에 순서를 보존하고, 입력을 디바운스하며, 전송 백프레셔를 적용할 수 있습니다. 에이전트 턴 자체를 둘러싼 별도의 타임아웃을 부과해서는 안 됩니다. 메시지가 세션으로 라우팅되면, 오래 실행되는 작업은 세션, 도구, 런타임 수명 주기에 의해 관리되므로 모든 채널이 느린 턴을 일관되게 보고하고 복구합니다. -## 스트리밍, 청킹, 배칭 +## 스트리밍, 청킹, 일괄 처리 -블록 스트리밍은 모델이 텍스트 블록을 생성할 때 부분 응답을 전송합니다. -청킹은 채널 텍스트 제한을 준수하고 fenced code 분할을 피합니다. +블록 스트리밍은 모델이 텍스트 블록을 생성하는 동안 부분 답장을 전송합니다. 청킹은 채널 텍스트 제한을 준수하고 펜스 코드 분할을 피합니다. -주요 설정: +핵심 설정: - `agents.defaults.blockStreamingDefault`(`on|off`, 기본값 off) - `agents.defaults.blockStreamingBreak`(`text_end|message_end`) - `agents.defaults.blockStreamingChunk`(`minChars|maxChars|breakPreference`) -- `agents.defaults.blockStreamingCoalesce`(유휴 기반 배칭) -- `agents.defaults.humanDelay`(블록 응답 사이의 사람 같은 일시 정지) -- 채널 재정의: `*.blockStreaming` 및 `*.blockStreamingCoalesce`(Telegram이 아닌 채널은 명시적인 `*.blockStreaming: true` 필요) +- `agents.defaults.blockStreamingCoalesce`(유휴 기반 일괄 처리) +- `agents.defaults.humanDelay`(블록 답장 사이의 사람 같은 일시 중지) +- 채널 재정의: `*.blockStreaming` 및 `*.blockStreamingCoalesce`(Telegram이 아닌 채널은 명시적 `*.blockStreaming: true`가 필요) 자세한 내용: [스트리밍 + 청킹](/ko/concepts/streaming). -## 추론 가시성과 토큰 +## 추론 가시성 및 토큰 OpenClaw는 모델 추론을 노출하거나 숨길 수 있습니다. - `/reasoning on|off|stream`은 가시성을 제어합니다. -- 모델이 생성한 추론 콘텐츠는 여전히 토큰 사용량에 포함됩니다. -- Telegram은 추론 스트림을 초안 말풍선으로 보내는 기능을 지원합니다. +- 추론 콘텐츠는 모델이 생성할 때 여전히 토큰 사용량에 포함됩니다. +- Telegram은 최종 전달 후 삭제되는 임시 초안 말풍선으로 추론 스트림을 지원합니다. 지속적인 추론 출력을 원하면 `/reasoning on`을 사용하세요. -자세한 내용: [사고 + 추론 지시문](/ko/tools/thinking) 및 [토큰 사용](/ko/reference/token-use). +자세한 내용: [사고 + 추론 지시문](/ko/tools/thinking) 및 [토큰 사용량](/ko/reference/token-use). -## 접두사, 스레딩, 응답 +## 접두사, 스레딩, 답장 아웃바운드 메시지 형식은 `messages`에 중앙화되어 있습니다. - `messages.responsePrefix`, `channels..responsePrefix`, `channels..accounts..responsePrefix`(아웃바운드 접두사 계단식 적용), 그리고 `channels.whatsapp.messagePrefix`(WhatsApp 인바운드 접두사) -- `replyToMode` 및 채널별 기본값을 통한 응답 스레딩 +- `replyToMode` 및 채널별 기본값을 통한 답장 스레딩 자세한 내용: [구성](/ko/gateway/config-agents#messages) 및 채널 문서. -## 무음 응답 +## 조용한 답장 -정확한 무음 토큰 `NO_REPLY` / `no_reply`는 “사용자에게 보이는 응답을 전달하지 않음”을 의미합니다. -턴에 생성된 TTS 오디오 같은 대기 중인 도구 미디어도 있을 경우, OpenClaw는 무음 텍스트를 제거하지만 미디어 첨부 파일은 계속 전달합니다. -OpenClaw는 대화 유형에 따라 이 동작을 해석합니다. +정확한 조용한 토큰 `NO_REPLY` / `no_reply`는 “사용자에게 보이는 답장을 전달하지 않음”을 의미합니다. +턴에 생성된 TTS 오디오 같은 대기 중인 도구 미디어도 있는 경우, OpenClaw는 조용한 텍스트를 제거하지만 미디어 첨부 파일은 계속 전달합니다. +OpenClaw는 대화 유형에 따라 이 동작을 결정합니다. -- 직접 대화는 기본적으로 무음을 허용하지 않으며, 단독 무음 응답을 짧고 표시되는 대체 응답으로 다시 작성합니다. -- 그룹/채널은 기본적으로 무음을 허용합니다. -- 내부 오케스트레이션은 기본적으로 무음을 허용합니다. +- 직접 대화는 기본적으로 침묵을 허용하지 않으며, 조용한 답장만 있는 경우 짧고 보이는 폴백으로 다시 작성합니다. +- 그룹/채널은 기본적으로 침묵을 허용합니다. +- 내부 오케스트레이션은 기본적으로 침묵을 허용합니다. -OpenClaw는 비직접 채팅에서 assistant 응답이 발생하기 전에 생기는 내부 runner 실패에도 무음 응답을 사용하므로, 그룹/채널에는 Gateway 오류 상용 문구가 표시되지 않습니다. 직접 채팅은 기본적으로 간결한 실패 문구를 표시합니다. 원시 runner 세부 정보는 `/verbose`가 `on` 또는 `full`일 때만 표시됩니다. +OpenClaw는 비직접 채팅에서 어시스턴트 답장 전에 발생하는 내부 러너 실패에도 조용한 답장을 사용하므로, 그룹/채널에는 Gateway 오류 상용구가 표시되지 않습니다. 직접 채팅은 기본적으로 간결한 실패 문구를 표시합니다. 원시 러너 세부 정보는 `/verbose`가 `on` 또는 `full`일 때만 표시됩니다. -기본값은 `agents.defaults.silentReply` 및 `agents.defaults.silentReplyRewrite` 아래에 있으며, `surfaces..silentReply` 및 `surfaces..silentReplyRewrite`는 표면별로 이를 재정의할 수 있습니다. +기본값은 `agents.defaults.silentReply` 및 `agents.defaults.silentReplyRewrite` 아래에 있으며, `surfaces..silentReply`와 `surfaces..silentReplyRewrite`는 표면별로 이를 재정의할 수 있습니다. -상위 세션에 대기 중인 spawned 하위 에이전트 실행이 하나 이상 있는 경우, 단독 무음 응답은 다시 작성되지 않고 모든 표면에서 삭제됩니다. 그래서 자식 완료 이벤트가 실제 응답을 전달할 때까지 상위 세션은 조용히 유지됩니다. +상위 세션에 대기 중인 생성된 하위 에이전트 실행이 하나 이상 있으면, 조용한 답장만 있는 경우 모든 표면에서 다시 작성되지 않고 삭제됩니다. 따라서 하위 완료 이벤트가 실제 답장을 전달할 때까지 상위는 조용히 유지됩니다. ## 관련 항목 diff --git a/docs/ko/concepts/progress-drafts.md b/docs/ko/concepts/progress-drafts.md index 1b36ea218..44739652a 100644 --- a/docs/ko/concepts/progress-drafts.md +++ b/docs/ko/concepts/progress-drafts.md @@ -1,26 +1,27 @@ --- read_when: - 장시간 실행되는 채팅 턴에 표시되는 진행 상황 업데이트 구성 - - 부분, 블록 및 진행 상황 스트리밍 모드 중 선택 - - 작업이 진행되는 동안 OpenClaw가 하나의 채널 메시지를 업데이트하는 방법 설명 - - 진행 초안, 독립형 진행 메시지 또는 최종화 폴백 문제 해결 -summary: '진행 초안: 에이전트가 실행되는 동안 업데이트되는 표시 가능한 작업 진행 중 메시지 하나' + - 부분, 블록, 진행률 스트리밍 모드 중 선택하기 + - 작업 진행 중 OpenClaw가 하나의 채널 메시지를 업데이트하는 방식 설명 + - 진행 상황 초안, 독립형 진행 상황 메시지 또는 완료 처리 폴백 문제 해결 +summary: '진행 상황 초안: 에이전트가 실행되는 동안 업데이트되는 표시 가능한 작업 진행 중 메시지 하나' title: 진행 중인 초안 x-i18n: - generated_at: "2026-05-04T02:23:08Z" + generated_at: "2026-05-04T06:23:15Z" model: gpt-5.5 provider: openai - source_hash: 8ce19262800f1c3c3e505a3cf1d41ed5c3dffcbca168ad7b7afabdce62eee8fe + source_hash: f78c07866cd7f613012a80a40413e5866c1dd2edd477088f9fc141347f5f3788 source_path: concepts/progress-drafts.md workflow: 16 --- -진행 상황 초안은 장시간 실행되는 에이전트 턴이 채팅에서 살아 움직이는 것처럼 느껴지게 하면서도 -대화를 임시 상태 답글 더미로 만들지 않습니다. +진행 상황 초안은 장시간 실행되는 에이전트 턴이 채팅에서 살아 있는 것처럼 느껴지게 하면서도 +대화를 임시 상태 답장의 더미로 만들지 않습니다. -진행 상황 초안을 활성화하면 OpenClaw는 턴이 실제 작업을 하고 있음이 확인된 뒤에만 -보이는 작업 진행 중 메시지를 하나 만들고, 에이전트가 읽기, 계획 수립, 도구 호출 또는 승인 대기를 하는 동안 이를 업데이트한 다음, -채널이 안전하게 처리할 수 있으면 그 초안을 최종 답변으로 전환합니다. +진행 상황 초안을 사용하면 OpenClaw는 턴이 실제 작업을 하고 있음이 확인된 뒤에만 +보이는 작업 진행 중 메시지를 하나 만들고, 에이전트가 읽고, 계획하고, 도구를 호출하거나, +승인을 기다리는 동안 이를 업데이트한 다음, 채널에서 안전하게 처리할 수 있으면 그 초안을 +최종 답변으로 전환합니다. ```text Shelling... @@ -30,11 +31,11 @@ Shelling... ``` 도구 사용이 많은 작업 중에는 깔끔한 상태 메시지 하나를 보여 주고 -턴이 끝나면 최종 답변을 표시하고 싶을 때 진행 상황 초안을 사용하세요. +턴이 끝나면 최종 답변을 보여 주고 싶을 때 진행 상황 초안을 사용하세요. ## 빠른 시작 -채널별로 `streaming.mode: "progress"`를 설정해 진행 상황 초안을 활성화합니다. +`streaming.mode: "progress"`로 채널별 진행 상황 초안을 활성화합니다. ```json5 { @@ -48,47 +49,57 @@ Shelling... } ``` -대개 이것만으로 충분합니다. OpenClaw는 자동 한 단어 라벨을 선택하고, 작업이 최소 5초 동안 지속되거나 두 번째 작업 이벤트가 발생할 때까지 기다린 뒤, 유용한 작업이 진행되는 동안 간결한 진행 상황 줄을 추가하며, 해당 턴의 중복된 독립 실행형 진행 상황 잡담을 억제합니다. +대개 이것만으로 충분합니다. OpenClaw는 자동 한 단어 레이블을 선택하고, 작업이 +최소 5초 동안 지속되거나 두 번째 작업 이벤트를 내보낼 때까지 기다린 뒤, 유용한 +작업이 진행되는 동안 간결한 진행 상황 줄을 추가하며, 해당 턴의 중복 독립형 진행 상황 +잡담을 억제합니다. ## 사용자에게 보이는 내용 -진행 상황 초안은 두 부분으로 구성됩니다. +진행 상황 초안에는 두 부분이 있습니다. | 부분 | 목적 | | -------------- | --------------------------------------------------------------------------- | -| 라벨 | `Thinking...` 또는 `Shelling...` 같은 짧은 제목. | -| 진행 상황 줄 | 상세 출력과 동일한 도구 라벨 및 아이콘을 사용하는 간결한 실행 업데이트. | +| 레이블 | `Thinking...` 또는 `Shelling...` 같은 짧은 제목입니다. | +| 진행 상황 줄 | 자세한 출력과 동일한 도구 레이블 및 아이콘을 사용하는 간결한 실행 업데이트입니다. | -라벨은 에이전트가 의미 있는 작업을 시작한 뒤 5초 동안 계속 바쁘거나 두 번째 작업 이벤트를 발생시키면 표시됩니다. 일반 텍스트만 있는 답글에는 진행 상황 초안이 표시되지 않습니다. 진행 상황 줄은 에이전트가 유용한 작업 업데이트를 발생시킬 때만 추가됩니다. 예를 들어 `🛠️ Exec`, `🔎 Web Search`, `✍️ Write: to /tmp/file` 같은 항목입니다. -기본적으로 `/verbose`와 동일한 간결한 설명 모드를 사용합니다. 디버깅 중이고 원시 명령/세부 정보도 추가하고 싶다면 -`agents.defaults.toolProgressDetail: "raw"`를 설정하세요. +레이블은 에이전트가 의미 있는 작업을 시작하고 5초 동안 계속 바쁘거나 두 번째 작업 이벤트를 +내보낸 뒤에 나타납니다. 일반 텍스트 전용 답장은 진행 상황 초안을 표시하지 않습니다. +진행 상황 줄은 에이전트가 유용한 작업 업데이트를 내보낼 때만 추가됩니다. 예를 들어 +`🛠️ Exec`, `🔎 Web Search`, `✍️ Write: to /tmp/file` 같은 항목입니다. +기본적으로 `/verbose`와 동일한 간결한 설명 모드를 사용합니다. 디버깅 중이고 원시 +명령/세부 정보도 덧붙이고 싶으면 `agents.defaults.toolProgressDetail: "raw"`를 설정하세요. 가능하면 최종 답변이 초안을 대체합니다. 그렇지 않으면 -OpenClaw는 최종 답변을 일반 방식으로 보내고 채널 전송 방식에 따라 -초안을 정리하거나 업데이트를 중단합니다. +OpenClaw가 최종 답변을 정상적으로 보내고 채널의 전송 방식에 따라 초안을 정리하거나 +업데이트를 중단합니다. ## 모드 선택 `channels..streaming.mode`는 보이는 진행 중 동작을 제어합니다. -| 모드 | 적합한 경우 | 채팅에 표시되는 내용 | +| 모드 | 가장 적합한 경우 | 채팅에 표시되는 내용 | | ---------- | -------------------------------- | ------------------------------------------------- | -| `off` | 조용한 채널 | 최종 답변만 표시. | -| `partial` | 답변 텍스트가 나타나는 과정을 보고 싶을 때 | 최신 답변 텍스트로 편집되는 초안 하나. | -| `block` | 더 큰 답변 미리보기 청크 | 더 큰 청크 단위로 업데이트되거나 추가되는 미리보기 하나. | -| `progress` | 도구 사용이 많거나 장시간 실행되는 턴 | 상태 초안 하나, 이후 최종 답변. | +| `off` | 조용한 채널 | 최종 답변만 표시됩니다. | +| `partial` | 답변 텍스트가 나타나는 과정을 보는 경우 | 최신 답변 텍스트로 편집되는 초안 하나입니다. | +| `block` | 더 큰 답변 미리보기 청크 | 더 큰 청크로 업데이트되거나 덧붙는 미리보기 하나입니다. | +| `progress` | 도구 사용이 많거나 장시간 실행되는 턴 | 상태 초안 하나가 표시된 뒤 최종 답변이 표시됩니다. | -사용자가 답변 텍스트가 토큰 단위로 스트리밍되는 것보다 "무슨 일이 일어나고 있는지"에 더 관심이 있을 때 `progress`를 선택하세요. +사용자가 답변 텍스트가 토큰 단위로 스트리밍되는 것을 보는 것보다 "무슨 일이 일어나고 있는지"에 +더 관심이 있다면 `progress`를 선택하세요. -답변 자체가 진행 상황 신호라면 `partial`을 선택하세요. +답변 자체가 진행 신호라면 `partial`을 선택하세요. -더 큰 텍스트 청크로 초안 미리보기 업데이트를 원할 때는 `block`을 선택하세요. Discord와 Telegram에서 `streaming.mode: "block"`은 여전히 일반 블록 전달이 아니라 미리보기 스트리밍입니다. 일반 블록 답글을 원할 때는 `streaming.block.enabled` 또는 레거시 `blockStreaming`을 사용하세요. +더 큰 텍스트 청크로 초안 미리보기 업데이트를 원한다면 `block`을 선택하세요. Discord와 +Telegram에서 `streaming.mode: "block"`은 여전히 미리보기 스트리밍이지 일반 블록 전달이 +아닙니다. 일반 블록 답장을 원하면 `streaming.block.enabled` 또는 레거시 +`blockStreaming`을 사용하세요. -## 라벨 구성 +## 레이블 구성 -진행 상황 라벨은 `channels..streaming.progress` 아래에 있습니다. +진행 상황 레이블은 `channels..streaming.progress` 아래에 있습니다. -기본 라벨은 `auto`이며, OpenClaw의 내장 -줄임표가 붙은 한 단어 라벨 풀에서 선택합니다. +기본 레이블은 `auto`이며, OpenClaw의 내장 +줄임표가 붙은 한 단어 레이블 풀에서 선택합니다. ```text Thinking... @@ -113,7 +124,7 @@ Snapping... Surfacing... ``` -고정 라벨을 사용합니다. +고정 레이블을 사용합니다. ```json5 { @@ -130,7 +141,7 @@ Surfacing... } ``` -직접 정의한 자동 라벨 풀을 사용합니다. +사용자 지정 자동 레이블 풀을 사용합니다. ```json5 { @@ -148,7 +159,7 @@ Surfacing... } ``` -라벨을 숨기고 진행 상황 줄만 표시합니다. +레이블을 숨기고 진행 상황 줄만 표시합니다. ```json5 { @@ -167,7 +178,9 @@ Surfacing... ## 진행 상황 줄 제어 -진행 상황 줄은 진행 상황 모드에서 기본적으로 활성화됩니다. 이 줄은 실제 실행 이벤트에서 생성됩니다. 도구 시작, 항목 업데이트, 작업 계획, 승인, 명령 출력, 패치 요약 및 이와 유사한 에이전트 활동이 여기에 포함됩니다. +진행 상황 줄은 진행 상황 모드에서 기본적으로 활성화됩니다. 이는 실제 실행 이벤트에서 +나옵니다. 도구 시작, 항목 업데이트, 작업 계획, 승인, 명령 출력, 패치 요약 및 유사한 +에이전트 활동입니다. OpenClaw는 진행 상황 초안과 `/verbose`에 동일한 포매터를 사용합니다. @@ -181,9 +194,11 @@ OpenClaw는 진행 상황 초안과 `/verbose`에 동일한 포매터를 사용 } ``` -`"explain"`은 기본값이며 `🛠️ Exec: check JS syntax for /tmp/app.js` 같은 간결한 라벨로 초안을 안정적으로 유지합니다. `"raw"`는 사용할 수 있을 때 내부 명령/세부 정보를 추가하므로 디버깅 중에는 유용하지만 채팅에서는 더 시끄럽습니다. +`"explain"`은 기본값이며 `🛠️ Exec: check JS syntax for /tmp/app.js` 같은 +간결한 레이블로 초안을 안정적으로 유지합니다. `"raw"`는 사용할 수 있을 때 내부 +명령/세부 정보를 덧붙이므로 디버깅 중에는 유용하지만 채팅에서는 더 시끄럽습니다. -예를 들어 동일한 명령도 세부 정보 모드에 따라 다르게 표시됩니다. +예를 들어 같은 명령도 세부 정보 모드에 따라 다르게 표시됩니다. | 모드 | 진행 상황 줄 | | --------- | -------------------------------------------------------------------- | @@ -207,6 +222,32 @@ OpenClaw는 진행 상황 초안과 `/verbose`에 동일한 포매터를 사용 } ``` +초안이 편집되는 동안 채팅 말풍선 재배치를 줄이기 위해 진행 상황 줄은 자동으로 압축됩니다. + +OpenClaw는 반복되는 초안 편집이 업데이트마다 다르게 줄바꿈되지 않도록 기본적으로 긴 진행 상황 줄을 +잘라냅니다. 접두사는 읽기 쉬운 상태로 유지되고, 경로나 원시 명령 같은 긴 세부 정보는 +줄임표로 짧아집니다. + +Slack은 진행 상황 줄을 단일 텍스트 본문 대신 구조화된 Block Kit 필드로 렌더링할 수 있습니다. + +```json5 +{ + channels: { + slack: { + streaming: { + mode: "progress", + progress: { + render: "rich", + }, + }, + }, + }, +} +``` + +리치 렌더링은 동일한 일반 텍스트 대체 표시를 유지하므로 더 풍부한 형태를 지원하지 않는 +채널과 클라이언트도 간결한 진행 상황 텍스트를 계속 표시할 수 있습니다. + 단일 진행 상황 초안은 유지하되 도구 및 작업 줄을 숨깁니다. ```json5 @@ -224,8 +265,9 @@ OpenClaw는 진행 상황 초안과 `/verbose`에 동일한 포매터를 사용 } ``` -`toolProgress: false`를 설정해도 OpenClaw는 해당 턴의 이전 독립 실행형 -도구 진행 상황 메시지를 계속 억제합니다. 라벨이 구성된 경우를 제외하면 채널은 최종 답변이 나올 때까지 시각적으로 조용하게 유지됩니다. +`toolProgress: false`를 사용하면 OpenClaw는 해당 턴의 이전 독립형 +도구 진행 상황 메시지도 계속 억제합니다. 레이블이 구성된 경우를 제외하면 채널은 +최종 답변이 올 때까지 시각적으로 조용하게 유지됩니다. ## 채널 동작 @@ -233,48 +275,63 @@ OpenClaw는 진행 상황 초안과 `/verbose`에 동일한 포매터를 사용 | 채널 | 진행 상황 전송 방식 | 참고 | | --------------- | -------------------------------------- | --------------------------------------------------------------------- | -| Discord | 메시지 하나를 보낸 뒤 편집. | 하나의 안전한 미리보기 메시지에 들어갈 때 최종 텍스트를 제자리에서 편집. | -| Matrix | 이벤트 하나를 보낸 뒤 편집. | 계정 수준 스트리밍 구성이 계정 수준 초안을 제어. | -| Microsoft Teams | 개인 채팅에서 네이티브 Teams 스트림. | `streaming.mode: "block"`은 Teams 블록 전달에 매핑됨. | -| Slack | 네이티브 스트림 또는 편집 가능한 초안 게시물. | 스레드 사용 가능 여부가 네이티브 스트리밍 사용 가능 여부에 영향을 줌. | -| Telegram | 메시지 하나를 보낸 뒤 편집. | 최종 타임스탬프가 유용하게 유지되도록 이전의 보이는 초안이 대체될 수 있음. | -| Mattermost | 편집 가능한 초안 게시물. | 도구 활동은 동일한 초안 스타일 게시물에 접힘. | +| Discord | 메시지 하나를 보낸 뒤 편집합니다. | 안전한 미리보기 메시지 하나에 들어가면 최종 텍스트가 제자리에서 편집됩니다. | +| Matrix | 이벤트 하나를 보낸 뒤 편집합니다. | 계정 수준 스트리밍 구성이 계정 수준 초안을 제어합니다. | +| Microsoft Teams | 개인 채팅에서 네이티브 Teams 스트림을 사용합니다. | `streaming.mode: "block"`은 Teams 블록 전달에 매핑됩니다. | +| Slack | 네이티브 스트림 또는 편집 가능한 초안 게시물입니다. | 스레드 사용 가능 여부가 네이티브 스트리밍 사용 가능 여부에 영향을 줍니다. | +| Telegram | 메시지 하나를 보낸 뒤 편집합니다. | 오래된 보이는 초안은 최종 타임스탬프가 유용하게 유지되도록 대체될 수 있습니다. | +| Mattermost | 편집 가능한 초안 게시물입니다. | 도구 활동은 동일한 초안 스타일 게시물에 접혀 들어갑니다. | -안전한 편집 지원이 없는 채널은 일반적으로 입력 표시기 또는 최종 답변만 전달하는 방식으로 대체됩니다. +안전한 편집 지원이 없는 채널은 일반적으로 입력 표시기 또는 최종 전용 전달로 대체됩니다. ## 마무리 -최종 답변이 준비되면 OpenClaw는 채팅을 깔끔하게 유지하려고 합니다. +최종 답변이 준비되면 OpenClaw는 채팅을 깔끔하게 유지하려고 시도합니다. -- 초안을 최종 답변으로 안전하게 전환할 수 있으면 OpenClaw는 이를 제자리에서 편집합니다. -- 채널이 네이티브 진행 상황 스트리밍을 사용하면 OpenClaw는 네이티브 전송이 최종 텍스트를 수락할 때 해당 스트림을 마무리합니다. -- 최종 답변에 미디어, 승인 프롬프트, 명시적 답글 대상, 너무 많은 청크가 있거나 편집/전송 실패가 발생하면 OpenClaw는 일반 채널 전달 경로를 통해 최종 답변을 보냅니다. +- 초안이 안전하게 최종 답변이 될 수 있으면 OpenClaw는 이를 제자리에서 편집합니다. +- 채널이 네이티브 진행 상황 스트리밍을 사용하면, 네이티브 전송 방식이 최종 텍스트를 + 받아들일 때 OpenClaw가 해당 스트림을 마무리합니다. +- 최종 답변에 미디어, 승인 프롬프트, 명시적 답장 대상, 너무 많은 청크가 있거나 + 편집/전송이 실패하면 OpenClaw는 일반 채널 전달 경로를 통해 최종 답변을 보냅니다. -대체 경로는 의도된 동작입니다. 텍스트를 잃거나, 답글이 잘못된 스레드에 달리거나, 채널이 안전하게 표현할 수 없는 페이로드로 초안을 덮어쓰는 것보다 새 최종 답변을 보내는 편이 낫습니다. +대체 경로는 의도된 동작입니다. 텍스트를 잃거나, 답장이 잘못된 스레드에 달리거나, +채널이 안전하게 표현할 수 없는 페이로드로 초안을 덮어쓰는 것보다 새 최종 답변을 보내는 편이 +낫습니다. ## 문제 해결 **최종 답변만 보입니다.** -메시지를 처리한 계정 또는 채널에 대해 `channels..streaming.mode`가 `progress`로 설정되어 있는지 확인하세요. 일부 그룹 또는 인용 답글 경로에서는 채널이 올바른 메시지를 안전하게 편집할 수 없을 때 해당 턴의 초안 미리보기가 비활성화될 수 있습니다. +메시지를 처리한 계정 또는 채널에 대해 `channels..streaming.mode`가 +`progress`로 설정되어 있는지 확인하세요. 일부 그룹 또는 인용 답장 경로에서는 채널이 올바른 +메시지를 안전하게 편집할 수 없을 때 해당 턴의 초안 미리보기를 비활성화할 수 있습니다. -**라벨은 보이지만 도구 줄이 보이지 않습니다.** +**레이블은 보이지만 도구 줄은 보이지 않습니다.** -`streaming.progress.toolProgress`를 확인하세요. `false`이면 OpenClaw는 단일 초안 동작은 유지하지만 도구 및 작업 진행 상황 줄을 숨깁니다. +`streaming.progress.toolProgress`를 확인하세요. `false`이면 OpenClaw는 +단일 초안 동작을 유지하지만 도구 및 작업 진행 상황 줄을 숨깁니다. **편집된 초안 대신 새 최종 메시지가 보입니다.** -이는 안전 대체 동작입니다. 미디어 답글, 긴 답변, 명시적 답글 대상, 오래된 Telegram 초안, 누락된 Slack 스레드 대상, 삭제된 미리보기 메시지 또는 네이티브 스트림 마무리 실패에서 발생할 수 있습니다. +이는 안전 대체 동작입니다. 미디어 답장, 긴 답변, 명시적 답장 대상, 오래된 Telegram 초안, +누락된 Slack 스레드 대상, 삭제된 미리보기 메시지 또는 네이티브 스트림 마무리 실패에서 +발생할 수 있습니다. -**독립 실행형 진행 상황 메시지가 계속 보입니다.** +**독립형 진행 상황 메시지가 계속 보입니다.** -진행 상황 모드는 초안이 활성화되어 있을 때 기본 독립 실행형 도구 진행 상황 메시지를 억제합니다. 독립 실행형 메시지가 계속 표시된다면 해당 턴이 실제로 진행 상황 모드를 사용하고 있는지, 그리고 `streaming.mode: "off"`나 해당 메시지에 대해 초안을 만들 수 없는 채널 경로를 사용하고 있지 않은지 확인하세요. +진행 상황 모드는 초안이 활성화되어 있을 때 기본 독립형 도구 진행 상황 메시지를 억제합니다. +독립형 메시지가 계속 나타나면 해당 턴이 실제로 진행 상황 모드를 사용하고 있으며 +`streaming.mode: "off"` 또는 해당 메시지에 대한 초안을 만들 수 없는 채널 경로를 +사용하고 있지 않은지 확인하세요. **Teams가 Discord 또는 Telegram과 다르게 동작합니다.** -Microsoft Teams는 일반적인 보내기-편집 미리보기 전송 방식 대신 개인 채팅에서 네이티브 스트림을 사용합니다. 또한 Teams는 Discord와 Telegram에서 사용하는 것과 같은 초안 미리보기 블록 모드가 없기 때문에 `streaming.mode: "block"`을 Teams 블록 전달로 처리합니다. +Microsoft Teams는 일반적인 보내고 편집하는 미리보기 전송 방식 대신 개인 채팅에서 +네이티브 스트림을 사용합니다. 또한 Teams는 Discord와 Telegram에서 사용하는 동일한 +초안 미리보기 블록 모드가 없기 때문에 `streaming.mode: "block"`을 Teams 블록 전달로 +취급합니다. -## 관련 항목 +## 관련 문서 - [스트리밍 및 청킹](/ko/concepts/streaming) - [메시지](/ko/concepts/messages) diff --git a/docs/ko/concepts/qa-e2e-automation.md b/docs/ko/concepts/qa-e2e-automation.md index bd51a2af9..c2a738aac 100644 --- a/docs/ko/concepts/qa-e2e-automation.md +++ b/docs/ko/concepts/qa-e2e-automation.md @@ -1,80 +1,81 @@ --- read_when: - - QA 스택이 어떻게 서로 맞물리는지 이해하기 + - QA 스택이 어떻게 함께 작동하는지 이해하기 - qa-lab, qa-channel 또는 전송 어댑터 확장하기 - 리포지토리 기반 QA 시나리오 추가 - - Gateway 대시보드를 중심으로 더 현실적인 QA 자동화 구축 -summary: 'QA 스택 개요: qa-lab, qa-channel, 리포지토리 기반 시나리오, 라이브 전송 레인, 전송 어댑터, 보고.' + - Gateway 대시보드를 중심으로 더 현실적인 QA 자동화 구축하기 +summary: 'QA 스택 개요: qa-lab, qa-channel, 리포지토리 기반 시나리오, 라이브 전송 레인, 전송 어댑터 및 보고.' title: QA 개요 x-i18n: - generated_at: "2026-05-04T02:23:08Z" + generated_at: "2026-05-04T06:23:55Z" model: gpt-5.5 provider: openai - source_hash: 0b376767b967a51cc8a45ca5ce420f78067b52e6368d2abe921ffed533f6f9ba + source_hash: 067f5aa0831724659ae36d548ef2e7bd28b40aad9cef45f325a01a2748003b29 source_path: concepts/qa-e2e-automation.md workflow: 16 --- -비공개 QA 스택은 단일 단위 테스트보다 더 현실적이고, +비공개 QA 스택은 단일 단위 테스트보다 더 현실적인, 채널 형태에 가까운 방식으로 OpenClaw를 검증하기 위한 것입니다. 현재 구성 요소: - `extensions/qa-channel`: DM, 채널, 스레드, - 반응, 편집, 삭제 표면을 갖춘 합성 메시지 채널. + 반응, 편집, 삭제 표면을 갖춘 합성 메시지 채널입니다. - `extensions/qa-lab`: 트랜스크립트를 관찰하고, - 인바운드 메시지를 주입하며, Markdown 보고서를 내보내기 위한 디버거 UI와 QA 버스. -- `extensions/qa-matrix`, 향후 runner Plugin: 하위 QA Gateway 안에서 - 실제 채널을 구동하는 라이브 전송 어댑터. -- `qa/`: 시작 태스크와 기준 QA - 시나리오를 위한 저장소 기반 시드 자산. -- [Mantis](/ko/concepts/mantis): 실제 전송, 브라우저 스크린샷, VM 상태, PR 증거가 - 필요한 버그에 대한 라이브 검증 전후 절차. + 인바운드 메시지를 주입하며, Markdown 보고서를 내보내기 위한 디버거 UI 및 QA 버스입니다. +- `extensions/qa-matrix`, 향후 러너 Plugin: 하위 QA Gateway 안에서 + 실제 채널을 구동하는 라이브 전송 어댑터입니다. +- `qa/`: 시작 작업 및 기준 QA + 시나리오를 위한 저장소 기반 시드 자산입니다. +- [Mantis](/ko/concepts/mantis): 실제 전송, 브라우저 스크린샷, + VM 상태, PR 증거가 필요한 버그를 위한 라이브 검증 전후 비교입니다. -## 명령 인터페이스 +## 명령어 인터페이스 -모든 QA 흐름은 `pnpm openclaw qa ` 아래에서 실행됩니다. 다수는 `pnpm qa:*` -스크립트 별칭을 가지고 있으며, 두 형식 모두 지원됩니다. +모든 QA 흐름은 `pnpm openclaw qa ` 아래에서 실행됩니다. 많은 명령에는 `pnpm qa:*` +스크립트 별칭이 있으며, 두 형식 모두 지원됩니다. -| 명령 | 목적 | -| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `qa run` | 번들된 QA 자체 점검이며, Markdown 보고서를 작성합니다. | -| `qa suite` | 저장소 기반 시나리오를 QA Gateway 레인에 대해 실행합니다. 별칭: 일회용 Linux VM에는 `pnpm openclaw qa suite --runner multipass`. | -| `qa coverage` | Markdown 시나리오 커버리지 인벤토리를 출력합니다(기계 출력은 `--json`). | -| `qa parity-report` | 두 `qa-suite-summary.json` 파일을 비교하고 agentic 패리티 보고서를 작성합니다. | -| `qa character-eval` | 여러 라이브 모델에 걸쳐 캐릭터 QA 시나리오를 실행하고 판정된 보고서를 생성합니다. [보고](#reporting)를 참조하세요. | -| `qa manual` | 선택한 provider/model 레인에 대해 일회성 프롬프트를 실행합니다. | -| `qa ui` | QA 디버거 UI와 로컬 QA 버스를 시작합니다(별칭: `pnpm qa:lab:ui`). | -| `qa docker-build-image` | 미리 빌드된 QA Docker 이미지를 빌드합니다. | -| `qa docker-scaffold` | QA 대시보드 + Gateway 레인을 위한 docker-compose 스캐폴드를 작성합니다. | -| `qa up` | QA 사이트를 빌드하고, Docker 기반 스택을 시작하고, URL을 출력합니다(별칭: `pnpm qa:lab:up`; `:fast` 변형은 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`를 추가). | -| `qa aimock` | AIMock provider 서버만 시작합니다. | -| `qa mock-openai` | 시나리오 인식 `mock-openai` provider 서버만 시작합니다. | -| `qa credentials doctor` / `add` / `list` / `remove` | 공유 Convex 자격 증명 풀을 관리합니다. | -| `qa matrix` | 일회용 Tuwunel homeserver에 대한 라이브 전송 레인입니다. [Matrix QA](/ko/concepts/qa-matrix)를 참조하세요. | -| `qa telegram` | 실제 비공개 Telegram 그룹에 대한 라이브 전송 레인입니다. | -| `qa discord` | 실제 비공개 Discord 길드 채널에 대한 라이브 전송 레인입니다. | -| `qa slack` | 실제 비공개 Slack 채널에 대한 라이브 전송 레인입니다. | -| `qa mantis` | 라이브 전송 버그를 위한 검증 전후 runner이며, Discord 상태 반응 증거와 Crabbox 데스크톱/브라우저 smoke를 포함합니다. [Mantis](/ko/concepts/mantis)를 참조하세요. | +| 명령어 | 목적 | +| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `qa run` | 번들된 QA 자체 점검을 실행하고 Markdown 보고서를 작성합니다. | +| `qa suite` | QA Gateway 레인에 대해 저장소 기반 시나리오를 실행합니다. 별칭: 일회용 Linux VM에는 `pnpm openclaw qa suite --runner multipass`를 사용합니다. | +| `qa coverage` | Markdown 시나리오 범위 인벤토리를 출력합니다(머신 출력에는 `--json`). | +| `qa parity-report` | 두 `qa-suite-summary.json` 파일을 비교하고 에이전트식 패리티 보고서를 작성합니다. | +| `qa character-eval` | 여러 라이브 모델에서 캐릭터 QA 시나리오를 실행하고 판정 보고서를 생성합니다. [보고](#reporting)를 참조하세요. | +| `qa manual` | 선택한 공급자/모델 레인에 대해 일회성 프롬프트를 실행합니다. | +| `qa ui` | QA 디버거 UI와 로컬 QA 버스를 시작합니다(별칭: `pnpm qa:lab:ui`). | +| `qa docker-build-image` | 사전 빌드된 QA Docker 이미지를 빌드합니다. | +| `qa docker-scaffold` | QA 대시보드 + Gateway 레인을 위한 docker-compose 스캐폴드를 작성합니다. | +| `qa up` | QA 사이트를 빌드하고, Docker 기반 스택을 시작하며, URL을 출력합니다(별칭: `pnpm qa:lab:up`; `:fast` 변형은 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`를 추가합니다). | +| `qa aimock` | AIMock 공급자 서버만 시작합니다. | +| `qa mock-openai` | 시나리오 인식 `mock-openai` 공급자 서버만 시작합니다. | +| `qa credentials doctor` / `add` / `list` / `remove` | 공유 Convex 자격 증명 풀을 관리합니다. | +| `qa matrix` | 일회용 Tuwunel 홈서버에 대한 라이브 전송 레인입니다. [Matrix QA](/ko/concepts/qa-matrix)를 참조하세요. | +| `qa telegram` | 실제 비공개 Telegram 그룹에 대한 라이브 전송 레인입니다. | +| `qa discord` | 실제 비공개 Discord 길드 채널에 대한 라이브 전송 레인입니다. | +| `qa slack` | 실제 비공개 Slack 채널에 대한 라이브 전송 레인입니다. | +| `qa mantis` | 라이브 전송 버그를 위한 검증 전후 러너이며, Discord 상태 반응 증거, Crabbox 데스크톱/브라우저 스모크, Slack-in-VNC 스모크를 포함합니다. [Mantis](/ko/concepts/mantis)를 참조하세요. | ## 운영자 흐름 -현재 QA 운영자 흐름은 두 패널 QA 사이트입니다. +현재 QA 운영자 흐름은 2개 패널로 구성된 QA 사이트입니다. -- 왼쪽: 에이전트가 포함된 Gateway 대시보드(Control UI). -- 오른쪽: Slack과 유사한 트랜스크립트와 시나리오 계획을 보여 주는 QA Lab. +- 왼쪽: 에이전트가 있는 Gateway 대시보드(Control UI)입니다. +- 오른쪽: Slack과 유사한 트랜스크립트와 시나리오 계획을 보여 주는 QA Lab입니다. -다음으로 실행합니다. +다음 명령으로 실행합니다. ```bash pnpm qa:lab:up ``` -이 명령은 QA 사이트를 빌드하고, Docker 기반 Gateway 레인을 시작하며, 운영자나 자동화 루프가 에이전트에 QA -미션을 부여하고, 실제 채널 동작을 관찰하며, 작동한 것, 실패한 것, 또는 -차단 상태로 남은 것을 기록할 수 있는 QA Lab 페이지를 노출합니다. +이 명령은 QA 사이트를 빌드하고, Docker 기반 Gateway 레인을 시작하며, +운영자 또는 자동화 루프가 에이전트에 QA +미션을 부여하고, 실제 채널 동작을 관찰하며, 무엇이 작동했는지, 실패했는지, 또는 +차단 상태로 남았는지를 기록할 수 있는 QA Lab 페이지를 노출합니다. -매번 Docker 이미지를 다시 빌드하지 않고 더 빠르게 QA Lab UI를 반복 작업하려면, +매번 Docker 이미지를 다시 빌드하지 않고 더 빠르게 QA Lab UI를 반복하려면, 바인드 마운트된 QA Lab 번들로 스택을 시작하세요. ```bash @@ -84,39 +85,39 @@ pnpm qa:lab:up:fast pnpm qa:lab:watch ``` -`qa:lab:up:fast`는 Docker 서비스를 미리 빌드된 이미지에 유지하고 +`qa:lab:up:fast`는 Docker 서비스를 사전 빌드된 이미지에 유지하고 `extensions/qa-lab/web/dist`를 `qa-lab` 컨테이너에 바인드 마운트합니다. `qa:lab:watch`는 변경 시 해당 번들을 다시 빌드하며, QA Lab 자산 해시가 변경되면 브라우저가 자동으로 다시 로드됩니다. -로컬 OpenTelemetry trace smoke의 경우 다음을 실행하세요. +로컬 OpenTelemetry 트레이스 스모크를 실행하려면 다음을 실행하세요. ```bash pnpm qa:otel:smoke ``` -이 스크립트는 로컬 OTLP/HTTP trace receiver를 시작하고, +이 스크립트는 로컬 OTLP/HTTP 트레이스 수신기를 시작하고, `diagnostics-otel` Plugin을 활성화한 상태로 `otel-trace-smoke` QA 시나리오를 실행한 다음, -내보낸 protobuf span을 디코딩하고 릴리스에 중요한 형태를 단언합니다. +내보낸 protobuf span을 디코딩하고 릴리스에 중요한 형태를 검증합니다: `openclaw.run`, `openclaw.harness.run`, `openclaw.model.call`, -`openclaw.context.assembled`, `openclaw.message.delivery`가 반드시 있어야 하며, -성공한 턴의 모델 호출은 `StreamAbandoned`를 내보내면 안 됩니다. 원시 진단 ID와 -`openclaw.content.*` 속성은 trace에 포함되지 않아야 합니다. 이 스크립트는 +`openclaw.context.assembled`, `openclaw.message.delivery`가 있어야 하며, +성공한 턴에서는 모델 호출이 `StreamAbandoned`를 내보내면 안 되고, 원시 진단 ID와 +`openclaw.content.*` 속성은 트레이스에 포함되지 않아야 합니다. 이 스크립트는 QA suite 아티팩트 옆에 `otel-smoke-summary.json`을 작성합니다. -관측성 QA는 소스 체크아웃 전용으로 유지됩니다. npm tarball은 의도적으로 -QA Lab을 생략하므로 패키지 Docker 릴리스 레인은 `qa` 명령을 실행하지 않습니다. 진단 +관찰 가능성 QA는 소스 체크아웃 전용으로 유지됩니다. npm tarball은 의도적으로 +QA Lab을 제외하므로 패키지 Docker 릴리스 레인에서는 `qa` 명령을 실행하지 않습니다. 진단 계측을 변경할 때는 빌드된 소스 체크아웃에서 `pnpm qa:otel:smoke`를 사용하세요. -실제 전송 Matrix smoke 레인의 경우 다음을 실행하세요. +전송이 실제인 Matrix 스모크 레인을 실행하려면 다음을 실행하세요. ```bash pnpm openclaw qa matrix --profile fast --fail-fast ``` -이 레인의 전체 CLI 참조, profile/scenario 카탈로그, env vars, 아티팩트 레이아웃은 [Matrix QA](/ko/concepts/qa-matrix)에 있습니다. 요약하면 Docker에서 일회용 Tuwunel homeserver를 프로비저닝하고, 임시 driver/SUT/observer 사용자를 등록하며, 해당 전송에 범위가 지정된 하위 QA Gateway 안에서 실제 Matrix Plugin을 실행하고(`qa-channel` 없음), 이후 `.artifacts/qa-e2e/matrix-/` 아래에 Markdown 보고서, JSON 요약, observed-events 아티팩트, 결합된 출력 로그를 작성합니다. +이 레인의 전체 CLI 참조, 프로필/시나리오 카탈로그, 환경 변수, 아티팩트 레이아웃은 [Matrix QA](/ko/concepts/qa-matrix)에 있습니다. 간단히 말해, Docker에서 일회용 Tuwunel 홈서버를 프로비저닝하고, 임시 드라이버/SUT/관찰자 사용자를 등록하며, 해당 전송 범위로 제한된 하위 QA Gateway 안에서 실제 Matrix Plugin을 실행하고(`qa-channel` 없음), 그런 다음 `.artifacts/qa-e2e/matrix-/` 아래에 Markdown 보고서, JSON 요약, 관찰된 이벤트 아티팩트, 통합 출력 로그를 작성합니다. -실제 전송 Telegram, Discord, Slack smoke 레인의 경우: +전송이 실제인 Telegram, Discord, Slack 스모크 레인의 경우: ```bash pnpm openclaw qa telegram @@ -124,7 +125,25 @@ pnpm openclaw qa discord pnpm openclaw qa slack ``` -이들은 두 봇(driver + SUT)이 있는 기존 실제 채널을 대상으로 합니다. 필수 env vars, 시나리오 목록, 출력 아티팩트, Convex 자격 증명 풀은 아래 [Telegram, Discord, Slack QA 참조](#telegram-discord-and-slack-qa-reference)에 문서화되어 있습니다. +이들은 두 봇(드라이버 + SUT)이 있는 기존 실제 채널을 대상으로 합니다. 필수 환경 변수, 시나리오 목록, 출력 아티팩트, Convex 자격 증명 풀은 아래의 [Telegram, Discord 및 Slack QA 참조](#telegram-discord-and-slack-qa-reference)에 문서화되어 있습니다. + +VNC 복구가 포함된 전체 Slack 데스크톱 VM 실행의 경우 다음을 실행하세요. + +```bash +pnpm openclaw qa mantis slack-desktop-smoke \ + --gateway-setup \ + --scenario slack-canary \ + --keep-lease +``` + +이 명령은 Crabbox 데스크톱/브라우저 머신을 임대하고, VM 안에서 Slack 라이브 레인을 +실행하며, VNC 브라우저에서 Slack Web을 열고, 데스크톱을 캡처한 다음, +`slack-qa/`와 `slack-desktop-smoke.png`를 Mantis 아티팩트 +디렉터리로 복사합니다. VNC를 통해 Slack Web에 수동으로 로그인한 뒤에는 +`--lease-id `를 재사용하세요. `--gateway-setup`을 사용하면 Mantis는 VM 안에서 포트 `38973`에 +영구 OpenClaw Slack +Gateway를 실행 상태로 둡니다. 이 옵션이 없으면 명령은 +일반적인 봇 간 Slack QA 레인을 실행하고 아티팩트 캡처 후 종료합니다. 풀링된 라이브 자격 증명을 사용하기 전에 다음을 실행하세요. @@ -132,22 +151,22 @@ pnpm openclaw qa slack pnpm openclaw qa credentials doctor ``` -doctor는 Convex broker 환경을 확인하고, 엔드포인트 설정을 검증하며, 유지관리자 secret이 있을 때 admin/list 도달 가능성을 확인합니다. secret에 대해서는 설정됨/누락 상태만 보고합니다. +doctor는 Convex 브로커 환경을 확인하고, 엔드포인트 설정을 검증하며, 유지 관리자 시크릿이 있을 때 admin/list 도달 가능성을 확인합니다. 시크릿에 대해서는 설정됨/누락 상태만 보고합니다. -## 라이브 전송 커버리지 +## 라이브 전송 범위 -라이브 전송 레인은 각자 고유한 시나리오 목록 형태를 만들지 않고 하나의 계약을 공유합니다. `qa-channel`은 광범위한 합성 제품 동작 suite이며 라이브 전송 커버리지 매트릭스의 일부가 아닙니다. +라이브 전송 레인은 각자 고유한 시나리오 목록 형태를 만들지 않고 하나의 계약을 공유합니다. `qa-channel`은 폭넓은 합성 제품 동작 suite이며 라이브 전송 범위 매트릭스의 일부가 아닙니다. -| 레인 | Canary | 멘션 게이팅 | 봇 간 통신 | 허용 목록 차단 | 최상위 답글 | 재시작 재개 | 스레드 후속 조치 | 스레드 격리 | 반응 관찰 | 도움말 명령 | 네이티브 명령 등록 | -| -------- | ------ | ----------- | ---------- | --------------- | ----------- | ----------- | ---------------- | ----------- | --------- | ----------- | ------------------ | -| Matrix | x | x | x | x | x | x | x | x | x | | | -| Telegram | x | x | x | | | | | | | x | | -| Discord | x | x | x | | | | | | | | x | -| Slack | x | x | x | | | | | | | | | +| 레인 | Canary | 멘션 게이팅 | 봇 간 | 허용 목록 차단 | 최상위 답장 | 재시작 재개 | 스레드 후속 응답 | 스레드 격리 | 반응 관찰 | 도움말 명령 | 네이티브 명령 등록 | +| -------- | ------ | ----------- | ----- | --------------- | ----------- | ----------- | ---------------- | ----------- | --------- | ----------- | ------------------ | +| Matrix | x | x | x | x | x | x | x | x | x | | | +| Telegram | x | x | x | | | | | | | x | | +| Discord | x | x | x | | | | | | | | x | +| Slack | x | x | x | | | | | | | | | -이렇게 하면 `qa-channel`은 광범위한 제품 동작 suite로 유지되는 한편 Matrix, -Telegram, 향후 라이브 전송은 하나의 명시적 전송 계약 -체크리스트를 공유합니다. +이는 `qa-channel`을 폭넓은 제품 동작 suite로 유지하면서, Matrix, +Telegram 및 향후 라이브 전송이 하나의 명시적인 전송 계약 +체크리스트를 공유하도록 합니다. QA 경로에 Docker를 포함하지 않는 일회용 Linux VM 레인의 경우 다음을 실행하세요. @@ -155,41 +174,33 @@ QA 경로에 Docker를 포함하지 않는 일회용 Linux VM 레인의 경우 pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline ``` -이 명령은 새 Multipass guest를 부팅하고, 의존성을 설치하고, guest 안에서 OpenClaw를 -빌드하고, `qa suite`를 실행한 다음 일반 QA 보고서와 -요약을 host의 `.artifacts/qa-e2e/...`로 다시 복사합니다. -host에서의 `qa suite`와 동일한 시나리오 선택 동작을 재사용합니다. -host 및 Multipass suite 실행은 기본적으로 격리된 Gateway worker로 선택한 여러 시나리오를 병렬로 실행합니다. `qa-channel`의 기본 concurrency는 -4이며, 선택된 시나리오 수로 제한됩니다. worker 수를 조정하려면 `--concurrency `를 사용하고, -직렬 실행에는 `--concurrency 1`을 사용하세요. -어떤 시나리오든 실패하면 명령은 0이 아닌 코드로 종료됩니다. 실패 종료 코드 없이 -아티팩트를 원할 때는 `--allow-failures`를 사용하세요. -라이브 실행은 guest에 실용적으로 전달 가능한 지원 QA auth 입력을 전달합니다. -env 기반 provider 키, QA 라이브 provider config 경로, -그리고 있을 경우 `CODEX_HOME`입니다. guest가 마운트된 workspace를 통해 다시 쓸 수 있도록 -`--output-dir`를 저장소 루트 아래에 두세요. +새 Multipass 게스트를 부팅하고, 종속성을 설치하고, 게스트 안에서 OpenClaw를 빌드하고, `qa suite`를 실행한 다음, 일반 QA 보고서와 요약을 호스트의 `.artifacts/qa-e2e/...`로 다시 복사합니다. +호스트의 `qa suite`와 동일한 시나리오 선택 동작을 재사용합니다. +호스트와 Multipass 스위트 실행은 기본적으로 격리된 Gateway 워커로 선택된 여러 시나리오를 병렬 실행합니다. `qa-channel`은 기본 동시 실행 수가 4이며, 선택된 시나리오 수로 상한이 제한됩니다. 워커 수를 조정하려면 `--concurrency `를 사용하고, 직렬 실행에는 `--concurrency 1`을 사용하세요. +시나리오 하나라도 실패하면 명령은 0이 아닌 값으로 종료됩니다. 실패 종료 코드 없이 아티팩트를 얻고 싶을 때는 `--allow-failures`를 사용하세요. +라이브 실행은 게스트에서 실용적으로 사용할 수 있는 지원 QA 인증 입력을 전달합니다. 여기에는 env 기반 공급자 키, QA 라이브 공급자 구성 경로, 그리고 있을 경우 `CODEX_HOME`이 포함됩니다. 게스트가 마운트된 워크스페이스를 통해 다시 쓸 수 있도록 `--output-dir`을 리포지토리 루트 아래에 두세요. ## Telegram, Discord, Slack QA 참조 -Matrix는 시나리오 수와 Docker 기반 homeserver 프로비저닝 때문에 [전용 페이지](/ko/concepts/qa-matrix)가 있습니다. Telegram, Discord, Slack은 더 작습니다. 각각 몇 개의 시나리오만 있고, profile 시스템이 없으며, 기존 실제 채널을 대상으로 하므로 참조는 여기에 있습니다. +Matrix는 시나리오 수와 Docker 기반 homeserver 프로비저닝 때문에 [전용 페이지](/ko/concepts/qa-matrix)가 있습니다. Telegram, Discord, Slack은 각각 몇 개의 시나리오만 있고, 프로필 시스템이 없으며, 기존 실제 채널을 대상으로 하므로 해당 참조는 여기에 있습니다. -### 공유 CLI flags +### 공유 CLI 플래그 -이 레인들은 `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts`를 통해 등록되며 동일한 flags를 허용합니다. +이 레인들은 `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts`를 통해 등록되며 같은 플래그를 받습니다. | 플래그 | 기본값 | 설명 | | ------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| `--scenario ` | — | 이 시나리오만 실행합니다. 반복해서 지정할 수 있습니다. | +| `--scenario ` | — | 이 시나리오만 실행합니다. 반복할 수 있습니다. | | `--output-dir ` | `/.artifacts/qa-e2e/{telegram,discord,slack}-` | 보고서/요약/관찰된 메시지와 출력 로그가 기록되는 위치입니다. 상대 경로는 `--repo-root`를 기준으로 해석됩니다. | -| `--repo-root ` | `process.cwd()` | 중립적인 cwd에서 호출할 때의 저장소 루트입니다. | -| `--sut-account ` | `sut` | QA Gateway 설정 내부의 임시 계정 ID입니다. | -| `--provider-mode ` | `live-frontier` | `mock-openai` 또는 `live-frontier`입니다. 기존 `live-openai`도 계속 작동합니다. | -| `--model ` / `--alt-model ` | 프로바이더 기본값 | 기본/대체 모델 참조입니다. | -| `--fast` | 꺼짐 | 지원되는 경우 프로바이더 빠른 모드입니다. | +| `--repo-root ` | `process.cwd()` | 중립적인 cwd에서 호출할 때의 리포지토리 루트입니다. | +| `--sut-account ` | `sut` | QA Gateway 구성 안의 임시 계정 ID입니다. | +| `--provider-mode ` | `live-frontier` | `mock-openai` 또는 `live-frontier`입니다. 레거시 `live-openai`도 계속 작동합니다. | +| `--model ` / `--alt-model ` | 공급자 기본값 | 기본/대체 모델 참조입니다. | +| `--fast` | 꺼짐 | 지원되는 경우 공급자 빠른 모드입니다. | | `--credential-source ` | `env` | [Convex 자격 증명 풀](#convex-credential-pool)을 참조하세요. | | `--credential-role ` | CI에서는 `ci`, 그 외에는 `maintainer` | `--credential-source convex`일 때 사용되는 역할입니다. | -각 레인은 실패한 시나리오가 있으면 0이 아닌 값으로 종료됩니다. `--allow-failures`는 실패 종료 코드를 설정하지 않고 아티팩트를 기록합니다. +각 레인은 실패한 시나리오가 하나라도 있으면 0이 아닌 값으로 종료됩니다. `--allow-failures`는 실패 종료 코드를 설정하지 않고 아티팩트를 작성합니다. ### Telegram QA @@ -197,17 +208,17 @@ Matrix는 시나리오 수와 Docker 기반 homeserver 프로비저닝 때문에 pnpm openclaw qa telegram ``` -두 개의 서로 다른 봇(driver + SUT)이 있는 실제 비공개 Telegram 그룹 하나를 대상으로 합니다. SUT 봇에는 Telegram 사용자 이름이 있어야 합니다. 두 봇 모두 `@BotFather`에서 **Bot-to-Bot Communication Mode**를 활성화하면 봇 간 관찰이 가장 잘 작동합니다. +서로 다른 두 봇(드라이버 + SUT)이 있는 실제 비공개 Telegram 그룹 하나를 대상으로 합니다. SUT 봇에는 Telegram 사용자 이름이 있어야 합니다. 봇 간 관찰은 두 봇 모두 `@BotFather`에서 **봇 간 통신 모드**가 활성화되어 있을 때 가장 잘 작동합니다. `--credential-source env`일 때 필요한 env: -- `OPENCLAW_QA_TELEGRAM_GROUP_ID` — 숫자 채팅 ID(문자열)입니다. +- `OPENCLAW_QA_TELEGRAM_GROUP_ID` — 숫자 채팅 ID(문자열). - `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` - `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN` 선택 사항: -- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`은 관찰된 메시지 아티팩트에 메시지 본문을 유지합니다. 기본값은 비식별 처리입니다. +- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`은 관찰된 메시지 아티팩트에 메시지 본문을 유지합니다(기본값은 마스킹). 시나리오(`extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts:44`): @@ -223,8 +234,8 @@ pnpm openclaw qa telegram 출력 아티팩트: - `telegram-qa-report.md` -- `telegram-qa-summary.json` — 카나리부터 시작해 응답별 RTT(driver 전송 → 관찰된 SUT 응답)를 포함합니다. -- `telegram-qa-observed-messages.json` — `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`이 아니면 본문은 비식별 처리됩니다. +- `telegram-qa-summary.json` — 카나리부터 답장별 RTT(드라이버 전송 → 관찰된 SUT 답장)를 포함합니다. +- `telegram-qa-observed-messages.json` — `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`이 아니면 본문이 마스킹됩니다. ### Discord QA @@ -232,7 +243,7 @@ pnpm openclaw qa telegram pnpm openclaw qa discord ``` -두 개의 봇이 있는 실제 비공개 Discord 길드 채널 하나를 대상으로 합니다. 하나는 하네스가 제어하는 driver 봇이고, 다른 하나는 번들 Discord Plugin을 통해 자식 OpenClaw Gateway가 시작하는 SUT 봇입니다. 채널 멘션 처리, SUT 봇이 Discord에 네이티브 `/help` 명령을 등록했는지, 옵트인 Mantis 증거 시나리오를 검증합니다. +두 봇이 있는 실제 비공개 Discord 길드 채널 하나를 대상으로 합니다. 하니스가 제어하는 드라이버 봇과 번들 Discord Plugin을 통해 자식 OpenClaw Gateway가 시작하는 SUT 봇입니다. 채널 멘션 처리를 검증하고, SUT 봇이 Discord에 네이티브 `/help` 명령을 등록했는지 확인하며, 옵트인 Mantis 증거 시나리오를 검증합니다. `--credential-source env`일 때 필요한 env: @@ -240,7 +251,7 @@ pnpm openclaw qa discord - `OPENCLAW_QA_DISCORD_CHANNEL_ID` - `OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN` - `OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN` -- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — Discord가 반환한 SUT 봇 사용자 ID와 일치해야 합니다. 그렇지 않으면 레인이 빠르게 실패합니다. +- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — Discord가 반환한 SUT 봇 사용자 ID와 일치해야 합니다(그렇지 않으면 레인이 빠르게 실패합니다). 선택 사항: @@ -251,7 +262,7 @@ pnpm openclaw qa discord - `discord-canary` - `discord-mention-gating` - `discord-native-help-command-registration` -- `discord-status-reactions-tool-only` — 옵트인 Mantis 시나리오입니다. SUT를 항상 켜진 도구 전용 길드 응답으로 전환하고 `messages.statusReactions.enabled=true`를 설정한 뒤, REST 반응 타임라인과 HTML/PNG 시각적 아티팩트를 캡처하므로 단독으로 실행됩니다. +- `discord-status-reactions-tool-only` — 옵트인 Mantis 시나리오입니다. SUT를 `messages.statusReactions.enabled=true`가 있는 항상 켜짐, 도구 전용 길드 답장으로 전환한 뒤 REST 반응 타임라인과 HTML/PNG 시각적 아티팩트를 캡처하므로 단독으로 실행됩니다. Mantis 상태 반응 시나리오를 명시적으로 실행합니다. @@ -268,7 +279,7 @@ pnpm openclaw qa discord \ - `discord-qa-report.md` - `discord-qa-summary.json` -- `discord-qa-observed-messages.json` — `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1`이 아니면 본문은 비식별 처리됩니다. +- `discord-qa-observed-messages.json` — `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1`이 아니면 본문이 마스킹됩니다. - 상태 반응 시나리오가 실행될 때 `discord-qa-reaction-timelines.json` 및 `discord-status-reactions-tool-only-timeline.png`. ### Slack QA @@ -277,7 +288,7 @@ pnpm openclaw qa discord \ pnpm openclaw qa slack ``` -두 개의 서로 다른 봇이 있는 실제 비공개 Slack 채널 하나를 대상으로 합니다. 하나는 하네스가 제어하는 driver 봇이고, 다른 하나는 번들 Slack Plugin을 통해 자식 OpenClaw Gateway가 시작하는 SUT 봇입니다. +서로 다른 두 봇이 있는 실제 비공개 Slack 채널 하나를 대상으로 합니다. 하니스가 제어하는 드라이버 봇과 번들 Slack Plugin을 통해 자식 OpenClaw Gateway가 시작하는 SUT 봇입니다. `--credential-source env`일 때 필요한 env: @@ -299,42 +310,43 @@ pnpm openclaw qa slack - `slack-qa-report.md` - `slack-qa-summary.json` -- `slack-qa-observed-messages.json` — `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1`이 아니면 본문은 비식별 처리됩니다. +- `slack-qa-observed-messages.json` — `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1`이 아니면 본문이 마스킹됩니다. ### Convex 자격 증명 풀 -Telegram, Discord, Slack 레인은 위의 env vars를 읽는 대신 공유 Convex 풀에서 자격 증명을 임대할 수 있습니다. `--credential-source convex`를 전달하거나 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`를 설정하세요. QA Lab은 독점 임대를 획득하고 실행 중에는 Heartbeat를 보내며, 종료 시 임대를 해제합니다. 풀 종류는 `"telegram"`, `"discord"`, `"slack"`입니다. +Telegram, Discord, Slack 레인은 위 env vars를 읽는 대신 공유 Convex 풀에서 자격 증명을 임대할 수 있습니다. `--credential-source convex`를 전달하거나 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`를 설정하세요. QA Lab은 독점 임대를 획득하고, 실행 기간 동안 Heartbeat를 보내며, 종료 시 해제합니다. 풀 종류는 `"telegram"`, `"discord"`, `"slack"`입니다. 브로커가 `admin/add`에서 검증하는 페이로드 형태: - Telegram(`kind: "telegram"`): `{ groupId: string, driverToken: string, sutToken: string }` — `groupId`는 숫자 채팅 ID 문자열이어야 합니다. - Discord(`kind: "discord"`): `{ guildId: string, channelId: string, driverBotToken: string, sutBotToken: string, sutApplicationId: string }`. -운영 env vars와 Convex 브로커 엔드포인트 계약은 [테스트 → Convex를 통한 공유 Telegram 자격 증명](/ko/help/testing#shared-telegram-credentials-via-convex-v1)에 있습니다. 섹션 이름은 Discord 지원보다 먼저 만들어졌지만, 브로커 의미론은 두 종류 모두 동일합니다. +운영 env vars와 Convex 브로커 엔드포인트 계약은 [테스트 → Convex를 통한 공유 Telegram 자격 증명](/ko/help/testing#shared-telegram-credentials-via-convex-v1)에 있습니다(섹션 이름은 Discord 지원보다 앞서 만들어졌지만, 브로커 의미 체계는 두 종류 모두 동일합니다). -## 저장소 기반 시드 +## 리포지토리 기반 시드 시드 자산은 `qa/`에 있습니다. - `qa/scenarios/index.md` - `qa/scenarios//*.md` -이 파일들은 의도적으로 git에 포함되어 QA 계획이 사람과 에이전트 모두에게 보이도록 합니다. +QA 계획이 사람과 에이전트 모두에게 보이도록 의도적으로 git에 포함되어 있습니다. -`qa-lab`은 일반적인 Markdown 실행기로 유지해야 합니다. 각 시나리오 Markdown 파일은 하나의 테스트 실행에 대한 신뢰할 수 있는 원천이어야 하며 다음을 정의해야 합니다. +`qa-lab`은 범용 마크다운 러너로 유지되어야 합니다. 각 시나리오 마크다운 파일은 +하나의 테스트 실행에 대한 진실 공급원이며 다음을 정의해야 합니다. - 시나리오 메타데이터 -- 선택적 카테고리, 기능, 레인, 위험 메타데이터 +- 선택적 범주, 기능, 레인, 위험 메타데이터 - 문서 및 코드 참조 - 선택적 Plugin 요구 사항 -- 선택적 Gateway 설정 패치 +- 선택적 Gateway 구성 패치 - 실행 가능한 `qa-flow` -`qa-flow`를 뒷받침하는 재사용 가능한 런타임 표면은 일반적이고 교차 영역으로 유지될 수 있습니다. 예를 들어 Markdown 시나리오는 Gateway `browser.request` 경계면을 통해 내장 Control UI를 구동하는 브라우저 측 헬퍼와 트랜스포트 측 헬퍼를 결합할 수 있으며, 이를 위해 특수 사례 실행기를 추가할 필요는 없습니다. +`qa-flow`를 뒷받침하는 재사용 가능한 런타임 표면은 범용적이고 교차 영역적으로 유지될 수 있습니다. 예를 들어, 마크다운 시나리오는 전송 측 헬퍼와 브라우저 측 헬퍼를 결합하여, 특수 사례 러너를 추가하지 않고도 Gateway `browser.request` 연결부를 통해 내장 Control UI를 구동할 수 있습니다. -시나리오 파일은 소스 트리 폴더가 아니라 제품 기능별로 그룹화해야 합니다. 파일이 이동해도 시나리오 ID를 안정적으로 유지하세요. 구현 추적 가능성을 위해 `docsRefs`와 `codeRefs`를 사용하세요. +시나리오 파일은 소스 트리 폴더가 아니라 제품 기능별로 그룹화해야 합니다. 파일이 이동하더라도 시나리오 ID는 안정적으로 유지하세요. 구현 추적 가능성에는 `docsRefs`와 `codeRefs`를 사용하세요. -기준 목록은 다음을 다룰 만큼 충분히 넓게 유지해야 합니다. +기준 목록은 다음을 포함할 수 있을 만큼 넓게 유지해야 합니다. - DM 및 채널 채팅 - 스레드 동작 @@ -343,78 +355,81 @@ Telegram, Discord, Slack 레인은 위의 env vars를 읽는 대신 공유 Conve - 메모리 회상 - 모델 전환 - 하위 에이전트 인계 -- 저장소 읽기 및 문서 읽기 +- 리포지토리 읽기 및 문서 읽기 - Lobster Invaders 같은 작은 빌드 작업 하나 -## 프로바이더 목 레인 +## 공급자 모의 레인 -`qa suite`에는 두 개의 로컬 프로바이더 목 레인이 있습니다. +`qa suite`에는 두 개의 로컬 공급자 모의 레인이 있습니다. -- `mock-openai`는 시나리오 인식 OpenClaw 목입니다. 저장소 기반 QA와 패리티 게이트를 위한 기본 결정적 목 레인으로 유지됩니다. -- `aimock`은 실험적 프로토콜, 픽스처, 기록/재생, 카오스 커버리지를 위해 AIMock 기반 프로바이더 서버를 시작합니다. 이는 추가적인 것이며 `mock-openai` 시나리오 디스패처를 대체하지 않습니다. +- `mock-openai`는 시나리오 인식 OpenClaw 모의입니다. 리포지토리 기반 QA 및 동등성 게이트를 위한 기본 결정론적 모의 레인으로 남습니다. +- `aimock`은 실험적 프로토콜, 픽스처, 기록/재생, 카오스 커버리지를 위해 AIMock 기반 공급자 서버를 시작합니다. 이는 추가적인 것이며 `mock-openai` 시나리오 디스패처를 대체하지 않습니다. -프로바이더 레인 구현은 `extensions/qa-lab/src/providers/` 아래에 있습니다. 각 프로바이더는 자체 기본값, 로컬 서버 시작, Gateway 모델 설정, 인증 프로필 스테이징 요구 사항, 라이브/목 기능 플래그를 소유합니다. 공유 스위트와 Gateway 코드는 프로바이더 이름으로 분기하는 대신 프로바이더 레지스트리를 통해 라우팅해야 합니다. +공급자 레인 구현은 `extensions/qa-lab/src/providers/` 아래에 있습니다. +각 공급자는 자체 기본값, 로컬 서버 시작, Gateway 모델 구성, +인증 프로필 스테이징 요구 사항, 라이브/모의 기능 플래그를 소유합니다. 공유 스위트 및 +Gateway 코드는 공급자 이름으로 분기하는 대신 공급자 레지스트리를 통해 라우팅해야 합니다. -## 트랜스포트 어댑터 +## 전송 어댑터 -`qa-lab`은 Markdown QA 시나리오를 위한 일반 트랜스포트 경계면을 소유합니다. `qa-channel`은 해당 경계면의 첫 번째 어댑터이지만, 설계 대상은 더 넓습니다. 향후 실제 또는 합성 채널은 트랜스포트별 QA 실행기를 추가하는 대신 동일한 스위트 실행기에 연결되어야 합니다. +`qa-lab`은 마크다운 QA 시나리오를 위한 범용 전송 연결부를 소유합니다. `qa-channel`은 이 연결부의 첫 번째 어댑터이지만, 설계 목표는 더 넓습니다. 향후 실제 또는 합성 채널은 전송별 QA 러너를 추가하는 대신 같은 스위트 러너에 연결되어야 합니다. 아키텍처 수준에서 분리는 다음과 같습니다. -- `qa-lab`은 일반 시나리오 실행, 워커 동시성, 아티팩트 기록, 보고를 소유합니다. -- 트랜스포트 어댑터는 Gateway 설정, 준비 상태, 인바운드 및 아웃바운드 관찰, 트랜스포트 작업, 정규화된 트랜스포트 상태를 소유합니다. -- `qa/scenarios/` 아래의 Markdown 시나리오 파일은 테스트 실행을 정의합니다. `qa-lab`은 이를 실행하는 재사용 가능한 런타임 표면을 제공합니다. +- `qa-lab`은 범용 시나리오 실행, 워커 동시성, 아티팩트 작성, 보고를 소유합니다. +- 전송 어댑터는 Gateway 구성, 준비 상태, 인바운드 및 아웃바운드 관찰, 전송 작업, 정규화된 전송 상태를 소유합니다. +- `qa/scenarios/` 아래의 마크다운 시나리오 파일은 테스트 실행을 정의하고, `qa-lab`은 이를 실행하는 재사용 가능한 런타임 표면을 제공합니다. ### 채널 추가 -Markdown QA 시스템에 채널을 추가하려면 정확히 두 가지가 필요합니다. +마크다운 QA 시스템에 채널을 추가하려면 정확히 두 가지가 필요합니다. -1. 해당 채널의 트랜스포트 어댑터. +1. 해당 채널의 전송 어댑터. 2. 채널 계약을 실행하는 시나리오 팩. 공유 `qa-lab` 호스트가 흐름을 소유할 수 있을 때는 새 최상위 QA 명령 루트를 추가하지 마세요. -`qa-lab`은 공유 호스트 메커니즘을 소유합니다. +`qa-lab`는 공유 호스트 메커니즘을 소유합니다. - `openclaw qa` 명령 루트 -- 스위트 시작 및 종료 -- 워커 동시성 -- 아티팩트 기록 +- suite 시작 및 종료 +- worker 동시성 +- artifact 작성 - 보고서 생성 -- 시나리오 실행 -- 이전 `qa-channel` 시나리오에 대한 호환성 별칭 +- scenario 실행 +- 이전 `qa-channel` scenario와의 호환성 alias -실행기 Plugin은 트랜스포트 계약을 소유합니다. +러너 Plugin은 전송 계약을 소유합니다. - `openclaw qa `가 공유 `qa` 루트 아래에 마운트되는 방식 -- 해당 트랜스포트에 맞게 Gateway가 설정되는 방식 +- 해당 전송을 위해 Gateway가 구성되는 방식 - 준비 상태를 확인하는 방식 - 인바운드 이벤트를 주입하는 방식 - 아웃바운드 메시지를 관찰하는 방식 -- 트랜스크립트와 정규화된 트랜스포트 상태를 노출하는 방식 -- 트랜스포트 기반 작업을 실행하는 방식 -- 트랜스포트별 재설정 또는 정리를 처리하는 방식 +- transcript와 정규화된 전송 상태를 노출하는 방식 +- 전송 기반 action을 실행하는 방식 +- 전송별 reset 또는 cleanup을 처리하는 방식 -새 채널의 최소 채택 기준: +새 채널의 최소 도입 기준은 다음과 같습니다. -1. 공유 `qa` 루트의 소유자는 `qa-lab`으로 유지합니다. -2. 공유 `qa-lab` 호스트 seam에 전송 러너를 구현합니다. -3. 전송별 메커니즘은 러너 Plugin 또는 채널 하네스 내부에 유지합니다. -4. 경쟁 루트 명령을 등록하는 대신 러너를 `openclaw qa `로 마운트합니다. 러너 Plugin은 `openclaw.plugin.json`에서 `qaRunners`를 선언하고 `runtime-api.ts`에서 일치하는 `qaRunnerCliRegistrations` 배열을 내보내야 합니다. `runtime-api.ts`는 가볍게 유지하세요. 지연 CLI와 러너 실행은 별도 엔트리포인트 뒤에 있어야 합니다. -5. 테마별 `qa/scenarios/` 디렉터리 아래에 Markdown 시나리오를 작성하거나 조정합니다. -6. 새 시나리오에는 일반 시나리오 헬퍼를 사용합니다. -7. 저장소가 의도적인 마이그레이션을 진행 중인 경우가 아니라면 기존 호환성 별칭이 계속 작동하도록 유지합니다. +1. `qa-lab`를 공유 `qa` 루트의 소유자로 유지합니다. +2. 공유 `qa-lab` 호스트 확장 지점 위에 전송 러너를 구현합니다. +3. 전송별 메커니즘은 러너 Plugin 또는 채널 harness 안에 유지합니다. +4. 경쟁하는 루트 명령을 등록하는 대신 러너를 `openclaw qa `로 마운트합니다. 러너 Plugin은 `openclaw.plugin.json`에 `qaRunners`를 선언하고 `runtime-api.ts`에서 일치하는 `qaRunnerCliRegistrations` 배열을 export해야 합니다. `runtime-api.ts`는 가볍게 유지하세요. lazy CLI와 러너 실행은 별도 entrypoint 뒤에 있어야 합니다. +5. 테마별 `qa/scenarios/` 디렉터리 아래에 markdown scenario를 작성하거나 조정합니다. +6. 새 scenario에는 generic scenario helper를 사용합니다. +7. repo가 의도적인 migration을 진행하는 경우가 아니라면 기존 호환성 alias가 계속 작동하도록 유지합니다. 판단 규칙은 엄격합니다. -- 동작을 `qa-lab`에서 한 번만 표현할 수 있다면 `qa-lab`에 넣습니다. -- 동작이 하나의 채널 전송에 의존한다면 해당 러너 Plugin 또는 Plugin 하네스에 유지합니다. -- 시나리오에 둘 이상의 채널에서 사용할 수 있는 새 기능이 필요하다면 `suite.ts`에 채널별 분기를 추가하는 대신 일반 헬퍼를 추가합니다. -- 동작이 하나의 전송에서만 의미가 있다면 시나리오를 전송별로 유지하고 시나리오 계약에서 이를 명시합니다. +- 동작을 `qa-lab`에서 한 번만 표현할 수 있다면 `qa-lab`에 둡니다. +- 동작이 하나의 채널 전송에 의존한다면 해당 러너 Plugin 또는 Plugin harness에 유지합니다. +- scenario에 둘 이상의 채널이 사용할 수 있는 새 capability가 필요하다면 `suite.ts`에 채널별 branch를 추가하지 말고 generic helper를 추가합니다. +- 동작이 하나의 전송에만 의미가 있다면 scenario를 전송별로 유지하고 scenario 계약에 이를 명시합니다. -### 시나리오 헬퍼 이름 +### Scenario helper 이름 -새 시나리오에 권장되는 일반 헬퍼: +새 scenario에 선호되는 generic helper: - `waitForTransportReady` - `waitForChannelReady` @@ -429,22 +444,22 @@ Markdown QA 시스템에 채널을 추가하려면 정확히 두 가지가 필 - `formatTransportTranscript` - `resetTransport` -기존 시나리오를 위해 호환성 별칭인 `waitForQaChannelReady`, `waitForOutboundMessage`, `waitForNoOutbound`, `formatConversationTranscript`, `resetBus`도 계속 사용할 수 있습니다. 하지만 새 시나리오 작성에는 일반 이름을 사용해야 합니다. 이 별칭은 일괄 마이그레이션을 피하기 위해 존재하는 것이지, 앞으로의 모델로 쓰기 위한 것이 아닙니다. +기존 scenario를 위해 호환성 alias인 `waitForQaChannelReady`, `waitForOutboundMessage`, `waitForNoOutbound`, `formatConversationTranscript`, `resetBus`는 계속 사용할 수 있지만, 새 scenario 작성에는 generic 이름을 사용해야 합니다. 이 alias들은 일괄 migration을 피하기 위해 존재하며, 앞으로의 모델로 삼기 위한 것이 아닙니다. ## 보고 -`qa-lab`은 관찰된 버스 타임라인에서 Markdown 프로토콜 보고서를 내보냅니다. +`qa-lab`는 관찰된 bus timeline에서 Markdown protocol 보고서를 export합니다. 보고서는 다음에 답해야 합니다. - 작동한 것 - 실패한 것 - 계속 차단된 것 -- 추가할 가치가 있는 후속 시나리오 +- 추가할 가치가 있는 후속 scenario -사용 가능한 시나리오 목록을 확인하려면, 즉 후속 작업의 규모를 산정하거나 새 전송을 연결할 때 유용한 목록을 보려면 `pnpm openclaw qa coverage`를 실행하세요. 기계가 읽을 수 있는 출력이 필요하면 `--json`을 추가합니다. +사용 가능한 scenario의 inventory를 확인하려면, 후속 작업 규모를 산정하거나 새 전송을 연결할 때 유용한 `pnpm openclaw qa coverage`를 실행하세요. machine-readable 출력을 원하면 `--json`을 추가합니다. -문자와 스타일 검사를 위해 동일한 시나리오를 여러 라이브 모델 -ref에서 실행하고 판정된 Markdown 보고서를 작성합니다. +문자와 스타일 확인을 위해 여러 live model ref에서 동일한 scenario를 실행하고 +판정된 Markdown 보고서를 작성합니다. ```bash pnpm openclaw qa character-eval \ @@ -463,25 +478,24 @@ pnpm openclaw qa character-eval \ --judge-concurrency 16 ``` -이 명령은 Docker가 아니라 로컬 QA Gateway 자식 프로세스를 실행합니다. 문자 평가 -시나리오는 `SOUL.md`를 통해 페르소나를 설정한 다음, 채팅, workspace 도움말, 작은 파일 작업 같은 일반 사용자 턴을 실행해야 합니다. 후보 모델에는 평가 중이라는 사실을 알려서는 안 됩니다. 이 명령은 각 전체 -transcript를 보존하고 기본 실행 통계를 기록한 뒤, 지원되는 경우 `xhigh` 추론을 사용해 fast 모드의 judge 모델에 자연스러움, vibe, 유머 기준으로 실행 순위를 매기도록 요청합니다. -제공자를 비교할 때는 `--blind-judge-models`를 사용하세요. judge 프롬프트는 여전히 모든 transcript와 실행 상태를 받지만, 후보 ref는 `candidate-01` 같은 중립 레이블로 대체됩니다. 보고서는 파싱 후 순위를 실제 ref에 다시 매핑합니다. -후보 실행은 기본적으로 `high` thinking을 사용하며, GPT-5.5에는 `medium`, 이를 지원하는 이전 OpenAI 평가 ref에는 `xhigh`를 사용합니다. 특정 후보는 `--model provider/model,thinking=`로 인라인 재정의하세요. `--thinking `은 여전히 전역 fallback을 설정하며, 이전 `--model-thinking ` 형식은 호환성을 위해 유지됩니다. -OpenAI 후보 ref는 기본적으로 fast 모드로 실행되어 제공자가 지원하는 경우 priority processing이 사용됩니다. 단일 후보 또는 judge에 재정의가 필요하면 인라인으로 `,fast`, `,no-fast`, `,fast=false`를 추가하세요. 모든 후보 모델에 fast 모드를 강제로 켜고 싶을 때만 `--fast`를 전달합니다. 후보와 judge 실행 시간은 benchmark 분석을 위해 보고서에 기록되지만, judge 프롬프트는 속도로 순위를 매기지 말라고 명시합니다. -후보와 judge 모델 실행은 모두 기본 동시성 16을 사용합니다. 제공자 제한이나 로컬 Gateway 압력 때문에 실행이 너무 잡음이 많아지면 `--concurrency` 또는 `--judge-concurrency`를 낮추세요. -후보 `--model`이 전달되지 않으면 character eval은 +이 명령은 Docker가 아니라 로컬 QA Gateway child process를 실행합니다. Character eval +scenario는 `SOUL.md`를 통해 persona를 설정한 다음 chat, workspace help, 작은 파일 작업 같은 일반 user turn을 실행해야 합니다. 후보 model에게 평가 중이라는 사실을 알려서는 안 됩니다. 이 명령은 각 전체 transcript를 보존하고 기본 run stats를 기록한 다음, 지원되는 경우 `xhigh` reasoning이 적용된 fast mode로 judge model에 실행 결과를 naturalness, vibe, humor 기준으로 순위를 매기도록 요청합니다. +provider를 비교할 때는 `--blind-judge-models`를 사용하세요. judge prompt는 여전히 모든 transcript와 run status를 받지만, candidate ref는 `candidate-01` 같은 중립 label로 대체되며, 보고서는 parsing 후 순위를 실제 ref에 다시 매핑합니다. +Candidate run은 기본적으로 `high` thinking을 사용하며, GPT-5.5에는 `medium`, 이를 지원하는 이전 OpenAI eval ref에는 `xhigh`를 사용합니다. 특정 candidate를 override하려면 `--model provider/model,thinking=` 형식으로 inline 지정하세요. `--thinking `은 여전히 global fallback을 설정하며, 이전 `--model-thinking ` 형식은 호환성을 위해 유지됩니다. +OpenAI candidate ref는 provider가 지원하는 경우 priority processing이 사용되도록 기본적으로 fast mode를 사용합니다. 단일 candidate 또는 judge에 override가 필요하면 inline으로 `,fast`, `,no-fast`, 또는 `,fast=false`를 추가합니다. 모든 candidate model에 fast mode를 강제로 켜려는 경우에만 `--fast`를 전달하세요. Candidate와 judge duration은 benchmark 분석을 위해 보고서에 기록되지만, judge prompt는 속도 기준으로 순위를 매기지 말라고 명시합니다. +Candidate와 judge model run은 모두 기본 concurrency 16을 사용합니다. provider limit 또는 로컬 Gateway pressure 때문에 run이 너무 noisy해지면 `--concurrency` 또는 `--judge-concurrency`를 낮추세요. +candidate `--model`이 전달되지 않으면 character eval은 `openai/gpt-5.5`, `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`이 전달되지 않으면 judge 기본값은 +`--judge-model`이 전달되지 않으면 judge는 기본적으로 `openai/gpt-5.5,thinking=xhigh,fast`와 -`anthropic/claude-opus-4-6,thinking=high`입니다. +`anthropic/claude-opus-4-6,thinking=high`를 사용합니다. ## 관련 문서 -- [Matrix QA](/ko/concepts/qa-matrix) +- [매트릭스 QA](/ko/concepts/qa-matrix) - [QA 채널](/ko/channels/qa-channel) - [테스트](/ko/help/testing) -- [Dashboard](/ko/web/dashboard) +- [대시보드](/ko/web/dashboard) diff --git a/docs/ko/concepts/streaming.md b/docs/ko/concepts/streaming.md index 051620588..d71e29b31 100644 --- a/docs/ko/concepts/streaming.md +++ b/docs/ko/concepts/streaming.md @@ -1,15 +1,15 @@ --- read_when: - - 채널에서 스트리밍 또는 청크 처리가 작동하는 방식 설명 + - 채널에서 스트리밍 또는 청크 처리 방식 설명 - 블록 스트리밍 또는 채널 청크 처리 동작 변경 - 중복/조기 블록 응답 또는 채널 미리보기 스트리밍 디버깅 -summary: 스트리밍 + 청크 처리 동작(블록 답장, 채널 미리보기 스트리밍, 모드 매핑) +summary: 스트리밍 + 청킹 동작 (블록 응답, 채널 미리보기 스트리밍, 모드 매핑) title: 스트리밍 및 청크 처리 x-i18n: - generated_at: "2026-05-03T21:30:53Z" + generated_at: "2026-05-04T06:23:53Z" model: gpt-5.5 provider: openai - source_hash: 1335f4f5532060bd8bf839683a2b1fbab38f38887c5583135652b4753e0f6a50 + source_hash: fcb41ceb5602ab42c3fd41a59de62cc965ea61fdbc058c052fb93689a9c5299b source_path: concepts/streaming.md workflow: 16 --- @@ -19,11 +19,11 @@ OpenClaw에는 두 개의 별도 스트리밍 계층이 있습니다. - **블록 스트리밍(채널):** 어시스턴트가 작성하는 동안 완료된 **블록**을 내보냅니다. 이는 일반 채널 메시지입니다(토큰 델타가 아님). - **미리보기 스트리밍(Telegram/Discord/Slack):** 생성 중 임시 **미리보기 메시지**를 업데이트합니다. -현재 채널 메시지에는 **진정한 토큰 델타 스트리밍**이 없습니다. 미리보기 스트리밍은 메시지 기반입니다(전송 + 편집/추가). +현재 채널 메시지로 보내는 **진정한 토큰 델타 스트리밍**은 없습니다. 미리보기 스트리밍은 메시지 기반입니다(전송 + 편집/추가). ## 블록 스트리밍(채널 메시지) -블록 스트리밍은 어시스턴트 출력을 사용 가능해지는 대로 큰 단위의 청크로 전송합니다. +블록 스트리밍은 사용할 수 있게 되는 대로 어시스턴트 출력을 큼직한 청크로 보냅니다. ``` Model output @@ -37,76 +37,75 @@ Model output 범례: -- `text_delta/events`: 모델 스트림 이벤트(비스트리밍 모델에서는 드물 수 있음). -- `chunker`: 최소/최대 경계와 중단 선호도를 적용하는 `EmbeddedBlockChunker`. -- `channel send`: 실제 발신 메시지(블록 답장). +- `text_delta/events`: 모델 스트림 이벤트입니다(비스트리밍 모델에서는 드물 수 있음). +- `chunker`: 최소/최대 경계와 분할 선호도를 적용하는 `EmbeddedBlockChunker`입니다. +- `channel send`: 실제 발신 메시지입니다(블록 응답). -**제어 항목:** +**제어:** -- `agents.defaults.blockStreamingDefault`: `"on"`/`"off"`(기본값 off). +- `agents.defaults.blockStreamingDefault`: `"on"`/`"off"`(기본값 꺼짐). - 채널 재정의: 채널별로 `"on"`/`"off"`를 강제하는 `*.blockStreaming`(및 계정별 변형). - `agents.defaults.blockStreamingBreak`: `"text_end"` 또는 `"message_end"`. - `agents.defaults.blockStreamingChunk`: `{ minChars, maxChars, breakPreference? }`. - `agents.defaults.blockStreamingCoalesce`: `{ minChars?, maxChars?, idleMs? }`(전송 전 스트리밍된 블록 병합). - 채널 하드 한도: `*.textChunkLimit`(예: `channels.whatsapp.textChunkLimit`). -- 채널 청크 모드: `*.chunkMode`(`length` 기본값, `newline`은 길이 청크 전에 빈 줄(문단 경계)에서 분할). -- Discord 소프트 한도: `channels.discord.maxLinesPerMessage`(기본값 17)는 UI 잘림을 피하기 위해 긴 답장을 분할합니다. +- 채널 청크 모드: `*.chunkMode`(`length`가 기본값, `newline`은 길이 기준 청킹 전에 빈 줄(문단 경계)에서 분할). +- Discord 소프트 한도: `channels.discord.maxLinesPerMessage`(기본값 17)는 UI 잘림을 피하기 위해 긴 응답을 분할합니다. **경계 의미:** -- `text_end`: chunker가 내보내는 즉시 블록을 스트리밍하고, 각 `text_end`에서 플러시합니다. -- `message_end`: 어시스턴트 메시지가 끝날 때까지 기다린 뒤 버퍼링된 출력을 플러시합니다. +- `text_end`: 청크 처리기가 내보내는 즉시 블록을 스트리밍하고, 각 `text_end`에서 플러시합니다. +- `message_end`: 어시스턴트 메시지가 끝날 때까지 기다린 다음 버퍼링된 출력을 플러시합니다. -버퍼링된 텍스트가 `maxChars`를 초과하면 `message_end`도 chunker를 사용하므로, 끝에서 여러 청크를 내보낼 수 있습니다. +`message_end`는 버퍼링된 텍스트가 `maxChars`를 초과하면 여전히 청크 처리기를 사용하므로, 끝에서 여러 청크를 내보낼 수 있습니다. -### 블록 스트리밍에서의 미디어 전달 +### 블록 스트리밍의 미디어 전달 -`MEDIA:` 지시문은 일반 전달 메타데이터입니다. 블록 스트리밍이 미디어 블록을 일찍 전송하면 OpenClaw는 해당 턴의 전달을 기억합니다. 최종 어시스턴트 페이로드가 같은 미디어 URL을 반복하면, 최종 전달은 첨부 파일을 다시 보내는 대신 중복 미디어를 제거합니다. +`MEDIA:` 지시문은 일반 전달 메타데이터입니다. 블록 스트리밍이 미디어 블록을 일찍 보내면 OpenClaw는 해당 턴의 전달을 기억합니다. 최종 어시스턴트 페이로드가 같은 미디어 URL을 반복하면, 최종 전달은 첨부 파일을 다시 보내는 대신 중복 미디어를 제거합니다. -정확히 중복되는 최종 페이로드는 억제됩니다. 최종 페이로드가 이미 스트리밍된 미디어 주변에 별도의 텍스트를 추가하면, OpenClaw는 미디어를 한 번만 전달하면서 새 텍스트는 계속 전송합니다. 이를 통해 에이전트가 스트리밍 중 `MEDIA:`를 내보내고 제공자도 완료된 답장에 이를 포함하는 경우 Telegram 같은 채널에서 음성 메모나 파일이 중복되는 것을 방지합니다. +완전히 중복되는 최종 페이로드는 억제됩니다. 최종 페이로드가 이미 스트리밍된 미디어 주변에 별도의 텍스트를 추가하면, OpenClaw는 미디어를 한 번만 전달하도록 유지하면서 새 텍스트는 계속 보냅니다. 이렇게 하면 에이전트가 스트리밍 중 `MEDIA:`를 내보내고 제공자도 완료된 응답에 이를 포함할 때 Telegram 같은 채널에서 음성 메모나 파일이 중복되는 일을 방지합니다. -## 청크 처리 알고리즘(하한/상한) +## 청킹 알고리즘(하한/상한 경계) -블록 청크 처리는 `EmbeddedBlockChunker`로 구현됩니다. +블록 청킹은 `EmbeddedBlockChunker`로 구현됩니다. -- **하한:** 버퍼 >= `minChars`가 될 때까지 내보내지 않습니다(강제된 경우 제외). -- **상한:** `maxChars` 전에 분할하는 것을 선호합니다. 강제된 경우 `maxChars`에서 분할합니다. -- **중단 선호도:** `paragraph` → `newline` → `sentence` → `whitespace` → 강제 중단. -- **코드 펜스:** 펜스 내부에서는 절대 분할하지 않습니다. `maxChars`에서 강제될 때는 Markdown을 유효하게 유지하기 위해 펜스를 닫고 다시 엽니다. +- **하한 경계:** 버퍼 >= `minChars`가 될 때까지 내보내지 않습니다(강제된 경우 제외). +- **상한 경계:** `maxChars` 전에 분할하는 것을 선호하며, 강제된 경우 `maxChars`에서 분할합니다. +- **분할 선호도:** `paragraph` → `newline` → `sentence` → `whitespace` → 하드 분할. +- **코드 펜스:** 펜스 내부에서는 절대 분할하지 않습니다. `maxChars`에서 강제 분할할 때는 Markdown이 유효하게 유지되도록 펜스를 닫고 다시 엽니다. `maxChars`는 채널 `textChunkLimit`로 제한되므로 채널별 한도를 초과할 수 없습니다. ## 병합(스트리밍된 블록 병합) -블록 스트리밍이 활성화되면 OpenClaw는 전송 전에 **연속된 블록 청크를 병합**할 수 있습니다. 이는 점진적 출력을 제공하면서도 “한 줄 스팸”을 줄입니다. +블록 스트리밍이 활성화되면 OpenClaw는 전송하기 전에 **연속된 블록 청크를 병합**할 수 있습니다. 이렇게 하면 점진적 출력을 제공하면서도 “한 줄 스팸”을 줄일 수 있습니다. -- 병합은 플러시 전에 **유휴 간격**(`idleMs`)을 기다립니다. -- 버퍼는 `maxChars`로 제한되며 이를 초과하면 플러시됩니다. -- `minChars`는 충분한 텍스트가 누적될 때까지 작은 조각이 전송되지 않도록 합니다(최종 플러시는 남은 텍스트를 항상 전송). -- 연결자는 `blockStreamingChunk.breakPreference`에서 파생됩니다 - (`paragraph` → `\n\n`, `newline` → `\n`, `sentence` → 공백). -- 채널 재정의는 `*.blockStreamingCoalesce`를 통해 사용할 수 있습니다(계정별 구성 포함). -- 재정의되지 않는 한 Signal/Slack/Discord의 기본 병합 `minChars`는 1500으로 올라갑니다. +- 병합은 플러시하기 전에 **유휴 간격**(`idleMs`)을 기다립니다. +- 버퍼는 `maxChars`로 제한되며, 이를 초과하면 플러시됩니다. +- `minChars`는 충분한 텍스트가 누적될 때까지 작은 조각이 전송되지 않도록 합니다(최종 플러시는 항상 남은 텍스트를 보냄). +- 조인자는 `blockStreamingChunk.breakPreference`에서 파생됩니다(`paragraph` → `\n\n`, `newline` → `\n`, `sentence` → 공백). +- 채널 재정의는 `*.blockStreamingCoalesce`를 통해 사용할 수 있습니다(계정별 설정 포함). +- 기본 병합 `minChars`는 재정의하지 않는 한 Signal/Slack/Discord에서 1500으로 올라갑니다. ## 블록 사이의 사람 같은 속도 조절 -블록 스트리밍이 활성화되면 블록 답장 사이(첫 번째 블록 이후)에 **무작위 일시 중지**를 추가할 수 있습니다. 이렇게 하면 여러 말풍선 응답이 더 자연스럽게 느껴집니다. +블록 스트리밍이 활성화되면 블록 응답 사이에(첫 번째 블록 이후) **무작위 일시 중지**를 추가할 수 있습니다. 이렇게 하면 여러 말풍선 응답이 더 자연스럽게 느껴집니다. -- 구성: `agents.defaults.humanDelay`(`agents.list[].humanDelay`로 에이전트별 재정의). -- 모드: `off`(기본값), `natural`(800-2500ms), `custom`(`minMs`/`maxMs`). -- **블록 답장**에만 적용되며, 최종 답장이나 도구 요약에는 적용되지 않습니다. +- 설정: `agents.defaults.humanDelay`(`agents.list[].humanDelay`로 에이전트별 재정의). +- 모드: `off`(기본값), `natural`(800~2500ms), `custom`(`minMs`/`maxMs`). +- **블록 응답**에만 적용되며, 최종 응답이나 도구 요약에는 적용되지 않습니다. ## "청크 스트리밍 또는 전체 스트리밍" -이는 다음에 대응됩니다. +이는 다음에 매핑됩니다. - **청크 스트리밍:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"`(진행하면서 내보냄). Telegram이 아닌 채널은 `*.blockStreaming: true`도 필요합니다. - **끝에서 전체 스트리밍:** `blockStreamingBreak: "message_end"`(한 번 플러시, 매우 길면 여러 청크 가능). -- **블록 스트리밍 없음:** `blockStreamingDefault: "off"`(최종 답장만). +- **블록 스트리밍 없음:** `blockStreamingDefault: "off"`(최종 응답만). -**채널 참고:** `*.blockStreaming`이 명시적으로 `true`로 설정되지 않으면 블록 스트리밍은 **꺼져 있습니다**. 채널은 블록 답장 없이도 실시간 미리보기(`channels..streaming`)를 스트리밍할 수 있습니다. +**채널 참고:** `*.blockStreaming`이 명시적으로 `true`로 설정되지 않는 한 블록 스트리밍은 **꺼져 있습니다**. 채널은 블록 응답 없이 실시간 미리보기(`channels..streaming`)를 스트리밍할 수 있습니다. -구성 위치 알림: `blockStreaming*` 기본값은 루트 구성이 아니라 `agents.defaults` 아래에 있습니다. +설정 위치 알림: `blockStreaming*` 기본값은 루트 설정이 아니라 `agents.defaults` 아래에 있습니다. ## 미리보기 스트리밍 모드 @@ -115,81 +114,81 @@ Model output 모드: - `off`: 미리보기 스트리밍을 비활성화합니다. -- `partial`: 최신 텍스트로 교체되는 단일 미리보기. +- `partial`: 최신 텍스트로 교체되는 단일 미리보기입니다. - `block`: 청크/추가 단계로 미리보기를 업데이트합니다. -- `progress`: 생성 중 진행/상태 미리보기, 완료 시 최종 답변. +- `progress`: 생성 중 진행/상태 미리보기, 완료 시 최종 답변입니다. -`streaming.mode: "block"`은 Discord 및 Telegram 같은 편집 가능한 채널을 위한 미리보기 스트리밍 모드입니다. 이는 해당 채널에서 채널 블록 전달을 활성화하지 않습니다. 일반 블록 답장을 원할 때는 `streaming.block.enabled` 또는 레거시 `blockStreaming` 채널 키를 사용하세요. Microsoft Teams는 예외입니다. 초안 미리보기 블록 전송 수단이 없으므로 `streaming.mode: "block"`은 네이티브 partial/progress 스트리밍 대신 Teams 블록 전달에 매핑됩니다. +`streaming.mode: "block"`은 Discord와 Telegram처럼 편집 가능한 채널을 위한 미리보기 스트리밍 모드입니다. 이것이 해당 채널에서 채널 블록 전달을 활성화하지는 않습니다. 일반 블록 응답을 원할 때는 `streaming.block.enabled` 또는 레거시 `blockStreaming` 채널 키를 사용하세요. Microsoft Teams는 예외입니다. 초안 미리보기 블록 전송이 없으므로 `streaming.mode: "block"`은 네이티브 partial/progress 스트리밍 대신 Teams 블록 전달에 매핑됩니다. ### 채널 매핑 -| 채널 | `off` | `partial` | `block` | `progress` | -| ---------- | ----- | --------- | ------- | ----------------------- | -| Telegram | ✅ | ✅ | ✅ | 편집 가능한 진행 초안 | -| Discord | ✅ | ✅ | ✅ | 편집 가능한 진행 초안 | -| Slack | ✅ | ✅ | ✅ | ✅ | -| Mattermost | ✅ | ✅ | ✅ | ✅ | -| MS Teams | ✅ | ✅ | ✅ | 네이티브 진행 스트림 | +| 채널 | `off` | `partial` | `block` | `progress` | +| ---------- | ----- | --------- | ------- | ------------------- | +| Telegram | ✅ | ✅ | ✅ | 편집 가능한 진행 초안 | +| Discord | ✅ | ✅ | ✅ | 편집 가능한 진행 초안 | +| Slack | ✅ | ✅ | ✅ | ✅ | +| Mattermost | ✅ | ✅ | ✅ | ✅ | +| MS Teams | ✅ | ✅ | ✅ | 네이티브 진행 스트림 | Slack 전용: - `channels.slack.streaming.nativeTransport`는 `channels.slack.streaming.mode="partial"`일 때 Slack 네이티브 스트리밍 API 호출을 전환합니다(기본값: `true`). -- Slack 네이티브 스트리밍과 Slack 어시스턴트 스레드 상태에는 답장 스레드 대상이 필요합니다. 최상위 DM은 해당 스레드 스타일 미리보기를 표시하지 않지만, Slack 초안 미리보기 게시물과 편집은 계속 사용할 수 있습니다. +- Slack 네이티브 스트리밍과 Slack 어시스턴트 스레드 상태에는 응답 스레드 대상이 필요합니다. 최상위 DM은 해당 스레드 스타일 미리보기를 표시하지 않지만, Slack 초안 미리보기 게시물과 편집은 계속 사용할 수 있습니다. 레거시 키 마이그레이션: - Telegram: 레거시 `streamMode` 및 스칼라/불리언 `streaming` 값은 doctor/config 호환성 경로에서 감지되어 `streaming.mode`로 마이그레이션됩니다. - Discord: `streamMode` + 불리언 `streaming`은 `streaming` 열거형으로 자동 마이그레이션됩니다. -- Slack: `streamMode`는 `streaming.mode`로 자동 마이그레이션됩니다. 불리언 `streaming`은 `streaming.mode` 및 `streaming.nativeTransport`로 자동 마이그레이션됩니다. 레거시 `nativeStreaming`은 `streaming.nativeTransport`로 자동 마이그레이션됩니다. +- Slack: `streamMode`는 `streaming.mode`로 자동 마이그레이션됩니다. 불리언 `streaming`은 `streaming.mode`와 `streaming.nativeTransport`로 자동 마이그레이션됩니다. 레거시 `nativeStreaming`은 `streaming.nativeTransport`로 자동 마이그레이션됩니다. ### 런타임 동작 Telegram: -- DM 및 그룹/토픽 전반에서 `sendMessage` + `editMessageText` 미리보기 업데이트를 사용합니다. -- 미리보기가 약 1분 동안 표시된 경우 제자리 편집 대신 새 최종 메시지를 보낸 뒤 미리보기를 정리하여 Telegram 타임스탬프가 답장 완료를 반영하도록 합니다. -- Telegram 블록 스트리밍이 명시적으로 활성화되면 미리보기 스트리밍을 건너뜁니다(이중 스트리밍 방지). -- `/reasoning stream`은 추론을 미리보기에 쓸 수 있습니다. +- DM과 그룹/토픽 전반에서 `sendMessage` + `editMessageText` 미리보기 업데이트를 사용합니다. +- 미리보기가 약 1분 동안 표시된 경우, 제자리에서 편집하는 대신 새로운 최종 메시지를 보낸 다음 Telegram의 타임스탬프가 응답 완료를 반영하도록 미리보기를 정리합니다. +- Telegram 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍은 건너뜁니다(이중 스트리밍 방지). +- `/reasoning stream`은 최종 전달 후 삭제되는 임시 미리보기에 추론을 쓸 수 있습니다. Discord: - 전송 + 편집 미리보기 메시지를 사용합니다. -- `block` 모드는 초안 청크 처리(`draftChunk`)를 사용합니다. -- Discord 블록 스트리밍이 명시적으로 활성화되면 미리보기 스트리밍을 건너뜁니다. -- 최종 미디어, 오류, 명시적 답장 페이로드는 새 초안을 플러시하지 않고 대기 중인 미리보기를 취소한 뒤 일반 전달을 사용합니다. +- `block` 모드는 초안 청킹(`draftChunk`)을 사용합니다. +- Discord 블록 스트리밍이 명시적으로 활성화된 경우 미리보기 스트리밍은 건너뜁니다. +- 최종 미디어, 오류, 명시적 응답 페이로드는 새 초안을 플러시하지 않고 대기 중인 미리보기를 취소한 다음 일반 전달을 사용합니다. Slack: -- `partial`은 사용 가능한 경우 Slack 네이티브 스트리밍(`chat.startStream`/`append`/`stop`)을 사용할 수 있습니다. +- `partial`은 사용할 수 있을 때 Slack 네이티브 스트리밍(`chat.startStream`/`append`/`stop`)을 사용할 수 있습니다. - `block`은 추가 스타일 초안 미리보기를 사용합니다. -- `progress`는 상태 미리보기 텍스트를 사용한 뒤 최종 답변을 보냅니다. -- 답장 스레드가 없는 최상위 DM은 Slack 네이티브 스트리밍 대신 초안 미리보기 게시물과 편집을 사용합니다. -- 네이티브 및 초안 미리보기 스트리밍은 해당 턴의 블록 답장을 억제하므로 Slack 답장은 하나의 전달 경로로만 스트리밍됩니다. -- 최종 미디어/오류 페이로드와 진행 최종 응답은 일회용 초안 메시지를 만들지 않습니다. 미리보기를 편집할 수 있는 텍스트/블록 최종 응답만 대기 중인 초안 텍스트를 플러시합니다. +- `progress`는 상태 미리보기 텍스트를 사용한 다음 최종 답변을 보냅니다. +- 응답 스레드가 없는 최상위 DM은 Slack 네이티브 스트리밍 대신 초안 미리보기 게시물과 편집을 사용합니다. +- 네이티브 및 초안 미리보기 스트리밍은 해당 턴의 블록 응답을 억제하므로 Slack 응답은 하나의 전달 경로로만 스트리밍됩니다. +- 최종 미디어/오류 페이로드와 진행 최종 메시지는 일회용 초안 메시지를 만들지 않습니다. 미리보기를 편집할 수 있는 텍스트/블록 최종 메시지만 대기 중인 초안 텍스트를 플러시합니다. Mattermost: -- 생각, 도구 활동, 부분 답장 텍스트를 단일 초안 미리보기 게시물로 스트리밍하며, 최종 답변을 안전하게 보낼 수 있을 때 제자리에서 완료합니다. -- 미리보기 게시물이 삭제되었거나 완료 시 사용할 수 없는 경우 새 최종 게시물 전송으로 폴백합니다. +- 사고 과정, 도구 활동, 부분 응답 텍스트를 단일 초안 미리보기 게시물로 스트리밍하며, 최종 답변을 보내도 안전할 때 제자리에서 최종화합니다. +- 미리보기 게시물이 삭제되었거나 최종화 시 사용할 수 없는 경우 새 최종 게시물을 보내는 방식으로 폴백합니다. - 최종 미디어/오류 페이로드는 임시 미리보기 게시물을 플러시하는 대신 일반 전달 전에 대기 중인 미리보기 업데이트를 취소합니다. Matrix: -- 최종 텍스트가 미리보기 이벤트를 재사용할 수 있으면 초안 미리보기를 제자리에서 완료합니다. -- 미디어 전용, 오류, 답장 대상 불일치 최종 응답은 일반 전달 전에 대기 중인 미리보기 업데이트를 취소합니다. 이미 표시된 오래된 미리보기는 삭제 처리됩니다. +- 최종 텍스트가 미리보기 이벤트를 재사용할 수 있으면 초안 미리보기를 제자리에서 최종화합니다. +- 미디어 전용, 오류, 응답 대상 불일치 최종 메시지는 일반 전달 전에 대기 중인 미리보기 업데이트를 취소합니다. 이미 표시된 오래된 미리보기는 삭제됩니다. -### 도구 진행률 미리보기 업데이트 +### 도구 진행 미리보기 업데이트 -미리보기 스트리밍은 **도구 진행률** 업데이트도 포함할 수 있습니다. 이는 "웹 검색 중", "파일 읽는 중", "도구 호출 중" 같은 짧은 상태 줄이며, 도구가 실행되는 동안 최종 답장보다 앞서 같은 미리보기 메시지에 표시됩니다. 이렇게 하면 여러 단계의 도구 턴이 첫 번째 생각 미리보기와 최종 답변 사이에서 침묵하는 대신 시각적으로 계속 살아 있게 됩니다. +미리보기 스트리밍에는 **도구 진행** 업데이트도 포함될 수 있습니다. 이는 "웹 검색 중", "파일 읽는 중", "도구 호출 중" 같은 짧은 상태 줄로, 도구가 실행되는 동안 최종 응답보다 먼저 같은 미리보기 메시지에 표시됩니다. 이렇게 하면 여러 단계의 도구 턴이 첫 사고 과정 미리보기와 최종 답변 사이에 조용히 멈춰 있는 대신 시각적으로 살아 있게 유지됩니다. -지원 표면: +지원되는 표면: -- **Discord**, **Slack**, **Telegram**, **Matrix**는 미리보기 스트리밍이 활성화된 경우 기본적으로 도구 진행률을 실시간 미리보기 편집에 스트리밍합니다. Microsoft Teams는 개인 채팅에서 네이티브 진행 스트림을 사용합니다. -- Telegram은 `v2026.4.22`부터 도구 진행률 미리보기 업데이트를 활성화한 상태로 출시되었습니다. 이를 계속 활성화하면 출시된 동작이 유지됩니다. -- **Mattermost**는 이미 도구 활동을 단일 초안 미리보기 게시물에 접어 넣습니다(위 참조). -- 도구 진행률 편집은 활성 미리보기 스트리밍 모드를 따릅니다. 미리보기 스트리밍이 `off`이거나 블록 스트리밍이 메시지를 가져간 경우 건너뜁니다. Telegram에서 `streaming.mode: "off"`는 최종 전용입니다. 일반 진행 잡담도 독립 상태 메시지로 전달되는 대신 억제되지만, 승인 프롬프트, 미디어 페이로드, 오류는 계속 정상적으로 라우팅됩니다. -- 미리보기 스트리밍은 유지하되 도구 진행률 줄을 숨기려면 해당 채널의 `streaming.preview.toolProgress`를 `false`로 설정하세요. 미리보기 편집을 완전히 비활성화하려면 `streaming.mode`를 `off`로 설정하세요. -- Telegram 선택 인용 답장은 예외입니다. `replyToMode`가 `"off"`가 아니고 선택된 인용 텍스트가 있으면, OpenClaw는 해당 턴의 답변 미리보기 스트림을 건너뛰므로 도구 진행률 미리보기 줄을 렌더링할 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 답장은 미리보기 스트리밍을 계속 유지합니다. 자세한 내용은 [Telegram 채널 문서](/ko/channels/telegram)를 참고하세요. +- **Discord**, **Slack**, **Telegram**, **Matrix**는 미리보기 스트리밍이 활성화된 경우 기본적으로 도구 진행을 실시간 미리보기 편집으로 스트리밍합니다. Microsoft Teams는 개인 채팅에서 네이티브 진행 스트림을 사용합니다. +- Telegram은 `v2026.4.22`부터 도구 진행 미리보기 업데이트가 활성화된 상태로 출시되었습니다. 이를 활성화 상태로 유지하면 릴리스된 동작이 보존됩니다. +- **Mattermost**는 이미 도구 활동을 단일 초안 미리보기 게시물에 포함합니다(위 참조). +- 도구 진행 편집은 활성 미리보기 스트리밍 모드를 따릅니다. 미리보기 스트리밍이 `off`이거나 블록 스트리밍이 메시지를 넘겨받은 경우 건너뜁니다. Telegram에서 `streaming.mode: "off"`는 최종 응답 전용입니다. 일반 진행 잡담도 독립 상태 메시지로 전달되지 않고 억제되지만, 승인 프롬프트, 미디어 페이로드, 오류는 계속 정상 라우팅됩니다. +- 미리보기 스트리밍은 유지하되 도구 진행 줄을 숨기려면 해당 채널의 `streaming.preview.toolProgress`를 `false`로 설정하세요. 미리보기 편집을 완전히 비활성화하려면 `streaming.mode`를 `off`로 설정하세요. +- Telegram 선택 인용 응답은 예외입니다. `replyToMode`가 `"off"`가 아니고 선택된 인용 텍스트가 있으면, OpenClaw는 해당 턴의 답변 미리보기 스트림을 건너뛰므로 도구 진행 미리보기 줄이 렌더링될 수 없습니다. 선택된 인용 텍스트가 없는 현재 메시지 응답은 미리보기 스트리밍을 계속 유지합니다. 자세한 내용은 [Telegram 채널 문서](/ko/channels/telegram)를 참조하세요. 예: @@ -210,7 +209,7 @@ Matrix: ## 관련 항목 -- [진행 초안](/ko/concepts/progress-drafts) — 긴 턴 동안 업데이트되는 보이는 진행 중 작업 메시지 +- [진행 상황 초안](/ko/concepts/progress-drafts) — 긴 턴 동안 업데이트되는 표시 가능한 진행 중 작업 메시지 - [메시지](/ko/concepts/messages) — 메시지 수명 주기 및 전달 - [재시도](/ko/concepts/retry) — 전달 실패 시 재시도 동작 - [채널](/ko/channels) — 채널별 스트리밍 지원 diff --git a/docs/ko/install/updating.md b/docs/ko/install/updating.md index 0699f45c0..6253e3e9c 100644 --- a/docs/ko/install/updating.md +++ b/docs/ko/install/updating.md @@ -1,23 +1,23 @@ --- read_when: - OpenClaw 업데이트 - - 업데이트 후 문제가 발생함 -summary: OpenClaw를 안전하게 업데이트하기(전역 설치 또는 소스) 및 롤백 전략 + - 업데이트 후 문제가 발생하는 경우 +summary: OpenClaw 안전하게 업데이트하기(전역 설치 또는 소스) 및 롤백 전략 title: 업데이트 x-i18n: - generated_at: "2026-05-03T21:34:53Z" + generated_at: "2026-05-04T06:23:55Z" model: gpt-5.5 provider: openai - source_hash: f9e26ea71748dfd1573cdca01126bf29ebc56be56eac604e2b6a009b463820d1 + source_hash: 3c9ff1d70d74f45efea3c148718e5cbc74001ce3d924b760edc4d68622d23714 source_path: install/updating.md workflow: 16 --- -OpenClaw를 최신 상태로 유지합니다. +OpenClaw를 최신 상태로 유지하세요. ## 권장: `openclaw update` -가장 빠르게 업데이트하는 방법입니다. 설치 유형(npm 또는 git)을 감지하고, 최신 버전을 가져오며, `openclaw doctor`를 실행하고 Gateway를 재시작합니다. +가장 빠르게 업데이트하는 방법입니다. 설치 유형(npm 또는 git)을 감지하고, 최신 버전을 가져오며, `openclaw doctor`를 실행하고 Gateway를 다시 시작합니다. ```bash openclaw update @@ -32,21 +32,23 @@ openclaw update --tag main openclaw update --dry-run # preview without applying ``` -`openclaw update`는 `--verbose`를 허용하지 않습니다. 업데이트 진단에는 계획된 작업을 미리 보려면 -`--dry-run`을, 구조화된 결과에는 `--json`을, 채널 및 사용 가능 상태를 검사하려면 -`openclaw update status --json`을 사용하세요. 설치 프로그램에는 자체 `--verbose` 플래그가 있지만, 해당 플래그는 +`openclaw update`는 `--verbose`를 허용하지 않습니다. 업데이트 진단에는 +계획된 작업을 미리 보려면 `--dry-run`, 구조화된 결과를 보려면 `--json`, +채널 및 사용 가능 상태를 검사하려면 `openclaw update status --json`을 사용하세요. +설치 프로그램에는 자체 `--verbose` 플래그가 있지만, 이 플래그는 `openclaw update`의 일부가 아닙니다. `--channel beta`는 beta를 우선하지만, beta 태그가 없거나 최신 stable 릴리스보다 오래된 경우 -런타임은 stable/latest로 대체합니다. 일회성 패키지 업데이트에 원시 npm beta dist-tag가 필요하다면 `--tag beta`를 사용하세요. +런타임은 stable/latest로 대체됩니다. 일회성 패키지 업데이트에 원시 npm beta dist-tag를 원하면 +`--tag beta`를 사용하세요. -채널 의미 체계는 [개발 채널](/ko/install/development-channels)을 참고하세요. +채널 의미는 [개발 채널](/ko/install/development-channels)을 참조하세요. ## npm 설치와 git 설치 간 전환 -설치 유형을 변경하려면 채널을 사용하세요. 업데이트 도구는 `~/.openclaw`의 -상태, 설정, 자격 증명, 작업 영역을 유지합니다. CLI와 Gateway가 사용하는 -OpenClaw 코드 설치만 변경합니다. +설치 유형을 변경하려면 채널을 사용하세요. 업데이터는 +`~/.openclaw`의 상태, 구성, 자격 증명, 작업 공간을 유지하며, +CLI와 Gateway가 사용하는 OpenClaw 코드 설치만 변경합니다. ```bash # npm package install -> editable git checkout @@ -64,8 +66,8 @@ openclaw update --channel stable --dry-run ``` `dev` 채널은 git checkout을 보장하고, 빌드한 뒤, 해당 checkout에서 전역 CLI를 설치합니다. -`stable` 및 `beta` 채널은 패키지 설치를 사용합니다. Gateway가 이미 설치되어 있으면, -`--no-restart`를 전달하지 않는 한 `openclaw update`가 서비스 메타데이터를 새로 고치고 재시작합니다. +`stable` 및 `beta` 채널은 패키지 설치를 사용합니다. Gateway가 이미 설치되어 있으면 +`openclaw update`는 서비스 메타데이터를 새로 고치고, `--no-restart`를 전달하지 않는 한 다시 시작합니다. ## 대안: 설치 프로그램 다시 실행 @@ -77,15 +79,15 @@ curl -fsSL https://openclaw.ai/install.sh | bash `--install-method git --no-onboard` 또는 `--install-method npm --no-onboard`를 전달하세요. -npm 패키지 설치 단계 이후 `openclaw update`가 실패하면 설치 프로그램을 다시 실행하세요. -설치 프로그램은 이전 업데이트 도구를 호출하지 않습니다. 전역 패키지 설치를 직접 실행하며, -부분적으로 업데이트된 npm 설치를 복구할 수 있습니다. +npm 패키지 설치 단계 이후 `openclaw update`가 실패하면 +설치 프로그램을 다시 실행하세요. 설치 프로그램은 이전 업데이터를 호출하지 않습니다. 전역 +패키지 설치를 직접 실행하며, 부분적으로 업데이트된 npm 설치를 복구할 수 있습니다. ```bash curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm ``` -복구를 특정 버전 또는 dist-tag로 고정하려면 `--version`을 추가하세요. +복구를 특정 버전 또는 dist-tag에 고정하려면 `--version`을 추가하세요. ```bash curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm --version @@ -97,11 +99,17 @@ curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method npm --ve npm i -g openclaw@latest ``` -`openclaw update`가 전역 npm 설치를 관리할 때는 먼저 대상을 임시 npm prefix에 설치하고, -패키지된 `dist` 인벤토리를 확인한 다음, 깨끗한 패키지 트리를 실제 전역 prefix로 교체합니다. -이렇게 하면 npm이 이전 패키지의 오래된 파일 위에 새 패키지를 덮어쓰는 일을 피할 수 있습니다. 설치 명령이 실패하면 -OpenClaw는 `--omit=optional`로 한 번 다시 시도합니다. 이 재시도는 네이티브 선택적 의존성을 컴파일할 수 없는 호스트에 도움이 되며, -대체 시도도 실패하는 경우 원래 실패를 계속 볼 수 있게 합니다. +감독되는 설치에는 `openclaw update`를 권장합니다. 실행 중인 Gateway 서비스와 +패키지 교체를 조율할 수 있기 때문입니다. 관리형 Gateway가 실행 중인 동안 수동으로 업데이트하는 경우, +패키지 관리자가 완료되는 즉시 Gateway를 다시 시작하여 이전 프로세스가 교체된 패키지 +파일에서 계속 서비스를 제공하지 않도록 하세요. + +`openclaw update`가 전역 npm 설치를 관리할 때는 먼저 대상 버전을 +임시 npm prefix에 설치하고, 패키지된 `dist` 인벤토리를 검증한 다음, +정상 패키지 트리를 실제 전역 prefix로 교체합니다. 이렇게 하면 npm이 이전 패키지의 오래된 파일 위에 +새 패키지를 덮어쓰는 일을 피할 수 있습니다. 설치 명령이 실패하면 +OpenClaw는 `--omit=optional`로 한 번 다시 시도합니다. 이 재시도는 네이티브 +선택적 의존성을 컴파일할 수 없는 호스트에 도움이 되며, fallback도 실패할 경우 원래 실패를 계속 확인할 수 있게 합니다. ```bash pnpm add -g openclaw@latest @@ -115,27 +123,27 @@ bun add -g openclaw@latest - OpenClaw는 현재 사용자가 전역 패키지 디렉터리에 쓸 수 있는 경우에도, 패키지된 전역 설치를 런타임에서 읽기 전용으로 취급합니다. Plugin 패키지 설치는 사용자 설정 디렉터리 아래 OpenClaw 소유 npm/git 루트에 위치하며, Gateway 시작은 OpenClaw 패키지 트리를 변경하지 않습니다. + OpenClaw는 전역 패키지 디렉터리가 현재 사용자에게 쓰기 가능하더라도, 패키지된 전역 설치를 런타임에 읽기 전용으로 취급합니다. Plugin 패키지 설치는 사용자 구성 디렉터리 아래 OpenClaw 소유 npm/git 루트에 위치하며, Gateway 시작은 OpenClaw 패키지 트리를 변경하지 않습니다. - 일부 Linux npm 설정은 `/usr/lib/node_modules/openclaw` 같은 root 소유 디렉터리 아래에 전역 패키지를 설치합니다. OpenClaw는 Plugin 설치/업데이트 명령이 해당 전역 패키지 디렉터리 밖에 쓰기 때문에 이 레이아웃을 지원합니다. + 일부 Linux npm 설정은 `/usr/lib/node_modules/openclaw`와 같은 root 소유 디렉터리 아래에 전역 패키지를 설치합니다. OpenClaw는 Plugin 설치/업데이트 명령이 해당 전역 패키지 디렉터리 밖에 쓰기 때문에 이 레이아웃을 지원합니다. - 명시적 Plugin 설치, Plugin 업데이트, doctor 정리가 변경 사항을 유지할 수 있도록 OpenClaw에 설정/상태 루트에 대한 쓰기 권한을 부여하세요. + 명시적 Plugin 설치, Plugin 업데이트, doctor 정리가 변경 사항을 지속할 수 있도록 OpenClaw에 구성/상태 루트에 대한 쓰기 권한을 부여하세요. ```ini ReadWritePaths=/var/lib/openclaw /home/openclaw/.openclaw /tmp ``` - - 패키지 업데이트와 명시적 Plugin 설치 전에 OpenClaw는 대상 볼륨에 대해 최선 노력 방식의 디스크 공간 확인을 시도합니다. 공간이 부족하면 확인한 경로와 함께 경고가 표시되지만, 파일 시스템 할당량, 스냅샷, 네트워크 볼륨은 확인 후에도 변경될 수 있으므로 업데이트를 차단하지는 않습니다. 실제 패키지 관리자 설치와 설치 후 검증이 계속 권위 있는 기준입니다. + + 패키지 업데이트와 명시적 Plugin 설치 전에 OpenClaw는 대상 볼륨에 대해 최선의 디스크 공간 검사를 시도합니다. 공간이 부족하면 검사된 경로와 함께 경고가 표시되지만, 파일 시스템 할당량, 스냅샷, 네트워크 볼륨은 검사 후에도 변경될 수 있으므로 업데이트를 차단하지 않습니다. 실제 패키지 관리자 설치와 설치 후 검증이 계속 권위 있는 기준입니다. -## 자동 업데이트 도구 +## 자동 업데이터 -자동 업데이트 도구는 기본적으로 꺼져 있습니다. `~/.openclaw/openclaw.json`에서 활성화하세요. +자동 업데이터는 기본적으로 꺼져 있습니다. `~/.openclaw/openclaw.json`에서 활성화하세요. ```json5 { @@ -152,18 +160,19 @@ bun add -g openclaw@latest ``` | 채널 | 동작 | -| -------- | ------------------------------------------------------------------------------------------------------------- | +| -------- | --------------------------------------------------------------------------------------------------------- | | `stable` | `stableDelayHours`만큼 기다린 뒤, `stableJitterHours` 전반에 걸쳐 결정적 지터로 적용합니다(분산 롤아웃). | -| `beta` | `betaCheckIntervalHours`마다 확인하고(기본값: 매시간) 즉시 적용합니다. | -| `dev` | 자동 적용이 없습니다. `openclaw update`를 수동으로 사용하세요. | +| `beta` | `betaCheckIntervalHours`마다 확인하고(기본값: 매시간) 즉시 적용합니다. | +| `dev` | 자동 적용이 없습니다. `openclaw update`를 수동으로 사용하세요. | Gateway는 시작 시 업데이트 힌트도 기록합니다(`update.checkOnStart: false`로 비활성화). -다운그레이드 또는 사고 복구의 경우, Gateway 환경에서 `OPENCLAW_NO_AUTO_UPDATE=1`을 설정하여 `update.auto.enabled`가 구성되어 있어도 자동 적용을 차단하세요. 시작 업데이트 힌트는 `update.checkOnStart`도 비활성화하지 않는 한 계속 실행될 수 있습니다. +다운그레이드 또는 사고 복구의 경우, `update.auto.enabled`가 구성되어 있더라도 자동 적용을 차단하려면 Gateway 환경에 `OPENCLAW_NO_AUTO_UPDATE=1`을 설정하세요. `update.checkOnStart`도 비활성화하지 않는 한 시작 업데이트 힌트는 계속 실행될 수 있습니다. -실시간 Gateway 제어 평면 핸들러를 통해 요청된 패키지 관리자 업데이트는 -패키지 교체 후 지연 없고 쿨다운 없는 업데이트 재시작을 강제합니다. 이렇게 하면 이미 교체된 패키지 트리에서 청크를 지연 로드할 수 있을 만큼 -오래된 인메모리 프로세스가 남아 있는 일을 피할 수 있습니다. 셸 `openclaw update`는 업데이트 전후로 서비스를 중지하고 -재시작할 수 있으므로 관리형 설치에 계속 권장되는 경로입니다. +라이브 Gateway control-plane 핸들러를 통해 요청된 패키지 관리자 업데이트는 +패키지 교체 후 지연 없이 cooldown 없는 업데이트 재시작을 강제합니다. 이렇게 하면 이미 교체된 +패키지 트리에서 청크를 lazy-load할 수 있을 만큼 오래된 인메모리 프로세스가 남아 있는 일을 방지합니다. +감독되는 설치에는 서비스 중지와 재시작을 업데이트 전후로 조율할 수 있는 +셸 `openclaw update` 경로가 계속 권장됩니다. ## 업데이트 후 @@ -175,9 +184,9 @@ Gateway는 시작 시 업데이트 힌트도 기록합니다(`update.checkOnStar openclaw doctor ``` -설정을 마이그레이션하고, DM 정책을 감사하며, Gateway 상태를 확인합니다. 자세한 내용: [Doctor](/ko/gateway/doctor) +구성을 마이그레이션하고, DM 정책을 감사하며, Gateway 상태를 확인합니다. 자세한 내용: [Doctor](/ko/gateway/doctor) -### Gateway 재시작 +### Gateway 다시 시작 ```bash openclaw gateway restart @@ -216,15 +225,15 @@ openclaw gateway restart 최신으로 돌아가려면: `git checkout main && git pull`. -## 막힌 경우 +## 막혔을 때 - `openclaw doctor`를 다시 실행하고 출력을 주의 깊게 읽으세요. -- 소스 checkout에서 `openclaw update --channel dev`를 실행하는 경우, 업데이트 도구는 필요할 때 `pnpm`을 자동으로 부트스트랩합니다. pnpm/corepack 부트스트랩 오류가 보이면 `pnpm`을 수동으로 설치하거나(`corepack`을 다시 활성화) 업데이트를 다시 실행하세요. +- 소스 checkout에서 `openclaw update --channel dev`를 실행할 때 업데이터는 필요하면 `pnpm`을 자동으로 부트스트랩합니다. pnpm/corepack 부트스트랩 오류가 표시되면 `pnpm`을 수동으로 설치하거나 `corepack`을 다시 활성화한 뒤 업데이트를 다시 실행하세요. - 확인: [문제 해결](/ko/gateway/troubleshooting) -- Discord에서 질문: [https://discord.gg/clawd](https://discord.gg/clawd) +- Discord에서 질문하기: [https://discord.gg/clawd](https://discord.gg/clawd) -## 관련 문서 +## 관련 항목 -- [설치 개요](/ko/install): 모든 설치 방법입니다. -- [Doctor](/ko/gateway/doctor): 업데이트 후 상태 확인입니다. -- [마이그레이션](/ko/install/migrating): 주요 버전 마이그레이션 가이드입니다. +- [설치 개요](/ko/install): 모든 설치 방법. +- [Doctor](/ko/gateway/doctor): 업데이트 후 상태 점검. +- [마이그레이션](/ko/install/migrating): 주요 버전 마이그레이션 가이드. diff --git a/docs/ko/plugins/google-meet.md b/docs/ko/plugins/google-meet.md index 2a6415b70..5e5c7a053 100644 --- a/docs/ko/plugins/google-meet.md +++ b/docs/ko/plugins/google-meet.md @@ -1,15 +1,15 @@ --- read_when: - - OpenClaw 에이전트가 Google Meet 통화에 참여하도록 하려는 경우 - - OpenClaw 에이전트가 새 Google Meet 통화를 만들도록 하려는 경우 - - Chrome, Chrome 노드 또는 Twilio를 Google Meet 전송 수단으로 구성하고 있습니다 -summary: 'Google Meet Plugin: Chrome 또는 Twilio를 통해 명시적 Meet URL에 참여하고 실시간 음성 기본값 사용' + - OpenClaw 에이전트가 Google Meet 회의에 참여하도록 하고 싶습니다 + - OpenClaw 에이전트가 새 Google Meet 통화를 만들도록 하고 싶습니다 + - Google Meet 전송 수단으로 Chrome, Chrome 노드 또는 Twilio를 구성하고 있습니다 +summary: 'Google Meet Plugin: 명시적 Meet URL에 Chrome 또는 Twilio를 통해 참여하고 에이전트 응답 기본값 사용' title: Google Meet Plugin x-i18n: - generated_at: "2026-05-04T02:24:40Z" + generated_at: "2026-05-04T06:24:24Z" model: gpt-5.5 provider: openai - source_hash: 77ab70d27d47bcc037144c7c6cfad6f93f307355b6ebcf3ee75c85b96a24af2f + source_hash: 459802231a807001d96d43950993f612234a5394fbe8c57a9992e97e8851dda2 source_path: plugins/google-meet.md workflow: 16 --- @@ -18,34 +18,34 @@ OpenClaw의 Google Meet 참가자 지원은 설계상 명시적으로 동작합 - 명시적인 `https://meet.google.com/...` URL에만 참여합니다. - Google Meet API를 통해 새 Meet 공간을 만든 다음 반환된 URL에 참여할 수 있습니다. -- `realtime` 음성이 기본 모드입니다. -- 실시간 음성은 더 깊은 추론이나 도구가 필요할 때 전체 OpenClaw 에이전트를 다시 호출할 수 있습니다. -- 에이전트는 `mode`로 참여 동작을 선택합니다. 실시간 청취/응답에는 `realtime`을 사용하고, 실시간 음성 브리지 없이 브라우저에 참여하거나 제어하려면 `transcribe`를 사용합니다. +- `agent`는 기본 말하기 응답 모드입니다. 실시간 전사가 듣고, 구성된 OpenClaw 에이전트가 응답하며, 일반 OpenClaw TTS가 Meet에서 음성을 출력합니다. +- `bidi`는 대체용 직접 실시간 음성 모델 모드로 계속 사용할 수 있습니다. +- 에이전트는 `mode`로 참여 동작을 선택합니다. 실시간 듣기/말하기 응답에는 `agent`, 직접 실시간 음성 대체에는 `bidi`, 말하기 응답 브리지 없이 브라우저에 참여하고 제어하려면 `transcribe`를 사용합니다. - 인증은 개인 Google OAuth 또는 이미 로그인된 Chrome 프로필로 시작합니다. -- 자동 동의 안내는 없습니다. +- 자동 동의 안내 방송은 없습니다. - 기본 Chrome 오디오 백엔드는 `BlackHole 2ch`입니다. -- Chrome은 로컬 또는 페어링된 Node 호스트에서 실행할 수 있습니다. +- Chrome은 로컬 또는 페어링된 노드 호스트에서 실행할 수 있습니다. - Twilio는 전화 접속 번호와 선택적 PIN 또는 DTMF 시퀀스를 받습니다. Meet URL로 직접 전화를 걸 수는 없습니다. - CLI 명령은 `googlemeet`입니다. `meet`는 더 넓은 에이전트 원격 회의 워크플로용으로 예약되어 있습니다. ## 빠른 시작 -로컬 오디오 의존성을 설치하고 백엔드 실시간 음성 제공자를 구성합니다. 기본값은 OpenAI입니다. Google Gemini Live도 `realtime.provider: "google"`로 동작합니다. +로컬 오디오 의존성을 설치하고 실시간 전사 제공자와 일반 OpenClaw TTS를 구성합니다. OpenAI가 기본 전사 제공자입니다. Google Gemini Live도 `realtime.voiceProvider: "google"`이 설정된 별도의 `bidi` 음성 대체로 사용할 수 있습니다. ```bash brew install blackhole-2ch sox export OPENAI_API_KEY=sk-... -# or +# only needed when realtime.voiceProvider is "google" for bidi mode export GEMINI_API_KEY=... ``` -`blackhole-2ch`는 `BlackHole 2ch` 가상 오디오 장치를 설치합니다. Homebrew 설치 관리자는 macOS가 장치를 노출하기 전에 재부팅을 요구합니다. +`blackhole-2ch`는 `BlackHole 2ch` 가상 오디오 장치를 설치합니다. Homebrew의 설치 프로그램은 macOS가 장치를 노출하기 전에 재부팅을 요구합니다. ```bash sudo reboot ``` -재부팅 후 두 구성 요소를 모두 확인합니다. +재부팅 후 두 항목을 모두 확인합니다. ```bash system_profiler SPAudioDataType | grep -i BlackHole @@ -73,21 +73,21 @@ Plugin을 활성화합니다. openclaw googlemeet setup ``` -설정 출력은 에이전트가 읽을 수 있고 모드를 인식하도록 되어 있습니다. Chrome 프로필, Node 고정, 그리고 실시간 Chrome 참여의 경우 BlackHole/SoX 오디오 브리지와 지연된 실시간 소개 확인을 보고합니다. 관찰 전용 참여의 경우 `--mode transcribe`로 동일한 전송을 확인합니다. 이 모드는 브리지를 통해 듣거나 말하지 않으므로 실시간 오디오 필수 조건을 건너뜁니다. +설정 출력은 에이전트가 읽을 수 있고 모드를 인식하도록 설계되었습니다. Chrome 프로필, 노드 고정, 그리고 실시간 Chrome 참여의 경우 BlackHole/SoX 오디오 브리지와 지연된 실시간 인트로 검사를 보고합니다. 관찰 전용 참여의 경우 `--mode transcribe`로 동일한 전송을 확인합니다. 이 모드는 브리지를 통해 듣거나 말하지 않기 때문에 실시간 오디오 전제 조건을 건너뜁니다. ```bash openclaw googlemeet setup --transport chrome-node --mode transcribe ``` -Twilio 위임이 구성되어 있으면 설정은 `voice-call` Plugin, Twilio 자격 증명, 공개 Webhook 노출이 준비되었는지도 보고합니다. 에이전트에게 참여를 요청하기 전에 `ok: false` 확인은 해당 전송 및 모드의 차단 요인으로 처리합니다. 스크립트 또는 기계 판독 가능 출력에는 `openclaw googlemeet setup --json`을 사용합니다. 에이전트가 시도하기 전에 특정 전송을 사전 점검하려면 `--transport chrome`, `--transport chrome-node`, 또는 `--transport twilio`를 사용합니다. +Twilio 위임이 구성된 경우 설정은 `voice-call` Plugin, Twilio 자격 증명, 공개 Webhook 노출이 준비되었는지도 보고합니다. 에이전트에게 참여를 요청하기 전에 `ok: false` 검사는 해당 전송 및 모드의 차단 요소로 취급합니다. 스크립트 또는 기계 판독 가능한 출력에는 `openclaw googlemeet setup --json`을 사용합니다. 에이전트가 시도하기 전에 특정 전송을 사전 점검하려면 `--transport chrome`, `--transport chrome-node`, 또는 `--transport twilio`를 사용합니다. -Twilio의 경우 기본 전송이 Chrome일 때 항상 전송을 명시적으로 사전 점검합니다. +Twilio의 경우 기본 전송이 Chrome이면 항상 전송을 명시적으로 사전 점검합니다. ```bash openclaw googlemeet setup --transport twilio ``` -이렇게 하면 에이전트가 회의에 전화를 걸기 전에 누락된 `voice-call` 연결, Twilio 자격 증명, 또는 접근 불가능한 Webhook 노출을 잡아낼 수 있습니다. +이렇게 하면 에이전트가 회의에 전화를 걸기 전에 누락된 `voice-call` 연결, Twilio 자격 증명 또는 도달할 수 없는 Webhook 노출을 잡아냅니다. 회의에 참여합니다. @@ -106,23 +106,23 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij } ``` -에이전트용 `google_meet` 도구는 비 macOS 호스트에서도 아티팩트, 캘린더, 설정, 전사, Twilio, `chrome-node` 흐름에 계속 사용할 수 있습니다. 로컬 Chrome 응답 동작은 번들 Chrome 오디오 경로가 현재 macOS `BlackHole 2ch`에 의존하므로 해당 호스트에서는 차단됩니다. Linux에서는 Chrome 응답 참여를 위해 `mode: "transcribe"`, Twilio 전화 접속, 또는 macOS `chrome-node` 호스트를 사용합니다. +에이전트용 `google_meet` 도구는 macOS가 아닌 호스트에서도 아티팩트, 캘린더, 설정, 전사, Twilio, `chrome-node` 흐름에 계속 사용할 수 있습니다. 로컬 Chrome 말하기 응답 작업은 번들 Chrome 오디오 경로가 현재 macOS `BlackHole 2ch`에 의존하기 때문에 해당 호스트에서 차단됩니다. Linux에서는 Chrome 말하기 응답 참가에 `mode: "transcribe"`, Twilio 전화 접속, 또는 macOS `chrome-node` 호스트를 사용합니다. 새 회의를 만들고 참여합니다. ```bash -openclaw googlemeet create --transport chrome-node --mode realtime +openclaw googlemeet create --transport chrome-node --mode agent ``` -API로 생성한 회의실에서 Google 계정 기본값을 상속하지 않고 회의실의 무노크 정책을 명시하려면 Google Meet `SpaceConfig.accessType`을 사용합니다. +API로 만든 방의 경우, 방의 노크 없는 참여 정책을 Google 계정 기본값에서 상속하지 않고 명시하려면 Google Meet `SpaceConfig.accessType`을 사용합니다. ```bash -openclaw googlemeet create --access-type OPEN --transport chrome-node --mode realtime +openclaw googlemeet create --access-type OPEN --transport chrome-node --mode agent ``` -`OPEN`은 Meet URL을 가진 누구나 노크 없이 참여할 수 있게 합니다. `TRUSTED`는 호스트 조직의 신뢰할 수 있는 사용자, 초대된 외부 사용자, 전화 접속 사용자가 노크 없이 참여할 수 있게 합니다. `RESTRICTED`는 무노크 입장을 초대받은 사람으로 제한합니다. 이 설정은 공식 Google Meet API 생성 경로에만 적용되므로 OAuth 자격 증명이 구성되어 있어야 합니다. +`OPEN`은 Meet URL이 있는 누구나 노크 없이 참여할 수 있게 합니다. `TRUSTED`는 호스트 조직의 신뢰된 사용자, 초대된 외부 사용자, 전화 접속 사용자가 노크 없이 참여할 수 있게 합니다. `RESTRICTED`는 노크 없는 입장을 초대받은 사람으로 제한합니다. 이러한 설정은 공식 Google Meet API 생성 경로에만 적용되므로 OAuth 자격 증명이 구성되어 있어야 합니다. -이 옵션이 제공되기 전에 Google Meet을 인증했다면 Google OAuth 동의 화면에 `meetings.space.settings` 범위를 추가한 뒤 `openclaw googlemeet auth login --json`을 다시 실행합니다. +이 옵션을 사용할 수 있기 전에 Google Meet 인증을 완료했다면 Google OAuth 동의 화면에 `meetings.space.settings` 범위를 추가한 후 `openclaw googlemeet auth login --json`을 다시 실행합니다. 참여하지 않고 URL만 만듭니다. @@ -132,38 +132,38 @@ openclaw googlemeet create --no-join `googlemeet create`에는 두 가지 경로가 있습니다. -- API 생성: Google Meet OAuth 자격 증명이 구성되어 있을 때 사용됩니다. 가장 결정적인 경로이며 브라우저 UI 상태에 의존하지 않습니다. -- 브라우저 대체 경로: OAuth 자격 증명이 없을 때 사용됩니다. OpenClaw는 고정된 Chrome Node를 사용해 `https://meet.google.com/new`를 열고, Google이 실제 회의 코드 URL로 리디렉션할 때까지 기다린 다음 해당 URL을 반환합니다. 이 경로는 Node의 OpenClaw Chrome 프로필이 이미 Google에 로그인되어 있어야 합니다. 브라우저 자동화는 Meet 자체의 최초 실행 마이크 프롬프트를 처리합니다. 해당 프롬프트는 Google 로그인 실패로 취급되지 않습니다. - 참여 및 생성 흐름은 새 탭을 열기 전에 기존 Meet 탭도 재사용하려고 시도합니다. 매칭은 `authuser` 같은 무해한 URL 쿼리 문자열을 무시하므로, 에이전트 재시도는 두 번째 Chrome 탭을 만드는 대신 이미 열린 회의에 포커스해야 합니다. +- API 생성: Google Meet OAuth 자격 증명이 구성된 경우 사용됩니다. 가장 결정적인 경로이며 브라우저 UI 상태에 의존하지 않습니다. +- 브라우저 대체: OAuth 자격 증명이 없을 때 사용됩니다. OpenClaw는 고정된 Chrome 노드를 사용해 `https://meet.google.com/new`를 열고, Google이 실제 회의 코드 URL로 리디렉션할 때까지 기다린 다음 해당 URL을 반환합니다. 이 경로에서는 노드의 OpenClaw Chrome 프로필이 이미 Google에 로그인되어 있어야 합니다. 브라우저 자동화는 Meet 자체의 최초 실행 마이크 프롬프트를 처리합니다. 해당 프롬프트는 Google 로그인 실패로 취급되지 않습니다. + 참여 및 생성 흐름은 새 탭을 열기 전에 기존 Meet 탭도 재사용하려고 합니다. 매칭은 `authuser` 같은 무해한 URL 쿼리 문자열을 무시하므로, 에이전트가 재시도하면 두 번째 Chrome 탭을 만들지 않고 이미 열린 회의에 포커스해야 합니다. 명령/도구 출력에는 에이전트가 어떤 경로가 사용되었는지 설명할 수 있도록 `source` 필드(`api` 또는 `browser`)가 포함됩니다. `create`는 기본적으로 새 회의에 참여하고 `joined: true`와 참여 세션을 반환합니다. URL만 만들려면 CLI에서 `create --no-join`을 사용하거나 도구에 `"join": false`를 전달합니다. -또는 에이전트에게 다음과 같이 말합니다. “Google Meet을 만들고, 실시간 음성으로 참여한 다음, 링크를 보내 주세요.” 에이전트는 `action: "create"`로 `google_meet`을 호출한 뒤 반환된 `meetingUri`를 공유해야 합니다. +또는 에이전트에게 "Google Meet을 만들고, 에이전트 말하기 응답 모드로 참여한 다음, 링크를 보내줘."라고 말합니다. 에이전트는 `action: "create"`로 `google_meet`를 호출한 다음 반환된 `meetingUri`를 공유해야 합니다. ```json { "action": "create", "transport": "chrome-node", - "mode": "realtime" + "mode": "agent" } ``` -관찰 전용/브라우저 제어 참여의 경우 `"mode": "transcribe"`를 설정합니다. 이 모드는 양방향 실시간 음성 브리지를 시작하지 않고, BlackHole 또는 SoX를 요구하지 않으며, 회의에 응답하지 않습니다. 이 모드의 Chrome 참여는 OpenClaw의 마이크/카메라 권한 부여와 Meet **Use microphone** 경로도 피합니다. Meet이 오디오 선택 중간 화면을 표시하면 자동화는 마이크 없는 경로를 시도하고, 그렇지 않으면 로컬 마이크를 여는 대신 수동 조치를 보고합니다. 전사 모드에서 관리형 Chrome 전송은 최선 노력 방식의 Meet 캡션 관찰자도 설치합니다. `googlemeet status --json`과 `googlemeet doctor`는 운영자가 브라우저가 통화에 참여했는지, Meet 캡션이 텍스트를 생성하는지 확인할 수 있도록 `captioning`, `captionsEnabledAttempted`, `transcriptLines`, `lastCaptionAt`, `lastCaptionSpeaker`, `lastCaptionText`, 짧은 `recentTranscript` 꼬리를 표시합니다. -예/아니요 프로브가 필요할 때는 `openclaw googlemeet test-listen --transport chrome-node`를 사용합니다. 이 명령은 전사 모드로 참여하고, 새로운 캡션 또는 전사 움직임을 기다린 뒤 `listenVerified`, `listenTimedOut`, 수동 조치 필드, 최신 캡션 상태를 반환합니다. +관찰 전용/브라우저 제어 참여의 경우 `"mode": "transcribe"`를 설정합니다. 이 모드는 양방향 실시간 음성 브리지를 시작하지 않고, BlackHole 또는 SoX가 필요 없으며, 회의에 말하기 응답을 하지 않습니다. 이 모드의 Chrome 참여는 OpenClaw의 마이크/카메라 권한 부여와 Meet **Use microphone** 경로도 피합니다. Meet이 오디오 선택 중간 화면을 표시하면 자동화는 마이크 없는 경로를 시도하고, 그렇지 않으면 로컬 마이크를 열지 않고 수동 작업을 보고합니다. 전사 모드에서 관리형 Chrome 전송은 최선 노력 방식의 Meet 캡션 관찰자도 설치합니다. `googlemeet status --json` 및 `googlemeet doctor`는 운영자가 브라우저가 통화에 참여했는지, Meet 캡션이 텍스트를 생성하는지 알 수 있도록 `captioning`, `captionsEnabledAttempted`, `transcriptLines`, `lastCaptionAt`, `lastCaptionSpeaker`, `lastCaptionText`, 짧은 `recentTranscript` 꼬리를 노출합니다. +예/아니요 프로브가 필요하면 `openclaw googlemeet test-listen --transport chrome-node`를 사용합니다. 이 명령은 전사 모드로 참여하고, 새 캡션 또는 전사 움직임을 기다린 다음 `listenVerified`, `listenTimedOut`, 수동 작업 필드, 최신 캡션 상태를 반환합니다. -실시간 세션 중 `google_meet` 상태에는 `inCall`, `manualActionRequired`, `providerConnected`, `realtimeReady`, `audioInputActive`, `audioOutputActive`, 마지막 입력/출력 타임스탬프, 바이트 카운터, 브리지 종료 상태 같은 브라우저 및 오디오 브리지 상태가 포함됩니다. 안전한 Meet 페이지 프롬프트가 나타나면 브라우저 자동화가 가능한 경우 이를 처리합니다. 로그인, 호스트 승인, 브라우저/OS 권한 프롬프트는 에이전트가 전달할 이유와 메시지를 포함한 수동 조치로 보고됩니다. 관리형 Chrome 세션은 브라우저 상태가 `inCall: true`를 보고한 뒤에만 소개 또는 테스트 문구를 내보냅니다. 그렇지 않으면 상태는 `speechReady: false`를 보고하고, 음성 시도는 에이전트가 회의에서 말한 것처럼 가장하지 않고 차단됩니다. +실시간 세션 중 `google_meet` 상태에는 `inCall`, `manualActionRequired`, `providerConnected`, `realtimeReady`, `audioInputActive`, `audioOutputActive`, 마지막 입력/출력 타임스탬프, 바이트 카운터, 브리지 종료 상태 같은 브라우저 및 오디오 브리지 상태가 포함됩니다. 안전한 Meet 페이지 프롬프트가 나타나면 브라우저 자동화가 가능한 경우 이를 처리합니다. 로그인, 호스트 승인, 브라우저/OS 권한 프롬프트는 에이전트가 전달할 수 있도록 이유와 메시지를 포함한 수동 작업으로 보고됩니다. 관리형 Chrome 세션은 브라우저 상태가 `inCall: true`를 보고한 후에만 인트로 또는 테스트 문구를 내보냅니다. 그렇지 않으면 상태가 `speechReady: false`를 보고하고, 에이전트가 실제로 회의에서 말한 것처럼 가장하지 않고 말하기 시도를 차단합니다. -로컬 Chrome 참여는 로그인된 OpenClaw 브라우저 프로필을 통해 이루어집니다. 실시간 모드는 OpenClaw가 사용하는 마이크/스피커 경로에 `BlackHole 2ch`가 필요합니다. 깨끗한 양방향 오디오를 위해 별도의 가상 장치나 Loopback 스타일 그래프를 사용합니다. 첫 스모크 테스트에는 단일 BlackHole 장치로 충분하지만 에코가 생길 수 있습니다. +로컬 Chrome은 로그인된 OpenClaw 브라우저 프로필을 통해 참여합니다. 실시간 모드에는 OpenClaw가 사용하는 마이크/스피커 경로를 위해 `BlackHole 2ch`가 필요합니다. 깨끗한 양방향 오디오를 위해 별도의 가상 장치 또는 Loopback 스타일 그래프를 사용합니다. 단일 BlackHole 장치만으로도 첫 스모크 테스트에는 충분하지만 에코가 발생할 수 있습니다. ### 로컬 Gateway + Parallels Chrome -VM이 Chrome을 소유하게 하는 것만으로는 macOS VM 안에 전체 OpenClaw Gateway나 모델 API 키가 필요하지 않습니다. Gateway와 에이전트를 로컬에서 실행한 다음 VM에서 Node 호스트를 실행합니다. Node가 Chrome 명령을 광고하도록 VM에서 번들 Plugin을 한 번 활성화합니다. +VM이 Chrome을 소유하게 만들기 위해 macOS VM 안에 전체 OpenClaw Gateway나 모델 API 키가 필요하지는 않습니다. Gateway와 에이전트를 로컬에서 실행한 다음 VM에서 노드 호스트를 실행합니다. 노드가 Chrome 명령을 광고하도록 VM에서 번들 Plugin을 한 번 활성화합니다. -어디에서 무엇이 실행되는지: +각 위치에서 실행되는 항목: - Gateway 호스트: OpenClaw Gateway, 에이전트 워크스페이스, 모델/API 키, 실시간 제공자, Google Meet Plugin 구성. -- Parallels macOS VM: OpenClaw CLI/Node 호스트, Google Chrome, SoX, BlackHole 2ch, Google에 로그인된 Chrome 프로필. -- VM에 필요하지 않은 것: Gateway 서비스, 에이전트 구성, OpenAI/GPT 키, 또는 모델 제공자 설정. +- Parallels macOS VM: OpenClaw CLI/노드 호스트, Google Chrome, SoX, BlackHole 2ch, Google에 로그인된 Chrome 프로필. +- VM에 필요 없는 항목: Gateway 서비스, 에이전트 구성, OpenAI/GPT 키, 모델 제공자 설정. VM 의존성을 설치합니다. @@ -171,7 +171,7 @@ VM 의존성을 설치합니다. brew install blackhole-2ch sox ``` -BlackHole 설치 후 macOS가 `BlackHole 2ch`를 노출하도록 VM을 재부팅합니다. +BlackHole을 설치한 후 macOS가 `BlackHole 2ch`를 노출하도록 VM을 재부팅합니다. ```bash sudo reboot @@ -190,20 +190,20 @@ VM에 OpenClaw를 설치하거나 업데이트한 다음, 거기에서 번들 Pl openclaw plugins enable google-meet ``` -VM에서 Node 호스트를 시작합니다. +VM에서 노드 호스트를 시작합니다. ```bash openclaw node run --host --port 18789 --display-name parallels-macos ``` -``가 LAN IP이고 TLS를 사용하지 않는 경우, 신뢰할 수 있는 해당 사설 네트워크에 명시적으로 동의하지 않으면 Node는 평문 WebSocket을 거부합니다. +``가 LAN IP이고 TLS를 사용하지 않는 경우, 신뢰된 개인 네트워크에 명시적으로 동의하지 않으면 노드가 일반 텍스트 WebSocket을 거부합니다. ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node run --host --port 18789 --display-name parallels-macos ``` -Node를 LaunchAgent로 설치할 때도 같은 환경 변수를 사용합니다. +노드를 LaunchAgent로 설치할 때도 동일한 환경 변수를 사용합니다. ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -213,20 +213,20 @@ openclaw node restart `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`은 프로세스 환경이며 `openclaw.json` 설정이 아닙니다. `openclaw node install`은 설치 명령에 이 값이 있을 때 LaunchAgent 환경에 저장합니다. -Gateway 호스트에서 Node를 승인합니다. +Gateway 호스트에서 노드를 승인합니다. ```bash openclaw devices list openclaw devices approve ``` -Gateway가 Node를 보고, Node가 `googlemeet.chrome`와 브라우저 기능/`browser.proxy`를 모두 광고하는지 확인합니다. +Gateway가 노드를 보고 있고 노드가 `googlemeet.chrome` 및 브라우저 기능/`browser.proxy`를 모두 광고하는지 확인합니다. ```bash openclaw nodes status ``` -Gateway 호스트에서 Meet을 해당 Node로 라우팅합니다. +Gateway 호스트에서 해당 노드를 통해 Meet을 라우팅합니다. ```json5 { @@ -256,7 +256,7 @@ Gateway 호스트에서 Meet을 해당 Node로 라우팅합니다. } ``` -이제 Gateway 호스트에서 평소처럼 참여합니다. +이제 Gateway 호스트에서 일반적으로 참여합니다. ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij @@ -264,52 +264,53 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij 또는 에이전트에게 `transport: "chrome-node"`로 `google_meet` 도구를 사용하도록 요청합니다. -세션을 만들거나 재사용하고, 알려진 문구를 말한 뒤, 세션 상태를 출력하는 단일 명령 스모크 테스트는 다음과 같습니다. +세션을 만들거나 재사용하고, 알려진 문구를 말한 뒤, 세션 상태를 출력하는 단일 명령 스모크 테스트: ```bash openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij ``` -realtime join 중에는 OpenClaw 브라우저 자동화가 게스트 이름을 입력하고, -Join/Ask to join을 클릭하며, 해당 프롬프트가 표시되면 Meet의 첫 실행 -"Use microphone" 선택을 수락합니다. observe-only join 또는 browser-only 미팅 -생성 중에는 같은 프롬프트에서 마이크 없이 계속 진행할 수 있는 선택지가 있으면 -그 선택지로 넘어갑니다. 브라우저 프로필이 로그인되어 있지 않거나, Meet이 -호스트 입장을 기다리고 있거나, Chrome이 realtime join을 위해 마이크/카메라 -권한을 필요로 하거나, Meet이 자동화로 해결할 수 없는 프롬프트에서 멈춰 있으면 -join/test-speech 결과는 `manualActionReason` 및 `manualActionMessage`와 함께 -`manualActionRequired: true`를 보고합니다. 에이전트는 join 재시도를 중단하고, -그 정확한 메시지와 현재 `browserUrl`/`browserTitle`을 보고한 뒤, 수동 -브라우저 작업이 완료된 후에만 재시도해야 합니다. +실시간 참여 중에는 OpenClaw 브라우저 자동화가 게스트 이름을 입력하고, +참여/참여 요청을 클릭하며, 해당 프롬프트가 표시되면 Meet의 첫 실행 +"마이크 사용" 선택을 수락합니다. 관찰 전용 참여 또는 브라우저 전용 회의 생성 +중에는 해당 선택을 사용할 수 있을 때 마이크 없이 동일한 프롬프트를 지나갑니다. +브라우저 프로필이 로그인되어 있지 않거나, Meet이 호스트 승인을 기다리고 있거나, +실시간 참여를 위해 Chrome에 마이크/카메라 권한이 필요하거나, Meet이 자동화로 +해결할 수 없는 프롬프트에 멈춰 있는 경우, 참여/test-speech 결과는 +`manualActionRequired: true`를 `manualActionReason` 및 +`manualActionMessage`와 함께 보고합니다. 에이전트는 참여 재시도를 중지하고, +해당 정확한 메시지와 현재 `browserUrl`/`browserTitle`을 보고한 뒤, 수동 +브라우저 작업이 완료된 후에만 다시 시도해야 합니다. -`chromeNode.node`가 생략되면, 정확히 하나의 연결된 노드가 -`googlemeet.chrome`과 브라우저 제어를 모두 알릴 때만 OpenClaw가 자동 -선택합니다. 사용 가능한 노드가 여러 개 연결되어 있으면 `chromeNode.node`를 -노드 ID, 표시 이름 또는 원격 IP로 설정하세요. +`chromeNode.node`가 생략되면, OpenClaw는 정확히 하나의 연결된 노드만 +`googlemeet.chrome`과 브라우저 제어를 모두 알리는 경우에만 자동 선택합니다. +여러 사용 가능한 노드가 연결되어 있으면 `chromeNode.node`를 노드 ID, +표시 이름 또는 원격 IP로 설정하세요. -일반적인 실패 확인 사항: +일반적인 실패 점검: - `Configured Google Meet node ... is not usable: offline`: 고정된 노드는 - Gateway에 알려져 있지만 사용할 수 없습니다. 에이전트는 해당 노드를 사용 - 가능한 Chrome 호스트가 아니라 진단 상태로 취급해야 하며, 사용자가 요청하지 - 않은 한 다른 전송으로 대체하지 말고 설정 차단 원인을 보고해야 합니다. + Gateway에 알려져 있지만 사용할 수 없습니다. 에이전트는 해당 노드를 + 사용 가능한 Chrome 호스트가 아니라 진단 상태로 취급해야 하며, 사용자가 + 요청하지 않은 한 다른 전송으로 대체하지 말고 설정 차단 요인을 보고해야 + 합니다. - `No connected Google Meet-capable node`: VM에서 `openclaw node run`을 - 시작하고, 페어링을 승인한 뒤, VM에서 `openclaw plugins enable google-meet` - 및 `openclaw plugins enable browser`가 실행되었는지 확인하세요. 또한 - Gateway 호스트가 `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]`로 - 두 노드 명령을 모두 허용하는지 확인하세요. -- `BlackHole 2ch audio device not found`: 확인 중인 호스트에 - `blackhole-2ch`를 설치하고, 로컬 Chrome 오디오를 사용하기 전에 재부팅하세요. + 시작하고, 페어링을 승인하며, VM에서 `openclaw plugins enable google-meet`와 + `openclaw plugins enable browser`가 실행되었는지 확인하세요. 또한 Gateway + 호스트가 `gateway.nodes.allowCommands: ["googlemeet.chrome", "browser.proxy"]`로 + 두 노드 명령을 모두 허용하는지도 확인하세요. +- `BlackHole 2ch audio device not found`: 점검 중인 호스트에 + `blackhole-2ch`를 설치하고 로컬 Chrome 오디오를 사용하기 전에 재부팅하세요. - `BlackHole 2ch audio device not found on the node`: VM에 `blackhole-2ch`를 설치하고 VM을 재부팅하세요. -- Chrome은 열리지만 join할 수 없음: VM 내부의 브라우저 프로필에 로그인하거나, - 게스트 join을 위해 `chrome.guestName`을 설정된 상태로 유지하세요. 게스트 - 자동 join은 노드 브라우저 프록시를 통해 OpenClaw 브라우저 자동화를 - 사용합니다. 노드 브라우저 설정이 원하는 프로필을 가리키는지 확인하세요. 예: - `browser.defaultProfile: "user"` 또는 이름이 지정된 기존 세션 프로필. +- Chrome이 열리지만 참여할 수 없음: VM 내부의 브라우저 프로필에 로그인하거나, + 게스트 참여를 위해 `chrome.guestName`을 설정된 상태로 유지하세요. 게스트 + 자동 참여는 노드 브라우저 프록시를 통해 OpenClaw 브라우저 자동화를 + 사용합니다. 노드 브라우저 구성이 원하는 프로필을 가리키는지 확인하세요. + 예: `browser.defaultProfile: "user"` 또는 이름이 지정된 기존 세션 프로필. - 중복 Meet 탭: `chrome.reuseExistingTab: true`를 활성화된 상태로 두세요. - OpenClaw는 새 탭을 열기 전에 같은 Meet URL의 기존 탭을 활성화하며, - 브라우저 미팅 생성은 다른 탭을 열기 전에 진행 중인 + OpenClaw는 새 탭을 열기 전에 동일한 Meet URL의 기존 탭을 활성화하고, + 브라우저 회의 생성은 다른 탭을 열기 전에 진행 중인 `https://meet.google.com/new` 또는 Google 계정 프롬프트 탭을 재사용합니다. - 오디오 없음: Meet에서 마이크/스피커를 OpenClaw가 사용하는 가상 오디오 장치 경로로 라우팅하세요. 깨끗한 양방향 오디오를 위해 별도의 가상 장치나 @@ -317,29 +318,29 @@ join/test-speech 결과는 `manualActionReason` 및 `manualActionMessage`와 함 ## 설치 참고 사항 -Chrome talk-back 기본값은 두 외부 도구를 사용합니다. +Chrome 토크백 기본값은 두 가지 외부 도구를 사용합니다. - `sox`: 명령줄 오디오 유틸리티입니다. Plugin은 기본 24 kHz PCM16 오디오 - 브리지를 위해 명시적인 CoreAudio 장치 명령을 사용합니다. + 브리지에 명시적 CoreAudio 장치 명령을 사용합니다. - `blackhole-2ch`: macOS 가상 오디오 드라이버입니다. Chrome/Meet이 라우팅할 수 있는 `BlackHole 2ch` 오디오 장치를 만듭니다. -OpenClaw는 두 패키지 중 어느 것도 번들하거나 재배포하지 않습니다. 문서는 -사용자에게 Homebrew를 통해 호스트 종속성으로 설치하라고 안내합니다. SoX의 -라이선스는 `LGPL-2.0-only AND GPL-2.0-only`이고, BlackHole은 GPL-3.0입니다. -BlackHole을 OpenClaw와 함께 번들하는 설치 프로그램이나 어플라이언스를 -빌드하는 경우, BlackHole의 업스트림 라이선스 조건을 검토하거나 Existential -Audio에서 별도 라이선스를 받으세요. +OpenClaw는 두 패키지 중 어느 것도 번들로 제공하거나 재배포하지 않습니다. +문서는 사용자에게 Homebrew를 통해 호스트 의존성으로 설치하도록 안내합니다. +SoX는 `LGPL-2.0-only AND GPL-2.0-only`로 라이선스가 부여되며, BlackHole은 +GPL-3.0입니다. BlackHole을 OpenClaw와 함께 번들로 제공하는 설치 프로그램이나 +어플라이언스를 빌드하는 경우, BlackHole의 업스트림 라이선스 조건을 검토하거나 +Existential Audio에서 별도 라이선스를 받으세요. ## 전송 ### Chrome -Chrome 전송은 OpenClaw 브라우저 제어를 통해 Meet URL을 열고, 로그인된 -OpenClaw 브라우저 프로필로 join합니다. macOS에서는 Plugin이 실행 전에 -`BlackHole 2ch`를 확인합니다. 설정되어 있으면 Chrome을 열기 전에 오디오 -브리지 상태 명령과 시작 명령도 실행합니다. Chrome/오디오가 Gateway 호스트에 -있으면 `chrome`을 사용하고, Chrome/오디오가 Parallels macOS VM 같은 페어링된 +Chrome 전송은 OpenClaw 브라우저 제어를 통해 Meet URL을 열고 로그인된 +OpenClaw 브라우저 프로필로 참여합니다. macOS에서는 Plugin이 실행 전에 +`BlackHole 2ch`를 확인합니다. 구성된 경우 Chrome을 열기 전에 오디오 브리지 +상태 명령과 시작 명령도 실행합니다. Chrome/오디오가 Gateway 호스트에 있으면 +`chrome`을 사용하고, Chrome/오디오가 Parallels macOS VM과 같은 페어링된 노드에 있으면 `chrome-node`를 사용하세요. 로컬 Chrome의 경우 `browser.defaultProfile`로 프로필을 선택하세요. `chrome.browserProfile`은 `chrome-node` 호스트에 전달됩니다. @@ -349,56 +350,76 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome openclaw googlemeet join https://meet.google.com/abc-defg-hij --transport chrome-node ``` -Chrome 마이크 및 스피커 오디오를 로컬 OpenClaw 오디오 브리지를 통해 +Chrome 마이크와 스피커 오디오를 로컬 OpenClaw 오디오 브리지를 통해 라우팅하세요. `BlackHole 2ch`가 설치되어 있지 않으면 오디오 경로 없이 -조용히 join하는 대신 설정 오류와 함께 join이 실패합니다. +조용히 참여하는 대신 설정 오류로 참여가 실패합니다. ### Twilio -Twilio 전송은 Voice Call Plugin에 위임되는 엄격한 다이얼 플랜입니다. Meet -페이지에서 전화번호를 파싱하지 않습니다. +Twilio 전송은 Voice Call Plugin에 위임되는 엄격한 다이얼 플랜입니다. +Meet 페이지에서 전화번호를 파싱하지 않습니다. -Chrome 참여를 사용할 수 없거나 전화 다이얼인 대체 경로를 원할 때 사용하세요. -Google Meet은 미팅에 대한 전화 다이얼인 번호와 PIN을 노출해야 합니다. -OpenClaw는 Meet 페이지에서 이를 검색하지 않습니다. +Chrome 참여를 사용할 수 없거나 전화 다이얼인 대체 경로가 필요할 때 +사용하세요. Google Meet은 회의에 대한 전화 다이얼인 번호와 PIN을 노출해야 +합니다. OpenClaw는 Meet 페이지에서 이를 검색하지 않습니다. Chrome 노드가 아니라 Gateway 호스트에서 Voice Call Plugin을 활성화하세요. ```json5 { plugins: { - allow: ["google-meet", "voice-call"], + allow: ["google-meet", "voice-call", "google"], entries: { "google-meet": { enabled: true, config: { defaultTransport: "chrome-node", - // 또는 Twilio가 기본값이어야 하면 "twilio"로 설정 + // or set "twilio" if Twilio should be the default }, }, "voice-call": { enabled: true, config: { provider: "twilio", + inboundPolicy: "allowlist", + realtime: { + enabled: true, + provider: "google", + instructions: "Join this Google Meet as an OpenClaw agent. Be brief.", + toolPolicy: "safe-read-only", + providers: { + google: { + silenceDurationMs: 500, + startSensitivity: "high", + }, + }, + }, }, }, + google: { + enabled: true, + }, }, }, } ``` -환경 또는 설정을 통해 Twilio 자격 증명을 제공하세요. 환경 변수는 비밀 값을 +환경 또는 구성을 통해 Twilio 자격 증명을 제공하세요. 환경은 비밀 값을 `openclaw.json` 밖에 유지합니다. ```bash export TWILIO_ACCOUNT_SID=AC... export TWILIO_AUTH_TOKEN=... export TWILIO_FROM_NUMBER=+15550001234 +export GEMINI_API_KEY=... ``` -`voice-call`을 활성화한 뒤 Gateway를 재시작하거나 다시 로드하세요. Plugin -설정 변경 사항은 이미 실행 중인 Gateway 프로세스에 다시 로드되기 전까지 -나타나지 않습니다. +실시간 음성 제공자가 OpenAI인 경우 대신 OpenAI provider Plugin과 +`OPENAI_API_KEY`로 `realtime.provider: "openai"`를 사용하세요. + +`voice-call`을 활성화한 후 Gateway를 다시 시작하거나 다시 로드하세요. +Plugin 구성 변경 사항은 다시 로드되기 전까지 이미 실행 중인 Gateway +프로세스에 나타나지 않습니다. 그런 다음 확인하세요. @@ -410,7 +431,7 @@ openclaw googlemeet setup Twilio 위임이 연결되면 `googlemeet setup`에 성공한 `twilio-voice-call-plugin`, `twilio-voice-call-credentials`, -`twilio-voice-call-webhook` 확인이 포함됩니다. +`twilio-voice-call-webhook` 점검이 포함됩니다. ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -419,7 +440,7 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ --pin 123456 ``` -미팅에 사용자 지정 시퀀스가 필요하면 `--dtmf-sequence`를 사용하세요. +회의에 사용자 지정 시퀀스가 필요하면 `--dtmf-sequence`를 사용하세요. ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -431,18 +452,18 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ ## OAuth 및 사전 점검 `googlemeet create`가 브라우저 자동화로 대체할 수 있으므로 Meet 링크 생성에 -OAuth는 선택 사항입니다. 공식 API 생성, 스페이스 해석 또는 Meet Media API -사전 점검을 원할 때 OAuth를 설정하세요. +OAuth는 선택 사항입니다. 공식 API 생성, 공간 확인 또는 Meet Media API 사전 +점검이 필요할 때 OAuth를 구성하세요. -Google Meet API 액세스는 사용자 OAuth를 사용합니다. Google Cloud OAuth -클라이언트를 만들고, 필요한 범위를 요청하고, Google 계정을 승인한 뒤, 결과 -refresh token을 Google Meet Plugin 설정에 저장하거나 +Google Meet API 접근은 사용자 OAuth를 사용합니다. Google Cloud OAuth +클라이언트를 만들고, 필요한 범위를 요청하고, Google 계정을 승인한 다음, +결과 refresh token을 Google Meet Plugin 구성에 저장하거나 `OPENCLAW_GOOGLE_MEET_*` 환경 변수를 제공하세요. -OAuth는 Chrome join 경로를 대체하지 않습니다. Chrome 및 Chrome-node 전송은 -브라우저 참여를 사용할 때도 로그인된 Chrome 프로필, BlackHole/SoX 및 연결된 -노드를 통해 join합니다. OAuth는 공식 Google Meet API 경로, 즉 미팅 스페이스 -생성, 스페이스 해석, Meet Media API 사전 점검 실행에만 사용됩니다. +OAuth는 Chrome 참여 경로를 대체하지 않습니다. Chrome 및 Chrome-node 전송은 +브라우저 참여를 사용할 때도 로그인된 Chrome 프로필, BlackHole/SoX, 연결된 +노드를 통해 참여합니다. OAuth는 공식 Google Meet API 경로에만 사용됩니다. +회의 공간 생성, 공간 확인, Meet Media API 사전 점검 실행입니다. ### Google 자격 증명 만들기 @@ -450,10 +471,10 @@ Google Cloud Console에서: 1. Google Cloud 프로젝트를 만들거나 선택합니다. 2. 해당 프로젝트에 대해 **Google Meet REST API**를 활성화합니다. -3. OAuth 동의 화면을 설정합니다. - - Google Workspace 조직에는 **Internal**이 가장 간단합니다. - - 개인/테스트 설정에는 **External**이 작동합니다. 앱이 Testing 상태인 - 동안 앱을 승인할 각 Google 계정을 테스트 사용자로 추가하세요. +3. OAuth 동의 화면을 구성합니다. + - Google Workspace 조직의 경우 **Internal**이 가장 간단합니다. + - 개인/테스트 설정에는 **External**이 작동합니다. 앱이 Testing 상태인 동안, + 앱을 승인할 각 Google 계정을 테스트 사용자로 추가하세요. 4. OpenClaw가 요청하는 범위를 추가합니다. - `https://www.googleapis.com/auth/meetings.space.created` - `https://www.googleapis.com/auth/meetings.space.readonly` @@ -470,23 +491,25 @@ Google Cloud Console에서: 6. 클라이언트 ID와 클라이언트 보안 비밀을 복사합니다. `meetings.space.created`는 Google Meet `spaces.create`에 필요합니다. -`meetings.space.readonly`는 OpenClaw가 Meet URL/코드를 스페이스로 해석할 수 -있게 합니다. `meetings.space.settings`는 OpenClaw가 API 방 생성 중 -`accessType` 같은 `SpaceConfig` 설정을 전달할 수 있게 합니다. +`meetings.space.readonly`는 OpenClaw가 Meet URL/코드를 공간으로 확인할 수 +있게 합니다. +`meetings.space.settings`는 OpenClaw가 API 룸 생성 중 `accessType` 같은 +`SpaceConfig` 설정을 전달할 수 있게 합니다. `meetings.conference.media.readonly`는 Meet Media API 사전 점검 및 미디어 -작업용입니다. Google은 실제 Media API 사용에 Developer Preview 등록을 요구할 -수 있습니다. 브라우저 기반 Chrome join만 필요하다면 OAuth를 완전히 건너뛰세요. +작업을 위한 것입니다. 실제 Media API 사용에는 Google이 Developer Preview +등록을 요구할 수 있습니다. 브라우저 기반 Chrome 참여만 필요하다면 OAuth를 +완전히 건너뛰세요. ### refresh token 발급 -`oauth.clientId` 및 선택적으로 `oauth.clientSecret`을 설정하거나, 환경 변수로 -전달한 뒤 다음을 실행하세요. +`oauth.clientId`와 선택적으로 `oauth.clientSecret`을 구성하거나 환경 변수로 +전달한 다음 실행하세요. ```bash openclaw googlemeet auth login --json ``` -이 명령은 refresh token이 포함된 `oauth` 설정 블록을 출력합니다. PKCE, +이 명령은 refresh token이 포함된 `oauth` 구성 블록을 출력합니다. PKCE, `http://localhost:8085/oauth2callback`의 localhost 콜백, 그리고 `--manual`을 사용한 수동 복사/붙여넣기 흐름을 사용합니다. @@ -498,7 +521,7 @@ OPENCLAW_GOOGLE_MEET_CLIENT_SECRET="your-client-secret" \ openclaw googlemeet auth login --json ``` -브라우저가 로컬 콜백에 접근할 수 없으면 수동 모드를 사용하세요. +브라우저가 로컬 콜백에 도달할 수 없을 때는 수동 모드를 사용하세요. ```bash OPENCLAW_GOOGLE_MEET_CLIENT_ID="your-client-id" \ @@ -521,7 +544,7 @@ JSON 출력에는 다음이 포함됩니다. } ``` -Google Meet Plugin 설정 아래에 `oauth` 객체를 저장하세요. +`oauth` 객체를 Google Meet Plugin 구성 아래에 저장하세요. ```json5 { @@ -542,61 +565,60 @@ Google Meet Plugin 설정 아래에 `oauth` 객체를 저장하세요. } ``` -refresh token을 설정에 두고 싶지 않으면 환경 변수를 선호하세요. 설정 값과 -환경 값이 모두 있으면 Plugin은 먼저 설정을 해석한 다음 환경을 대체값으로 -사용합니다. +refresh token을 구성에 넣고 싶지 않을 때는 환경 변수를 선호하세요. +구성과 환경 값이 모두 있으면 Plugin은 먼저 구성을 확인한 다음 환경으로 +대체합니다. -OAuth 동의에는 Meet 스페이스 생성, Meet 스페이스 읽기 액세스, Meet 회의 -미디어 읽기 액세스가 포함됩니다. 미팅 생성 지원이 존재하기 전에 인증했다면 -refresh token이 `meetings.space.created` 범위를 갖도록 -`openclaw googlemeet auth login --json`을 다시 실행하세요. +OAuth 동의에는 Meet 공간 생성, Meet 공간 읽기 접근, Meet 회의 미디어 읽기 +접근이 포함됩니다. 회의 생성 지원이 생기기 전에 인증했다면 refresh token에 +`meetings.space.created` 범위가 있도록 `openclaw googlemeet auth login --json`을 +다시 실행하세요. ### doctor로 OAuth 확인 -빠르고 비밀 값을 출력하지 않는 상태 확인을 원하면 OAuth doctor를 실행하세요. +빠른 비밀 값 없는 상태 점검이 필요할 때 OAuth doctor를 실행하세요. ```bash openclaw googlemeet doctor --oauth --json ``` -이는 Chrome 런타임을 로드하지 않으며 연결된 Chrome 노드도 필요하지 않습니다. -OAuth 설정이 존재하는지, refresh token으로 access token을 발급할 수 있는지 -확인합니다. JSON 보고서에는 `ok`, `configured`, `tokenSource`, `expiresAt` 및 -확인 메시지 같은 상태 필드만 포함됩니다. access token, refresh token 또는 -클라이언트 보안 비밀은 출력하지 않습니다. +이 명령은 Chrome 런타임을 로드하지 않으며 연결된 Chrome 노드가 필요하지 +않습니다. OAuth 구성이 존재하는지와 refresh token이 access token을 발급할 수 +있는지 확인합니다. JSON 보고서에는 `ok`, `configured`, `tokenSource`, +`expiresAt`, 점검 메시지 같은 상태 필드만 포함됩니다. access token, +refresh token 또는 클라이언트 보안 비밀은 출력하지 않습니다. 일반적인 결과: -| 확인 | 의미 | +| 검사 | 의미 | | -------------------- | --------------------------------------------------------------------------------------- | -| `oauth-config` | `oauth.clientId`와 `oauth.refreshToken`, 또는 캐시된 access token이 있습니다. | -| `oauth-token` | 캐시된 access token이 아직 유효하거나, refresh token이 새 access token을 발급했습니다. | -| `meet-spaces-get` | 선택적 `--meeting` 확인이 기존 Meet 스페이스를 해석했습니다. | -| `meet-spaces-create` | 선택적 `--create-space` 확인이 새 Meet 스페이스를 만들었습니다. | +| `oauth-config` | `oauth.clientId`와 `oauth.refreshToken`, 또는 캐시된 액세스 토큰이 있습니다. | +| `oauth-token` | 캐시된 액세스 토큰이 아직 유효하거나, 새로고침 토큰이 새 액세스 토큰을 발급했습니다. | +| `meet-spaces-get` | 선택적 `--meeting` 검사가 기존 Meet 공간을 확인했습니다. | +| `meet-spaces-create` | 선택적 `--create-space` 검사가 새 Meet 공간을 만들었습니다. | -Google Meet API 활성화와 `spaces.create` 범위도 증명하려면 부작용이 있는 생성 -확인을 실행하세요. +Google Meet API 활성화와 `spaces.create` 범위도 증명하려면 부수 효과가 있는 만들기 검사를 실행하세요. ```bash openclaw googlemeet doctor --oauth --create-space --json openclaw googlemeet create --no-join --json ``` -`--create-space`는 폐기용 Meet URL을 만듭니다. Google Cloud 프로젝트에 Meet API가 활성화되어 있고 승인된 계정에 `meetings.space.created` 범위가 있는지 확인해야 할 때 사용하세요. +`--create-space`는 일회용 Meet URL을 만듭니다. Google Cloud 프로젝트에 Meet API가 활성화되어 있고 승인된 계정에 `meetings.space.created` 범위가 있는지 확인해야 할 때 사용하세요. -기존 회의 스페이스에 대한 읽기 액세스를 증명하려면: +기존 회의 공간에 대한 읽기 액세스를 증명하려면 다음을 실행하세요. ```bash openclaw googlemeet doctor --oauth --meeting https://meet.google.com/abc-defg-hij --json openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -`doctor --oauth --meeting` 및 `resolve-space`는 승인된 Google 계정이 접근할 수 있는 기존 스페이스에 대한 읽기 액세스를 증명합니다. 이러한 확인에서 `403`이 발생하면 보통 Google Meet REST API가 비활성화되어 있거나, 동의된 리프레시 토큰에 필요한 범위가 없거나, Google 계정이 해당 Meet 스페이스에 접근할 수 없다는 뜻입니다. 리프레시 토큰 오류는 `openclaw googlemeet auth login ---json`을 다시 실행하고 새 `oauth` 블록을 저장해야 한다는 뜻입니다. +`doctor --oauth --meeting` 및 `resolve-space`는 승인된 Google 계정이 액세스할 수 있는 기존 공간에 대한 읽기 액세스를 증명합니다. 이러한 검사에서 `403`이 반환되면 일반적으로 Google Meet REST API가 비활성화되어 있거나, 동의한 새로고침 토큰에 필요한 범위가 없거나, Google 계정이 해당 Meet 공간에 액세스할 수 없다는 의미입니다. 새로고침 토큰 오류는 `openclaw googlemeet auth login +--json`을 다시 실행하고 새 `oauth` 블록을 저장해야 함을 의미합니다. -브라우저 폴백에는 OAuth 자격 증명이 필요하지 않습니다. 이 모드에서는 Google 인증이 OpenClaw 구성에서 오는 것이 아니라 선택한 Node의 로그인된 Chrome 프로필에서 옵니다. +브라우저 대체 모드에는 OAuth 자격 증명이 필요하지 않습니다. 이 모드에서 Google 인증은 OpenClaw 구성에서가 아니라 선택한 Node의 로그인된 Chrome 프로필에서 가져옵니다. -이 환경 변수들은 폴백으로 허용됩니다: +다음 환경 변수를 대체값으로 사용할 수 있습니다. - `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 또는 `GOOGLE_MEET_CLIENT_ID` - `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET` 또는 `GOOGLE_MEET_CLIENT_SECRET` @@ -607,19 +629,19 @@ openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij - `OPENCLAW_GOOGLE_MEET_DEFAULT_MEETING` 또는 `GOOGLE_MEET_DEFAULT_MEETING` - `OPENCLAW_GOOGLE_MEET_PREVIEW_ACK` 또는 `GOOGLE_MEET_PREVIEW_ACK` -`spaces.get`을 통해 Meet URL, 코드 또는 `spaces/{id}`를 확인합니다: +Meet URL, 코드 또는 `spaces/{id}`를 `spaces.get`을 통해 확인하세요. ```bash openclaw googlemeet resolve-space --meeting https://meet.google.com/abc-defg-hij ``` -미디어 작업 전에 사전 검사를 실행합니다: +미디어 작업 전에 사전 점검을 실행하세요. ```bash openclaw googlemeet preflight --meeting https://meet.google.com/abc-defg-hij ``` -Meet가 회의 기록을 만든 뒤 회의 아티팩트와 참석 정보를 나열합니다: +Meet에서 회의 기록을 만든 후 회의 아티팩트와 참석 정보를 나열하세요. ```bash openclaw googlemeet artifacts --meeting https://meet.google.com/abc-defg-hij @@ -627,9 +649,9 @@ openclaw googlemeet attendance --meeting https://meet.google.com/abc-defg-hij openclaw googlemeet export --meeting https://meet.google.com/abc-defg-hij --output ./meet-export ``` -`--meeting`을 사용하면 `artifacts`와 `attendance`는 기본적으로 최신 회의 기록을 사용합니다. 해당 회의에 대해 보관된 모든 기록을 원하면 `--all-conference-records`를 전달하세요. +`--meeting`을 사용하면 `artifacts` 및 `attendance`는 기본적으로 최신 회의 기록을 사용합니다. 해당 회의의 보존된 모든 기록을 원할 때는 `--all-conference-records`를 전달하세요. -Calendar 조회는 Meet 아티팩트를 읽기 전에 Google Calendar에서 회의 URL을 확인할 수 있습니다: +캘린더 조회는 Meet 아티팩트를 읽기 전에 Google Calendar에서 회의 URL을 확인할 수 있습니다. ```bash openclaw googlemeet latest --today @@ -638,10 +660,10 @@ openclaw googlemeet artifacts --event "Weekly sync" openclaw googlemeet attendance --today --format csv --output attendance.csv ``` -`--today`는 오늘의 `primary` 캘린더에서 Google Meet 링크가 있는 Calendar 이벤트를 검색합니다. 일치하는 이벤트 텍스트를 검색하려면 `--event `를 사용하고, 기본 캘린더가 아닌 캘린더에는 `--calendar `를 사용하세요. Calendar 조회에는 Calendar 이벤트 읽기 전용 범위를 포함하는 새 OAuth 로그인이 필요합니다. -`calendar-events`는 일치하는 Meet 이벤트를 미리 보여주고 `latest`, `artifacts`, `attendance` 또는 `export`가 선택할 이벤트를 표시합니다. +`--today`는 오늘의 `primary` 캘린더에서 Google Meet 링크가 있는 Calendar 이벤트를 검색합니다. 일치하는 이벤트 텍스트를 검색하려면 `--event `를 사용하고, 기본 캘린더가 아닌 캘린더에는 `--calendar `를 사용하세요. 캘린더 조회에는 Calendar 이벤트 읽기 전용 범위를 포함하는 새로운 OAuth 로그인이 필요합니다. +`calendar-events`는 일치하는 Meet 이벤트를 미리 보여 주고 `latest`, `artifacts`, `attendance` 또는 `export`가 선택할 이벤트를 표시합니다. -회의 기록 ID를 이미 알고 있다면 직접 지정하세요: +이미 회의 기록 ID를 알고 있다면 직접 지정하세요. ```bash openclaw googlemeet latest --meeting https://meet.google.com/abc-defg-hij @@ -649,17 +671,17 @@ openclaw googlemeet artifacts --conference-record conferenceRecords/abc123 --jso openclaw googlemeet attendance --conference-record conferenceRecords/abc123 --json ``` -통화 후 회의실을 닫고 싶을 때 API로 생성된 스페이스의 활성 회의를 종료합니다: +통화 후 방을 닫고 싶을 때 API로 만든 공간의 활성 회의를 종료하세요. ```bash openclaw googlemeet end-active-conference https://meet.google.com/abc-defg-hij ``` -이는 Google Meet `spaces.endActiveConference`를 호출하며, 승인된 계정이 관리할 수 있는 스페이스에 대해 `meetings.space.created` 범위가 있는 OAuth가 필요합니다. -OpenClaw은 Meet URL, 회의 코드 또는 `spaces/{id}` 입력을 허용하고, 활성 회의를 종료하기 전에 이를 API 스페이스 리소스로 확인합니다. -이는 `googlemeet leave`와 별개입니다. `leave`는 OpenClaw의 로컬/세션 참여를 중지하는 반면, `end-active-conference`는 Google Meet에 해당 스페이스의 활성 회의를 종료하도록 요청합니다. +이는 Google Meet `spaces.endActiveConference`를 호출하며 승인된 계정이 관리할 수 있는 공간에 대해 `meetings.space.created` 범위가 포함된 OAuth가 필요합니다. +OpenClaw는 Meet URL, 회의 코드 또는 `spaces/{id}` 입력을 받아 활성 회의를 종료하기 전에 API 공간 리소스로 확인합니다. +이는 `googlemeet leave`와 별개입니다. `leave`는 OpenClaw의 로컬/세션 참여를 중지하는 반면, `end-active-conference`는 Google Meet에 해당 공간의 활성 회의를 종료하도록 요청합니다. -읽기 쉬운 보고서를 작성합니다: +읽기 쉬운 보고서를 작성하세요. ```bash openclaw googlemeet artifacts --conference-record conferenceRecords/abc123 \ @@ -674,13 +696,13 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ --include-doc-bodies --dry-run ``` -`artifacts`는 Google이 해당 회의에 대해 제공할 때 회의 기록 메타데이터와 참가자, 녹화, 스크립트, 구조화된 스크립트 항목, 스마트 노트 리소스 메타데이터를 반환합니다. 대규모 회의에서 항목 조회를 건너뛰려면 `--no-transcript-entries`를 사용하세요. `attendance`는 참가자를 참가자 세션 행으로 확장하며, 처음/마지막으로 확인된 시간, 총 세션 시간, 지각/조기 퇴장 플래그, 로그인 사용자 또는 표시 이름으로 병합된 중복 참가자 리소스를 포함합니다. 원시 참가자 리소스를 따로 유지하려면 `--no-merge-duplicates`를 전달하고, 지각 감지를 조정하려면 `--late-after-minutes`, 조기 퇴장 감지를 조정하려면 `--early-before-minutes`를 전달하세요. +Google이 회의에 대해 노출하는 경우 `artifacts`는 회의 기록 메타데이터와 참가자, 녹화, 스크립트, 구조화된 스크립트 항목, 스마트 노트 리소스 메타데이터를 반환합니다. 큰 회의에서 항목 조회를 건너뛰려면 `--no-transcript-entries`를 사용하세요. `attendance`는 참가자를 첫/마지막 확인 시간, 총 세션 지속 시간, 지각/조기 퇴장 플래그, 로그인한 사용자 또는 표시 이름으로 병합된 중복 참가자 리소스가 포함된 참가자 세션 행으로 확장합니다. 원시 참가자 리소스를 분리된 상태로 유지하려면 `--no-merge-duplicates`를, 지각 감지를 조정하려면 `--late-after-minutes`를, 조기 퇴장 감지를 조정하려면 `--early-before-minutes`를 전달하세요. -`export`는 `summary.md`, `attendance.csv`, `transcript.md`, `artifacts.json`, `attendance.json`, `manifest.json`을 포함하는 폴더를 작성합니다. -`manifest.json`은 선택된 입력, 내보내기 옵션, 회의 기록, 출력 파일, 개수, 토큰 소스, 사용된 경우 Calendar 이벤트, 부분 검색 경고를 기록합니다. 폴더 옆에 휴대 가능한 아카이브도 작성하려면 `--zip`을 전달하세요. 연결된 스크립트와 스마트 노트 Google Docs 텍스트를 Google Drive `files.export`를 통해 내보내려면 `--include-doc-bodies`를 전달하세요. 이를 위해서는 Drive Meet 읽기 전용 범위를 포함하는 새 OAuth 로그인이 필요합니다. `--include-doc-bodies`가 없으면 내보내기에는 Meet 메타데이터와 구조화된 스크립트 항목만 포함됩니다. Google이 스마트 노트 목록, 스크립트 항목 또는 Drive 문서 본문 오류처럼 부분 아티팩트 실패를 반환하면, 전체 내보내기를 실패시키는 대신 요약과 매니페스트에 경고가 유지됩니다. -폴더나 ZIP을 만들지 않고 동일한 아티팩트/참석 데이터를 가져와 매니페스트 JSON을 출력하려면 `--dry-run`을 사용하세요. 이는 대규모 내보내기를 작성하기 전이나 에이전트가 개수, 선택된 기록, 경고만 필요로 할 때 유용합니다. +`export`는 `summary.md`, `attendance.csv`, `transcript.md`, `artifacts.json`, `attendance.json`, `manifest.json`이 들어 있는 폴더를 작성합니다. +`manifest.json`은 선택한 입력, 내보내기 옵션, 회의 기록, 출력 파일, 개수, 토큰 소스, 사용된 경우 Calendar 이벤트, 부분 검색 경고를 기록합니다. 폴더 옆에 이식 가능한 아카이브도 작성하려면 `--zip`을 전달하세요. 연결된 스크립트 및 스마트 노트 Google Docs 텍스트를 Google Drive `files.export`를 통해 내보내려면 `--include-doc-bodies`를 전달하세요. 여기에는 Drive Meet 읽기 전용 범위를 포함하는 새로운 OAuth 로그인이 필요합니다. `--include-doc-bodies`가 없으면 내보내기에는 Meet 메타데이터와 구조화된 스크립트 항목만 포함됩니다. Google이 스마트 노트 목록, 스크립트 항목 또는 Drive 문서 본문 오류와 같은 부분 아티팩트 실패를 반환하면, 전체 내보내기를 실패시키지 않고 요약과 매니페스트에 경고를 유지합니다. +폴더나 ZIP을 만들지 않고 동일한 아티팩트/참석 데이터를 가져와 매니페스트 JSON을 출력하려면 `--dry-run`을 사용하세요. 큰 내보내기를 작성하기 전이나 에이전트에 개수, 선택된 기록, 경고만 필요할 때 유용합니다. -에이전트는 `google_meet` 도구를 통해 동일한 번들도 만들 수 있습니다: +에이전트는 `google_meet` 도구를 통해 동일한 번들도 만들 수 있습니다. ```json { @@ -692,20 +714,20 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -내보내기 매니페스트만 반환하고 파일 쓰기를 건너뛰려면 `"dryRun": true`를 설정하세요. +파일 쓰기를 건너뛰고 내보내기 매니페스트만 반환하려면 `"dryRun": true`를 설정하세요. -에이전트는 명시적 액세스 정책이 있는 API 기반 회의실도 만들 수 있습니다: +에이전트는 명시적 액세스 정책으로 API 기반 방도 만들 수 있습니다. ```json { "action": "create", "transport": "chrome-node", - "mode": "realtime", + "mode": "agent", "accessType": "OPEN" } ``` -그리고 알려진 회의실의 활성 회의를 종료할 수도 있습니다: +또한 알려진 방의 활성 회의를 종료할 수도 있습니다. ```json { @@ -714,7 +736,7 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -먼저 듣기 검증을 위해, 에이전트는 회의가 유용하다고 주장하기 전에 `test_listen`을 사용해야 합니다: +먼저 듣기 검증을 위해 에이전트는 회의가 유용하다고 주장하기 전에 `test_listen`을 사용해야 합니다. ```json { @@ -725,7 +747,7 @@ openclaw googlemeet export --conference-record conferenceRecords/abc123 \ } ``` -실제 보관된 회의를 대상으로 보호된 라이브 스모크를 실행합니다: +실제 보존된 회의에 대해 보호된 라이브 스모크를 실행하세요. ```bash OPENCLAW_LIVE_TEST=1 \ @@ -733,7 +755,7 @@ OPENCLAW_GOOGLE_MEET_LIVE_MEETING=https://meet.google.com/abc-defg-hij \ pnpm test:live -- extensions/google-meet/google-meet.live.test.ts ``` -누군가 말하고 Meet 캡션을 사용할 수 있는 회의를 대상으로 라이브 먼저 듣기 브라우저 프로브를 실행합니다: +누군가 말하고 Meet 자막을 사용할 수 있는 회의에 대해 라이브 먼저 듣기 브라우저 프로브를 실행하세요. ```bash openclaw googlemeet setup --transport chrome-node --mode transcribe @@ -743,31 +765,30 @@ openclaw googlemeet test-listen https://meet.google.com/abc-defg-hij --transport 라이브 스모크 환경: - `OPENCLAW_LIVE_TEST=1`은 보호된 라이브 테스트를 활성화합니다. -- `OPENCLAW_GOOGLE_MEET_LIVE_MEETING`은 보관된 Meet URL, 코드 또는 +- `OPENCLAW_GOOGLE_MEET_LIVE_MEETING`은 보존된 Meet URL, 코드 또는 `spaces/{id}`를 가리킵니다. - `OPENCLAW_GOOGLE_MEET_CLIENT_ID` 또는 `GOOGLE_MEET_CLIENT_ID`는 OAuth 클라이언트 ID를 제공합니다. - `OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN` 또는 `GOOGLE_MEET_REFRESH_TOKEN`은 - 리프레시 토큰을 제공합니다. + 새로고침 토큰을 제공합니다. - 선택 사항: `OPENCLAW_GOOGLE_MEET_CLIENT_SECRET`, - `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN`, 그리고 - `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT`은 `OPENCLAW_` 접두사 없는 - 동일한 폴백 이름을 사용합니다. + `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN`, 및 + `OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT`은 `OPENCLAW_` 접두사가 없는 동일한 대체 이름을 사용합니다. 기본 아티팩트/참석 라이브 스모크에는 `https://www.googleapis.com/auth/meetings.space.readonly` 및 -`https://www.googleapis.com/auth/meetings.conference.media.readonly`가 필요합니다. Calendar 조회에는 `https://www.googleapis.com/auth/calendar.events.readonly`가 필요합니다. Drive 문서 본문 내보내기에는 +`https://www.googleapis.com/auth/meetings.conference.media.readonly`가 필요합니다. 캘린더 조회에는 `https://www.googleapis.com/auth/calendar.events.readonly`가 필요합니다. Drive 문서 본문 내보내기에는 `https://www.googleapis.com/auth/drive.meet.readonly`가 필요합니다. -새 Meet 스페이스를 만듭니다: +새 Meet 공간을 만드세요. ```bash openclaw googlemeet create ``` -이 명령은 새 `meeting uri`, 소스, 참여 세션을 출력합니다. OAuth 자격 증명이 있으면 공식 Google Meet API를 사용합니다. OAuth 자격 증명이 없으면 고정된 Chrome Node의 로그인된 브라우저 프로필을 폴백으로 사용합니다. 에이전트는 한 단계에서 생성하고 참여하기 위해 `action: "create"`와 함께 `google_meet` 도구를 사용할 수 있습니다. URL만 생성하려면 `"join": false`를 전달하세요. +이 명령은 새 `meeting uri`, 소스, 참여 세션을 출력합니다. OAuth 자격 증명이 있으면 공식 Google Meet API를 사용합니다. OAuth 자격 증명이 없으면 고정된 Chrome Node의 로그인된 브라우저 프로필을 대체 수단으로 사용합니다. 에이전트는 `action: "create"`와 함께 `google_meet` 도구를 사용하여 한 단계로 만들고 참여할 수 있습니다. URL만 만들려면 `"join": false`를 전달하세요. -브라우저 폴백의 예시 JSON 출력: +브라우저 대체 모드의 예시 JSON 출력: ```json { @@ -787,7 +808,7 @@ openclaw googlemeet create } ``` -브라우저 폴백이 URL을 만들기 전에 Google 로그인 또는 Meet 권한 차단에 걸리면, Gateway 메서드는 실패 응답을 반환하고 `google_meet` 도구는 일반 문자열 대신 구조화된 세부 정보를 반환합니다: +브라우저 대체 모드가 URL을 만들기 전에 Google 로그인 또는 Meet 권한 차단에 걸리면 Gateway 메서드는 실패한 응답을 반환하고 `google_meet` 도구는 일반 문자열 대신 구조화된 세부 정보를 반환합니다. ```json { @@ -805,9 +826,9 @@ openclaw googlemeet create } ``` -에이전트가 `manualActionRequired: true`를 보면, `manualActionMessage`와 브라우저 Node/탭 컨텍스트를 보고하고 운영자가 브라우저 단계를 완료할 때까지 새 Meet 탭을 열지 않아야 합니다. +에이전트가 `manualActionRequired: true`를 보면 `manualActionMessage`와 브라우저 Node/탭 컨텍스트를 보고하고, 운영자가 브라우저 단계를 완료할 때까지 새 Meet 탭을 열지 않아야 합니다. -API 생성의 예시 JSON 출력: +API 만들기의 예시 JSON 출력: ```json { @@ -828,13 +849,23 @@ API 생성의 예시 JSON 출력: } ``` -Meet 생성은 기본적으로 참여까지 수행합니다. Chrome 또는 Chrome-node 전송은 브라우저를 통해 참여하려면 여전히 로그인된 Google Chrome 프로필이 필요합니다. 프로필이 로그아웃되어 있으면 OpenClaw는 `manualActionRequired: true` 또는 브라우저 폴백 오류를 보고하고 다시 시도하기 전에 운영자에게 Google 로그인을 완료하라고 요청합니다. +Meet를 만들면 기본적으로 참여합니다. Chrome 또는 Chrome-node 전송 방식은 +브라우저를 통해 참여하기 위해 로그인된 Google Chrome 프로필이 여전히 +필요합니다. 프로필이 로그아웃되어 있으면 OpenClaw는 +`manualActionRequired: true` 또는 브라우저 폴백 오류를 보고하고, 재시도하기 +전에 운영자가 Google 로그인을 완료하도록 요청합니다. -Cloud 프로젝트, OAuth 주체, 회의 참가자가 Meet 미디어 API용 Google Workspace Developer Preview Program에 등록되어 있음을 확인한 뒤에만 `preview.enrollmentAcknowledged: true`를 설정하세요. +Cloud 프로젝트, OAuth 주체, 회의 참가자가 Meet 미디어 API용 Google +Workspace Developer Preview Program에 등록되어 있음을 확인한 후에만 +`preview.enrollmentAcknowledged: true`를 설정하세요. ## 구성 -일반 Chrome 에이전트 경로에는 Plugin 활성화, BlackHole, SoX, 실시간 스크립트 제공자 키, 구성된 OpenClaw TTS 제공자만 필요합니다. OpenAI는 기본 스크립트 제공자입니다. `bidi` 모드에서 Google Gemini Live를 사용하려면 `realtime.provider: "google"`을 설정하세요: +공통 Chrome 에이전트 경로에는 Plugin 활성화, BlackHole, SoX, 실시간 전사 +제공자 키, 구성된 OpenClaw TTS 제공자만 필요합니다. OpenAI가 기본 전사 +제공자입니다. 기본 에이전트 모드 전사 제공자를 변경하지 않고 `bidi` +모드에서 Google Gemini Live를 사용하려면 `realtime.voiceProvider`를 +`"google"`로, `realtime.model`을 설정하세요. ```bash brew install blackhole-2ch sox @@ -843,7 +874,7 @@ export OPENAI_API_KEY=sk-... export GEMINI_API_KEY=... ``` -Plugin 구성을 `plugins.entries.google-meet.config` 아래에 설정합니다. +Plugin 구성을 `plugins.entries.google-meet.config` 아래에 설정하세요. ```json5 { @@ -861,28 +892,61 @@ Plugin 구성을 `plugins.entries.google-meet.config` 아래에 설정합니다. 기본값: - `defaultTransport: "chrome"` -- `defaultMode: "agent"` (`"realtime"`은 `"agent"`의 호환성 별칭으로 허용됨) +- `defaultMode: "agent"`(`"realtime"`은 `"agent"`의 레거시 호환 별칭으로만 + 허용됩니다. 새 도구 호출에서는 `"agent"`를 사용해야 합니다.) - `chromeNode.node`: `chrome-node`의 선택적 노드 ID/이름/IP - `chrome.audioBackend: "blackhole-2ch"` -- `chrome.guestName: "OpenClaw Agent"`: 로그아웃된 Meet 게스트 화면에서 사용하는 이름 -- `chrome.autoJoin: true`: `chrome-node`에서 OpenClaw 브라우저 자동화를 통해 게스트 이름 입력과 Join Now 클릭을 최선으로 시도 -- `chrome.reuseExistingTab: true`: 중복 탭을 열지 않고 기존 Meet 탭 활성화 -- `chrome.waitForInCallMs: 20000`: 실시간 인트로가 트리거되기 전에 Meet 탭이 통화 중이라고 보고할 때까지 대기 -- `chrome.audioFormat: "pcm16-24khz"`: 명령 쌍 오디오 형식. 여전히 전화 통신 오디오를 내보내는 레거시/사용자 지정 명령 쌍에만 `"g711-ulaw-8khz"`를 사용하세요. -- `chrome.audioInputCommand`: CoreAudio `BlackHole 2ch`에서 읽고 `chrome.audioFormat`의 오디오를 쓰는 SoX 명령 -- `chrome.audioOutputCommand`: `chrome.audioFormat`의 오디오를 읽고 CoreAudio `BlackHole 2ch`에 쓰는 SoX 명령 -- `chrome.bargeInInputCommand`: 어시스턴트 재생이 활성화된 동안 사람의 끼어들기 감지를 위해 부호 있는 16비트 리틀 엔디언 모노 PCM을 쓰는 선택적 로컬 마이크 명령입니다. 현재 Gateway에서 호스팅되는 `chrome` 명령 쌍 브리지에 적용됩니다. -- `chrome.bargeInRmsThreshold: 650`: `chrome.bargeInInputCommand`에서 사람의 중단으로 간주되는 RMS 레벨 -- `chrome.bargeInPeakThreshold: 2500`: `chrome.bargeInInputCommand`에서 사람의 중단으로 간주되는 피크 레벨 -- `chrome.bargeInCooldownMs: 900`: 반복되는 사람 중단 해제 사이의 최소 지연 시간 -- `mode: "agent"`: 기본 응답 모드. 참가자 발화는 구성된 실시간 전사 제공자가 전사하고, 회의별 하위 에이전트 세션에서 구성된 OpenClaw 에이전트로 전송되며, 일반 OpenClaw TTS 런타임을 통해 다시 말해집니다. -- `mode: "bidi"`: 대체 직접 양방향 실시간 모델 모드. 실시간 음성 제공자가 참가자 발화에 직접 응답하며, 더 깊거나 도구 기반 답변을 위해 `openclaw_agent_consult`를 호출할 수 있습니다. -- `mode: "transcribe"`: 응답 브리지 없는 관찰 전용 모드. -- `realtime.provider: "openai"`: `agent` 모드에서 실시간 전사에, `bidi` 모드에서 실시간 음성에 사용하는 제공자 ID. +- `chrome.guestName: "OpenClaw Agent"`: 로그아웃된 Meet 게스트 화면에서 + 사용하는 이름 +- `chrome.autoJoin: true`: `chrome-node`의 OpenClaw 브라우저 자동화를 통해 + 최선 노력 방식으로 게스트 이름을 입력하고 지금 참여를 클릭합니다. +- `chrome.reuseExistingTab: true`: 중복 탭을 여는 대신 기존 Meet 탭을 + 활성화합니다. +- `chrome.waitForInCallMs: 20000`: 응답 소개가 트리거되기 전에 Meet 탭이 + 통화 중임을 보고할 때까지 기다립니다. +- `chrome.audioFormat: "pcm16-24khz"`: 명령 쌍 오디오 형식입니다. 아직 전화 + 오디오를 내보내는 레거시/사용자 지정 명령 쌍에만 `"g711-ulaw-8khz"`를 + 사용하세요. +- `chrome.audioBufferBytes: 4096`: 생성된 Chrome 명령 쌍 오디오 명령의 SoX + 처리 버퍼입니다. 이는 SoX 기본 8192바이트 버퍼의 절반으로, 기본 파이프 + 지연 시간을 줄이면서 바쁜 호스트에서 값을 높일 여지를 남깁니다. SoX + 최솟값보다 낮은 값은 17바이트로 제한됩니다. +- `chrome.audioInputCommand`: CoreAudio `BlackHole 2ch`에서 읽고 + `chrome.audioFormat`으로 오디오를 쓰는 SoX 명령 +- `chrome.audioOutputCommand`: `chrome.audioFormat`의 오디오를 읽고 CoreAudio + `BlackHole 2ch`에 쓰는 SoX 명령 +- `chrome.bargeInInputCommand`: 어시스턴트 재생이 활성 상태일 때 사람의 + 끼어들기 감지를 위해 부호 있는 16비트 리틀 엔디언 모노 PCM을 쓰는 + 선택적 로컬 마이크 명령입니다. 현재 이는 Gateway 호스팅 `chrome` 명령 + 쌍 브리지에 적용됩니다. +- `chrome.bargeInRmsThreshold: 650`: `chrome.bargeInInputCommand`에서 사람의 + 끼어들기로 간주되는 RMS 수준 +- `chrome.bargeInPeakThreshold: 2500`: `chrome.bargeInInputCommand`에서 + 사람의 끼어들기로 간주되는 피크 수준 +- `chrome.bargeInCooldownMs: 900`: 반복되는 사람 끼어들기 해제 사이의 최소 + 지연 시간 +- `mode: "agent"`: 기본 응답 모드입니다. 참가자 음성은 구성된 실시간 전사 + 제공자가 전사하고, 회의별 하위 에이전트 세션의 구성된 OpenClaw + 에이전트로 전송되며, 일반 OpenClaw TTS 런타임을 통해 음성으로 + 출력됩니다. +- `mode: "bidi"`: 폴백 직접 양방향 실시간 모델 모드입니다. 실시간 음성 + 제공자가 참가자 음성에 직접 응답하며, 더 깊거나 도구 기반인 답변을 위해 + `openclaw_agent_consult`를 호출할 수 있습니다. +- `mode: "transcribe"`: 응답 브리지 없는 관찰 전용 모드입니다. +- `realtime.provider: "openai"`: 아래의 범위 지정 제공자 필드가 설정되지 + 않았을 때 사용되는 호환성 폴백입니다. +- `realtime.transcriptionProvider: "openai"`: `agent` 모드가 실시간 전사에 + 사용하는 제공자 ID입니다. +- `realtime.voiceProvider`: `bidi` 모드가 직접 실시간 음성에 사용하는 제공자 + ID입니다. 에이전트 모드 전사는 OpenAI로 유지하면서 Gemini Live를 + 사용하려면 이를 `"google"`로 설정하세요. - `realtime.toolPolicy: "safe-read-only"` -- `realtime.instructions`: 더 깊은 답변에는 `openclaw_agent_consult`를 사용하는 짧은 음성 답변 -- `realtime.introMessage`: 실시간 브리지가 연결될 때의 짧은 음성 준비 확인 메시지. 조용히 참여하려면 `""`로 설정하세요. -- `realtime.agentId`: `openclaw_agent_consult`에 사용할 선택적 OpenClaw 에이전트 ID. 기본값은 `main` +- `realtime.instructions`: 더 깊은 답변에는 `openclaw_agent_consult`를 + 사용하는 짧은 음성 응답 +- `realtime.introMessage`: 실시간 브리지가 연결될 때의 짧은 음성 준비 확인 + 메시지입니다. 조용히 참여하려면 `""`로 설정하세요. +- `realtime.agentId`: `openclaw_agent_consult`용 선택적 OpenClaw 에이전트 + ID입니다. 기본값은 `main`입니다. 선택적 재정의: @@ -921,13 +985,15 @@ Plugin 구성을 `plugins.entries.google-meet.config` 아래에 설정합니다. }, defaultMode: "agent", realtime: { - provider: "google", + provider: "openai", + transcriptionProvider: "openai", + voiceProvider: "google", + model: "gemini-2.5-flash-native-audio-preview-12-2025", agentId: "jay", toolPolicy: "owner", introMessage: "Say exactly: I'm here.", providers: { google: { - model: "gemini-2.5-flash-native-audio-preview-12-2025", voice: "Kore", }, }, @@ -935,6 +1001,50 @@ Plugin 구성을 `plugins.entries.google-meet.config` 아래에 설정합니다. } ``` +에이전트 모드 듣기와 말하기 모두에 ElevenLabs 사용: + +```json5 +{ + messages: { + tts: { + provider: "elevenlabs", + providers: { + elevenlabs: { + modelId: "eleven_v3", + voiceId: "pMsXgVXv3BLzUgSXRplE", + }, + }, + }, + }, + plugins: { + entries: { + "google-meet": { + config: { + realtime: { + transcriptionProvider: "elevenlabs", + providers: { + elevenlabs: { + modelId: "scribe_v2_realtime", + audioFormat: "ulaw_8000", + sampleRate: 8000, + commitStrategy: "vad", + }, + }, + }, + }, + }, + }, + }, +} +``` + +지속되는 Meet 음성은 `messages.tts.providers.elevenlabs.voiceId`에서 옵니다. +TTS 모델 재정의가 활성화된 경우 에이전트 응답은 응답별 +`[[tts:voiceId=... model=eleven_v3]]` 지시문도 사용할 수 있지만, 회의의 +결정적 기본값은 구성입니다. 참여 시 로그에는 +`transcriptionProvider=elevenlabs`가 표시되어야 하며, 각 음성 응답은 +`provider=elevenlabs model=eleven_v3 voice=`를 기록해야 합니다. + Twilio 전용 구성: ```json5 @@ -950,7 +1060,12 @@ Twilio 전용 구성: } ``` -`voiceCall.enabled`의 기본값은 `true`입니다. Twilio 전송을 사용할 때 실제 PSTN 통화, DTMF, 인트로 인사는 Voice Call Plugin에 위임합니다. Voice Call은 실시간 미디어 스트림을 열기 전에 DTMF 시퀀스를 재생한 다음, 저장된 인트로 텍스트를 초기 실시간 인사로 사용합니다. `voice-call`이 활성화되어 있지 않으면 Google Meet은 여전히 다이얼 플랜을 검증하고 기록할 수 있지만 Twilio 통화를 걸 수는 없습니다. +`voiceCall.enabled`의 기본값은 `true`입니다. Twilio 전송 방식을 사용하면 +실제 PSTN 통화, DTMF, 소개 인사말을 Voice Call Plugin에 위임합니다. Voice +Call은 실시간 미디어 스트림을 열기 전에 DTMF 시퀀스를 재생한 다음, 저장된 +소개 텍스트를 초기 실시간 인사말로 사용합니다. `voice-call`이 활성화되어 +있지 않으면 Google Meet은 여전히 다이얼 플랜을 검증하고 기록할 수 있지만 +Twilio 통화를 걸 수는 없습니다. ## 도구 @@ -965,20 +1080,48 @@ Twilio 전용 구성: } ``` -Chrome이 Gateway 호스트에서 실행될 때는 `transport: "chrome"`을 사용하세요. Chrome이 Parallels VM 같은 페어링된 노드에서 실행될 때는 `transport: "chrome-node"`를 사용하세요. 두 경우 모두 모델 제공자와 `openclaw_agent_consult`는 Gateway 호스트에서 실행되므로 모델 자격 증명은 그곳에 유지됩니다. 기본 `mode: "agent"`에서는 실시간 전사 제공자가 청취를 처리하고, 구성된 OpenClaw 에이전트가 답변을 생성하며, 일반 OpenClaw TTS가 이를 Meet에 말합니다. 실시간 음성 모델이 직접 답변하게 하려면 `mode: "bidi"`를 사용하세요. `mode: "realtime"`은 `mode: "agent"`의 호환성 별칭으로 계속 허용됩니다. +Chrome이 Gateway 호스트에서 실행될 때는 `transport: "chrome"`을 +사용하세요. Chrome이 Parallels VM 같은 페어링된 노드에서 실행될 때는 +`transport: "chrome-node"`를 사용하세요. 두 경우 모두 모델 제공자와 +`openclaw_agent_consult`는 Gateway 호스트에서 실행되므로 모델 자격 증명은 +그곳에 유지됩니다. 기본 `mode: "agent"`에서는 실시간 전사 제공자가 듣기를 +처리하고, 구성된 OpenClaw 에이전트가 답변을 생성하며, 일반 OpenClaw TTS가 +이를 Meet에 말합니다. 실시간 음성 모델이 직접 답변하도록 하려면 +`mode: "bidi"`를 사용하세요. 원시 `mode: "realtime"`은 `mode: "agent"`의 +레거시 호환 별칭으로 계속 허용되지만, 더 이상 에이전트 도구 스키마에 +노출되지 않습니다. 에이전트 모드 로그에는 브리지 시작 시 확인된 전사 +제공자/모델과, 각 합성 응답 후 TTS 제공자, 모델, 음성, 출력 형식, 샘플 +레이트가 포함됩니다. -활성 세션을 나열하거나 세션 ID를 검사하려면 `action: "status"`를 사용하세요. 실시간 에이전트가 즉시 말하게 하려면 `sessionId`와 `message`와 함께 `action: "speak"`를 사용하세요. 세션을 만들거나 재사용하고, 알려진 문구를 트리거하며, Chrome 호스트가 보고할 수 있을 때 `inCall` 상태를 반환하려면 `action: "test_speech"`를 사용하세요. `test_speech`는 항상 `mode: "agent"`를 강제하며, 관찰 전용 세션은 의도적으로 음성을 내보낼 수 없으므로 `mode: "transcribe"`에서 실행하도록 요청받으면 실패합니다. `speechOutputVerified` 결과는 이 테스트 호출 중 실시간 오디오 출력 바이트가 증가했는지를 기반으로 하므로, 오래된 오디오가 있는 재사용 세션은 새롭게 성공한 음성 확인으로 간주되지 않습니다. 세션이 종료된 것으로 표시하려면 `action: "leave"`를 사용하세요. +활성 세션을 나열하거나 세션 ID를 검사하려면 `action: "status"`를 +사용하세요. 실시간 에이전트가 즉시 말하도록 하려면 `sessionId` 및 +`message`와 함께 `action: "speak"`를 사용하세요. 세션을 생성하거나 +재사용하고, 알려진 문구를 트리거하며, Chrome 호스트가 보고할 수 있을 때 +`inCall` 상태를 반환하려면 `action: "test_speech"`를 사용하세요. +`test_speech`는 항상 `mode: "agent"`를 강제하며, 관찰 전용 세션은 의도적으로 +음성을 내보낼 수 없으므로 `mode: "transcribe"`로 실행하라고 요청하면 +실패합니다. `speechOutputVerified` 결과는 이 테스트 호출 중 실시간 오디오 +출력 바이트가 증가했는지를 기준으로 하므로, 이전 오디오가 있는 재사용된 +세션은 새로운 성공적 음성 확인으로 간주되지 않습니다. 세션을 종료됨으로 +표시하려면 `action: "leave"`를 사용하세요. -`status`에는 사용 가능할 때 Chrome 상태가 포함됩니다. +`status`에는 사용 가능한 경우 Chrome 상태가 포함됩니다. -- `inCall`: Chrome이 Meet 통화 안에 있는 것으로 보임 -- `micMuted`: 최선으로 파악한 Meet 마이크 상태 -- `manualActionRequired` / `manualActionReason` / `manualActionMessage`: 음성이 작동하기 전에 브라우저 프로필에 수동 로그인, Meet 호스트 승인, 권한, 또는 브라우저 제어 복구가 필요함 -- `speechReady` / `speechBlockedReason` / `speechBlockedMessage`: 관리형 Chrome 음성이 현재 허용되는지 여부. `speechReady: false`는 OpenClaw가 인트로/테스트 문구를 오디오 브리지로 보내지 않았음을 의미합니다. +- `inCall`: Chrome이 Meet 통화 안에 있는 것으로 보입니다. +- `micMuted`: 최선 노력 방식의 Meet 마이크 상태 +- `manualActionRequired` / `manualActionReason` / `manualActionMessage`: + 음성이 작동하기 전에 브라우저 프로필에 수동 로그인, Meet 호스트 승인, + 권한 또는 브라우저 제어 복구가 필요합니다. +- `speechReady` / `speechBlockedReason` / `speechBlockedMessage`: 관리형 + Chrome 음성이 지금 허용되는지 여부입니다. `speechReady: false`는 + OpenClaw가 소개/테스트 문구를 오디오 브리지로 보내지 않았음을 의미합니다. - `providerConnected` / `realtimeReady`: 실시간 음성 브리지 상태 -- `lastInputAt` / `lastOutputAt`: 브리지에서 마지막으로 보았거나 브리지로 보낸 오디오 -- `audioOutputRouted` / `audioOutputDeviceLabel`: Meet 탭의 미디어 출력이 브리지에서 사용하는 BlackHole 장치로 능동적으로 라우팅되었는지 여부 -- `lastSuppressedInputAt` / `suppressedInputBytes`: 어시스턴트 재생이 활성화된 동안 무시된 local loopback 입력 +- `lastInputAt` / `lastOutputAt`: 브리지에서 마지막으로 확인되었거나 + 브리지로 전송된 오디오 +- `audioOutputRouted` / `audioOutputDeviceLabel`: Meet 탭의 미디어 출력이 + 브리지에서 사용하는 BlackHole 장치로 능동적으로 라우팅되었는지 여부 +- `lastSuppressedInputAt` / `suppressedInputBytes`: 어시스턴트 재생이 활성 + 상태일 때 무시된 루프백 입력 ```json { @@ -990,38 +1133,46 @@ Chrome이 Gateway 호스트에서 실행될 때는 `transport: "chrome"`을 사 ## 에이전트 및 Bidi 모드 -Chrome `agent` 모드는 “내 에이전트가 회의에 들어와 있는” 동작에 최적화되어 있습니다. 실시간 전사 제공자가 회의 오디오를 듣고, 최종 참가자 전사문은 구성된 OpenClaw 에이전트를 통해 라우팅되며, 답변은 일반 OpenClaw TTS 런타임을 통해 말해집니다. 실시간 음성 모델이 직접 답변하게 하려면 `mode: "bidi"`를 설정하세요. -가까운 최종 전사 조각은 상담 전에 병합되어 하나의 발화 차례가 여러 개의 오래된 부분 답변을 만들지 않도록 합니다. 또한 큐에 있는 어시스턴트 오디오가 아직 재생 중이면 실시간 입력이 억제되며, -최근의 어시스턴트와 유사한 전사 에코는 에이전트 상담 전에 무시되어 BlackHole local loopback이 에이전트가 자기 음성에 답하게 만들지 않도록 합니다. +Chrome `agent` 모드는 "내 에이전트가 회의에 있음" 동작에 최적화되어 +있습니다. 실시간 전사 제공자가 회의 오디오를 듣고, 최종 참가자 전사는 +구성된 OpenClaw 에이전트로 라우팅되며, 답변은 일반 OpenClaw TTS 런타임을 +통해 음성으로 출력됩니다. 실시간 음성 모델이 직접 답변하도록 하려면 +`mode: "bidi"`를 설정하세요. 가까운 최종 전사 조각은 consult 전에 병합되어 +하나의 발화 차례가 여러 개의 오래된 부분 답변을 만들지 않도록 합니다. 또한 +대기 중인 어시스턴트 오디오가 아직 재생되는 동안에는 실시간 입력이 +억제되며, 최근 어시스턴트와 유사한 전사 에코는 에이전트 consult 전에 +무시되어 BlackHole 루프백으로 인해 에이전트가 자신의 말에 답변하지 않도록 +합니다. -| 모드 | 답변 결정 주체 | 음성 출력 경로 | 사용 시점 | +| 모드 | 답변을 결정하는 주체 | 음성 출력 경로 | 사용할 때 | | ------- | ----------------------------- | -------------------------------------- | ----------------------------------------------------- | -| `agent` | 구성된 OpenClaw 에이전트 | 일반 OpenClaw TTS 런타임 | “내 에이전트가 회의에 들어와 있는” 동작을 원할 때 | -| `bidi` | 실시간 음성 모델 | 실시간 음성 제공자 오디오 응답 | 지연 시간이 가장 낮은 대화형 음성 루프를 원할 때 | +| `agent` | 구성된 OpenClaw 에이전트 | 일반 OpenClaw TTS 런타임 | "내 에이전트가 회의에 있음" 동작을 원할 때 | +| `bidi` | 실시간 음성 모델 | 실시간 음성 제공자 오디오 응답 | 가장 낮은 지연 시간의 대화형 음성 루프를 원할 때 | -`bidi` 모드에서 실시간 모델이 더 깊은 추론, 최신 정보, 또는 일반 OpenClaw 도구가 필요하면 `openclaw_agent_consult`를 호출할 수 있습니다. +`bidi` 모드에서 실시간 모델에 더 깊은 추론, 최신 정보 또는 일반 OpenClaw +도구가 필요하면 `openclaw_agent_consult`를 호출할 수 있습니다. -상담 도구는 최근 회의 전사 컨텍스트와 함께 일반 OpenClaw 에이전트를 뒤에서 실행하고 간결한 음성 답변을 반환합니다. `agent` 모드에서는 OpenClaw가 해당 답변을 TTS 런타임으로 직접 보냅니다. `bidi` 모드에서는 실시간 음성 모델이 상담 결과를 회의에 다시 말할 수 있습니다. 이는 Voice Call과 동일한 공유 상담 메커니즘을 사용합니다. +consult 도구는 백그라운드에서 최근 회의 대화록 컨텍스트와 함께 일반 OpenClaw 에이전트를 실행하고 간결한 음성 답변을 반환합니다. `agent` 모드에서는 OpenClaw가 그 답변을 TTS 런타임으로 직접 보내며, `bidi` 모드에서는 실시간 음성 모델이 consult 결과를 회의에 다시 말할 수 있습니다. 이는 Voice Call과 동일한 공유 consult 메커니즘을 사용합니다. -기본적으로 상담은 `main` 에이전트를 대상으로 실행됩니다. Meet 레인이 전용 OpenClaw 에이전트 작업 공간, 모델 기본값, 도구 정책, 메모리, 세션 기록을 상담해야 할 때는 `realtime.agentId`를 설정하세요. +기본적으로 consult는 `main` 에이전트에서 실행됩니다. Meet 레인이 전용 OpenClaw 에이전트 워크스페이스, 모델 기본값, 도구 정책, 메모리, 세션 기록을 consult해야 하는 경우 `realtime.agentId`를 설정하세요. -에이전트 모드 상담은 회의별 `agent::subagent:google-meet:` 세션 키를 사용하므로 후속 질문은 구성된 에이전트의 일반 에이전트 정책을 상속하면서 회의 컨텍스트를 유지합니다. +에이전트 모드 consult는 회의별 `agent::subagent:google-meet:` 세션 키를 사용하므로 후속 질문은 구성된 에이전트의 일반 에이전트 정책을 상속하면서 회의 컨텍스트를 유지합니다. -`realtime.toolPolicy`는 상담 실행을 제어합니다. +`realtime.toolPolicy`는 consult 실행을 제어합니다. -- `safe-read-only`: 상담 도구를 노출하고 일반 에이전트를 `read`, `web_search`, `web_fetch`, `x_search`, `memory_search`, `memory_get`으로 제한합니다. -- `owner`: 상담 도구를 노출하고 일반 에이전트가 일반 에이전트 도구 정책을 사용하게 합니다. -- `none`: 실시간 음성 모델에 상담 도구를 노출하지 않습니다. +- `safe-read-only`: consult 도구를 노출하고 일반 에이전트를 `read`, `web_search`, `web_fetch`, `x_search`, `memory_search`, `memory_get`으로 제한합니다. +- `owner`: consult 도구를 노출하고 일반 에이전트가 일반 에이전트 도구 정책을 사용하도록 허용합니다. +- `none`: 실시간 음성 모델에 consult 도구를 노출하지 않습니다. -상담 세션 키는 Meet 세션별로 범위가 지정되므로, 후속 상담 호출은 같은 회의 중 이전 상담 컨텍스트를 재사용할 수 있습니다. +consult 세션 키는 Meet 세션별로 범위가 지정되므로 후속 consult 호출은 같은 회의 중 이전 consult 컨텍스트를 재사용할 수 있습니다. -Chrome이 통화에 완전히 참여한 뒤 음성 준비 확인을 강제하려면: +Chrome이 통화에 완전히 참가한 후 음성 준비 상태 확인을 강제하려면: ```bash openclaw googlemeet speak meet_... "Say exactly: I'm here and listening." ``` -전체 참여 및 말하기 스모크 테스트: +전체 참가 및 말하기 스모크 테스트는 다음과 같습니다. ```bash openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ @@ -1031,7 +1182,7 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ ## 라이브 테스트 체크리스트 -회의를 무인 에이전트에 넘기기 전에 이 순서를 사용하세요. +무인 에이전트에 회의를 넘기기 전에 이 순서를 사용하세요. ```bash openclaw googlemeet setup @@ -1044,12 +1195,12 @@ openclaw googlemeet test-speech https://meet.google.com/abc-defg-hij \ 예상 Chrome-node 상태: - `googlemeet setup`이 모두 초록색입니다. -- Chrome-node가 기본 전송이거나 노드가 고정된 경우 `googlemeet setup`에 `chrome-node-connected`가 포함됩니다. +- Chrome-node가 기본 전송 방식이거나 노드가 고정된 경우 `googlemeet setup`에 `chrome-node-connected`가 포함됩니다. - `nodes status`에 선택한 노드가 연결된 것으로 표시됩니다. -- 선택한 노드는 `googlemeet.chrome`과 `browser.proxy`를 모두 알립니다. -- Meet 탭이 통화에 참여하고 `test-speech`가 `inCall: true`가 포함된 Chrome 상태를 반환합니다. +- 선택한 노드가 `googlemeet.chrome`과 `browser.proxy`를 모두 알립니다. +- Meet 탭이 통화에 참가하고 `test-speech`가 `inCall: true`와 함께 Chrome 상태를 반환합니다. -Parallels macOS VM 같은 원격 Chrome 호스트의 경우, Gateway 또는 VM을 업데이트한 뒤 가장 짧고 안전한 확인은 다음과 같습니다. +Parallels macOS VM 같은 원격 Chrome 호스트의 경우, Gateway 또는 VM을 업데이트한 뒤 다음이 가장 짧은 안전 확인입니다. ```bash openclaw googlemeet setup @@ -1062,7 +1213,7 @@ openclaw nodes invoke \ 이는 에이전트가 실제 회의 탭을 열기 전에 Gateway Plugin이 로드되었고, VM 노드가 현재 토큰으로 연결되었으며, Meet 오디오 브리지를 사용할 수 있음을 증명합니다. -Twilio 스모크 테스트에는 전화 접속 세부 정보를 노출하는 회의를 사용하세요. +Twilio 스모크 테스트에는 전화 다이얼인 세부 정보를 노출하는 회의를 사용하세요. ```bash openclaw googlemeet setup @@ -1074,30 +1225,30 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ 예상 Twilio 상태: -- `googlemeet setup`에는 녹색 `twilio-voice-call-plugin`, `twilio-voice-call-credentials`, `twilio-voice-call-webhook` 검사가 포함됩니다. -- `voicecall`은 Gateway reload 후 CLI에서 사용할 수 있습니다. -- 반환된 session에는 `transport: "twilio"` 및 `twilio.voiceCallId`가 있습니다. -- `openclaw logs --follow`는 realtime TwiML 전에 DTMF TwiML이 제공된 다음, 초기 인사말이 대기열에 추가된 realtime bridge를 표시합니다. -- `googlemeet leave `는 위임된 voice call을 끊습니다. +- `googlemeet setup`에 초록색 `twilio-voice-call-plugin`, `twilio-voice-call-credentials`, `twilio-voice-call-webhook` 확인이 포함됩니다. +- Gateway 다시 로드 후 CLI에서 `voicecall`을 사용할 수 있습니다. +- 반환된 세션에 `transport: "twilio"`와 `twilio.voiceCallId`가 있습니다. +- `openclaw logs --follow`에 실시간 TwiML 전에 DTMF TwiML이 제공된 뒤, 초기 인사말이 대기열에 들어간 실시간 브리지가 표시됩니다. +- `googlemeet leave `가 위임된 음성 통화를 끊습니다. ## 문제 해결 -### Agent가 Google Meet 도구를 볼 수 없음 +### 에이전트가 Google Meet 도구를 볼 수 없음 -Gateway config에서 Plugin이 활성화되어 있는지 확인하고 Gateway를 reload하세요. +Gateway 구성에서 Plugin이 활성화되었는지 확인하고 Gateway를 다시 로드하세요. ```bash openclaw plugins list | grep google-meet openclaw googlemeet setup ``` -방금 `plugins.entries.google-meet`를 편집했다면 Gateway를 다시 시작하거나 reload하세요. 실행 중인 agent는 현재 Gateway process가 등록한 Plugin 도구만 볼 수 있습니다. +방금 `plugins.entries.google-meet`를 편집했다면 Gateway를 다시 시작하거나 다시 로드하세요. 실행 중인 에이전트는 현재 Gateway 프로세스가 등록한 Plugin 도구만 볼 수 있습니다. -macOS가 아닌 Gateway host에서는 agent-facing `google_meet` 도구가 계속 표시되지만, local Chrome talk-back 작업은 audio bridge에 도달하기 전에 차단됩니다. Local Chrome talk-back audio는 현재 macOS `BlackHole 2ch`에 의존하므로 Linux agent는 기본 local Chrome agent 경로 대신 `mode: "transcribe"`, Twilio dial-in 또는 macOS `chrome-node` host를 사용해야 합니다. +macOS가 아닌 Gateway 호스트에서는 에이전트용 `google_meet` 도구가 계속 표시되지만, 로컬 Chrome talk-back 작업은 오디오 브리지에 도달하기 전에 차단됩니다. 로컬 Chrome talk-back 오디오는 현재 macOS `BlackHole 2ch`에 의존하므로 Linux 에이전트는 기본 로컬 Chrome 에이전트 경로 대신 `mode: "transcribe"`, Twilio 다이얼인 또는 macOS `chrome-node` 호스트를 사용해야 합니다. -### 연결된 Google Meet 지원 node가 없음 +### 연결된 Google Meet 지원 노드 없음 -node host에서 다음을 실행하세요. +노드 호스트에서 실행하세요. ```bash openclaw plugins enable google-meet @@ -1106,7 +1257,7 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ openclaw node run --host --port 18789 --display-name parallels-macos ``` -Gateway host에서 node를 승인하고 명령을 확인하세요. +Gateway 호스트에서 노드를 승인하고 명령을 확인하세요. ```bash openclaw devices list @@ -1114,7 +1265,7 @@ openclaw devices approve openclaw nodes status ``` -node가 연결되어 있어야 하며 `googlemeet.chrome`와 `browser.proxy`가 나열되어야 합니다. Gateway config는 해당 node 명령을 허용해야 합니다. +노드는 연결되어 있어야 하며 `googlemeet.chrome` 및 `browser.proxy`를 나열해야 합니다. Gateway 구성은 해당 노드 명령을 허용해야 합니다. ```json5 { @@ -1126,7 +1277,7 @@ node가 연결되어 있어야 하며 `googlemeet.chrome`와 `browser.proxy`가 } ``` -`googlemeet setup`이 `chrome-node-connected`에서 실패하거나 Gateway log에 `gateway token mismatch`가 보고되면 현재 Gateway token으로 node를 다시 설치하거나 다시 시작하세요. LAN Gateway의 경우 일반적으로 다음을 의미합니다. +`googlemeet setup`에서 `chrome-node-connected`가 실패하거나 Gateway 로그가 `gateway token mismatch`를 보고하면, 현재 Gateway 토큰으로 노드를 다시 설치하거나 다시 시작하세요. LAN Gateway의 경우 이는 보통 다음을 의미합니다. ```bash OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ @@ -1137,74 +1288,74 @@ OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 \ --force ``` -그런 다음 node service를 reload하고 다시 실행하세요. +그런 다음 노드 서비스를 다시 로드하고 다시 실행하세요. ```bash openclaw googlemeet setup openclaw nodes status --connected ``` -### Browser는 열리지만 agent가 참여할 수 없음 +### 브라우저는 열리지만 에이전트가 참가할 수 없음 -observe-only 참여에는 `googlemeet test-listen`을, realtime 참여에는 `googlemeet test-speech`를 실행한 다음 반환된 Chrome health를 검사하세요. 두 probe 중 하나라도 `manualActionRequired: true`를 보고하면 operator에게 `manualActionMessage`를 보여주고 browser 작업이 완료될 때까지 재시도를 중지하세요. +관찰 전용 참가에는 `googlemeet test-listen`을, 실시간 참가에는 `googlemeet test-speech`를 실행한 다음 반환된 Chrome 상태를 검사하세요. 어느 프로브든 `manualActionRequired: true`를 보고하면 운영자에게 `manualActionMessage`를 보여주고 브라우저 작업이 완료될 때까지 재시도를 중지하세요. 일반적인 수동 작업: -- Chrome profile에 로그인합니다. -- Meet host account에서 guest를 승인합니다. -- Chrome의 native permission prompt가 나타나면 Chrome microphone/camera 권한을 부여합니다. -- 멈춘 Meet permission dialog를 닫거나 복구합니다. +- Chrome 프로필에 로그인합니다. +- Meet 호스트 계정에서 게스트를 승인합니다. +- Chrome의 네이티브 권한 프롬프트가 나타나면 Chrome 마이크/카메라 권한을 부여합니다. +- 멈춘 Meet 권한 대화 상자를 닫거나 복구합니다. -Meet에 "Do you want people to hear you in the meeting?"가 표시된다는 이유만으로 "not signed in"이라고 보고하지 마세요. 이는 Meet의 audio-choice interstitial입니다. OpenClaw는 가능한 경우 browser automation을 통해 **Use microphone**을 클릭하고 실제 meeting state를 계속 기다립니다. create-only browser fallback의 경우 URL 생성에는 realtime audio path가 필요하지 않으므로 OpenClaw가 **Continue without microphone**을 클릭할 수 있습니다. +Meet에 "Do you want people to hear you in the meeting?"가 표시된다는 이유만으로 "not signed in"을 보고하지 마세요. 이는 Meet의 오디오 선택 중간 화면입니다. OpenClaw는 사용 가능한 경우 브라우저 자동화를 통해 **Use microphone**을 클릭하고 실제 회의 상태를 계속 기다립니다. 생성 전용 브라우저 fallback의 경우 URL 생성에는 실시간 오디오 경로가 필요하지 않으므로 OpenClaw가 **Continue without microphone**을 클릭할 수 있습니다. -### Meeting 생성 실패 +### 회의 생성 실패 -`googlemeet create`는 OAuth credentials가 구성된 경우 먼저 Google Meet API `spaces.create` endpoint를 사용합니다. OAuth credentials가 없으면 고정된 Chrome node browser로 fallback합니다. 다음을 확인하세요. +`googlemeet create`는 OAuth 자격 증명이 구성된 경우 먼저 Google Meet API `spaces.create` 엔드포인트를 사용합니다. OAuth 자격 증명이 없으면 고정된 Chrome 노드 브라우저로 fallback합니다. 다음을 확인하세요. -- API 생성: `oauth.clientId`와 `oauth.refreshToken`이 구성되어 있거나 일치하는 `OPENCLAW_GOOGLE_MEET_*` environment variable이 있어야 합니다. -- API 생성: create support가 추가된 후 refresh token이 생성되었어야 합니다. 오래된 token에는 `meetings.space.created` scope가 없을 수 있습니다. `openclaw googlemeet auth login --json`을 다시 실행하고 Plugin config를 업데이트하세요. -- browser fallback: `defaultTransport: "chrome-node"`이고 `chromeNode.node`가 `browser.proxy`와 `googlemeet.chrome`가 있는 연결된 node를 가리켜야 합니다. -- browser fallback: 해당 node의 OpenClaw Chrome profile이 Google에 로그인되어 있고 `https://meet.google.com/new`를 열 수 있어야 합니다. -- browser fallback: 재시도는 새 tab을 열기 전에 기존 `https://meet.google.com/new` 또는 Google account prompt tab을 재사용합니다. agent가 timeout되면 다른 Meet tab을 수동으로 열지 말고 도구 호출을 다시 시도하세요. -- browser fallback: 도구가 `manualActionRequired: true`를 반환하면 반환된 `browser.nodeId`, `browser.targetId`, `browserUrl`, `manualActionMessage`를 사용해 operator를 안내하세요. 해당 작업이 완료될 때까지 loop로 재시도하지 마세요. -- browser fallback: Meet에 "Do you want people to hear you in the meeting?"가 표시되면 tab을 열어 둡니다. OpenClaw는 browser automation을 통해 **Use microphone** 또는 create-only fallback의 경우 **Continue without microphone**을 클릭하고 생성된 Meet URL을 계속 기다려야 합니다. 할 수 없으면 오류는 `google-login-required`가 아니라 `meet-audio-choice-required`를 언급해야 합니다. +- API 생성: `oauth.clientId`와 `oauth.refreshToken`이 구성되어 있거나, 일치하는 `OPENCLAW_GOOGLE_MEET_*` 환경 변수가 있어야 합니다. +- API 생성: 생성 지원이 추가된 뒤 refresh token이 발급되었어야 합니다. 오래된 토큰에는 `meetings.space.created` scope가 없을 수 있습니다. `openclaw googlemeet auth login --json`을 다시 실행하고 Plugin 구성을 업데이트하세요. +- 브라우저 fallback: `defaultTransport: "chrome-node"` 및 `chromeNode.node`가 `browser.proxy`와 `googlemeet.chrome`을 가진 연결된 노드를 가리켜야 합니다. +- 브라우저 fallback: 해당 노드의 OpenClaw Chrome 프로필이 Google에 로그인되어 있고 `https://meet.google.com/new`를 열 수 있어야 합니다. +- 브라우저 fallback: 재시도는 새 탭을 열기 전에 기존 `https://meet.google.com/new` 또는 Google 계정 프롬프트 탭을 재사용합니다. 에이전트가 시간 초과되면 다른 Meet 탭을 수동으로 열지 말고 도구 호출을 재시도하세요. +- 브라우저 fallback: 도구가 `manualActionRequired: true`를 반환하면 반환된 `browser.nodeId`, `browser.targetId`, `browserUrl`, `manualActionMessage`를 사용해 운영자를 안내하세요. 해당 작업이 완료될 때까지 루프로 재시도하지 마세요. +- 브라우저 fallback: Meet에 "Do you want people to hear you in the meeting?"가 표시되면 탭을 열어 둡니다. OpenClaw는 브라우저 자동화를 통해 **Use microphone** 또는 생성 전용 fallback의 경우 **Continue without microphone**을 클릭하고 생성된 Meet URL을 계속 기다려야 합니다. 할 수 없는 경우 오류는 `google-login-required`가 아니라 `meet-audio-choice-required`를 언급해야 합니다. -### Agent가 참여하지만 말하지 않음 +### 에이전트가 참가하지만 말하지 않음 -realtime path를 확인하세요. +실시간 경로를 확인하세요. ```bash openclaw googlemeet setup openclaw googlemeet doctor ``` -일반 STT -> OpenClaw agent -> TTS talk-back path에는 `mode: "agent"`를 사용하고, direct realtime voice fallback에는 `mode: "bidi"`를 사용하세요. `mode: "transcribe"`는 의도적으로 talk-back bridge를 시작하지 않습니다. observe-only debugging의 경우 participants가 말한 뒤 `openclaw googlemeet status --json `를 실행하고 `captioning`, `transcriptLines`, `lastCaptionText`를 확인하세요. `inCall`이 true인데 `transcriptLines`가 `0`에 머무르면 Meet captions가 비활성화되었거나, observer가 설치된 후 아무도 말하지 않았거나, Meet UI가 변경되었거나, meeting language/account에서 live captions를 사용할 수 없을 수 있습니다. +일반 STT -> OpenClaw 에이전트 -> TTS talk-back 경로에는 `mode: "agent"`를 사용하고, 직접 실시간 음성 fallback에는 `mode: "bidi"`를 사용하세요. `mode: "transcribe"`는 의도적으로 talk-back 브리지를 시작하지 않습니다. 관찰 전용 디버깅의 경우 참가자가 말한 뒤 `openclaw googlemeet status --json `를 실행하고 `captioning`, `transcriptLines`, `lastCaptionText`를 확인하세요. `inCall`이 true이지만 `transcriptLines`가 `0`에 머무르면 Meet 자막이 비활성화되었거나, 관찰자가 설치된 이후 아무도 말하지 않았거나, Meet UI가 변경되었거나, 회의 언어/계정에서 실시간 자막을 사용할 수 없을 수 있습니다. -`googlemeet test-speech`는 항상 realtime path를 확인하고 해당 호출에서 bridge output byte가 관찰되었는지 보고합니다. `speechOutputVerified`가 false이고 `speechOutputTimedOut`이 true이면 realtime provider가 utterance를 수락했지만 OpenClaw가 새 output byte가 Chrome audio bridge에 도달하는 것을 보지 못했을 수 있습니다. +`googlemeet test-speech`는 항상 실시간 경로를 확인하고 해당 호출에서 브리지 출력 바이트가 관찰되었는지 보고합니다. `speechOutputVerified`가 false이고 `speechOutputTimedOut`이 true이면 실시간 제공자가 발화를 수락했을 수 있지만, OpenClaw가 새 출력 바이트가 Chrome 오디오 브리지에 도달하는 것을 보지 못한 것입니다. 또한 다음을 확인하세요. -- Gateway host에서 `OPENAI_API_KEY` 또는 `GEMINI_API_KEY` 같은 realtime provider key를 사용할 수 있어야 합니다. -- Chrome host에서 `BlackHole 2ch`가 보여야 합니다. -- Chrome host에 `sox`가 있어야 합니다. -- Meet microphone과 speaker가 OpenClaw가 사용하는 virtual audio path를 통해 라우팅되어야 합니다. local Chrome realtime 참여의 경우 `doctor`는 `meet output routed: yes`를 표시해야 합니다. +- Gateway 호스트에서 `OPENAI_API_KEY` 또는 `GEMINI_API_KEY` 같은 실시간 제공자 키를 사용할 수 있습니다. +- Chrome 호스트에서 `BlackHole 2ch`가 보입니다. +- Chrome 호스트에 `sox`가 있습니다. +- Meet 마이크와 스피커가 OpenClaw가 사용하는 가상 오디오 경로를 통해 라우팅됩니다. 로컬 Chrome 실시간 참가의 경우 `doctor`에 `meet output routed: yes`가 표시되어야 합니다. -`googlemeet doctor [session-id]`는 session, node, in-call state, manual action reason, realtime provider connection, `realtimeReady`, audio input/output activity, last audio timestamps, byte counters, browser URL을 출력합니다. raw JSON이 필요하면 `googlemeet status [session-id] --json`을 사용하세요. token을 노출하지 않고 Google Meet OAuth refresh를 확인해야 할 때는 `googlemeet doctor --oauth`를 사용하세요. Google Meet API 증명도 필요하면 `--meeting` 또는 `--create-space`를 추가하세요. +`googlemeet doctor [session-id]`는 세션, 노드, 통화 중 상태, 수동 작업 이유, 실시간 제공자 연결, `realtimeReady`, 오디오 입력/출력 활동, 마지막 오디오 타임스탬프, 바이트 카운터, 브라우저 URL을 출력합니다. 원시 JSON이 필요하면 `googlemeet status [session-id] --json`을 사용하세요. 토큰을 노출하지 않고 Google Meet OAuth refresh를 확인해야 하면 `googlemeet doctor --oauth`를 사용하세요. Google Meet API 증명도 필요하면 `--meeting` 또는 `--create-space`를 추가하세요. -agent가 timeout되었고 Meet tab이 이미 열려 있는 것이 보이면 다른 tab을 열지 말고 해당 tab을 검사하세요. +에이전트가 시간 초과되었고 이미 열린 Meet 탭이 보인다면, 다른 탭을 열지 말고 해당 탭을 검사하세요. ```bash openclaw googlemeet recover-tab openclaw googlemeet recover-tab https://meet.google.com/abc-defg-hij ``` -동등한 도구 작업은 `recover_current_tab`입니다. 선택한 transport에 대해 기존 Meet tab에 focus하고 검사합니다. `chrome`에서는 Gateway를 통한 local browser control을 사용하고, `chrome-node`에서는 구성된 Chrome node를 사용합니다. 새 tab을 열거나 새 session을 만들지 않습니다. 대신 login, admission, permissions, audio-choice state 같은 현재 blocker를 보고합니다. CLI 명령은 구성된 Gateway와 통신하므로 Gateway가 실행 중이어야 합니다. `chrome-node`의 경우 Chrome node도 연결되어 있어야 합니다. +동등한 도구 작업은 `recover_current_tab`입니다. 선택한 전송 방식의 기존 Meet 탭에 포커스를 맞추고 검사합니다. `chrome`에서는 Gateway를 통한 로컬 브라우저 제어를 사용하고, `chrome-node`에서는 구성된 Chrome 노드를 사용합니다. 새 탭을 열거나 새 세션을 생성하지 않습니다. 로그인, 승인, 권한 또는 오디오 선택 상태 같은 현재 차단 요인을 보고합니다. CLI 명령은 구성된 Gateway와 통신하므로 Gateway가 실행 중이어야 합니다. `chrome-node`에는 Chrome 노드도 연결되어 있어야 합니다. -### Twilio setup 검사 실패 +### Twilio 설정 확인 실패 -`voice-call`이 허용되지 않았거나 활성화되지 않은 경우 `twilio-voice-call-plugin`이 실패합니다. `plugins.allow`에 추가하고 `plugins.entries.voice-call`을 활성화한 다음 Gateway를 reload하세요. +`voice-call`이 허용되지 않았거나 활성화되지 않은 경우 `twilio-voice-call-plugin`이 실패합니다. `plugins.allow`에 추가하고 `plugins.entries.voice-call`을 활성화한 뒤 Gateway를 다시 로드하세요. -Twilio backend에 account SID, auth token 또는 caller number가 없으면 `twilio-voice-call-credentials`가 실패합니다. Gateway host에서 다음을 설정하세요. +Twilio 백엔드에 계정 SID, 인증 토큰 또는 발신자 번호가 없으면 `twilio-voice-call-credentials`가 실패합니다. Gateway 호스트에서 다음을 설정하세요. ```bash export TWILIO_ACCOUNT_SID=AC... @@ -1212,11 +1363,11 @@ export TWILIO_AUTH_TOKEN=... export TWILIO_FROM_NUMBER=+15550001234 ``` -`voice-call`에 public webhook 노출이 없거나 `publicUrl`이 loopback 또는 private network space를 가리키면 `twilio-voice-call-webhook`이 실패합니다. `plugins.entries.voice-call.config.publicUrl`을 public provider URL로 설정하거나 `voice-call` tunnel/Tailscale 노출을 구성하세요. +`voice-call`에 공개 Webhook 노출이 없거나 `publicUrl`이 loopback 또는 사설 네트워크 공간을 가리키면 `twilio-voice-call-webhook`이 실패합니다. `plugins.entries.voice-call.config.publicUrl`을 공개 제공자 URL로 설정하거나 `voice-call` 터널/Tailscale 노출을 구성하세요. -Loopback 및 private URL은 carrier callback에 유효하지 않습니다. `publicUrl`로 `localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, `192.168.x`, `169.254.x`, `fc00::/7`, `fd00::/8`을 사용하지 마세요. +Loopback 및 사설 URL은 통신사 콜백에 유효하지 않습니다. `publicUrl`로 `localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, `192.168.x`, `169.254.x`, `fc00::/7`, `fd00::/8`을 사용하지 마세요. -안정적인 public URL의 경우: +안정적인 공개 URL의 경우: ```json5 { @@ -1235,7 +1386,7 @@ Loopback 및 private URL은 carrier callback에 유효하지 않습니다. `publ } ``` -local development의 경우 private host URL 대신 tunnel 또는 Tailscale 노출을 사용하세요. +로컬 개발에서는 비공개 호스트 URL 대신 터널이나 Tailscale 노출을 사용하세요. ```json5 { @@ -1253,7 +1404,7 @@ local development의 경우 private host URL 대신 tunnel 또는 Tailscale 노 } ``` -그런 다음 Gateway를 다시 시작하거나 reload하고 실행하세요. +그런 다음 Gateway를 다시 시작하거나 다시 로드하고 다음을 실행하세요. ```bash openclaw googlemeet setup --transport twilio @@ -1261,21 +1412,21 @@ openclaw voicecall setup openclaw voicecall smoke ``` -`voicecall smoke`는 기본적으로 readiness-only입니다. 특정 번호에 대해 dry-run하려면: +`voicecall smoke`는 기본적으로 준비 상태만 확인합니다. 특정 번호로 드라이런하려면: ```bash openclaw voicecall smoke --to "+15555550123" ``` -실제 outbound notify call을 의도적으로 걸려는 경우에만 `--yes`를 추가하세요. +실제 아웃바운드 알림 전화를 의도적으로 걸고 싶을 때만 `--yes`를 추가하세요. ```bash openclaw voicecall smoke --to "+15555550123" --yes ``` -### Twilio call은 시작되지만 meeting에 들어가지 않음 +### Twilio 통화가 시작되지만 회의에 들어가지 못함 -Meet event가 phone dial-in details를 노출하는지 확인하세요. 정확한 dial-in number와 PIN 또는 custom DTMF sequence를 전달하세요. +Meet 이벤트가 전화 다이얼인 세부 정보를 노출하는지 확인하세요. 정확한 다이얼인 번호와 PIN 또는 사용자 지정 DTMF 시퀀스를 전달하세요. ```bash openclaw googlemeet join https://meet.google.com/abc-defg-hij \ @@ -1284,62 +1435,38 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ --dtmf-sequence ww123456# ``` -PIN을 입력하기 전에 provider에 pause가 필요하면 `--dtmf-sequence`에서 앞쪽 `w` 또는 comma를 사용하세요. +제공자가 PIN 입력 전에 일시 중지가 필요하면 `--dtmf-sequence`에서 선행 `w` 또는 쉼표를 사용하세요. -phone call은 생성되지만 Meet roster에 dial-in participant가 표시되지 않으면: +전화 통화가 생성되었지만 Meet 명단에 다이얼인 참가자가 표시되지 않는 경우: -- `openclaw googlemeet doctor `를 실행해 위임된 Twilio call ID, DTMF가 queued되었는지 여부, intro greeting이 요청되었는지 여부를 확인하세요. -- `openclaw voicecall status --call-id `를 실행하고 call이 아직 active인지 확인하세요. -- `openclaw voicecall tail`을 실행하고 Twilio webhook이 Gateway에 도착하는지 확인하세요. -- `openclaw logs --follow`를 실행하고 Twilio Meet sequence를 찾으세요. Google Meet가 join을 위임하고, Voice Call이 phone leg를 시작하며, Google Meet가 `voiceCall.dtmfDelayMs`를 기다린 뒤 `voicecall.dtmf`로 DTMF를 보내고, `voiceCall.postDtmfSpeechDelayMs`를 기다린 다음 `voicecall.speak`로 intro speech를 요청합니다. -- `openclaw googlemeet setup --transport twilio`를 다시 실행하세요. 녹색 setup check는 필요하지만 meeting PIN sequence가 올바른지 증명하지는 않습니다. -- dial-in number가 PIN과 동일한 Meet invitation 및 region에 속하는지 확인하세요. -- Meet가 느리게 응답하거나 call transcript에 DTMF가 전송된 후에도 PIN을 요청하는 prompt가 계속 표시되면 `voiceCall.dtmfDelayMs`를 늘리세요. -- participant가 참여했지만 greeting이 들리지 않으면 `openclaw logs --follow`에서 post-DTMF `voicecall.speak` request와 media-stream TTS playback 또는 Twilio `` fallback을 확인하세요. call transcript에 여전히 "enter the meeting PIN"이 포함되어 있으면 phone leg가 아직 Meet room에 참여하지 않은 것이므로 meeting participants에게 speech가 들리지 않습니다. +- `openclaw googlemeet doctor `를 실행하여 위임된 Twilio 통화 ID, DTMF가 대기열에 들어갔는지 여부, 소개 인사말이 요청되었는지 여부를 확인하세요. +- `openclaw voicecall status --call-id `를 실행하고 통화가 아직 활성 상태인지 확인하세요. +- `openclaw voicecall tail`을 실행하고 Twilio Webhook이 Gateway에 도착하는지 확인하세요. +- `openclaw logs --follow`를 실행하고 Twilio Meet 시퀀스를 찾으세요. Google Meet가 참여를 위임하고, Voice Call이 전화 구간을 시작하고, Google Meet가 `voiceCall.dtmfDelayMs`만큼 기다린 뒤 `voicecall.dtmf`로 DTMF를 보내고, `voiceCall.postDtmfSpeechDelayMs`만큼 기다린 다음 `voicecall.speak`로 소개 음성을 요청합니다. +- `openclaw googlemeet setup --transport twilio`를 다시 실행하세요. 녹색 설정 확인은 필수이지만 회의 PIN 시퀀스가 올바르다는 것을 증명하지는 않습니다. +- 다이얼인 번호가 PIN과 같은 Meet 초대 및 지역에 속하는지 확인하세요. +- Meet 응답이 느리거나 DTMF가 전송된 후에도 통화 기록에 PIN을 요청하는 프롬프트가 계속 표시되면 `voiceCall.dtmfDelayMs`를 늘리세요. +- 참가자가 참여했지만 인사말이 들리지 않으면 `openclaw logs --follow`에서 DTMF 이후 `voicecall.speak` 요청과 미디어 스트림 TTS 재생 또는 Twilio `` 대체 경로를 확인하세요. 통화 기록에 여전히 "enter the meeting PIN"이 포함되어 있으면 전화 구간이 아직 Meet 회의실에 참여하지 않은 것이므로 회의 참가자는 음성을 들을 수 없습니다. -Webhook이 도착하지 않으면 먼저 Voice Call Plugin을 디버그하세요. 공급자가 -`plugins.entries.voice-call.config.publicUrl` 또는 구성된 터널에 -도달할 수 있어야 합니다. [Voice Call 문제 해결](/ko/plugins/voice-call#troubleshooting)을 참조하세요. +Webhook이 도착하지 않으면 먼저 Voice Call Plugin을 디버그하세요. 제공자는 `plugins.entries.voice-call.config.publicUrl` 또는 구성된 터널에 도달할 수 있어야 합니다. [음성 통화 문제 해결](/ko/plugins/voice-call#troubleshooting)을 참조하세요. ## 참고 -Google Meet의 공식 미디어 API는 수신 지향이므로 Meet -통화에서 말하려면 여전히 참여자 경로가 필요합니다. 이 Plugin은 그 경계를 명확히 드러냅니다: -Chrome은 브라우저 참여와 로컬 오디오 라우팅을 처리하고, Twilio는 -전화 다이얼인 참여를 처리합니다. +Google Meet의 공식 미디어 API는 수신 중심이므로 Meet 통화에서 말하려면 여전히 참가자 경로가 필요합니다. 이 Plugin은 그 경계를 명확히 유지합니다. Chrome은 브라우저 참여와 로컬 오디오 라우팅을 처리하고, Twilio는 전화 다이얼인 참여를 처리합니다. -Chrome 말하기 응답 모드에는 `BlackHole 2ch`와 다음 중 하나가 필요합니다. +Chrome 토크백 모드에는 `BlackHole 2ch`와 다음 중 하나가 필요합니다. -- `chrome.audioInputCommand`와 `chrome.audioOutputCommand`: OpenClaw가 - 브리지를 소유하고 해당 명령과 선택한 공급자 사이에서 - `chrome.audioFormat` 형식으로 오디오를 파이프합니다. 에이전트 모드는 실시간 전사와 일반 TTS를 사용하고, - bidi 모드는 실시간 음성 공급자를 사용합니다. 기본 Chrome 경로는 24 kHz - PCM16이며, 8 kHz G.711 mu-law는 레거시 명령 쌍을 위해 계속 사용할 수 있습니다. -- `chrome.audioBridgeCommand`: 외부 브리지 명령이 전체 로컬 - 오디오 경로를 소유하며 데몬을 시작하거나 검증한 뒤 종료해야 합니다. 이는 - `bidi`에만 유효합니다. `agent` 모드는 TTS를 위해 명령 쌍에 직접 접근해야 하기 때문입니다. +- `chrome.audioInputCommand`와 `chrome.audioOutputCommand`: OpenClaw가 브리지를 소유하고, 해당 명령과 선택된 제공자 사이에서 `chrome.audioFormat`의 오디오를 파이프합니다. 에이전트 모드는 실시간 전사와 일반 TTS를 사용하고, bidi 모드는 실시간 음성 제공자를 사용합니다. 기본 Chrome 경로는 `chrome.audioBufferBytes: 4096`을 사용하는 24 kHz PCM16입니다. 8 kHz G.711 mu-law는 레거시 명령 쌍을 위해 계속 사용할 수 있습니다. +- `chrome.audioBridgeCommand`: 외부 브리지 명령이 전체 로컬 오디오 경로를 소유하며 데몬을 시작하거나 검증한 뒤 종료해야 합니다. `agent` 모드는 TTS를 위해 직접 명령 쌍 액세스가 필요하므로 이는 `bidi`에만 유효합니다. -깨끗한 양방향 오디오를 위해 Meet 출력과 Meet 마이크를 별도의 -가상 장치 또는 Loopback 스타일 가상 장치 그래프로 라우팅하세요. 단일 공유 -BlackHole 장치는 다른 참여자의 음성을 통화로 다시 반향시킬 수 있습니다. +깔끔한 양방향 오디오를 위해 Meet 출력과 Meet 마이크를 별도의 가상 장치나 Loopback 스타일 가상 장치 그래프로 라우팅하세요. 하나의 공유 BlackHole 장치는 다른 참가자의 소리를 통화로 다시 에코할 수 있습니다. -명령 쌍 Chrome 브리지를 사용할 때 `chrome.bargeInInputCommand`는 -별도의 로컬 마이크를 수신하고 사람이 말하기 시작하면 -어시스턴트 재생을 지울 수 있습니다. 이렇게 하면 어시스턴트 재생 중 공유 -BlackHole local loopback 입력이 일시적으로 억제되더라도 사람의 발화가 -어시스턴트 출력보다 앞서 유지됩니다. `chrome.audioInputCommand` 및 -`chrome.audioOutputCommand`와 마찬가지로, 이는 운영자가 구성하는 로컬 명령입니다. -명시적으로 신뢰할 수 있는 명령 경로나 인수 목록을 사용하고, -신뢰할 수 없는 위치의 스크립트를 가리키지 마세요. +명령 쌍 Chrome 브리지를 사용할 때 `chrome.bargeInInputCommand`는 별도의 로컬 마이크를 수신하고 사람이 말하기 시작하면 어시스턴트 재생을 지울 수 있습니다. 이렇게 하면 공유 BlackHole loopback 입력이 어시스턴트 재생 중에 일시적으로 억제되더라도 사람의 음성이 어시스턴트 출력보다 앞서 유지됩니다. `chrome.audioInputCommand` 및 `chrome.audioOutputCommand`와 마찬가지로 이는 운영자가 구성하는 로컬 명령입니다. 명시적으로 신뢰할 수 있는 명령 경로나 인수 목록을 사용하고, 신뢰할 수 없는 위치의 스크립트를 가리키지 마세요. -`googlemeet speak`는 Chrome 세션의 활성 말하기 응답 오디오 브리지를 트리거합니다. -`googlemeet leave`는 해당 브리지를 중지합니다. Voice Call Plugin을 통해 위임된 -Twilio 세션의 경우 `leave`는 기본 음성 통화도 종료합니다. -API로 관리되는 공간의 활성 Google Meet 회의도 닫으려면 -`googlemeet end-active-conference`를 사용하세요. +`googlemeet speak`는 Chrome 세션에 대해 활성 토크백 오디오 브리지를 트리거합니다. `googlemeet leave`는 해당 브리지를 중지합니다. Voice Call Plugin을 통해 위임된 Twilio 세션의 경우 `leave`는 기반 음성 통화도 끊습니다. API로 관리되는 공간의 활성 Google Meet 회의도 닫으려면 `googlemeet end-active-conference`를 사용하세요. ## 관련 항목 - [Voice Call Plugin](/ko/plugins/voice-call) -- [Talk 모드](/ko/nodes/talk) -- [Plugin 빌드](/ko/plugins/building-plugins) +- [대화 모드](/ko/nodes/talk) +- [Plugin 빌드하기](/ko/plugins/building-plugins) diff --git a/docs/ko/plugins/voice-call.md b/docs/ko/plugins/voice-call.md index e00d34c81..4c9cd4cac 100644 --- a/docs/ko/plugins/voice-call.md +++ b/docs/ko/plugins/voice-call.md @@ -1,26 +1,32 @@ --- read_when: - OpenClaw에서 발신 음성 통화를 걸려고 합니다 - - 음성 통화 Plugin을 구성하거나 개발하고 있습니다 + - 음성 통화 Plugin을 설정하거나 개발하고 있습니다 - 전화 통신에서 실시간 음성 또는 스트리밍 전사가 필요합니다 sidebarTitle: Voice call -summary: Twilio, Telnyx 또는 Plivo를 통해 발신 음성 통화를 걸고 수신 음성 통화를 받으며, 선택적으로 실시간 음성 및 스트리밍 전사를 지원합니다 +summary: Twilio, Telnyx 또는 Plivo를 통해 발신 음성 통화를 걸고 수신 음성 통화를 받으며, 선택적으로 실시간 음성 및 스트리밍 전사를 사용할 수 있습니다 title: 음성 통화 Plugin x-i18n: - generated_at: "2026-05-02T22:21:45Z" + generated_at: "2026-05-04T06:24:46Z" model: gpt-5.5 provider: openai - source_hash: 18a9a0d7095ec92036b516cc26c69219a0a2fd9bb8e0cb2e7509123bb4f3f65a + source_hash: 8ec2c22dcc9073572963744685a432328787bcedb14025e0326c20d9d842f857 source_path: plugins/voice-call.md workflow: 16 --- -OpenClaw용 음성 통화 Plugin. 발신 알림, 다중 턴 대화, 전이중 실시간 음성, 스트리밍 전사, 허용 목록 정책이 있는 수신 통화를 지원합니다. +Plugin을 통해 OpenClaw에서 음성 통화를 사용할 수 있습니다. 발신 알림, +다중 턴 대화, 전이중 실시간 음성, 스트리밍 +전사, 허용 목록 정책이 적용된 수신 통화를 지원합니다. -**현재 제공자:** `twilio`(Programmable Voice + Media Streams), `telnyx`(Call Control v2), `plivo`(Voice API + XML transfer + GetInput speech), `mock`(개발/네트워크 없음). +**현재 제공자:** `twilio` (Programmable Voice + Media Streams), +`telnyx` (Call Control v2), `plivo` (Voice API + XML transfer + GetInput +speech), `mock` (개발/네트워크 없음). -Voice Call Plugin은 **Gateway 프로세스 내부에서** 실행됩니다. 원격 Gateway를 사용하는 경우, Gateway를 실행하는 머신에 Plugin을 설치하고 구성한 다음 Gateway를 다시 시작하여 로드하세요. +음성 통화 Plugin은 **Gateway 프로세스 내부에서** 실행됩니다. 원격 Gateway를 +사용하는 경우 Gateway가 실행되는 머신에 Plugin을 설치하고 구성한 다음, +Gateway를 다시 시작해 로드하세요. ## 빠른 시작 @@ -28,12 +34,12 @@ Voice Call Plugin은 **Gateway 프로세스 내부에서** 실행됩니다. 원 - + ```bash openclaw plugins install @openclaw/voice-call ``` - + ```bash PLUGIN_SRC=./path/to/local/voice-call-plugin openclaw plugins install "$PLUGIN_SRC" @@ -42,20 +48,25 @@ Voice Call Plugin은 **Gateway 프로세스 내부에서** 실행됩니다. 원 - 현재 공식 릴리스 태그를 따르려면 순수 패키지를 사용하세요. 재현 가능한 설치가 필요할 때만 정확한 버전을 고정하세요. + 현재 공식 릴리스 태그를 따르려면 버전 없는 패키지를 사용하세요. 재현 가능한 설치가 + 필요할 때만 정확한 버전을 고정하세요. - 이후 Gateway를 다시 시작하여 Plugin이 로드되게 하세요. + 이후 Plugin이 로드되도록 Gateway를 다시 시작하세요. - `plugins.entries.voice-call.config` 아래에 구성을 설정하세요(전체 형태는 아래 [구성](#configuration) 참조). 최소한 `provider`, 제공자 자격 증명, `fromNumber`, 공개적으로 접근 가능한 Webhook URL이 필요합니다. + `plugins.entries.voice-call.config` 아래에 구성을 설정합니다(전체 형태는 + 아래 [구성](#configuration)을 참조). 최소한 `provider`, 제공자 자격 증명, + `fromNumber`, 공개적으로 접근 가능한 Webhook URL이 필요합니다. ```bash openclaw voicecall setup ``` - 기본 출력은 채팅 로그와 터미널에서 읽기 쉽습니다. Plugin 활성화, 제공자 자격 증명, Webhook 노출, 그리고 오디오 모드(`streaming` 또는 `realtime`)가 하나만 활성화되어 있는지 확인합니다. 스크립트에는 `--json`을 사용하세요. + 기본 출력은 채팅 로그와 터미널에서 읽기 쉽게 표시됩니다. Plugin 활성화, + 제공자 자격 증명, Webhook 노출, 오디오 모드(`streaming` 또는 `realtime`)가 + 하나만 활성화되었는지 확인합니다. 스크립트에는 `--json`을 사용하세요. @@ -64,7 +75,8 @@ Voice Call Plugin은 **Gateway 프로세스 내부에서** 실행됩니다. 원 openclaw voicecall smoke --to "+15555550123" ``` - 둘 다 기본적으로 드라이 런입니다. 짧은 발신 알림 통화를 실제로 걸려면 `--yes`를 추가하세요. + 둘 다 기본적으로 드라이런입니다. 실제로 짧은 발신 알림 통화를 걸려면 + `--yes`를 추가하세요. ```bash openclaw voicecall smoke --to "+15555550123" --yes @@ -74,15 +86,21 @@ Voice Call Plugin은 **Gateway 프로세스 내부에서** 실행됩니다. 원 -Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어야 합니다. `publicUrl`, 터널 URL, Tailscale URL 또는 serve 폴백이 loopback이나 사설 네트워크 공간으로 해석되면, 통신사 Webhook을 받을 수 없는 제공자를 시작하는 대신 설정이 실패합니다. +Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 확인되어야 합니다. +`publicUrl`, 터널 URL, Tailscale URL 또는 serve 폴백이 loopback이나 사설 네트워크 +공간으로 확인되면, 수신사 Webhook을 받을 수 없는 제공자를 시작하는 대신 설정이 +실패합니다. ## 구성 -`enabled: true`이지만 선택한 제공자에 자격 증명이 없으면 Gateway 시작 로그에 누락된 키와 함께 설정 미완료 경고가 기록되고 런타임 시작을 건너뜁니다. 명령, RPC 호출, 에이전트 도구는 사용 시에도 정확히 누락된 제공자 구성을 반환합니다. +`enabled: true`이지만 선택한 제공자에 자격 증명이 없으면, +Gateway 시작 시 누락된 키와 함께 설정 미완료 경고를 기록하고 +런타임 시작을 건너뜁니다. 명령, RPC 호출, 에이전트 도구는 사용 시에도 +누락된 제공자 구성을 정확히 반환합니다. -음성 통화 자격 증명은 SecretRef를 허용합니다. `plugins.entries.voice-call.config.twilio.authToken`, `plugins.entries.voice-call.config.realtime.providers.*.apiKey`, `plugins.entries.voice-call.config.streaming.providers.*.apiKey`, `plugins.entries.voice-call.config.tts.providers.*.apiKey`는 표준 SecretRef 표면을 통해 해석됩니다. [SecretRef 자격 증명 표면](/ko/reference/secretref-credential-surface)을 참조하세요. +음성 통화 자격 증명은 SecretRef를 허용합니다. `plugins.entries.voice-call.config.twilio.authToken`, `plugins.entries.voice-call.config.realtime.providers.*.apiKey`, `plugins.entries.voice-call.config.streaming.providers.*.apiKey`, `plugins.entries.voice-call.config.tts.providers.*.apiKey`는 표준 SecretRef 표면을 통해 확인됩니다. [SecretRef 자격 증명 표면](/ko/reference/secretref-credential-surface)을 참조하세요. ```json5 @@ -158,22 +176,26 @@ Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어 - Twilio, Telnyx, Plivo는 모두 **공개적으로 접근 가능한** Webhook URL이 필요합니다. - `mock`은 로컬 개발 제공자입니다(네트워크 호출 없음). - - `skipSignatureVerification`이 true가 아니라면 Telnyx에는 `telnyx.publicKey`(또는 `TELNYX_PUBLIC_KEY`)가 필요합니다. + - `skipSignatureVerification`이 true가 아닌 한 Telnyx에는 `telnyx.publicKey`(또는 `TELNYX_PUBLIC_KEY`)가 필요합니다. - `skipSignatureVerification`은 로컬 테스트 전용입니다. - - ngrok 무료 계층에서는 `publicUrl`을 정확한 ngrok URL로 설정하세요. 서명 검증은 항상 적용됩니다. - - `tunnel.allowNgrokFreeTierLoopbackBypass: true`는 `tunnel.provider="ngrok"`이고 `serve.bind`가 loopback(ngrok 로컬 에이전트)인 경우에만 잘못된 서명이 있는 Twilio Webhook을 허용합니다. 로컬 개발 전용입니다. - - Ngrok 무료 계층 URL은 변경되거나 인터스티셜 동작을 추가할 수 있습니다. `publicUrl`이 달라지면 Twilio 서명이 실패합니다. 프로덕션에서는 안정적인 도메인이나 Tailscale funnel을 권장합니다. + - ngrok 무료 티어에서는 `publicUrl`을 정확한 ngrok URL로 설정하세요. 서명 검증은 항상 강제됩니다. + - `tunnel.allowNgrokFreeTierLoopbackBypass: true`는 `tunnel.provider="ngrok"`이고 `serve.bind`가 loopback(ngrok 로컬 에이전트)일 때만, 유효하지 않은 서명의 Twilio Webhook을 허용합니다. 로컬 개발 전용입니다. + - Ngrok 무료 티어 URL은 변경되거나 중간 페이지 동작이 추가될 수 있습니다. `publicUrl`이 달라지면 Twilio 서명이 실패합니다. 프로덕션에서는 안정적인 도메인 또는 Tailscale funnel을 선호하세요. - `streaming.preStartTimeoutMs`는 유효한 `start` 프레임을 보내지 않는 소켓을 닫습니다. - - `streaming.maxPendingConnections`는 인증되지 않은 전체 시작 전 소켓 수를 제한합니다. + - `streaming.maxPendingConnections`는 인증되지 않은 시작 전 소켓의 총수를 제한합니다. - `streaming.maxPendingConnectionsPerIp`는 소스 IP별 인증되지 않은 시작 전 소켓 수를 제한합니다. - - `streaming.maxConnections`는 열려 있는 전체 미디어 스트림 소켓 수(대기 + 활성)를 제한합니다. + - `streaming.maxConnections`는 열린 미디어 스트림 소켓(대기 중 + 활성)의 총수를 제한합니다. - `provider: "log"`, `twilio.from` 또는 레거시 `streaming.*` OpenAI 키를 사용하는 이전 구성은 `openclaw doctor --fix`로 다시 작성됩니다. 런타임 폴백은 현재 이전 음성 통화 키를 계속 허용하지만, 다시 작성 경로는 `openclaw doctor --fix`이며 호환성 shim은 임시입니다. + `provider: "log"`, `twilio.from` 또는 레거시 + `streaming.*` OpenAI 키를 사용하는 이전 구성은 `openclaw doctor --fix`로 다시 작성됩니다. + 런타임 폴백은 현재로서는 이전 음성 통화 키를 계속 허용하지만, + 다시 작성 경로는 `openclaw doctor --fix`이며 호환성 shim은 + 임시입니다. 자동 마이그레이션되는 스트리밍 키: @@ -188,26 +210,31 @@ Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어 ## 세션 범위 -기본적으로 Voice Call은 `sessionScope: "per-phone"`을 사용하므로 같은 발신자의 반복 통화가 대화 메모리를 유지합니다. 각 통신사 통화가 새 컨텍스트로 시작해야 하는 경우, 예를 들어 접수, 예약, IVR 또는 같은 전화번호가 서로 다른 회의를 나타낼 수 있는 Google Meet 브리지 플로에서는 `sessionScope: "per-call"`을 설정하세요. +기본적으로 음성 통화는 `sessionScope: "per-phone"`을 사용하므로 같은 발신자의 +반복 통화는 대화 메모리를 유지합니다. 각 수신사 통화가 새 컨텍스트로 시작되어야 하는 경우, +예를 들어 같은 전화번호가 서로 다른 회의를 나타낼 수 있는 접수, +예약, IVR 또는 Google Meet 브리지 흐름에서는 `sessionScope: "per-call"`을 설정하세요. ## 실시간 음성 대화 -`realtime`은 실시간 통화 오디오를 위한 전이중 실시간 음성 제공자를 선택합니다. 이는 오디오를 실시간 전사 제공자에게만 전달하는 `streaming`과 별개입니다. +`realtime`은 실시간 통화 오디오를 위한 전이중 실시간 음성 제공자를 선택합니다. +이는 오디오를 실시간 전사 제공자로만 전달하는 `streaming`과는 별개입니다. -`realtime.enabled`는 `streaming.enabled`와 함께 사용할 수 없습니다. 통화당 하나의 오디오 모드만 선택하세요. +`realtime.enabled`는 `streaming.enabled`와 함께 사용할 수 없습니다. 통화별로 +오디오 모드 하나를 선택하세요. 현재 런타임 동작: - `realtime.enabled`는 Twilio Media Streams에서 지원됩니다. -- `realtime.provider`는 선택 사항입니다. 설정하지 않으면 Voice Call은 등록된 첫 번째 실시간 음성 제공자를 사용합니다. -- 번들 실시간 음성 제공자: Google Gemini Live(`google`) 및 OpenAI(`openai`)이며, 각 제공자 Plugin에서 등록됩니다. -- 제공자가 소유한 원시 구성은 `realtime.providers.` 아래에 있습니다. -- Voice Call은 기본적으로 공유 `openclaw_agent_consult` 실시간 도구를 노출합니다. 발신자가 더 깊은 추론, 최신 정보 또는 일반 OpenClaw 도구를 요청할 때 실시간 모델이 이를 호출할 수 있습니다. -- `realtime.fastContext.enabled`는 기본적으로 꺼져 있습니다. 활성화하면 Voice Call은 먼저 consult 질문에 대해 인덱싱된 메모리/세션 컨텍스트를 검색하고, `realtime.fastContext.fallbackToConsult`가 true인 경우에만 전체 consult 에이전트로 폴백하기 전에 해당 스니펫을 `realtime.fastContext.timeoutMs` 내에 실시간 모델에 반환합니다. -- `realtime.provider`가 등록되지 않은 제공자를 가리키거나 등록된 실시간 음성 제공자가 전혀 없으면, Voice Call은 전체 Plugin을 실패시키는 대신 경고를 기록하고 실시간 미디어를 건너뜁니다. -- Consult 세션 키는 사용 가능한 경우 저장된 통화 세션을 재사용한 다음, 구성된 `sessionScope`로 폴백합니다(기본값은 `per-phone`, 격리된 통화의 경우 `per-call`). +- `realtime.provider`는 선택 사항입니다. 설정하지 않으면 음성 통화는 첫 번째로 등록된 실시간 음성 제공자를 사용합니다. +- 번들 실시간 음성 제공자: Google Gemini Live(`google`) 및 OpenAI(`openai`). 각 제공자 Plugin이 등록합니다. +- 제공자 소유 원시 구성은 `realtime.providers.` 아래에 있습니다. +- 음성 통화는 기본적으로 공유 `openclaw_agent_consult` 실시간 도구를 노출합니다. 발신자가 더 깊은 추론, 현재 정보 또는 일반 OpenClaw 도구를 요청하면 실시간 모델이 이를 호출할 수 있습니다. +- `realtime.fastContext.enabled`는 기본적으로 꺼져 있습니다. 활성화하면 음성 통화는 먼저 consult 질문에 대해 색인된 메모리/세션 컨텍스트를 검색하고, `realtime.fastContext.timeoutMs` 내에 해당 스니펫을 실시간 모델에 반환한 다음, `realtime.fastContext.fallbackToConsult`가 true인 경우에만 전체 consult 에이전트로 폴백합니다. +- `realtime.provider`가 등록되지 않은 제공자를 가리키거나 실시간 음성 제공자가 전혀 등록되어 있지 않으면, 음성 통화는 전체 Plugin을 실패시키는 대신 경고를 기록하고 실시간 미디어를 건너뜁니다. +- consult 세션 키는 사용 가능한 경우 저장된 통화 세션을 재사용한 다음, 구성된 `sessionScope`(기본값은 `per-phone`, 격리된 통화의 경우 `per-call`)로 폴백합니다. ### 도구 정책 @@ -216,14 +243,19 @@ Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어 | 정책 | 동작 | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `safe-read-only` | consult 도구를 노출하고 일반 에이전트를 `read`, `web_search`, `web_fetch`, `x_search`, `memory_search`, `memory_get`으로 제한합니다. | -| `owner` | consult 도구를 노출하고 일반 에이전트가 일반 에이전트 도구 정책을 사용하게 합니다. | -| `none` | consult 도구를 노출하지 않습니다. 사용자 지정 `realtime.tools`는 여전히 실시간 제공자에게 전달됩니다. | +| `owner` | consult 도구를 노출하고 일반 에이전트가 일반 에이전트 도구 정책을 사용하도록 합니다. | +| `none` | consult 도구를 노출하지 않습니다. 사용자 지정 `realtime.tools`는 여전히 실시간 제공자로 전달됩니다. | ### 실시간 제공자 예시 - 기본값: `realtime.providers.google.apiKey`, `GEMINI_API_KEY` 또는 `GOOGLE_GENERATIVE_AI_API_KEY`의 API 키; 모델 `gemini-2.5-flash-native-audio-preview-12-2025`; 음성 `Kore`. + 기본값: `realtime.providers.google.apiKey`, + `GEMINI_API_KEY` 또는 `GOOGLE_GENERATIVE_AI_API_KEY`의 API 키, 모델 + `gemini-2.5-flash-native-audio-preview-12-2025`, 음성 `Kore`. + `sessionResumption` 및 `contextWindowCompression`은 더 길고 + 재연결 가능한 통화를 위해 기본적으로 켜져 있습니다. 전화 오디오에서 더 빠른 턴 전환을 + 조정하려면 `silenceDurationMs`, `startSensitivity`, `endSensitivity`를 사용하세요. ```json5 { @@ -244,6 +276,8 @@ Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어 apiKey: "${GEMINI_API_KEY}", model: "gemini-2.5-flash-native-audio-preview-12-2025", voice: "Kore", + silenceDurationMs: 500, + startSensitivity: "high", }, }, }, @@ -278,19 +312,21 @@ Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어 -제공자별 실시간 음성 옵션은 [Google 제공자](/ko/providers/google) 및 [OpenAI 제공자](/ko/providers/openai)를 참조하세요. +[Google 제공자](/ko/providers/google) 및 +[OpenAI 제공자](/ko/providers/openai)에서 제공자별 실시간 음성 +옵션을 참조하세요. ## 스트리밍 전사 -`streaming`은 실시간 통화 오디오를 위한 실시간 전사 제공자를 선택합니다. +`streaming`은 라이브 통화 오디오에 사용할 실시간 전사 제공자를 선택합니다. 현재 런타임 동작: -- `streaming.provider`는 선택 사항입니다. 설정하지 않으면 Voice Call은 처음 등록된 실시간 전사 제공자를 사용합니다. -- 번들 실시간 전사 제공자: Deepgram(`deepgram`), ElevenLabs(`elevenlabs`), Mistral(`mistral`), OpenAI(`openai`), xAI(`xai`)이며, 각 제공자 Plugin이 등록합니다. -- 제공자가 소유하는 원시 설정은 `streaming.providers.` 아래에 있습니다. -- Twilio가 수락된 스트림 `start` 메시지를 보낸 뒤 Voice Call은 즉시 스트림을 등록하고, 제공자가 연결되는 동안 수신 미디어를 전사 제공자로 큐에 넣으며, 실시간 전사가 준비된 뒤에만 초기 인사말을 시작합니다. -- `streaming.provider`가 등록되지 않은 제공자를 가리키거나 등록된 제공자가 없으면, Voice Call은 전체 Plugin을 실패시키는 대신 경고를 기록하고 미디어 스트리밍을 건너뜁니다. +- `streaming.provider`는 선택 사항입니다. 설정하지 않으면 Voice Call은 등록된 첫 번째 실시간 전사 제공자를 사용합니다. +- 번들 실시간 전사 제공자: Deepgram(`deepgram`), ElevenLabs(`elevenlabs`), Mistral(`mistral`), OpenAI(`openai`), xAI(`xai`)이며, 각각의 제공자 plugins가 등록합니다. +- 제공자가 소유한 원시 config는 `streaming.providers.` 아래에 있습니다. +- Twilio가 수락된 스트림 `start` 메시지를 보내면 Voice Call은 즉시 스트림을 등록하고, 제공자가 연결되는 동안 전사 제공자를 통해 인바운드 미디어를 큐에 넣으며, 실시간 전사가 준비된 뒤에만 초기 인사말을 시작합니다. +- `streaming.provider`가 등록되지 않은 제공자를 가리키거나 등록된 제공자가 없으면, Voice Call은 전체 plugin을 실패시키지 않고 경고를 로그로 남긴 뒤 미디어 스트리밍을 건너뜁니다. ### 스트리밍 제공자 예시 @@ -362,7 +398,9 @@ Twilio, Telnyx, Plivo의 경우 설정은 **공개 Webhook URL**로 해석되어 ## 통화용 TTS -Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` 설정을 사용합니다. Plugin 설정 아래에서 **동일한 형태**로 재정의할 수 있으며, `messages.tts`와 깊은 병합됩니다. +Voice Call은 통화에서 스트리밍 음성에 core `messages.tts` 구성을 사용합니다. +plugin config 아래에서 **동일한 형태**로 재정의할 수 있으며, 이는 `messages.tts`와 +deep-merge됩니다. ```json5 { @@ -380,21 +418,21 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` **Microsoft speech는 음성 통화에서 무시됩니다.** 전화 오디오는 PCM이 필요합니다. -현재 Microsoft 전송 계층은 전화용 PCM 출력을 노출하지 않습니다. +현재 Microsoft 전송 방식은 전화 PCM 출력을 노출하지 않습니다. 동작 참고 사항: -- Plugin 설정 안의 레거시 `tts.` 키(`openai`, `elevenlabs`, `microsoft`, `edge`)는 `openclaw doctor --fix`로 복구됩니다. 커밋되는 설정은 `tts.providers.`를 사용해야 합니다. -- Twilio 미디어 스트리밍이 활성화된 경우 코어 TTS가 사용됩니다. 그렇지 않으면 통화는 제공자 네이티브 음성으로 폴백합니다. -- Twilio 미디어 스트림이 이미 활성 상태이면 Voice Call은 TwiML ``로 폴백하지 않습니다. 그 상태에서 전화 TTS를 사용할 수 없으면, 재생 요청은 두 재생 경로를 혼합하는 대신 실패합니다. -- 전화 TTS가 보조 제공자로 폴백하면, Voice Call은 디버깅을 위해 제공자 체인(`from`, `to`, `attempts`)과 함께 경고를 기록합니다. -- Twilio 끼어들기 또는 스트림 해체가 대기 중인 TTS 큐를 비우면, 큐에 있던 재생 요청은 재생 완료를 기다리는 발신자를 멈춰 두는 대신 정산됩니다. +- plugin config 내부의 레거시 `tts.` 키(`openai`, `elevenlabs`, `microsoft`, `edge`)는 `openclaw doctor --fix`로 복구됩니다. 커밋되는 config는 `tts.providers.`를 사용해야 합니다. +- Twilio 미디어 스트리밍이 활성화되면 Core TTS가 사용됩니다. 그렇지 않으면 통화는 제공자 네이티브 음성으로 폴백합니다. +- Twilio 미디어 스트림이 이미 활성 상태이면 Voice Call은 TwiML ``로 폴백하지 않습니다. 이 상태에서 전화 TTS를 사용할 수 없으면, 재생 요청은 두 재생 경로를 섞는 대신 실패합니다. +- 전화 TTS가 보조 제공자로 폴백하면, Voice Call은 디버깅을 위해 제공자 체인(`from`, `to`, `attempts`)과 함께 경고를 로그로 남깁니다. +- Twilio barge-in 또는 스트림 teardown으로 대기 중인 TTS 큐가 비워지면, 큐에 있던 재생 요청은 재생 완료를 기다리는 발신자를 계속 대기시키지 않고 settled 상태가 됩니다. ### TTS 예시 - + ```json5 { messages: { @@ -408,7 +446,7 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` } ``` - + ```json5 { plugins: { @@ -432,7 +470,7 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` } ``` - + ```json5 { plugins: { @@ -456,9 +494,9 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` -## 수신 통화 +## 인바운드 통화 -수신 정책의 기본값은 `disabled`입니다. 수신 통화를 활성화하려면 다음을 설정하세요. +인바운드 정책의 기본값은 `disabled`입니다. 인바운드 통화를 활성화하려면 다음을 설정하세요. ```json5 { @@ -469,17 +507,28 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` ``` -`inboundPolicy: "allowlist"`는 보증 수준이 낮은 발신자 ID 검사입니다. Plugin은 제공자가 제공한 `From` 값을 정규화하고 `allowFrom`과 비교합니다. Webhook 검증은 제공자 전달과 페이로드 무결성을 인증하지만, PSTN/VoIP 발신자 번호 소유권을 **증명하지는 않습니다**. `allowFrom`은 강한 발신자 신원이 아니라 발신자 ID 필터링으로 취급하세요. +`inboundPolicy: "allowlist"`는 낮은 보증 수준의 발신자 ID 필터입니다. +plugin은 제공자가 제공한 `From` 값을 정규화하고 이를 `allowFrom`과 비교합니다. +Webhook 검증은 제공자 전달과 페이로드 무결성을 인증하지만, PSTN/VoIP 발신자 번호 +소유권을 **증명하지는 않습니다**. `allowFrom`은 강력한 발신자 신원이 아니라 +발신자 ID 필터링으로 취급하세요. -자동 응답은 에이전트 시스템을 사용합니다. `responseModel`, `responseSystemPrompt`, `responseTimeoutMs`로 조정하세요. +자동 응답은 에이전트 시스템을 사용합니다. `responseModel`, +`responseSystemPrompt`, `responseTimeoutMs`로 조정하세요. ### 번호별 라우팅 -하나의 Voice Call Plugin이 여러 전화번호의 통화를 받고 각 번호가 다른 회선처럼 동작해야 할 때 `numbers`를 사용하세요. 예를 들어 한 번호는 캐주얼한 개인 비서를 사용하고, 다른 번호는 비즈니스 페르소나, 다른 응답 에이전트, 다른 TTS 음성을 사용할 수 있습니다. +하나의 Voice Call plugin이 여러 전화번호의 통화를 수신하고 각 번호가 서로 다른 회선처럼 +동작해야 할 때 `numbers`를 사용하세요. 예를 들어 한 번호는 캐주얼한 개인 비서를 사용하고, +다른 번호는 비즈니스 페르소나, 다른 응답 에이전트, 다른 TTS 음성을 사용할 수 있습니다. -라우트는 제공자가 제공한 다이얼된 `To` 번호에서 선택됩니다. 키는 E.164 번호여야 합니다. 통화가 도착하면 Voice Call은 일치하는 라우트를 한 번 확인하고, 일치한 라우트를 통화 레코드에 저장하며, 인사말, 클래식 자동 응답 경로, 실시간 상담 경로, TTS 재생에 해당 유효 설정을 재사용합니다. 일치하는 라우트가 없으면 전역 Voice Call 설정이 사용됩니다. -발신 통화는 `numbers`를 사용하지 않습니다. 통화를 시작할 때 발신 대상, 메시지, 세션을 명시적으로 전달하세요. +라우트는 제공자가 제공한 다이얼된 `To` 번호에서 선택됩니다. 키는 E.164 번호여야 합니다. +통화가 도착하면 Voice Call은 일치하는 라우트를 한 번 resolve하고, 일치한 라우트를 통화 +레코드에 저장하며, 인사말, classic 자동 응답 경로, 실시간 상담 경로, TTS 재생에 +그 유효 config를 재사용합니다. 일치하는 라우트가 없으면 전역 Voice Call config가 사용됩니다. +아웃바운드 통화는 `numbers`를 사용하지 않습니다. 통화를 시작할 때 아웃바운드 대상, 메시지, +세션을 명시적으로 전달하세요. 라우트 재정의는 현재 다음을 지원합니다. @@ -490,7 +539,8 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` - `responseSystemPrompt` - `responseTimeoutMs` -`tts` 라우트 값은 전역 Voice Call `tts` 설정 위로 깊은 병합되므로, 보통 제공자 음성만 재정의하면 됩니다. +`tts` 라우트 값은 전역 Voice Call `tts` config 위에 deep-merge되므로, 일반적으로 제공자 +음성만 재정의하면 됩니다. ```json5 { @@ -526,37 +576,39 @@ Voice Call은 통화에서 스트리밍 음성을 위해 코어 `messages.tts` Voice Call은 방어적으로 음성 텍스트를 추출합니다. -- reasoning/오류 콘텐츠로 표시된 페이로드를 무시합니다. -- 직접 JSON, 펜스 처리된 JSON, 인라인 `"spoken"` 키를 파싱합니다. -- 일반 텍스트로 폴백하고, 계획/메타 성격의 도입 단락으로 보이는 내용을 제거합니다. +- reasoning/error 콘텐츠로 표시된 페이로드는 무시합니다. +- 직접 JSON, fenced JSON, 인라인 `"spoken"` 키를 파싱합니다. +- 일반 텍스트로 폴백하고 계획/메타 성격으로 보이는 도입 문단을 제거합니다. -이렇게 하면 음성 재생이 발신자에게 전달할 텍스트에 집중되고 계획 텍스트가 오디오로 유출되는 것을 방지할 수 있습니다. +이렇게 하면 음성 재생이 발신자에게 보여줄 텍스트에 집중되며, +계획 텍스트가 오디오로 유출되는 것을 방지할 수 있습니다. ### 대화 시작 동작 -발신 `conversation` 통화의 경우 첫 메시지 처리는 실시간 재생 상태와 연결됩니다. +아웃바운드 `conversation` 통화의 경우 첫 메시지 처리는 라이브 재생 상태와 연결됩니다. -- 끼어들기 큐 비우기와 자동 응답은 초기 인사말이 실제로 재생 중일 때만 억제됩니다. -- 초기 재생이 실패하면 통화는 `listening`으로 돌아가고 초기 메시지는 재시도를 위해 큐에 남습니다. -- Twilio 스트리밍의 초기 재생은 스트림 연결 시 추가 지연 없이 시작됩니다. -- 끼어들기는 활성 재생을 중단하고 아직 재생되기 전인 큐의 Twilio TTS 항목을 비웁니다. 비워진 항목은 건너뜀으로 해결되므로, 후속 응답 로직은 재생되지 않을 오디오를 기다리지 않고 계속 진행할 수 있습니다. -- 실시간 음성 대화는 실시간 스트림 자체의 시작 턴을 사용합니다. Voice Call은 해당 초기 메시지에 대해 레거시 `` TwiML 업데이트를 게시하지 않으므로, 발신 `` 세션은 연결된 상태로 유지됩니다. +- Barge-in 큐 비우기와 자동 응답은 초기 인사말이 실제로 말해지는 동안에만 억제됩니다. +- 초기 재생이 실패하면 통화는 `listening`으로 돌아가고, 초기 메시지는 재시도를 위해 큐에 남아 있습니다. +- Twilio 스트리밍의 초기 재생은 추가 지연 없이 스트림 연결 시 시작됩니다. +- Barge-in은 활성 재생을 중단하고 큐에 있지만 아직 재생 중이 아닌 Twilio TTS 항목을 비웁니다. 비워진 항목은 건너뜀으로 resolve되므로, 후속 응답 로직은 절대 재생되지 않을 오디오를 기다리지 않고 계속될 수 있습니다. +- 실시간 음성 대화는 실시간 스트림 자체의 opening turn을 사용합니다. Voice Call은 해당 초기 메시지에 대해 레거시 `` TwiML 업데이트를 게시하지 않으므로, 아웃바운드 `` 세션은 계속 연결된 상태로 유지됩니다. ### Twilio 스트림 연결 해제 유예 -Twilio 미디어 스트림 연결이 끊기면, Voice Call은 통화를 자동 종료하기 전에 **2000 ms**를 기다립니다. +Twilio 미디어 스트림 연결이 끊기면 Voice Call은 통화를 자동 종료하기 전에 **2000 ms**를 기다립니다. -- 해당 기간 동안 스트림이 다시 연결되면 자동 종료가 취소됩니다. -- 유예 기간 후에도 스트림이 다시 등록되지 않으면, 통화가 활성 상태로 멈추는 것을 방지하기 위해 통화를 종료합니다. +- 해당 시간 안에 스트림이 다시 연결되면 자동 종료가 취소됩니다. +- 유예 기간 이후 다시 등록되는 스트림이 없으면, 활성 통화가 멈춘 상태로 남는 것을 방지하기 위해 통화가 종료됩니다. -## 오래된 통화 정리기 +## 오래된 통화 reaper -`staleCallReaperSeconds`를 사용해 종료 Webhook을 받지 못한 통화(예: 완료되지 않는 알림 모드 통화)를 종료합니다. 기본값은 `0`(비활성화)입니다. +종료 Webhook을 받지 못한 통화(예: 완료되지 않는 notify-mode 통화)를 종료하려면 +`staleCallReaperSeconds`를 사용하세요. 기본값은 `0`(비활성화)입니다. 권장 범위: -- **프로덕션:** 알림 스타일 흐름에는 `120`-`300`초. -- 정상 통화가 완료될 수 있도록 이 값을 **`maxDurationSeconds`보다 높게** 유지하세요. 좋은 시작점은 `maxDurationSeconds + 30-60`초입니다. +- **프로덕션:** notify 스타일 흐름에는 `120`-`300`초. +- 정상 통화가 끝날 수 있도록 이 값을 **`maxDurationSeconds`보다 높게** 유지하세요. 좋은 시작점은 `maxDurationSeconds + 30-60`초입니다. ```json5 { @@ -575,26 +627,27 @@ Twilio 미디어 스트림 연결이 끊기면, Voice Call은 통화를 자동 ## Webhook 보안 -프록시 또는 터널이 Gateway 앞에 있을 때, Plugin은 서명 검증을 위해 공개 URL을 재구성합니다. 다음 옵션은 신뢰할 전달 헤더를 제어합니다. +프록시 또는 터널이 Gateway 앞에 있을 때 plugin은 서명 검증을 위해 공개 URL을 +재구성합니다. 다음 옵션은 어떤 forwarded header를 신뢰할지 제어합니다. - 전달 헤더의 호스트 허용 목록입니다. + forwarding header의 host allowlist입니다. - 허용 목록 없이 전달 헤더를 신뢰합니다. + allowlist 없이 forwarded header를 신뢰합니다. - 요청의 원격 IP가 목록과 일치할 때만 전달 헤더를 신뢰합니다. + 요청 remote IP가 목록과 일치할 때만 forwarded header를 신뢰합니다. 추가 보호: -- Webhook **재전송 보호**는 Twilio와 Plivo에 활성화되어 있습니다. 재전송된 유효한 Webhook 요청은 승인되지만 부수 효과는 건너뜁니다. -- Twilio 대화 턴은 `` 콜백에 턴별 토큰을 포함하므로, 오래되었거나 재전송된 음성 콜백은 더 최신의 대기 중인 전사 턴을 충족할 수 없습니다. -- 인증되지 않은 Webhook 요청은 제공자의 필수 서명 헤더가 누락된 경우 본문을 읽기 전에 거부됩니다. -- voice-call Webhook은 공유 사전 인증 본문 프로필(64 KB / 5초)과 서명 검증 전 IP별 진행 중 요청 상한을 사용합니다. +- Webhook **replay protection**은 Twilio 및 Plivo에 대해 활성화됩니다. 재전송된 유효 Webhook 요청은 승인되지만 부작용은 건너뜁니다. +- Twilio 대화 turn은 `` 콜백에 turn별 토큰을 포함하므로, 오래되었거나 재전송된 음성 콜백은 더 새로운 대기 중 transcript turn을 만족시킬 수 없습니다. +- 인증되지 않은 Webhook 요청은 제공자의 필수 서명 header가 없을 때 body를 읽기 전에 거부됩니다. +- voice-call Webhook은 서명 검증 전에 공유 pre-auth body profile(64 KB / 5초)과 IP별 in-flight cap을 사용합니다. -안정적인 공개 호스트 예시: +안정적인 공개 host를 사용하는 예시: ```json5 { @@ -628,12 +681,9 @@ openclaw voicecall latency # summarize turn latency from lo openclaw voicecall expose --mode funnel ``` -Gateway가 이미 실행 중이면, 운영용 `voicecall` 명령은 CLI가 두 번째 Webhook 서버에 바인딩하지 않도록 Gateway가 소유한 voice-call 런타임에 위임됩니다. 도달 가능한 Gateway가 없으면, 명령은 독립 실행형 CLI 런타임으로 폴백합니다. +Gateway가 이미 실행 중이면 운영용 `voicecall` 명령은 Gateway가 소유한 음성 통화 런타임에 위임하므로 CLI가 두 번째 Webhook 서버를 바인딩하지 않습니다. Gateway에 연결할 수 없으면 명령은 독립 실행형 CLI 런타임으로 대체됩니다. -`latency`는 기본 음성 통화 저장소 경로에서 `calls.jsonl`을 읽습니다. -다른 로그를 지정하려면 `--file `를 사용하고, 분석을 마지막 N개 레코드로 -제한하려면 `--last `을 사용합니다(기본값 200). 출력에는 턴 지연 시간과 -듣기 대기 시간의 p50/p90/p99가 포함됩니다. +`latency`는 기본 음성 통화 저장소 경로에서 `calls.jsonl`을 읽습니다. 다른 로그를 지정하려면 `--file `를 사용하고, 분석을 마지막 N개 레코드로 제한하려면 `--last `을 사용합니다(기본값 200). 출력에는 턴 지연 시간과 듣기 대기 시간의 p50/p90/p99가 포함됩니다. ## 에이전트 도구 @@ -648,7 +698,7 @@ Gateway가 이미 실행 중이면, 운영용 `voicecall` 명령은 CLI가 두 | `end_call` | `callId` | | `get_status` | `callId` | -이 repo에는 `skills/voice-call/SKILL.md`에 일치하는 Skill 문서가 포함되어 있습니다. +이 저장소는 `skills/voice-call/SKILL.md`에 일치하는 스킬 문서를 함께 제공합니다. ## Gateway RPC @@ -661,12 +711,11 @@ Gateway가 이미 실행 중이면, 운영용 `voicecall` 명령은 CLI가 두 | `voicecall.end` | `callId` | | `voicecall.status` | `callId` | -`dtmfSequence`는 `mode: "conversation"`에서만 유효합니다. 알림 모드 호출에서 -연결 후 숫자가 필요한 경우 호출이 생성된 뒤 `voicecall.dtmf`를 사용해야 합니다. +`dtmfSequence`는 `mode: "conversation"`에서만 유효합니다. 알림 모드 호출에서 연결 후 숫자가 필요한 경우 호출이 존재한 뒤 `voicecall.dtmf`를 사용해야 합니다. ## 문제 해결 -### 설정이 Webhook 노출에 실패함 +### 설정에서 Webhook 노출 실패 Gateway를 실행하는 동일한 환경에서 설정을 실행하세요. @@ -675,16 +724,9 @@ openclaw voicecall setup openclaw voicecall setup --json ``` -`twilio`, `telnyx`, `plivo`의 경우 `webhook-exposure`가 녹색이어야 합니다. -구성된 `publicUrl`이 로컬 또는 사설 네트워크 공간을 가리키는 경우에도 -통신사가 해당 주소로 콜백할 수 없으므로 실패합니다. `publicUrl`로 -`localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, -`192.168.x`, `169.254.x`, `fc00::/7`, `fd00::/8`을 사용하지 마세요. +`twilio`, `telnyx`, `plivo`의 경우 `webhook-exposure`가 녹색이어야 합니다. 구성된 `publicUrl`도 로컬 또는 사설 네트워크 공간을 가리키면 실패합니다. 통신사가 해당 주소로 콜백할 수 없기 때문입니다. `publicUrl`로 `localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, `192.168.x`, `169.254.x`, `fc00::/7`, `fd00::/8`를 사용하지 마세요. -Twilio 알림 모드 발신 호출은 최초 `` TwiML을 생성 호출 요청에서 직접 -보내므로 첫 음성 메시지는 Twilio가 Webhook TwiML을 가져오는 것에 의존하지 -않습니다. 상태 콜백, 대화 호출, 연결 전 DTMF, 실시간 스트림, 연결 후 호출 -제어에는 여전히 공개 Webhook이 필요합니다. +Twilio 알림 모드 발신 호출은 초기 `` TwiML을 생성 호출 요청에 직접 전송하므로 첫 음성 메시지는 Twilio가 Webhook TwiML을 가져오는 것에 의존하지 않습니다. 상태 콜백, 대화 호출, 연결 전 DTMF, 실시간 스트림, 연결 후 호출 제어에는 여전히 공개 Webhook이 필요합니다. 공개 노출 경로 하나를 사용하세요. @@ -706,28 +748,24 @@ Twilio 알림 모드 발신 호출은 최초 `` TwiML을 생성 호출 요 } ``` -구성을 변경한 뒤 Gateway를 다시 시작하거나 다시 로드한 다음 실행하세요. +구성을 변경한 뒤 Gateway를 재시작하거나 다시 로드한 다음 실행하세요. ```bash openclaw voicecall setup openclaw voicecall smoke ``` -`voicecall smoke`는 `--yes`를 전달하지 않는 한 드라이 런입니다. +`--yes`를 전달하지 않으면 `voicecall smoke`는 드라이 런입니다. -### 제공자 자격 증명이 실패함 +### 제공자 자격 증명 실패 선택한 제공자와 필요한 자격 증명 필드를 확인하세요. -- Twilio: `twilio.accountSid`, `twilio.authToken`, `fromNumber` 또는 - `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_FROM_NUMBER`. -- Telnyx: `telnyx.apiKey`, `telnyx.connectionId`, `telnyx.publicKey`, - `fromNumber`. +- Twilio: `twilio.accountSid`, `twilio.authToken`, `fromNumber` 또는 `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_FROM_NUMBER`. +- Telnyx: `telnyx.apiKey`, `telnyx.connectionId`, `telnyx.publicKey`, `fromNumber`. - Plivo: `plivo.authId`, `plivo.authToken`, `fromNumber`. -자격 증명은 Gateway 호스트에 있어야 합니다. 로컬 셸 프로필을 편집해도 -Gateway가 다시 시작되거나 환경을 다시 로드하기 전까지 이미 실행 중인 -Gateway에는 영향을 주지 않습니다. +자격 증명은 Gateway 호스트에 있어야 합니다. 로컬 셸 프로필을 편집해도 Gateway가 재시작되거나 환경을 다시 로드하기 전까지는 이미 실행 중인 Gateway에 영향을 주지 않습니다. ### 호출은 시작되지만 제공자 Webhook이 도착하지 않음 @@ -749,29 +787,24 @@ openclaw logs --follow - `publicUrl`이 `serve.path`와 다른 경로를 가리킵니다. - Gateway가 시작된 뒤 터널 URL이 변경되었습니다. -- 프록시가 요청을 전달하지만 host/proto 헤더를 제거하거나 다시 씁니다. +- 프록시가 요청을 전달하지만 호스트 또는 프로토 헤더를 제거하거나 다시 씁니다. - 방화벽 또는 DNS가 공개 호스트 이름을 Gateway가 아닌 다른 곳으로 라우팅합니다. -- Voice Call Plugin이 활성화되지 않은 상태로 Gateway가 다시 시작되었습니다. +- Voice Call Plugin이 활성화되지 않은 상태로 Gateway가 재시작되었습니다. -Gateway 앞에 리버스 프록시나 터널이 있는 경우 `webhookSecurity.allowedHosts`를 -공개 호스트 이름으로 설정하거나, 알려진 프록시 주소에는 -`webhookSecurity.trustedProxyIPs`를 사용하세요. 프록시 경계가 사용자의 제어 -아래에 있을 때만 `webhookSecurity.trustForwardingHeaders`를 사용하세요. +Gateway 앞에 역방향 프록시나 터널이 있는 경우 `webhookSecurity.allowedHosts`를 공개 호스트 이름으로 설정하거나, 알려진 프록시 주소에는 `webhookSecurity.trustedProxyIPs`를 사용하세요. 프록시 경계를 직접 제어하는 경우에만 `webhookSecurity.trustForwardingHeaders`를 사용하세요. -### 서명 검증이 실패함 +### 서명 검증 실패 -제공자 서명은 OpenClaw가 수신 요청에서 재구성한 공개 URL을 기준으로 확인됩니다. -서명이 실패하면 다음을 확인하세요. +제공자 서명은 OpenClaw가 수신 요청에서 재구성한 공개 URL을 기준으로 확인됩니다. 서명이 실패하는 경우: - 제공자 Webhook URL이 스킴, 호스트, 경로를 포함해 `publicUrl`과 정확히 일치하는지 확인하세요. - ngrok 무료 티어 URL의 경우 터널 호스트 이름이 변경되면 `publicUrl`을 업데이트하세요. -- 프록시가 원래 host 및 proto 헤더를 보존하는지 확인하거나 - `webhookSecurity.allowedHosts`를 구성하세요. -- 로컬 테스트 외부에서는 `skipSignatureVerification`을 활성화하지 마세요. +- 프록시가 원래 호스트와 프로토 헤더를 보존하는지 확인하거나 `webhookSecurity.allowedHosts`를 구성하세요. +- 로컬 테스트 외에는 `skipSignatureVerification`를 활성화하지 마세요. -### Google Meet Twilio 참가가 실패함 +### Google Meet Twilio 참여 실패 -Google Meet은 Twilio 전화 참가에 이 Plugin을 사용합니다. 먼저 Voice Call을 확인하세요. +Google Meet은 Twilio 전화 참여에 이 Plugin을 사용합니다. 먼저 Voice Call을 확인하세요. ```bash openclaw voicecall setup @@ -784,42 +817,33 @@ openclaw voicecall smoke --to "+15555550123" openclaw googlemeet setup --transport twilio ``` -Voice Call은 녹색이지만 Meet 참가자가 참가하지 않는 경우 Meet 전화 접속 번호, -PIN, `--dtmf-sequence`를 확인하세요. 회의가 잘못된 DTMF 시퀀스를 거부하거나 -무시하는 동안에도 전화 통화 자체는 정상일 수 있습니다. +Voice Call은 녹색이지만 Meet 참가자가 참여하지 않는 경우 Meet 전화 접속 번호, PIN, `--dtmf-sequence`를 확인하세요. 전화 통화는 정상이어도 회의가 잘못된 DTMF 시퀀스를 거부하거나 무시할 수 있습니다. -Google Meet은 Meet DTMF 시퀀스와 인트로 텍스트를 `voicecall.start`에 전달합니다. -Twilio 호출의 경우 Voice Call은 DTMF TwiML을 먼저 제공하고, Webhook으로 다시 -리디렉션한 다음, 전화 참가자가 회의에 참가한 뒤 저장된 인트로가 생성되도록 -실시간 미디어 스트림을 엽니다. +Google Meet은 Meet DTMF 시퀀스와 소개 텍스트를 `voicecall.start`에 전달합니다. Twilio 호출의 경우 Voice Call은 DTMF TwiML을 먼저 제공하고 Webhook으로 다시 리디렉션한 다음 실시간 미디어 스트림을 열어, 저장된 소개가 전화 참가자가 회의에 참여한 뒤 생성되도록 합니다. -실시간 단계 추적에는 `openclaw logs --follow`를 사용하세요. 정상적인 Twilio Meet -참가는 이 순서로 로그를 남깁니다. +라이브 단계 추적에는 `openclaw logs --follow`를 사용하세요. 정상적인 Twilio Meet 참여는 다음 순서로 로그를 남깁니다. -- Google Meet이 Twilio 참가를 Voice Call에 위임합니다. +- Google Meet이 Twilio 참여를 Voice Call에 위임합니다. - Voice Call이 연결 전 DTMF TwiML을 저장합니다. -- Twilio 초기 TwiML이 실시간 처리 전에 사용되고 제공됩니다. +- Twilio 초기 TwiML이 실시간 처리 전에 소비되고 제공됩니다. - Voice Call이 Twilio 호출에 실시간 TwiML을 제공합니다. -- 실시간 브리지가 초기 인사를 큐에 넣은 상태로 시작됩니다. +- 실시간 브리지가 초기 인사말을 대기열에 넣은 상태로 시작됩니다. -`openclaw voicecall tail`은 여전히 영구 저장된 호출 레코드를 표시합니다. 호출 -상태와 대화 기록에는 유용하지만, 모든 Webhook/실시간 전환이 여기에 나타나는 -것은 아닙니다. +`openclaw voicecall tail`은 계속 영구 저장된 호출 레코드를 표시합니다. 호출 상태와 대화 기록에는 유용하지만 모든 Webhook/실시간 전환이 여기에 나타나는 것은 아닙니다. ### 실시간 호출에 음성이 없음 -오디오 모드가 하나만 활성화되어 있는지 확인하세요. `realtime.enabled`와 -`streaming.enabled`는 둘 다 true일 수 없습니다. +오디오 모드가 하나만 활성화되어 있는지 확인하세요. `realtime.enabled`와 `streaming.enabled`는 둘 다 `true`일 수 없습니다. 실시간 Twilio 호출의 경우 다음도 확인하세요. -- 실시간 제공자 Plugin이 로드되고 등록되어 있습니다. +- 실시간 제공자 Plugin이 로드되고 등록되었습니다. - `realtime.provider`가 설정되지 않았거나 등록된 제공자 이름입니다. -- 제공자 API 키가 Gateway 프로세스에서 사용할 수 있습니다. -- `openclaw logs --follow`에 실시간 TwiML 제공, 실시간 브리지 시작, 초기 인사 큐 등록이 표시됩니다. +- 제공자 API 키를 Gateway 프로세스에서 사용할 수 있습니다. +- `openclaw logs --follow`에 실시간 TwiML 제공, 실시간 브리지 시작, 초기 인사말 대기열 추가가 표시됩니다. ## 관련 항목 -- [대화 모드](/ko/nodes/talk) +- [Talk 모드](/ko/nodes/talk) - [텍스트 음성 변환](/ko/tools/tts) - [음성 깨우기](/ko/nodes/voicewake) diff --git a/docs/ko/providers/elevenlabs.md b/docs/ko/providers/elevenlabs.md index 83f8d9144..1e15fd0f9 100644 --- a/docs/ko/providers/elevenlabs.md +++ b/docs/ko/providers/elevenlabs.md @@ -1,38 +1,37 @@ --- read_when: - - OpenClaw에서 ElevenLabs text-to-speech를 사용하려고 합니다 - - 오디오 첨부 파일에 ElevenLabs Scribe speech-to-text를 사용하려고 합니다 - - Voice Call에 ElevenLabs 실시간 전사를 사용하려고 합니다 -summary: OpenClaw에서 ElevenLabs 음성, Scribe STT, 실시간 전사를 사용하기 + - OpenClaw에서 ElevenLabs 텍스트 음성 변환을 사용하려는 경우 + - 오디오 첨부 파일에 ElevenLabs Scribe 음성-텍스트 변환을 사용하려는 경우 + - 음성 통화 또는 Google Meet에서 ElevenLabs 실시간 전사를 사용하려는 경우 +summary: OpenClaw에서 ElevenLabs 음성, Scribe STT 및 실시간 전사 사용하기 title: ElevenLabs x-i18n: - generated_at: "2026-04-25T12:28:06Z" - model: gpt-5.4 + generated_at: "2026-05-04T06:24:51Z" + model: gpt-5.5 provider: openai - source_hash: 1f858a344228c6355cd5fdc3775cddac39e0075f2e9fcf7683271f11be03a31a + source_hash: 4c880bf9dcab01ef70779c74576c70ea5d0203b96b5f739291842fafcb4bdb4b source_path: providers/elevenlabs.md - workflow: 15 + workflow: 16 --- -OpenClaw는 text-to-speech, Scribe -v2를 사용한 배치 speech-to-text, Scribe v2 Realtime을 사용한 Voice Call 스트리밍 STT에 ElevenLabs를 사용합니다. +OpenClaw는 텍스트 음성 변환에 ElevenLabs를, Scribe v2를 사용하는 일괄 음성 텍스트 변환과 Scribe v2 Realtime을 사용하는 스트리밍 STT에 ElevenLabs를 사용합니다. -| 기능 | OpenClaw 표면 | 기본값 | -| ------------------------ | --------------------------------------------- | ----------------------- | -| Text-to-speech | `messages.tts` / `talk` | `eleven_multilingual_v2` | -| 배치 speech-to-text | `tools.media.audio` | `scribe_v2` | -| 스트리밍 speech-to-text | Voice Call `streaming.provider: "elevenlabs"` | `scribe_v2_realtime` | +| 기능 | OpenClaw 인터페이스 | 기본값 | +| ------------------------ | -------------------------------------------------------------------- | ------------------------ | +| 텍스트 음성 변환 | `messages.tts` / `talk` | `eleven_multilingual_v2` | +| 일괄 음성 텍스트 변환 | `tools.media.audio` | `scribe_v2` | +| 스트리밍 음성 텍스트 변환 | 음성 통화 스트리밍 또는 Google Meet `realtime.transcriptionProvider` | `scribe_v2_realtime` | ## 인증 -환경 변수에 `ELEVENLABS_API_KEY`를 설정하세요. 기존 ElevenLabs 도구와의 -호환성을 위해 `XI_API_KEY`도 허용됩니다. +환경에서 `ELEVENLABS_API_KEY`를 설정합니다. 기존 ElevenLabs 도구와의 호환성을 위해 +`XI_API_KEY`도 허용됩니다. ```bash export ELEVENLABS_API_KEY="..." ``` -## Text-to-speech +## 텍스트 음성 변환 ```json5 { @@ -50,12 +49,12 @@ export ELEVENLABS_API_KEY="..." } ``` -ElevenLabs v3 TTS를 사용하려면 `modelId`를 `eleven_v3`로 설정하세요. OpenClaw는 -기존 설치를 위해 기본값으로 `eleven_multilingual_v2`를 유지합니다. +ElevenLabs v3 TTS를 사용하려면 `modelId`를 `eleven_v3`로 설정합니다. OpenClaw는 기존 설치를 위해 +`eleven_multilingual_v2`를 기본값으로 유지합니다. -## Speech-to-text +## 음성 텍스트 변환 -인바운드 오디오 첨부 파일과 짧게 녹음된 음성 세그먼트에는 Scribe v2를 사용하세요: +수신 오디오 첨부 파일과 짧게 녹음된 음성 세그먼트에는 Scribe v2를 사용합니다. ```json5 { @@ -70,21 +69,20 @@ ElevenLabs v3 TTS를 사용하려면 `modelId`를 `eleven_v3`로 설정하세요 } ``` -OpenClaw는 multipart 오디오를 `model_id: "scribe_v2"`와 함께 ElevenLabs `/v1/speech-to-text`로 전송합니다. 언어 힌트가 있으면 `language_code`에 매핑됩니다. +OpenClaw는 `model_id: "scribe_v2"`와 함께 multipart 오디오를 ElevenLabs `/v1/speech-to-text`로 보냅니다. 언어 힌트가 있으면 `language_code`에 매핑됩니다. -## Voice Call 스트리밍 STT +## 스트리밍 STT -번들된 `elevenlabs` plugin은 Voice Call -스트리밍 전사를 위해 Scribe v2 Realtime을 등록합니다. +번들 `elevenlabs` Plugin은 음성 통화와 Google Meet 에이전트 모드 스트리밍 전사를 위해 Scribe v2 Realtime을 등록합니다. -| 설정 | 구성 경로 | 기본값 | -| --------------- | ----------------------------------------------------------------------- | ------------------------------------------------- | -| API 키 | `plugins.entries.voice-call.config.streaming.providers.elevenlabs.apiKey` | `ELEVENLABS_API_KEY` / `XI_API_KEY`로 폴백 | -| 모델 | `...elevenlabs.modelId` | `scribe_v2_realtime` | -| 오디오 형식 | `...elevenlabs.audioFormat` | `ulaw_8000` | -| 샘플링 속도 | `...elevenlabs.sampleRate` | `8000` | -| 커밋 전략 | `...elevenlabs.commitStrategy` | `vad` | -| 언어 | `...elevenlabs.languageCode` | (설정되지 않음) | +| 설정 | Config 경로 | 기본값 | +| --------------- | ------------------------------------------------------------------------- | ------------------------------------------------- | +| API 키 | `plugins.entries.voice-call.config.streaming.providers.elevenlabs.apiKey` | 없으면 `ELEVENLABS_API_KEY` / `XI_API_KEY` 사용 | +| 모델 | `...elevenlabs.modelId` | `scribe_v2_realtime` | +| 오디오 형식 | `...elevenlabs.audioFormat` | `ulaw_8000` | +| 샘플 레이트 | `...elevenlabs.sampleRate` | `8000` | +| 커밋 전략 | `...elevenlabs.commitStrategy` | `vad` | +| 언어 | `...elevenlabs.languageCode` | (설정되지 않음) | ```json5 { @@ -112,12 +110,17 @@ OpenClaw는 multipart 오디오를 `model_id: "scribe_v2"`와 함께 ElevenLabs ``` -Voice Call은 Twilio 미디어를 8 kHz G.711 u-law로 수신합니다. ElevenLabs 실시간 -제공자는 기본값으로 `ulaw_8000`을 사용하므로 전화 프레임을 트랜스코딩 없이 -전달할 수 있습니다. +음성 통화는 Twilio 미디어를 8 kHz G.711 u-law로 수신합니다. ElevenLabs realtime +provider는 기본적으로 `ulaw_8000`을 사용하므로, 전화 통신 프레임을 트랜스코딩 없이 전달할 수 있습니다. -## 관련 문서 +Google Meet 에이전트 모드의 경우 +`plugins.entries.google-meet.config.realtime.transcriptionProvider`를 +`"elevenlabs"`로 설정하고 동일한 provider 블록을 +`plugins.entries.google-meet.config.realtime.providers.elevenlabs` 아래에 구성합니다. -- [Text-to-speech](/ko/tools/tts) +## 관련 항목 + +- [텍스트 음성 변환](/ko/tools/tts) +- [Google Meet](/ko/plugins/google-meet) - [모델 선택](/ko/concepts/model-providers) diff --git a/docs/ko/providers/google.md b/docs/ko/providers/google.md index b5d3016d5..285c021dd 100644 --- a/docs/ko/providers/google.md +++ b/docs/ko/providers/google.md @@ -5,37 +5,38 @@ read_when: summary: Google Gemini 설정(API 키 + OAuth, 이미지 생성, 미디어 이해, TTS, 웹 검색) title: Google (Gemini) x-i18n: - generated_at: "2026-05-02T21:11:05Z" + generated_at: "2026-05-04T06:25:04Z" model: gpt-5.5 provider: openai - source_hash: 14605b88f0d1d7e01796d429113a73b2b52a48fde6443565dcb3db47653be5e7 + source_hash: 3e45627f5d5cd57e858c7590a90435b7fc0e9381509f3312a16fc9e9a4cbd908 source_path: providers/google.md workflow: 16 --- -Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 이미지 생성, 미디어 이해(이미지/오디오/비디오), 텍스트 음성 변환, Gemini Grounding을 통한 웹 검색을 제공합니다. +Google Plugin은 Google AI Studio를 통해 Gemini 모델에 접근할 수 있게 해 주며, +이미지 생성, 미디어 이해(이미지/오디오/비디오), 텍스트 음성 변환, Gemini Grounding을 통한 웹 검색도 제공합니다. -- 제공자: `google` -- 인증: `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY` +- Provider: `google` +- Auth: `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY` - API: Google Gemini API -- 런타임 옵션: `agents.defaults.agentRuntime.id: "google-gemini-cli"` - Gemini CLI OAuth를 재사용하면서 모델 참조는 `google/*`로 정규화된 상태로 유지합니다. +- Runtime 옵션: `agents.defaults.agentRuntime.id: "google-gemini-cli"` + Gemini CLI OAuth를 재사용하면서 모델 참조는 `google/*`로 표준화된 상태를 유지합니다. ## 시작하기 -선호하는 인증 방식을 선택하고 설정 단계를 따르세요. +선호하는 인증 방법을 선택하고 설정 단계를 따르세요. - - **적합한 용도:** Google AI Studio를 통한 표준 Gemini API 액세스. + + **적합한 용도:** Google AI Studio를 통한 표준 Gemini API 접근. - + ```bash openclaw onboard --auth-choice gemini-api-key ``` - 또는 키를 직접 전달합니다. + 또는 키를 직접 전달하세요. ```bash openclaw onboard --non-interactive \ @@ -44,7 +45,7 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 --gemini-api-key "$GEMINI_API_KEY" ``` - + ```json5 { agents: { @@ -55,7 +56,7 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 } ``` - + ```bash openclaw models list --provider google ``` @@ -63,7 +64,7 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 - 환경 변수 `GEMINI_API_KEY`와 `GOOGLE_API_KEY`는 모두 허용됩니다. 이미 구성해 둔 것을 사용하세요. + `GEMINI_API_KEY`와 `GOOGLE_API_KEY` 환경 변수는 둘 다 허용됩니다. 이미 구성해 둔 것을 사용하세요. @@ -72,11 +73,12 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 **적합한 용도:** 별도의 API 키 대신 PKCE OAuth를 통해 기존 Gemini CLI 로그인을 재사용. - `google-gemini-cli` 제공자는 비공식 통합입니다. 일부 사용자는 이 방식으로 OAuth를 사용할 때 계정 제한이 발생한다고 보고합니다. 본인 책임하에 사용하세요. + `google-gemini-cli` provider는 비공식 통합입니다. 일부 사용자는 + 이 방식으로 OAuth를 사용할 때 계정 제한이 발생한다고 보고합니다. 본인 책임하에 사용하세요. - + 로컬 `gemini` 명령은 `PATH`에서 사용할 수 있어야 합니다. ```bash @@ -89,12 +91,12 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 OpenClaw는 일반적인 Windows/npm 레이아웃을 포함해 Homebrew 설치와 전역 npm 설치를 모두 지원합니다. - + ```bash openclaw models auth login --provider google-gemini-cli --set-default ``` - + ```bash openclaw models list --provider google ``` @@ -102,10 +104,10 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 - 기본 모델: `google/gemini-3.1-pro-preview` - - 런타임: `google-gemini-cli` + - Runtime: `google-gemini-cli` - 별칭: `gemini-cli` - Gemini 3.1 Pro의 Gemini API 모델 ID는 `gemini-3.1-pro-preview`입니다. OpenClaw는 편의 별칭으로 더 짧은 `google/gemini-3.1-pro`를 허용하며, 제공자 호출 전에 이를 정규화합니다. + Gemini 3.1 Pro의 Gemini API 모델 ID는 `gemini-3.1-pro-preview`입니다. OpenClaw는 편의 별칭으로 더 짧은 `google/gemini-3.1-pro`를 허용하며 provider 호출 전에 이를 정규화합니다. **환경 변수:** @@ -115,21 +117,25 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 (또는 `GEMINI_CLI_*` 변형.) - 로그인 후 Gemini CLI OAuth 요청이 실패하면 Gateway 호스트에 `GOOGLE_CLOUD_PROJECT` 또는 `GOOGLE_CLOUD_PROJECT_ID`를 설정하고 다시 시도하세요. + 로그인 후 Gemini CLI OAuth 요청이 실패하면 Gateway 호스트에서 `GOOGLE_CLOUD_PROJECT` 또는 + `GOOGLE_CLOUD_PROJECT_ID`를 설정한 뒤 다시 시도하세요. - 브라우저 흐름이 시작되기 전에 로그인이 실패하면 로컬 `gemini` 명령이 설치되어 있고 `PATH`에 있는지 확인하세요. + 브라우저 흐름이 시작되기 전에 로그인이 실패하면 로컬 `gemini` + 명령이 설치되어 있고 `PATH`에 있는지 확인하세요. - `google-gemini-cli/*` 모델 참조는 레거시 호환성 별칭입니다. 새 구성에서는 로컬 Gemini CLI 실행을 원할 때 `google/*` 모델 참조와 `google-gemini-cli` 런타임을 사용해야 합니다. + `google-gemini-cli/*` 모델 참조는 레거시 호환성 별칭입니다. 새 + 구성은 로컬 Gemini CLI 실행을 원할 때 `google/*` 모델 참조와 `google-gemini-cli` + Runtime을 함께 사용해야 합니다. ## 기능 -| 기능 | 지원 여부 | +| 기능 | 지원 | | ---------------------- | ----------------------------- | | 채팅 완성 | 예 | | 이미지 생성 | 예 | @@ -145,7 +151,9 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 ## 웹 검색 -번들된 `gemini` 웹 검색 제공자는 Gemini Google Search grounding을 사용합니다. `plugins.entries.google.config.webSearch` 아래에 전용 검색 키를 구성하거나, `GEMINI_API_KEY` 다음에 `models.providers.google.apiKey`를 재사용하게 할 수 있습니다. +번들 `gemini` 웹 검색 provider는 Gemini Google Search grounding을 사용합니다. +`plugins.entries.google.config.webSearch` 아래에 전용 검색 키를 구성하거나, +`GEMINI_API_KEY` 이후 `models.providers.google.apiKey`를 재사용하게 둘 수 있습니다. ```json5 { @@ -165,26 +173,38 @@ Google Plugin은 Google AI Studio를 통한 Gemini 모델 액세스와 함께 } ``` -자격 증명 우선순위는 전용 `webSearch.apiKey`, 그다음 `GEMINI_API_KEY`, 그다음 `models.providers.google.apiKey`입니다. `webSearch.baseUrl`은 선택 사항이며 운영자 프록시 또는 호환되는 Gemini API 엔드포인트를 위해 존재합니다. 생략하면 Gemini 웹 검색은 `models.providers.google.baseUrl`을 재사용합니다. 제공자별 도구 동작은 [Gemini 검색](/ko/tools/gemini-search)을 참조하세요. +자격 증명 우선순위는 전용 `webSearch.apiKey`, 그다음 `GEMINI_API_KEY`, +그다음 `models.providers.google.apiKey`입니다. `webSearch.baseUrl`은 선택 사항이며 +운영자 프록시 또는 호환 Gemini API 엔드포인트용입니다. 생략하면 +Gemini 웹 검색은 `models.providers.google.baseUrl`을 재사용합니다. provider별 도구 동작은 +[Gemini 검색](/ko/tools/gemini-search)을 참조하세요. -Gemini 3 모델은 `thinkingBudget` 대신 `thinkingLevel`을 사용합니다. OpenClaw는 Gemini 3, Gemini 3.1, `gemini-*-latest` 별칭의 추론 제어를 `thinkingLevel`에 매핑하여 기본/저지연 실행에서 비활성화된 `thinkingBudget` 값을 보내지 않도록 합니다. +Gemini 3 모델은 `thinkingBudget` 대신 `thinkingLevel`을 사용합니다. OpenClaw는 +Gemini 3, Gemini 3.1 및 `gemini-*-latest` 별칭 추론 제어를 +`thinkingLevel`에 매핑하므로 기본/저지연 실행에서 비활성화된 +`thinkingBudget` 값을 보내지 않습니다. -`/think adaptive`는 고정 OpenClaw 수준을 선택하는 대신 Google의 동적 사고 의미 체계를 유지합니다. Gemini 3 및 Gemini 3.1은 Google이 수준을 선택할 수 있도록 고정 `thinkingLevel`을 생략합니다. Gemini 2.5는 Google의 동적 센티널 `thinkingBudget: -1`을 보냅니다. +`/think adaptive`는 고정 OpenClaw 수준을 선택하는 대신 Google의 동적 사고 의미 체계를 유지합니다. +Gemini 3 및 Gemini 3.1은 Google이 수준을 선택할 수 있도록 고정 `thinkingLevel`을 생략하며, +Gemini 2.5는 Google의 동적 센티널 `thinkingBudget: -1`을 보냅니다. -Gemma 4 모델(예: `gemma-4-26b-a4b-it`)은 사고 모드를 지원합니다. OpenClaw는 Gemma 4에 대해 `thinkingBudget`을 지원되는 Google `thinkingLevel`로 다시 작성합니다. 사고를 `off`로 설정하면 `MINIMAL`로 매핑하지 않고 사고 비활성화 상태를 유지합니다. +Gemma 4 모델(예: `gemma-4-26b-a4b-it`)은 사고 모드를 지원합니다. OpenClaw는 +Gemma 4에 대해 `thinkingBudget`을 지원되는 Google `thinkingLevel`로 다시 작성합니다. +사고를 `off`로 설정하면 `MINIMAL`로 매핑하지 않고 사고 비활성화 상태를 유지합니다. ## 이미지 생성 -번들된 `google` 이미지 생성 제공자의 기본값은 `google/gemini-3.1-flash-image-preview`입니다. +번들 `google` 이미지 생성 provider는 기본값으로 +`google/gemini-3.1-flash-image-preview`를 사용합니다. - `google/gemini-3-pro-image-preview`도 지원 - 생성: 요청당 최대 4개 이미지 - 편집 모드: 활성화됨, 입력 이미지 최대 5개 - 기하 제어: `size`, `aspectRatio`, `resolution` -Google을 기본 이미지 제공자로 사용하려면: +Google을 기본 이미지 provider로 사용하려면 다음을 설정하세요. ```json5 { @@ -199,19 +219,19 @@ Google을 기본 이미지 제공자로 사용하려면: ``` -공유 도구 매개변수, 제공자 선택, 장애 조치 동작은 [이미지 생성](/ko/tools/image-generation)을 참조하세요. +공유 도구 매개변수, provider 선택, 장애 조치 동작은 [이미지 생성](/ko/tools/image-generation)을 참조하세요. ## 비디오 생성 -번들된 `google` Plugin은 공유 `video_generate` 도구를 통해 비디오 생성도 등록합니다. +번들 `google` Plugin은 공유 `video_generate` 도구를 통해 비디오 생성도 등록합니다. - 기본 비디오 모델: `google/veo-3.1-fast-generate-preview` -- 모드: 텍스트-비디오, 이미지-비디오, 단일 비디오 참조 흐름 +- 모드: 텍스트-비디오, 이미지-비디오 및 단일 비디오 참조 흐름 - `aspectRatio`, `resolution`, `audio` 지원 -- 현재 길이 제한: **4초에서 8초** +- 현재 지속 시간 제한: **4~8초** -Google을 기본 비디오 제공자로 사용하려면: +Google을 기본 비디오 provider로 사용하려면 다음을 설정하세요. ```json5 { @@ -226,21 +246,21 @@ Google을 기본 비디오 제공자로 사용하려면: ``` -공유 도구 매개변수, 제공자 선택, 장애 조치 동작은 [비디오 생성](/ko/tools/video-generation)을 참조하세요. +공유 도구 매개변수, provider 선택, 장애 조치 동작은 [비디오 생성](/ko/tools/video-generation)을 참조하세요. ## 음악 생성 -번들된 `google` Plugin은 공유 `music_generate` 도구를 통해 음악 생성도 등록합니다. +번들 `google` Plugin은 공유 `music_generate` 도구를 통해 음악 생성도 등록합니다. - 기본 음악 모델: `google/lyria-3-clip-preview` - `google/lyria-3-pro-preview`도 지원 - 프롬프트 제어: `lyrics` 및 `instrumental` - 출력 형식: 기본값은 `mp3`, `google/lyria-3-pro-preview`에서는 `wav`도 지원 - 참조 입력: 최대 10개 이미지 -- 세션 기반 실행은 `action: "status"`를 포함해 공유 작업/상태 흐름을 통해 분리됩니다. +- 세션 기반 실행은 `action: "status"`를 포함해 공유 작업/상태 흐름을 통해 분리됩니다 -Google을 기본 음악 제공자로 사용하려면: +Google을 기본 음악 provider로 사용하려면 다음을 설정하세요. ```json5 { @@ -255,19 +275,20 @@ Google을 기본 음악 제공자로 사용하려면: ``` -공유 도구 매개변수, 제공자 선택, 장애 조치 동작은 [음악 생성](/ko/tools/music-generation)을 참조하세요. +공유 도구 매개변수, provider 선택, 장애 조치 동작은 [음악 생성](/ko/tools/music-generation)을 참조하세요. ## 텍스트 음성 변환 -번들된 `google` 음성 제공자는 `gemini-3.1-flash-tts-preview`와 함께 Gemini API TTS 경로를 사용합니다. +번들 `google` 음성 provider는 +`gemini-3.1-flash-tts-preview`와 함께 Gemini API TTS 경로를 사용합니다. - 기본 음성: `Kore` -- 인증: `messages.tts.providers.google.apiKey`, `models.providers.google.apiKey`, `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY` +- Auth: `messages.tts.providers.google.apiKey`, `models.providers.google.apiKey`, `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY` - 출력: 일반 TTS 첨부 파일은 WAV, 음성 메모 대상은 Opus, Talk/전화 통신은 PCM -- 음성 메모 출력: Google PCM은 WAV로 래핑되고 `ffmpeg`로 48 kHz Opus로 트랜스코딩됩니다. +- 음성 메모 출력: Google PCM은 WAV로 래핑되고 `ffmpeg`를 통해 48 kHz Opus로 트랜스코딩됩니다 -Google을 기본 TTS 제공자로 사용하려면: +Google을 기본 TTS provider로 사용하려면 다음을 설정하세요. ```json5 { @@ -287,9 +308,13 @@ Google을 기본 TTS 제공자로 사용하려면: } ``` -Gemini API TTS는 스타일 제어에 자연어 프롬프팅을 사용합니다. 재사용 가능한 스타일 프롬프트를 음성으로 읽을 텍스트 앞에 추가하려면 `audioProfile`을 설정하세요. 프롬프트 텍스트가 이름 있는 화자를 참조할 때는 `speakerName`을 설정하세요. +Gemini API TTS는 스타일 제어에 자연어 프롬프트를 사용합니다. 말할 텍스트 앞에 재사용 가능한 스타일 프롬프트를 붙이려면 +`audioProfile`을 설정하세요. 프롬프트 텍스트가 이름 있는 화자를 참조할 때는 +`speakerName`을 설정하세요. -Gemini API TTS는 텍스트에서 `[whispers]` 또는 `[laughs]` 같은 표현형 대괄호 오디오 태그도 허용합니다. 태그를 보이는 채팅 답변에서는 제외하면서 TTS로 보내려면 `[[tts:text]]...[[/tts:text]]` 블록 안에 넣으세요. +Gemini API TTS는 텍스트 안에서 `[whispers]` 또는 `[laughs]`와 같은 표현용 대괄호 오디오 태그도 허용합니다. +태그를 표시되는 채팅 답장에는 포함하지 않고 TTS로 보내려면 +`[[tts:text]]...[[/tts:text]]` 블록 안에 넣으세요. ```text Here is the clean reply text. @@ -298,25 +323,29 @@ Here is the clean reply text. ``` -Gemini API로 제한된 Google Cloud Console API 키는 이 제공자에 유효합니다. 이는 별도의 Cloud Text-to-Speech API 경로가 아닙니다. +Gemini API로 제한된 Google Cloud Console API 키는 이 provider에 유효합니다. +이는 별도의 Cloud Text-to-Speech API 경로가 아닙니다. ## 실시간 음성 -번들된 `google` Plugin은 Voice Call 및 Google Meet 같은 백엔드 오디오 브리지용 Gemini Live API 기반 실시간 음성 제공자를 등록합니다. +번들 `google` Plugin은 Voice Call 및 Google Meet 같은 백엔드 오디오 브리지용 +Gemini Live API 기반 실시간 음성 provider를 등록합니다. -| 설정 | 구성 경로 | 기본값 | +| 설정 | Config path | 기본값 | | --------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | 모델 | `plugins.entries.voice-call.config.realtime.providers.google.model` | `gemini-2.5-flash-native-audio-preview-12-2025` | | 음성 | `...google.voice` | `Kore` | -| 온도 | `...google.temperature` | (설정되지 않음) | -| VAD 시작 민감도 | `...google.startSensitivity` | (설정되지 않음) | -| VAD 종료 민감도 | `...google.endSensitivity` | (설정되지 않음) | -| 무음 지속 시간 | `...google.silenceDurationMs` | (설정되지 않음) | +| 온도 | `...google.temperature` | (설정 안 됨) | +| VAD 시작 민감도 | `...google.startSensitivity` | (설정 안 됨) | +| VAD 종료 민감도 | `...google.endSensitivity` | (설정 안 됨) | +| 무음 지속 시간 | `...google.silenceDurationMs` | (설정 안 됨) | | 활동 처리 | `...google.activityHandling` | Google 기본값, `start-of-activity-interrupts` | | 턴 범위 | `...google.turnCoverage` | Google 기본값, `only-activity` | | 자동 VAD 비활성화 | `...google.automaticActivityDetectionDisabled` | `false` | -| API 키 | `...google.apiKey` | `models.providers.google.apiKey`, `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY`로 대체됨 | +| 세션 재개 | `...google.sessionResumption` | `true` | +| 컨텍스트 압축 | `...google.contextWindowCompression` | `true` | +| API 키 | `...google.apiKey` | `models.providers.google.apiKey`, `GEMINI_API_KEY` 또는 `GOOGLE_API_KEY`로 대체됨 | Voice Call 실시간 구성 예시: @@ -348,12 +377,12 @@ Voice Call 실시간 구성 예시: Google Live API는 WebSocket을 통해 양방향 오디오와 함수 호출을 사용합니다. -OpenClaw는 전화 통신/Meet 브리지 오디오를 Gemini의 PCM Live API 스트림에 맞게 조정하고 -도구 호출을 공유 실시간 음성 계약에 유지합니다. 샘플링 변경이 필요하지 않다면 `temperature`를 -설정하지 않은 상태로 두세요. Google Live가 `temperature: 0`에서 오디오 없이 전사만 반환할 수 있으므로 -OpenClaw는 양수가 아닌 값을 생략합니다. -Gemini API 전사는 `languageCodes` 없이 활성화됩니다. 현재 Google -SDK는 이 API 경로에서 언어 코드 힌트를 거부합니다. +OpenClaw는 텔레포니/Meet 브리지 오디오를 Gemini의 PCM Live API 스트림에 맞게 조정하고, +공유 실시간 음성 계약에서 도구 호출을 유지합니다. 샘플링 변경이 필요한 경우가 아니면 +`temperature`를 설정하지 않은 상태로 두세요. Google Live는 `temperature: 0`일 때 +오디오 없이 transcript를 반환할 수 있으므로 OpenClaw는 양수가 아닌 값을 생략합니다. +Gemini API transcription은 `languageCodes` 없이 활성화됩니다. 현재 Google SDK는 +이 API 경로에서 언어 코드 힌트를 거부합니다. @@ -362,10 +391,10 @@ Control UI Talk는 제한된 일회용 토큰으로 Google Live 브라우저 세 이 방식은 제공자 자격 증명을 Gateway에 보관합니다. -관리자 실시간 검증을 위해 다음을 실행하세요. -`OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts`. +관리자 라이브 검증을 위해 +`OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts`를 실행하세요. Google 구간은 Control UI Talk에서 사용하는 것과 동일한 제한된 Live API 토큰 형태를 발급하고, -브라우저 WebSocket 엔드포인트를 열고, 초기 설정 페이로드를 보낸 다음, +브라우저 WebSocket 엔드포인트를 열고, 초기 설정 페이로드를 보낸 뒤 `setupComplete`를 기다립니다. ## 고급 구성 @@ -375,10 +404,10 @@ Google 구간은 Control UI Talk에서 사용하는 것과 동일한 제한된 L 직접 Gemini API 실행(`api: "google-generative-ai"`)의 경우 OpenClaw는 구성된 `cachedContent` 핸들을 Gemini 요청으로 전달합니다. - - 모델별 또는 전역 매개변수를 `cachedContent` 또는 레거시 `cached_content`로 구성 - - 둘 다 있으면 `cachedContent`가 우선 적용됨 + - 모델별 또는 전역 params를 `cachedContent` 또는 기존 `cached_content` 중 하나로 구성합니다 + - 둘 다 있으면 `cachedContent`가 우선합니다 - 예시 값: `cachedContents/prebuilt-context` - - Gemini 캐시 적중 사용량은 업스트림 `cachedContentTokenCount`에서 OpenClaw `cacheRead`로 정규화됨 + - Gemini 캐시 적중 사용량은 업스트림 `cachedContentTokenCount`에서 OpenClaw `cacheRead`로 정규화됩니다 ```json5 { @@ -398,22 +427,22 @@ Google 구간은 Control UI Talk에서 사용하는 것과 동일한 제한된 L - + `google-gemini-cli` OAuth 제공자를 사용할 때 OpenClaw는 CLI JSON 출력을 다음과 같이 정규화합니다. - 응답 텍스트는 CLI JSON `response` 필드에서 가져옵니다. - CLI가 `usage`를 비워 두면 사용량은 `stats`로 대체됩니다. - `stats.cached`는 OpenClaw `cacheRead`로 정규화됩니다. - - `stats.input`이 없으면 OpenClaw는 `stats.input_tokens - stats.cached`에서 - 입력 토큰을 도출합니다. + - `stats.input`이 없으면 OpenClaw는 + `stats.input_tokens - stats.cached`에서 입력 토큰을 파생합니다. - + Gateway가 데몬(launchd/systemd)으로 실행되는 경우 `GEMINI_API_KEY`가 해당 프로세스에서 사용 가능해야 합니다. 예를 들어 `~/.openclaw/.env` 또는 - `env.shellEnv`를 통해 제공하세요. + `env.shellEnv`를 통해 설정하세요. diff --git a/docs/ko/security/network-proxy.md b/docs/ko/security/network-proxy.md index e2ac12ec1..023bf4e95 100644 --- a/docs/ko/security/network-proxy.md +++ b/docs/ko/security/network-proxy.md @@ -1,40 +1,40 @@ --- read_when: - - SSRF 및 DNS 리바인딩 공격에 대한 심층 방어가 필요합니다 + - SSRF 및 DNS 리바인딩 공격에 대한 심층 방어가 필요한 경우 - OpenClaw 런타임 트래픽을 위한 외부 포워드 프록시 구성 summary: 운영자가 관리하는 필터링 프록시를 통해 OpenClaw 런타임 HTTP 및 WebSocket 트래픽을 라우팅하는 방법 title: 네트워크 프록시 x-i18n: - generated_at: "2026-05-04T02:25:18Z" + generated_at: "2026-05-04T06:25:10Z" model: gpt-5.5 provider: openai - source_hash: cd5594324e8c6b7da51d903e98fda0feacb8970e0b15d980f7a249d6641461c9 + source_hash: fc7140c5ced0e7454a6f85d1ea8f3256bbd28cc0cb42eeafe8e5e6439b90e3f0 source_path: security/network-proxy.md workflow: 16 --- # 네트워크 프록시 -OpenClaw는 런타임 HTTP 및 WebSocket 트래픽을 운영자가 관리하는 포워드 프록시를 통해 라우팅할 수 있습니다. 이는 중앙 집중식 이그레스 제어, 더 강력한 SSRF 보호, 더 나은 네트워크 감사 가능성을 원하는 배포를 위한 선택적 심층 방어입니다. +OpenClaw는 런타임 HTTP 및 WebSocket 트래픽을 운영자가 관리하는 포워드 프록시를 통해 라우팅할 수 있습니다. 이는 중앙 집중식 이그레스 제어, 더 강력한 SSRF 보호, 더 나은 네트워크 감사 가능성이 필요한 배포 환경을 위한 선택적 심층 방어 수단입니다. -OpenClaw는 프록시를 제공하거나, 다운로드하거나, 시작하거나, 구성하거나, 인증하지 않습니다. 사용자의 환경에 맞는 프록시 기술을 직접 실행하면, OpenClaw는 일반적인 프로세스 로컬 HTTP 및 WebSocket 클라이언트를 그 프록시를 통해 라우팅합니다. +OpenClaw는 프록시를 제공, 다운로드, 시작, 구성 또는 인증하지 않습니다. 환경에 맞는 프록시 기술을 직접 운영하며, OpenClaw는 일반적인 프로세스 로컬 HTTP 및 WebSocket 클라이언트를 그 프록시를 통해 라우팅합니다. -## 왜 프록시를 사용하나요? +## 프록시를 사용하는 이유 -프록시는 운영자에게 아웃바운드 HTTP 및 WebSocket 트래픽에 대한 단일 네트워크 제어 지점을 제공합니다. 이는 SSRF 강화 이외의 상황에서도 유용할 수 있습니다. +프록시는 운영자에게 아웃바운드 HTTP 및 WebSocket 트래픽을 제어하는 단일 네트워크 지점을 제공합니다. 이는 SSRF 강화 외의 상황에서도 유용할 수 있습니다. -- 중앙 정책: 모든 애플리케이션 HTTP 호출 지점이 네트워크 규칙을 올바르게 처리하도록 의존하는 대신 하나의 이그레스 정책을 유지합니다. -- 연결 시점 검사: DNS 확인 후, 프록시가 업스트림 연결을 열기 직전에 대상을 평가합니다. +- 중앙 정책: 모든 애플리케이션 HTTP 호출 지점이 네트워크 규칙을 올바르게 적용하는 것에 의존하지 않고 하나의 이그레스 정책을 유지합니다. +- 연결 시점 검사: DNS 해석 후, 프록시가 업스트림 연결을 열기 직전에 목적지를 평가합니다. - DNS 리바인딩 방어: 애플리케이션 수준 DNS 검사와 실제 아웃바운드 연결 사이의 간격을 줄입니다. -- 더 넓은 JavaScript 적용 범위: 일반적인 `fetch`, `node:http`, `node:https`, WebSocket, axios, got, node-fetch 및 유사 클라이언트를 같은 경로로 라우팅합니다. -- 감사 가능성: 이그레스 경계에서 허용 및 거부된 대상을 기록합니다. -- 운영 제어: OpenClaw를 다시 빌드하지 않고 대상 규칙, 네트워크 세분화, 속도 제한 또는 아웃바운드 허용 목록을 적용합니다. +- 더 넓은 JavaScript 적용 범위: 일반적인 `fetch`, `node:http`, `node:https`, WebSocket, axios, got, node-fetch 및 유사한 클라이언트를 동일한 경로로 라우팅합니다. +- 감사 가능성: 이그레스 경계에서 허용 및 거부된 목적지를 기록합니다. +- 운영 제어: OpenClaw를 다시 빌드하지 않고 목적지 규칙, 네트워크 세분화, 속도 제한 또는 아웃바운드 허용 목록을 적용합니다. -프록시 라우팅은 일반 HTTP 및 WebSocket 이그레스에 대한 프로세스 수준 가드레일입니다. 운영자가 지원되는 JavaScript HTTP 클라이언트를 자체 필터링 프록시를 통해 라우팅할 수 있는 실패 시 차단 경로를 제공하지만, 이는 OS 수준 네트워크 샌드박스가 아니며 OpenClaw가 프록시의 대상 정책을 인증한다는 의미도 아닙니다. +프록시 라우팅은 일반 HTTP 및 WebSocket 이그레스에 대한 프로세스 수준 보호 장치입니다. 운영자에게 지원되는 JavaScript HTTP 클라이언트를 자체 필터링 프록시를 통해 라우팅하는 실패 시 폐쇄 경로를 제공하지만, OS 수준 네트워크 샌드박스는 아니며 OpenClaw가 프록시의 목적지 정책을 인증하게 만들지는 않습니다. ## OpenClaw가 트래픽을 라우팅하는 방식 -`proxy.enabled=true`이고 프록시 URL이 구성되어 있으면, `openclaw gateway run`, `openclaw node run`, `openclaw agent --local` 같은 보호된 런타임 프로세스는 일반 HTTP 및 WebSocket 이그레스를 구성된 프록시를 통해 라우팅합니다. +`proxy.enabled=true`이고 프록시 URL이 구성되면 `openclaw gateway run`, `openclaw node run`, `openclaw agent --local` 같은 보호된 런타임 프로세스는 일반 HTTP 및 WebSocket 이그레스를 구성된 프록시를 통해 라우팅합니다. ```text OpenClaw process @@ -43,27 +43,27 @@ OpenClaw process WebSocket clients -> operator-managed filtering proxy -> public internet ``` -공개 계약은 이를 구현하는 데 사용되는 내부 Node 훅이 아니라 라우팅 동작입니다. OpenClaw Gateway 제어 평면 WebSocket 클라이언트는 Gateway URL이 `localhost` 또는 `127.0.0.1`이나 `[::1]` 같은 리터럴 루프백 IP를 사용할 때 local loopback Gateway RPC 트래픽에 대해 좁은 직접 경로를 사용합니다. 이 제어 평면 경로는 운영자 프록시가 루프백 대상을 차단하더라도 루프백 Gateway에 도달할 수 있어야 합니다. 일반 런타임 HTTP 및 WebSocket 요청은 계속 구성된 프록시를 사용합니다. +공개 계약은 이를 구현하는 데 사용되는 내부 Node 훅이 아니라 라우팅 동작입니다. OpenClaw Gateway 제어 평면 WebSocket 클라이언트는 Gateway URL이 `localhost` 또는 `127.0.0.1`이나 `[::1]` 같은 리터럴 루프백 IP를 사용할 때 local loopback Gateway RPC 트래픽에 대해 좁은 직접 경로를 사용합니다. 이 제어 평면 경로는 운영자 프록시가 루프백 목적지를 차단하더라도 루프백 Gateway에 도달할 수 있어야 합니다. 일반 런타임 HTTP 및 WebSocket 요청은 계속 구성된 프록시를 사용합니다. -내부적으로 OpenClaw는 이 기능에 두 가지 프로세스 수준 라우팅 훅을 사용합니다. +내부적으로 OpenClaw는 이 기능에 대해 두 가지 프로세스 수준 라우팅 훅을 사용합니다. - Undici 디스패처 라우팅은 `fetch`, undici 기반 클라이언트, 자체 undici 디스패처를 제공하는 전송 계층을 처리합니다. -- `global-agent` 라우팅은 `http.request`, `https.request`, `http.get`, `https.get` 위에 구성된 많은 라이브러리를 포함하여 Node 코어 `node:http` 및 `node:https` 호출자를 처리합니다. 관리형 프록시 모드는 명시적 Node HTTP 에이전트가 실수로 운영자 프록시를 우회하지 않도록 해당 전역 에이전트를 강제합니다. +- `global-agent` 라우팅은 `http.request`, `https.request`, `http.get`, `https.get` 위에 구성된 많은 라이브러리를 포함해 Node 코어 `node:http` 및 `node:https` 호출자를 처리합니다. 관리형 프록시 모드는 명시적 Node HTTP 에이전트가 운영자 프록시를 실수로 우회하지 않도록 해당 전역 에이전트를 강제합니다. -일부 Plugin은 프로세스 수준 라우팅이 존재하더라도 명시적 프록시 연결이 필요한 사용자 지정 전송 계층을 소유합니다. 예를 들어 Telegram의 Bot API 전송 계층은 자체 HTTP/1 undici 디스패처를 사용하므로, 해당 소유자별 전송 경로에서 프로세스 프록시 환경과 관리형 `OPENCLAW_PROXY_URL` 폴백을 따릅니다. +일부 Plugin은 프로세스 수준 라우팅이 존재하더라도 명시적인 프록시 연결이 필요한 사용자 지정 전송 계층을 소유합니다. 예를 들어 Telegram의 Bot API 전송 계층은 자체 HTTP/1 undici 디스패처를 사용하므로 해당 소유자별 전송 경로에서 프로세스 프록시 환경과 관리형 `OPENCLAW_PROXY_URL` 대체 값을 따릅니다. -프록시 URL 자체는 `http://`를 사용해야 합니다. HTTPS 대상은 여전히 HTTP `CONNECT`를 통해 프록시에서 지원됩니다. 이는 OpenClaw가 `http://127.0.0.1:3128` 같은 일반 HTTP 포워드 프록시 리스너를 기대한다는 뜻일 뿐입니다. +프록시 URL 자체는 `http://`를 사용해야 합니다. HTTPS 목적지는 HTTP `CONNECT`를 통해 프록시에서 계속 지원됩니다. 이는 OpenClaw가 `http://127.0.0.1:3128` 같은 일반 HTTP 포워드 프록시 리스너를 기대한다는 의미일 뿐입니다. -프록시가 활성화된 동안 OpenClaw는 `no_proxy`, `NO_PROXY`, `GLOBAL_AGENT_NO_PROXY`를 지웁니다. 이러한 우회 목록은 대상 기반이므로, 거기에 `localhost` 또는 `127.0.0.1`이 남아 있으면 고위험 SSRF 대상이 필터링 프록시를 건너뛸 수 있습니다. +프록시가 활성화된 동안 OpenClaw는 `no_proxy`, `NO_PROXY`, `GLOBAL_AGENT_NO_PROXY`를 비웁니다. 이러한 우회 목록은 목적지 기반이므로, 여기에 `localhost` 또는 `127.0.0.1`이 남아 있으면 고위험 SSRF 대상이 필터링 프록시를 건너뛸 수 있습니다. 종료 시 OpenClaw는 이전 프록시 환경을 복원하고 캐시된 프로세스 라우팅 상태를 재설정합니다. ## 관련 프록시 용어 - `proxy.enabled` / `proxy.proxyUrl`: OpenClaw 런타임 이그레스를 위한 아웃바운드 포워드 프록시 라우팅입니다. 이 페이지는 해당 기능을 문서화합니다. -- `gateway.auth.mode: "trusted-proxy"`: Gateway 접근을 위한 인바운드 ID 인식 리버스 프록시 인증입니다. [신뢰할 수 있는 프록시 인증](/ko/gateway/trusted-proxy-auth)을 참조하세요. -- `openclaw proxy`: 개발 및 지원을 위한 로컬 디버그 프록시와 캡처 검사기입니다. [openclaw proxy](/ko/cli/proxy)를 참조하세요. -- 채널 또는 공급자별 프록시 설정: 특정 전송 계층에 대한 소유자별 오버라이드입니다. 목표가 런타임 전반의 중앙 이그레스 제어라면 관리형 네트워크 프록시를 선호하세요. +- `gateway.auth.mode: "trusted-proxy"`: Gateway 액세스를 위한 인바운드 ID 인식 리버스 프록시 인증입니다. [신뢰할 수 있는 프록시 인증](/ko/gateway/trusted-proxy-auth)을 참고하세요. +- `openclaw proxy`: 개발 및 지원을 위한 로컬 디버그 프록시와 캡처 검사기입니다. [openclaw proxy](/ko/cli/proxy)를 참고하세요. +- 채널 또는 공급자별 프록시 설정: 특정 전송 계층에 대한 소유자별 재정의입니다. 목표가 런타임 전반의 중앙 이그레스 제어라면 관리형 네트워크 프록시를 선호하세요. ## 구성 @@ -81,9 +81,9 @@ OPENCLAW_PROXY_URL=http://127.0.0.1:3128 openclaw gateway run `proxy.proxyUrl`은 `OPENCLAW_PROXY_URL`보다 우선합니다. -`enabled=true`이지만 유효한 프록시 URL이 구성되어 있지 않으면, 보호된 명령은 직접 네트워크 접근으로 폴백하는 대신 시작에 실패합니다. +`enabled=true`이지만 유효한 프록시 URL이 구성되지 않은 경우 보호된 명령은 직접 네트워크 액세스로 대체하지 않고 시작에 실패합니다. -`openclaw gateway start`로 시작되는 관리형 Gateway 서비스의 경우 URL을 구성에 저장하는 방식을 선호하세요. +`openclaw gateway start`로 시작되는 관리형 게이트웨이 서비스의 경우 URL을 구성에 저장하는 것을 권장합니다. ```bash openclaw config set proxy.enabled true @@ -92,30 +92,30 @@ openclaw gateway install --force openclaw gateway start ``` -환경 폴백은 포그라운드 실행에 가장 적합합니다. 설치된 서비스에서 이를 사용하는 경우, `OPENCLAW_PROXY_URL`을 `$OPENCLAW_STATE_DIR/.env` 또는 `~/.openclaw/.env` 같은 서비스의 지속 환경에 넣은 다음 서비스를 다시 설치하여 launchd, systemd 또는 Scheduled Tasks가 해당 값으로 Gateway를 시작하도록 하세요. +환경 대체 값은 포그라운드 실행에 가장 적합합니다. 설치된 서비스와 함께 사용하는 경우 `OPENCLAW_PROXY_URL`을 `$OPENCLAW_STATE_DIR/.env` 또는 `~/.openclaw/.env` 같은 서비스의 영구 환경에 넣은 다음, launchd, systemd 또는 Scheduled Tasks가 해당 값으로 게이트웨이를 시작하도록 서비스를 다시 설치하세요. -`openclaw --container ...` 명령의 경우, OpenClaw는 설정된 `OPENCLAW_PROXY_URL`을 컨테이너 대상 하위 CLI로 전달합니다. URL은 컨테이너 내부에서 도달 가능해야 합니다. `127.0.0.1`은 호스트가 아니라 컨테이너 자체를 가리킵니다. OpenClaw는 사용자가 해당 안전 검사를 명시적으로 오버라이드하지 않는 한 컨테이너 대상 명령에 대한 루프백 프록시 URL을 거부합니다. +`openclaw --container ...` 명령의 경우 설정되어 있으면 OpenClaw가 `OPENCLAW_PROXY_URL`을 컨테이너 대상 자식 CLI로 전달합니다. URL은 컨테이너 내부에서 도달 가능해야 합니다. `127.0.0.1`은 호스트가 아니라 컨테이너 자체를 가리킵니다. 명시적으로 해당 안전 검사를 재정의하지 않는 한 OpenClaw는 컨테이너 대상 명령에 대해 루프백 프록시 URL을 거부합니다. ## 프록시 요구 사항 프록시 정책이 보안 경계입니다. OpenClaw는 프록시가 올바른 대상을 차단하는지 확인할 수 없습니다. -프록시를 다음과 같이 구성하세요. +프록시는 다음과 같이 구성하세요. -- 루프백 또는 신뢰할 수 있는 비공개 인터페이스에만 바인딩합니다. -- OpenClaw 프로세스, 호스트, 컨테이너 또는 서비스 계정만 사용할 수 있도록 접근을 제한합니다. -- 대상을 자체적으로 확인하고 DNS 확인 후 대상 IP를 차단합니다. +- 루프백 또는 비공개 신뢰 인터페이스에만 바인딩합니다. +- OpenClaw 프로세스, 호스트, 컨테이너 또는 서비스 계정만 사용할 수 있도록 액세스를 제한합니다. +- 목적지를 자체적으로 해석하고 DNS 해석 후 목적지 IP를 차단합니다. - 일반 HTTP 요청과 HTTPS `CONNECT` 터널 모두에 대해 연결 시점에 정책을 적용합니다. -- 루프백, 비공개, 링크 로컬, 메타데이터, 멀티캐스트, 예약 또는 문서화 범위에 대한 대상 기반 우회를 거부합니다. -- DNS 확인 경로를 완전히 신뢰하지 않는 한 호스트 이름 허용 목록을 피합니다. -- 요청 본문, 인증 헤더, 쿠키 또는 기타 비밀을 기록하지 않고 대상, 결정, 상태 및 이유를 기록합니다. -- 프록시 정책을 버전 관리하에 두고 보안에 민감한 구성처럼 변경 사항을 검토합니다. +- 루프백, 비공개, 링크 로컬, 메타데이터, 멀티캐스트, 예약 또는 문서화 범위에 대한 목적지 기반 우회를 거부합니다. +- DNS 해석 경로를 완전히 신뢰하지 않는 한 호스트 이름 허용 목록은 피합니다. +- 요청 본문, 인증 헤더, 쿠키 또는 기타 비밀을 기록하지 않고 목적지, 결정, 상태 및 이유를 기록합니다. +- 프록시 정책을 버전 관리하고 보안에 민감한 구성처럼 변경 사항을 검토합니다. -## 권장 차단 대상 +## 권장 차단 목적지 -이 거부 목록을 모든 포워드 프록시, 방화벽 또는 이그레스 정책의 시작점으로 사용하세요. +모든 포워드 프록시, 방화벽 또는 이그레스 정책의 시작점으로 이 거부 목록을 사용하세요. -OpenClaw 애플리케이션 수준 분류기 로직은 `src/infra/net/ssrf.ts` 및 `src/shared/net/ip.ts`에 있습니다. 관련 패리티 훅은 `BLOCKED_HOSTNAMES`, `BLOCKED_IPV4_SPECIAL_USE_RANGES`, `BLOCKED_IPV6_SPECIAL_USE_RANGES`, `RFC2544_BENCHMARK_PREFIX`, 그리고 NAT64, 6to4, Teredo, ISATAP 및 IPv4 매핑 형식에 대한 내장 IPv4 센티널 처리입니다. 이러한 파일은 외부 프록시 정책을 유지 관리할 때 유용한 참고 자료이지만, OpenClaw가 해당 규칙을 사용자의 프록시에 자동으로 내보내거나 적용하지는 않습니다. +OpenClaw 애플리케이션 수준 분류기 로직은 `src/infra/net/ssrf.ts` 및 `src/shared/net/ip.ts`에 있습니다. 관련 패리티 훅은 `BLOCKED_HOSTNAMES`, `BLOCKED_IPV4_SPECIAL_USE_RANGES`, `BLOCKED_IPV6_SPECIAL_USE_RANGES`, `RFC2544_BENCHMARK_PREFIX`, 그리고 NAT64, 6to4, Teredo, ISATAP, IPv4 매핑 형식에 대한 내장 IPv4 센티널 처리입니다. 이러한 파일은 외부 프록시 정책을 유지 관리할 때 유용한 참고 자료이지만, OpenClaw는 해당 규칙을 프록시로 자동 내보내거나 강제하지 않습니다. | 범위 또는 호스트 | 차단 이유 | | ------------------------------------------------------------------------------------ | ---------------------------------------------------- | @@ -125,18 +125,18 @@ OpenClaw 애플리케이션 수준 분류기 로직은 `src/infra/net/ssrf.ts` | `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` | RFC1918 비공개 네트워크 | | `169.254.0.0/16`, `fe80::/10` | 링크 로컬 주소 및 일반적인 클라우드 메타데이터 경로 | | `169.254.169.254`, `metadata.google.internal` | 클라우드 메타데이터 서비스 | -| `100.64.0.0/10` | 캐리어급 NAT 공유 주소 공간 | +| `100.64.0.0/10` | 캐리어급 NAT 공유 주소 공간 | | `198.18.0.0/15`, `2001:2::/48` | 벤치마킹 범위 | | `192.0.0.0/24`, `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`, `2001:db8::/32` | 특수 용도 및 문서화 범위 | -| `224.0.0.0/4`, `ff00::/8` | 멀티캐스트 | +| `224.0.0.0/4`, `ff00::/8` | 멀티캐스트 | | `240.0.0.0/4` | 예약된 IPv4 | | `fc00::/7`, `fec0::/10` | IPv6 로컬/비공개 범위 | | `100::/64`, `2001:20::/28` | IPv6 폐기 및 ORCHIDv2 범위 | -| `64:ff9b::/96`, `64:ff9b:1::/48` | 내장 IPv4가 포함된 NAT64 접두사 | -| `2002::/16`, `2001::/32` | 내장 IPv4가 포함된 6to4 및 Teredo | +| `64:ff9b::/96`, `64:ff9b:1::/48` | 내장 IPv4가 있는 NAT64 접두사 | +| `2002::/16`, `2001::/32` | 내장 IPv4가 있는 6to4 및 Teredo | | `::/96`, `::ffff:0:0/96` | IPv4 호환 및 IPv4 매핑 IPv6 | -클라우드 공급자 또는 네트워크 플랫폼이 추가 메타데이터 호스트나 예약 범위를 문서화한 경우, 그것들도 추가하세요. +클라우드 공급자 또는 네트워크 플랫폼이 추가 메타데이터 호스트나 예약 범위를 문서화하는 경우 해당 항목도 추가하세요. ## 검증 @@ -146,9 +146,9 @@ OpenClaw를 실행하는 동일한 호스트, 컨테이너 또는 서비스 계 openclaw proxy validate --proxy-url http://127.0.0.1:3128 ``` -기본적으로 사용자 지정 대상이 제공되지 않으면, 명령은 `https://example.com/`이 성공하는지 확인하고 프록시가 도달해서는 안 되는 임시 루프백 카나리를 시작합니다. 기본 거부 검사는 프록시가 2xx가 아닌 거부 응답을 반환하거나 전송 실패로 카나리를 차단하면 통과합니다. 성공 응답이 카나리에 도달하면 실패합니다. 프록시가 활성화되고 구성되어 있지 않으면 검증은 구성 문제를 보고합니다. 구성을 변경하기 전 일회성 사전 점검에는 `--proxy-url`을 사용하세요. 배포별 기대 사항을 테스트하려면 `--allowed-url` 및 `--denied-url`을 사용하세요. 사용자 지정 거부 대상은 실패 시 차단됩니다. 어떤 HTTP 응답이든 대상이 프록시를 통해 도달 가능했다는 의미이며, 어떤 전송 오류든 OpenClaw가 프록시가 도달 가능한 원본을 차단했음을 증명할 수 없기 때문에 결론 불가로 보고됩니다. 검증 실패 시 명령은 코드 1로 종료됩니다. +기본적으로 사용자 지정 목적지가 제공되지 않으면 이 명령은 `https://example.com/`이 성공하는지 확인하고 프록시가 도달해서는 안 되는 임시 루프백 카나리를 시작합니다. 기본 거부 검사는 프록시가 2xx가 아닌 거부 응답을 반환하거나 전송 실패로 카나리를 차단하면 통과합니다. 성공 응답이 카나리에 도달하면 실패합니다. 프록시가 활성화 및 구성되어 있지 않으면 검증은 구성 문제를 보고합니다. 구성을 변경하기 전 일회성 사전 검사에는 `--proxy-url`을 사용하세요. 배포별 기대치를 테스트하려면 `--allowed-url` 및 `--denied-url`을 사용하세요. 사용자 지정 거부 목적지는 실패 시 폐쇄 방식입니다. HTTP 응답이 있으면 해당 목적지가 프록시를 통해 도달 가능했다는 의미이며, 모든 전송 오류는 OpenClaw가 프록시가 도달 가능한 원본을 차단했음을 증명할 수 없기 때문에 결론 불가로 보고됩니다. 검증 실패 시 명령은 코드 1로 종료됩니다. -자동화에는 `--json`을 사용하세요. JSON 출력에는 전체 결과, 유효한 프록시 구성 소스, 구성 오류 및 각 대상 검사가 포함됩니다. 프록시 URL 자격 증명은 텍스트 및 JSON 출력에서 수정 처리됩니다. +자동화에는 `--json`을 사용하세요. JSON 출력에는 전체 결과, 유효한 프록시 구성 소스, 구성 오류 및 각 목적지 검사가 포함됩니다. 프록시 URL 자격 증명은 텍스트 및 JSON 출력에서 편집 처리됩니다. ```json { @@ -170,7 +170,7 @@ openclaw proxy validate --proxy-url http://127.0.0.1:3128 } ``` -`curl`로 수동 검증할 수도 있습니다. +수동으로 `curl`을 사용해 검증할 수도 있습니다. ```bash curl -x http://127.0.0.1:3128 https://example.com/ @@ -178,7 +178,7 @@ curl -x http://127.0.0.1:3128 http://127.0.0.1/ curl -x http://127.0.0.1:3128 http://169.254.169.254/ ``` -공개 요청은 성공해야 합니다. 루프백 및 메타데이터 요청은 프록시에 의해 차단되어야 합니다. `openclaw proxy validate`의 경우, 내장 루프백 카나리아는 프록시 거부와 도달 가능한 원본을 구분할 수 있습니다. 사용자 지정 `--denied-url` 검사에는 해당 카나리아가 없으므로, 프록시가 별도로 검증할 수 있는 배포별 거부 신호를 노출하지 않는 한 HTTP 응답과 모호한 전송 실패를 모두 검증 실패로 처리하세요. +공개 요청은 성공해야 합니다. 루프백 및 메타데이터 요청은 프록시에서 차단되어야 합니다. `openclaw proxy validate`의 경우, 내장 루프백 카나리는 프록시 거부와 도달 가능한 오리진을 구분할 수 있습니다. 사용자 지정 `--denied-url` 검사는 해당 카나리가 없으므로, 프록시가 별도로 검증할 수 있는 배포별 거부 신호를 노출하지 않는 한 HTTP 응답과 모호한 전송 실패를 모두 검증 실패로 간주하세요. 그런 다음 OpenClaw 프록시 라우팅을 활성화합니다. @@ -200,8 +200,9 @@ proxy: - 프록시는 프로세스 로컬 JavaScript HTTP 및 WebSocket 클라이언트에 대한 적용 범위를 개선하지만, OS 수준 네트워크 샌드박스는 아닙니다. - 원시 `net`, `tls`, `http2` 소켓, 네이티브 애드온, 자식 프로세스는 프록시 환경 변수를 상속하고 준수하지 않는 한 Node 수준 프록시 라우팅을 우회할 수 있습니다. -- IRC는 운영자가 관리하는 전달 프록시 라우팅 외부의 원시 TCP/TLS 채널입니다. 모든 송신 트래픽이 해당 전달 프록시를 거쳐야 하는 배포에서는 직접 IRC 송신이 명시적으로 승인되지 않는 한 `channels.irc.enabled=false`를 설정하세요. -- 사용자 로컬 WebUI와 로컬 모델 서버는 필요할 때 운영자 프록시 정책의 허용 목록에 추가해야 합니다. OpenClaw는 이를 위한 일반적인 로컬 네트워크 우회를 노출하지 않습니다. -- Gateway 제어 평면 프록시 우회는 의도적으로 `localhost`와 리터럴 루프백 IP URL로 제한됩니다. 로컬 직접 Gateway 제어 평면 연결에는 `ws://127.0.0.1:18789`, `ws://[::1]:18789` 또는 `ws://localhost:18789`를 사용하세요. 다른 호스트 이름은 일반적인 호스트 이름 기반 트래픽처럼 라우팅됩니다. -- OpenClaw는 프록시 정책을 검사하거나 테스트하거나 인증하지 않습니다. +- IRC는 운영자 관리형 포워드 프록시 라우팅 외부의 원시 TCP/TLS 채널입니다. 모든 송신 트래픽이 해당 포워드 프록시를 거쳐야 하는 배포에서는 직접 IRC 송신이 명시적으로 승인되지 않는 한 `channels.irc.enabled=false`를 설정하세요. +- 로컬 디버그 프록시는 진단 도구이며, 프록시 요청과 CONNECT 터널에 대한 직접 업스트림 전달은 관리형 프록시 모드가 활성화된 동안 기본적으로 비활성화됩니다. 승인된 로컬 진단에만 직접 전달을 활성화하세요. +- 사용자 로컬 WebUI와 로컬 모델 서버는 필요한 경우 운영자 프록시 정책에서 허용 목록에 등록해야 합니다. OpenClaw는 이를 위한 일반적인 로컬 네트워크 우회를 노출하지 않습니다. +- Gateway 제어 플레인 프록시 우회는 의도적으로 `localhost` 및 리터럴 루프백 IP URL로 제한됩니다. 로컬 직접 Gateway 제어 플레인 연결에는 `ws://127.0.0.1:18789`, `ws://[::1]:18789` 또는 `ws://localhost:18789`를 사용하세요. 다른 호스트 이름은 일반적인 호스트 이름 기반 트래픽처럼 라우팅됩니다. +- OpenClaw는 사용자의 프록시 정책을 검사, 테스트 또는 인증하지 않습니다. - 프록시 정책 변경은 보안에 민감한 운영 변경으로 취급하세요. diff --git a/docs/ko/tools/subagents.md b/docs/ko/tools/subagents.md index 2a8731f45..db4e056de 100644 --- a/docs/ko/tools/subagents.md +++ b/docs/ko/tools/subagents.md @@ -2,44 +2,45 @@ read_when: - 에이전트를 통해 백그라운드 작업이나 병렬 작업을 실행하려는 경우 - sessions_spawn 또는 하위 에이전트 도구 정책을 변경하고 있습니다 - - 스레드에 바인딩된 서브에이전트 세션을 구현하거나 문제를 해결하는 중입니다 + - 스레드에 바인딩된 하위 에이전트 세션을 구현하거나 문제를 해결하는 경우 sidebarTitle: Sub-agents -summary: 결과를 요청자 채팅으로 다시 알리는 격리된 백그라운드 에이전트 실행을 생성합니다 +summary: 결과를 요청자 채팅에 다시 알리는 격리된 백그라운드 에이전트 실행 생성 title: 하위 에이전트 x-i18n: - generated_at: "2026-05-04T02:26:10Z" + generated_at: "2026-05-04T06:25:39Z" model: gpt-5.5 provider: openai - source_hash: d0df39e06b952def3eb0b296f36c7dc8c0b0a115785d865236a970c5d453fc37 + source_hash: 65d60bf6813d667b7311aa28109d4bd6be012a16e638c64cfff130831db88cd8 source_path: tools/subagents.md workflow: 16 --- 하위 에이전트는 기존 에이전트 실행에서 생성되는 백그라운드 에이전트 실행입니다. -각자의 세션(`agent::subagent:`)에서 실행되며, +자체 세션(`agent::subagent:`)에서 실행되며, 완료되면 결과를 요청자 채팅 채널로 **알립니다**. -각 하위 에이전트 실행은 [백그라운드 작업](/ko/automation/tasks)으로 추적됩니다. +각 하위 에이전트 실행은 +[백그라운드 작업](/ko/automation/tasks)으로 추적됩니다. 주요 목표: -- 기본 실행을 차단하지 않고 "조사 / 장기 작업 / 느린 도구" 작업을 병렬화합니다. -- 기본적으로 하위 에이전트를 격리된 상태로 유지합니다(세션 분리 + 선택적 샌드박싱). -- 도구 표면을 오용하기 어렵게 유지합니다. 하위 에이전트에는 기본적으로 세션 도구가 제공되지 **않습니다**. +- 기본 실행을 차단하지 않고 "조사 / 긴 작업 / 느린 도구" 작업을 병렬화합니다. +- 하위 에이전트를 기본적으로 격리합니다(세션 분리 + 선택적 샌드박싱). +- 도구 표면이 오용되기 어렵게 유지합니다. 하위 에이전트는 기본적으로 세션 도구를 받지 **않습니다**. - 오케스트레이터 패턴을 위한 구성 가능한 중첩 깊이를 지원합니다. -**비용 참고:** 기본적으로 각 하위 에이전트에는 자체 컨텍스트와 토큰 사용량이 있습니다. -무겁거나 반복적인 작업의 경우 하위 에이전트에는 더 저렴한 모델을 설정하고 +**비용 참고:** 각 하위 에이전트는 기본적으로 자체 컨텍스트와 토큰 사용량을 가집니다. +무겁거나 반복적인 작업의 경우 하위 에이전트에는 더 저렴한 모델을 설정하고, 기본 에이전트는 더 높은 품질의 모델로 유지하세요. `agents.defaults.subagents.model` -또는 에이전트별 재정의를 통해 구성합니다. 자식이 요청자의 현재 transcript가 - 실제로 필요한 경우, 에이전트는 해당 생성 한 번에 대해 `context: "fork"`를 요청할 수 있습니다. - 스레드 바인딩된 하위 에이전트 세션은 현재 대화를 후속 스레드로 분기하므로 - 기본값이 `context: "fork"`입니다. +또는 에이전트별 재정의를 통해 구성합니다. 자식이 요청자의 현재 트랜스크립트를 +실제로 필요로 하는 경우, 에이전트는 해당 생성에 대해 `context: "fork"`를 +요청할 수 있습니다. 스레드에 바인딩된 하위 에이전트 세션은 현재 대화를 +후속 스레드로 분기하므로 기본값이 `context: "fork"`입니다. ## 슬래시 명령 -**현재 세션**의 하위 에이전트 실행을 검사하거나 제어하려면 `/subagents`를 사용하세요. +`/subagents`를 사용하여 **현재 세션**의 하위 에이전트 실행을 검사하거나 제어합니다. ```text /subagents list @@ -51,17 +52,17 @@ x-i18n: /subagents spawn [--model ] [--thinking ] ``` -현재 요청자 세션의 활성 실행을 조종하려면 최상위 [`/steer `](/ko/tools/steer)를 사용하세요. 대상이 자식 실행이면 `/subagents steer `를 사용하세요. +현재 요청자 세션의 활성 실행을 조종하려면 최상위 [`/steer `](/ko/tools/steer)를 사용합니다. 대상이 자식 실행인 경우 `/subagents steer `를 사용합니다. `/subagents info`는 실행 메타데이터(상태, 타임스탬프, 세션 ID, -transcript 경로, 정리)를 표시합니다. 제한되고 안전 필터링된 회수 보기는 -`sessions_history`를 사용하고, 원시 전체 transcript가 필요할 때는 디스크의 -transcript 경로를 검사하세요. +트랜스크립트 경로, 정리)를 표시합니다. 범위가 제한되고 안전 필터링된 +회상 보기는 `sessions_history`를 사용하세요. 원시 전체 트랜스크립트가 +필요하면 디스크의 트랜스크립트 경로를 검사하세요. ### 스레드 바인딩 제어 이 명령은 영구 스레드 바인딩을 지원하는 채널에서 작동합니다. -아래의 [스레드 지원 채널](#thread-supporting-channels)을 참조하세요. +아래 [스레드를 지원하는 채널](#thread-supporting-channels)을 참조하세요. ```text /focus @@ -73,54 +74,55 @@ transcript 경로를 검사하세요. ### 생성 동작 -`/subagents spawn`은 내부 릴레이가 아닌 사용자 명령으로 백그라운드 하위 에이전트를 시작하고, -실행이 끝나면 요청자 채팅으로 최종 완료 업데이트 하나를 보냅니다. +`/subagents spawn`은 백그라운드 하위 에이전트를 사용자 명령(내부 릴레이가 아님)으로 시작하고, +실행이 완료되면 요청자 채팅으로 최종 완료 업데이트 하나를 보냅니다. - - - 생성 명령은 비차단 방식이며, 실행 ID를 즉시 반환합니다. - - 완료 시 하위 에이전트는 요약/결과 메시지를 요청자 채팅 채널로 알립니다. - - 완료는 푸시 기반입니다. 생성된 후에는 완료를 기다리기 위해 `/subagents list`, `sessions_list`, 또는 `sessions_history`를 루프에서 폴링하지 **마세요**. 디버깅이나 개입이 필요할 때만 온디맨드로 상태를 검사하세요. - - 완료 시 OpenClaw는 알림 정리 흐름이 계속되기 전에 해당 하위 에이전트 세션이 연 추적된 브라우저 탭/프로세스를 최선 노력으로 닫습니다. + + - 생성 명령은 비차단 방식이며, 즉시 실행 ID를 반환합니다. + - 완료 시 하위 에이전트는 요청자 채팅 채널로 요약/결과 메시지를 알립니다. + - 완료는 푸시 기반입니다. 생성된 후에는 완료를 기다리기 위해 `/subagents list`, `sessions_list`, `sessions_history`를 루프로 폴링하지 **마세요**. 디버깅이나 개입이 필요할 때만 필요에 따라 상태를 검사하세요. + - 완료 시 OpenClaw는 알림 정리 흐름이 계속되기 전에 해당 하위 에이전트 세션이 연 추적된 브라우저 탭/프로세스를 최선의 노력으로 닫습니다. - - - OpenClaw는 안정적인 멱등성 키로 직접 `agent` 전달을 먼저 시도합니다. - - 직접 전달이 실패하면 큐 라우팅으로 폴백합니다. + + - OpenClaw는 안정적인 멱등성 키를 사용해 먼저 직접 `agent` 전달을 시도합니다. + - 요청자 에이전트 완료 턴이 실패하거나, 표시 가능한 출력을 생성하지 않거나, 캡처된 자식 결과의 명백히 불완전한 접두사만 반환하면 OpenClaw는 캡처된 자식 결과에서 직접 완료 전달로 대체합니다. + - 직접 전달을 사용할 수 없으면 큐 라우팅으로 대체합니다. - 큐 라우팅도 여전히 사용할 수 없으면 최종 포기 전에 짧은 지수 백오프로 알림을 재시도합니다. - - 완료 전달은 확인된 요청자 경로를 유지합니다. 스레드 바인딩 또는 대화 바인딩 완료 경로가 사용 가능하면 우선하며, 완료 출처가 채널만 제공하는 경우 OpenClaw는 요청자 세션의 확인된 경로(`lastChannel` / `lastTo` / `lastAccountId`)에서 누락된 대상/계정을 채워 직접 전달이 계속 작동하도록 합니다. + - 완료 전달은 확인된 요청자 라우트를 유지합니다. 사용 가능한 경우 스레드 바인딩 또는 대화 바인딩 완료 라우트가 우선합니다. 완료 출처가 채널만 제공하는 경우 OpenClaw는 요청자 세션의 확인된 라우트(`lastChannel` / `lastTo` / `lastAccountId`)에서 누락된 대상/계정을 채워 직접 전달이 계속 작동하도록 합니다. - - 요청자 세션으로의 완료 인계는 런타임에서 생성한 내부 컨텍스트(사용자가 작성한 텍스트가 아님)이며 다음을 포함합니다. + + 요청자 세션으로의 완료 핸드오프는 런타임에서 생성된 내부 컨텍스트(사용자가 작성한 텍스트가 아님)이며 다음을 포함합니다. - - `Result` — 최신 가시 `assistant` 응답 텍스트, 없으면 정리된 최신 도구/toolResult 텍스트입니다. 종료된 실패 실행은 캡처된 응답 텍스트를 재사용하지 않습니다. + - `Result` — 최신 표시 가능한 `assistant` 응답 텍스트, 없으면 정리된 최신 도구/toolResult 텍스트. 터미널 실패 실행은 캡처된 응답 텍스트를 재사용하지 않습니다. - `Status` — `completed successfully` / `failed` / `timed out` / `unknown`. - - 간결한 런타임/토큰 통계. - - 요청자 에이전트에게 원시 내부 메타데이터를 전달하지 말고 일반 assistant 음성으로 다시 쓰라고 지시하는 전달 지침. + - 압축된 런타임/토큰 통계. + - 요청자 에이전트가 원시 내부 메타데이터를 전달하지 않고 일반 assistant 음성으로 다시 작성하도록 지시하는 전달 지침. - - - `--model`과 `--thinking`은 해당 특정 실행의 기본값을 재정의합니다. - - 완료 후 세부 정보와 출력을 검사하려면 `info`/`log`를 사용하세요. - - `/subagents spawn`은 일회성 모드(`mode: "run"`)입니다. 영구 스레드 바인딩 세션의 경우 `thread: true` 및 `mode: "session"`과 함께 `sessions_spawn`을 사용하세요. - - ACP 하네스 세션(Claude Code, Gemini CLI, OpenCode, 또는 명시적 Codex ACP/acpx)의 경우 도구가 해당 런타임을 알릴 때 `runtime: "acp"`와 함께 `sessions_spawn`을 사용하세요. 완료나 에이전트 간 루프를 디버깅할 때는 [ACP 전달 모델](/ko/tools/acp-agents#delivery-model)을 참조하세요. `codex` Plugin이 활성화된 경우, 사용자가 ACP/acpx를 명시적으로 요청하지 않는 한 Codex 채팅/스레드 제어는 ACP보다 `/codex ...`를 선호해야 합니다. - - OpenClaw는 ACP가 활성화되고, 요청자가 샌드박스 처리되어 있지 않으며, `acpx` 같은 백엔드 Plugin이 로드될 때까지 `runtime: "acp"`를 숨깁니다. `runtime: "acp"`는 외부 ACP 하네스 ID 또는 `runtime.type="acp"`인 `agents.list[]` 항목을 기대합니다. `agents_list`의 일반 OpenClaw 구성 에이전트에는 기본 하위 에이전트 런타임을 사용하세요. + + - `--model` 및 `--thinking`은 해당 특정 실행의 기본값을 재정의합니다. + - 완료 후 세부 정보와 출력을 검사하려면 `info`/`log`를 사용합니다. + - `/subagents spawn`은 일회성 모드(`mode: "run"`)입니다. 영구 스레드 바인딩 세션의 경우 `thread: true` 및 `mode: "session"`과 함께 `sessions_spawn`을 사용합니다. + - ACP 하네스 세션(Claude Code, Gemini CLI, OpenCode 또는 명시적 Codex ACP/acpx)의 경우, 도구가 해당 런타임을 광고할 때 `runtime: "acp"`와 함께 `sessions_spawn`을 사용합니다. 완료 또는 에이전트 간 루프를 디버깅할 때 [ACP 전달 모델](/ko/tools/acp-agents#delivery-model)을 참조하세요. `codex` Plugin이 활성화된 경우 사용자가 ACP/acpx를 명시적으로 요청하지 않는 한 Codex 채팅/스레드 제어는 ACP보다 `/codex ...`를 선호해야 합니다. + - OpenClaw는 ACP가 활성화되고, 요청자가 샌드박스 처리되지 않았으며, `acpx` 같은 백엔드 Plugin이 로드될 때까지 `runtime: "acp"`를 숨깁니다. `runtime: "acp"`는 외부 ACP 하네스 ID 또는 `runtime.type="acp"`인 `agents.list[]` 항목을 기대합니다. `agents_list`의 일반 OpenClaw 구성 에이전트에는 기본 하위 에이전트 런타임을 사용하세요. ## 컨텍스트 모드 -네이티브 하위 에이전트는 호출자가 현재 transcript를 포크하도록 명시적으로 요청하지 않는 한 격리된 상태로 시작합니다. +네이티브 하위 에이전트는 호출자가 현재 트랜스크립트 포크를 명시적으로 요청하지 않는 한 격리된 상태로 시작합니다. | 모드 | 사용 시점 | 동작 | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -| `isolated` | 새로운 조사, 독립 구현, 느린 도구 작업, 또는 작업 텍스트로 간략히 설명할 수 있는 모든 작업 | 깨끗한 자식 transcript를 만듭니다. 이것이 기본값이며 토큰 사용량을 낮게 유지합니다. | -| `fork` | 현재 대화, 이전 도구 결과, 또는 요청자 transcript에 이미 있는 미묘한 지침에 의존하는 작업 | 자식이 시작되기 전에 요청자 transcript를 자식 세션으로 분기합니다. | +| `isolated` | 새로운 조사, 독립 구현, 느린 도구 작업 또는 작업 텍스트로 간단히 설명할 수 있는 모든 작업 | 깨끗한 자식 트랜스크립트를 생성합니다. 기본값이며 토큰 사용량을 낮게 유지합니다. | +| `fork` | 현재 대화, 이전 도구 결과 또는 요청자 트랜스크립트에 이미 있는 세부 지침에 의존하는 작업 | 요청자 트랜스크립트를 자식 세션으로 분기한 뒤 자식을 시작합니다. | `fork`는 아껴서 사용하세요. 이는 컨텍스트에 민감한 위임을 위한 것이며, -명확한 작업 프롬프트 작성의 대체물이 아닙니다. +명확한 작업 프롬프트 작성을 대체하지 않습니다. ## 도구: `sessions_spawn` @@ -129,16 +131,16 @@ transcript 경로를 검사하세요. 사용 가능 여부는 호출자의 유효 도구 정책에 따라 달라집니다. `coding` 및 `full` 프로필은 기본적으로 `sessions_spawn`을 노출합니다. `messaging` 프로필은 -그렇지 않습니다. 작업을 위임해야 하는 에이전트에는 `tools.alsoAllow: ["sessions_spawn", "sessions_yield", +노출하지 않습니다. 작업을 위임해야 하는 에이전트에는 `tools.alsoAllow: ["sessions_spawn", "sessions_yield", "subagents"]`를 추가하거나 `tools.profile: "coding"`을 사용하세요. -채널/그룹, 제공자, 샌드박스, 에이전트별 허용/거부 정책은 프로필 단계 이후에도 +채널/그룹, 공급자, 샌드박스, 에이전트별 허용/거부 정책은 프로필 단계 이후에도 도구를 제거할 수 있습니다. 유효 도구 목록을 확인하려면 같은 세션에서 `/tools`를 사용하세요. **기본값:** -- **모델:** `agents.defaults.subagents.model`(또는 에이전트별 `agents.list[].subagents.model`)을 설정하지 않으면 호출자를 상속합니다. 명시적 `sessions_spawn.model`이 여전히 우선합니다. -- **Thinking:** `agents.defaults.subagents.thinking`(또는 에이전트별 `agents.list[].subagents.thinking`)을 설정하지 않으면 호출자를 상속합니다. 명시적 `sessions_spawn.thinking`이 여전히 우선합니다. -- **실행 제한 시간:** `sessions_spawn.runTimeoutSeconds`가 생략되면 OpenClaw는 설정된 경우 `agents.defaults.subagents.runTimeoutSeconds`를 사용하고, 그렇지 않으면 `0`(제한 시간 없음)으로 폴백합니다. +- **모델:** `agents.defaults.subagents.model`(또는 에이전트별 `agents.list[].subagents.model`)을 설정하지 않는 한 호출자를 상속합니다. 명시적 `sessions_spawn.model`이 있으면 여전히 우선합니다. +- **Thinking:** `agents.defaults.subagents.thinking`(또는 에이전트별 `agents.list[].subagents.thinking`)을 설정하지 않는 한 호출자를 상속합니다. 명시적 `sessions_spawn.thinking`이 있으면 여전히 우선합니다. +- **실행 시간 제한:** `sessions_spawn.runTimeoutSeconds`가 생략되면 OpenClaw는 설정된 경우 `agents.defaults.subagents.runTimeoutSeconds`를 사용하고, 그렇지 않으면 `0`(시간 제한 없음)으로 대체합니다. ### 도구 매개변수 @@ -149,40 +151,40 @@ transcript 경로를 검사하세요. 선택적 사람이 읽을 수 있는 레이블입니다. - `subagents.allowAgents`에서 허용되는 경우 다른 에이전트 ID 아래에서 생성합니다. + `subagents.allowAgents`에서 허용되는 경우 다른 에이전트 ID 아래에 생성합니다. - `acp`는 외부 ACP 하네스(`claude`, `droid`, `gemini`, `opencode`, 또는 명시적으로 요청된 Codex ACP/acpx)와 `runtime.type`이 `acp`인 `agents.list[]` 항목에만 사용됩니다. + `acp`는 외부 ACP 하네스(`claude`, `droid`, `gemini`, `opencode` 또는 명시적으로 요청된 Codex ACP/acpx)와 `runtime.type`이 `acp`인 `agents.list[]` 항목에만 사용됩니다. - ACP 전용입니다. `runtime: "acp"`일 때 기존 ACP 하네스 세션을 재개하며, 네이티브 하위 에이전트 생성에서는 무시됩니다. + ACP 전용입니다. `runtime: "acp"`일 때 기존 ACP 하네스 세션을 재개합니다. 네이티브 하위 에이전트 생성에서는 무시됩니다. - ACP 전용입니다. `runtime: "acp"`일 때 ACP 실행 출력을 부모 세션으로 스트리밍합니다. 네이티브 하위 에이전트 생성에서는 생략하세요. + ACP 전용입니다. `runtime: "acp"`일 때 ACP 실행 출력을 상위 세션으로 스트리밍합니다. 네이티브 하위 에이전트 생성에서는 생략하세요. - 하위 에이전트 모델을 재정의합니다. 유효하지 않은 값은 건너뛰며, 하위 에이전트는 도구 결과에 경고를 남기고 기본 모델로 실행됩니다. + 하위 에이전트 모델을 재정의합니다. 유효하지 않은 값은 건너뛰며 하위 에이전트는 도구 결과에 경고를 남기고 기본 모델로 실행됩니다. 하위 에이전트 실행의 thinking 수준을 재정의합니다. - 설정된 경우 기본값은 `agents.defaults.subagents.runTimeoutSeconds`이고, 그렇지 않으면 `0`입니다. 설정하면 하위 에이전트 실행은 N초 후 중단됩니다. + 설정된 경우 기본값은 `agents.defaults.subagents.runTimeoutSeconds`이며, 그렇지 않으면 `0`입니다. 설정하면 하위 에이전트 실행은 N초 후 중단됩니다. - `true`이면 이 하위 에이전트 세션에 채널 스레드 바인딩을 요청합니다. + `true`이면 이 하위 에이전트 세션에 대한 채널 스레드 바인딩을 요청합니다. `thread: true`이고 `mode`가 생략되면 기본값은 `session`이 됩니다. `mode: "session"`에는 `thread: true`가 필요합니다. - `"delete"`는 알림 직후 아카이브합니다(이름 변경을 통해 transcript는 여전히 유지). + `"delete"`는 알림 직후 아카이브합니다(이름 변경을 통해 트랜스크립트는 계속 유지). - `require`는 대상 자식 런타임이 샌드박스 처리되어 있지 않으면 생성을 거부합니다. + `require`는 대상 자식 런타임이 샌드박스 처리되지 않은 경우 생성을 거부합니다. - `fork`는 요청자의 현재 transcript를 자식 세션으로 분기합니다. 네이티브 하위 에이전트 전용입니다. 스레드 바인딩 생성은 기본값이 `fork`이고, 비스레드 생성은 기본값이 `isolated`입니다. + `fork`는 요청자의 현재 트랜스크립트를 자식 세션으로 분기합니다. 네이티브 하위 에이전트 전용입니다. 스레드 바인딩 생성의 기본값은 `fork`이고, 비스레드 생성의 기본값은 `isolated`입니다. @@ -193,15 +195,14 @@ transcript 경로를 검사하세요. ## 스레드 바인딩 세션 -채널에 스레드 바인딩이 활성화되어 있으면, 하위 에이전트는 스레드에 바인딩된 상태로 유지되어 -해당 스레드의 후속 사용자 메시지가 같은 하위 에이전트 세션으로 계속 라우팅되도록 할 수 있습니다. +채널에 스레드 바인딩이 활성화되어 있으면, 하위 에이전트가 스레드에 계속 바인딩되어 +해당 스레드의 후속 사용자 메시지가 같은 하위 에이전트 세션으로 계속 라우팅될 수 있습니다. -### 스레드 지원 채널 +### 스레드를 지원하는 채널 -**Discord**가 현재 유일하게 지원되는 채널입니다. 영구 스레드 바인딩 하위 에이전트 세션(`thread: true`와 함께 `sessions_spawn`), -수동 스레드 제어(`/focus`, `/unfocus`, `/agents`, -`/session idle`, `/session max-age`), 그리고 어댑터 키 -`channels.discord.threadBindings.enabled`, +**Discord**는 현재 지원되는 유일한 채널입니다. 영구 스레드 바인딩 하위 에이전트 세션(`thread: true`와 함께 `sessions_spawn`), +수동 스레드 제어(`/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age`), +그리고 어댑터 키 `channels.discord.threadBindings.enabled`, `channels.discord.threadBindings.idleHours`, `channels.discord.threadBindings.maxAgeHours`, 및 `channels.discord.threadBindings.spawnSessions`를 지원합니다. @@ -209,49 +210,49 @@ transcript 경로를 검사하세요. ### 빠른 흐름 - - `thread: true`(선택적으로 `mode: "session"` 포함)와 함께 `sessions_spawn`. + + `sessions_spawn`을 `thread: true`(그리고 선택적으로 `mode: "session"`)와 함께 사용합니다. - - OpenClaw는 활성 채널에서 해당 세션 대상에 스레드를 생성하거나 바인딩합니다. + + OpenClaw는 활성 채널에서 해당 세션 대상에 스레드를 만들거나 바인딩합니다. - + 해당 스레드의 답장과 후속 메시지는 바인딩된 세션으로 라우팅됩니다. - - 비활성 자동 unfocus를 검사/업데이트하려면 `/session idle`을 사용하고, - 하드 상한을 제어하려면 `/session max-age`를 사용하세요. + + `/session idle`을 사용해 비활동 자동 언포커스를 확인/업데이트하고 + `/session max-age`로 하드 상한을 제어합니다. - - 수동으로 분리하려면 `/unfocus`를 사용하세요. + + `/unfocus`를 사용해 수동으로 분리합니다. ### 수동 제어 -| 명령어 | 효과 | +| 명령 | 효과 | | ------------------ | --------------------------------------------------------------------- | -| `/focus ` | 현재 스레드를 하위 에이전트/세션 대상에 바인딩하거나 새로 만듭니다 | -| `/unfocus` | 현재 바인딩된 스레드의 바인딩을 제거합니다 | -| `/agents` | 활성 실행과 바인딩 상태(`thread:` 또는 `unbound`)를 나열합니다 | -| `/session idle` | 유휴 자동 포커스 해제를 검사/업데이트합니다(포커스된 바인딩 스레드만) | -| `/session max-age` | 하드 한도를 검사/업데이트합니다(포커스된 바인딩 스레드만) | +| `/focus ` | 현재 스레드(또는 새로 만든 스레드)를 하위 에이전트/세션 대상에 바인딩 | +| `/unfocus` | 현재 바인딩된 스레드의 바인딩 제거 | +| `/agents` | 활성 실행 및 바인딩 상태(`thread:` 또는 `unbound`) 나열 | +| `/session idle` | 유휴 자동 언포커스 확인/업데이트(포커스된 바인딩 스레드만 해당) | +| `/session max-age` | 하드 상한 확인/업데이트(포커스된 바인딩 스레드만 해당) | ### 구성 스위치 - **전역 기본값:** `session.threadBindings.enabled`, `session.threadBindings.idleHours`, `session.threadBindings.maxAgeHours`. -- **채널 재정의 및 생성 자동 바인딩 키**는 어댑터별로 다릅니다. 위의 [스레드 지원 채널](#thread-supporting-channels)을 참조하세요. +- **채널 재정의 및 생성 자동 바인딩 키**는 어댑터별로 다릅니다. 위의 [스레드 지원 채널](#thread-supporting-channels)을 참고하세요. 현재 어댑터 세부 정보는 [구성 참조](/ko/gateway/configuration-reference) 및 -[슬래시 명령어](/ko/tools/slash-commands)를 참조하세요. +[슬래시 명령](/ko/tools/slash-commands)을 참고하세요. ### 허용 목록 - 명시적 `agentId`를 통해 대상으로 지정할 수 있는 에이전트 id 목록입니다(`["*"]`는 모두 허용). 기본값: 요청자 에이전트만. 목록을 설정하면서 요청자가 `agentId`로 자기 자신을 생성하도록 하려면, 목록에 요청자 id를 포함하세요. + 명시적 `agentId`를 통해 대상으로 지정할 수 있는 에이전트 ID 목록입니다(`["*"]`는 모두 허용). 기본값: 요청자 에이전트만. 목록을 설정하면서 요청자가 `agentId`로 자신을 생성할 수 있게 하려면 목록에 요청자 ID를 포함하세요. - 요청자 에이전트가 자체 `subagents.allowAgents`를 설정하지 않을 때 사용되는 기본 대상 에이전트 허용 목록입니다. + 요청자 에이전트가 자체 `subagents.allowAgents`를 설정하지 않았을 때 사용되는 기본 대상 에이전트 허용 목록입니다. `agentId`를 생략한 `sessions_spawn` 호출을 차단합니다(명시적 프로필 선택 강제). 에이전트별 재정의: `agents.list[].subagents.requireAgentId`. @@ -262,26 +263,26 @@ transcript 경로를 검사하세요. ### 검색 -`sessions_spawn`에 현재 허용된 에이전트 id를 보려면 `agents_list`를 사용하세요. -응답에는 각 나열된 에이전트의 유효 모델과 포함된 런타임 메타데이터가 포함되므로 -호출자는 PI, Codex app-server 및 기타 구성된 네이티브 런타임을 구분할 수 있습니다. +`sessions_spawn`에 현재 허용된 에이전트 ID를 확인하려면 `agents_list`를 사용하세요. +응답에는 나열된 각 에이전트의 유효 모델과 내장 런타임 메타데이터가 포함되어 +호출자가 PI, Codex 앱 서버, 기타 구성된 네이티브 런타임을 구분할 수 있습니다. -### 자동 아카이브 +### 자동 보관 -- 하위 에이전트 세션은 `agents.defaults.subagents.archiveAfterMinutes` 이후 자동으로 아카이브됩니다(기본값 `60`). -- 아카이브는 `sessions.delete`를 사용하고 트랜스크립트 이름을 `*.deleted.`로 바꿉니다(같은 폴더). -- `cleanup: "delete"`는 알림 직후 아카이브합니다(그래도 이름 변경을 통해 트랜스크립트는 유지). -- 자동 아카이브는 최선 노력 방식입니다. Gateway가 다시 시작되면 대기 중인 타이머는 손실됩니다. -- `runTimeoutSeconds`는 자동 아카이브하지 않습니다. 실행만 중지합니다. 세션은 자동 아카이브될 때까지 유지됩니다. -- 자동 아카이브는 깊이 1 및 깊이 2 세션에 동일하게 적용됩니다. -- 브라우저 정리는 아카이브 정리와 별개입니다. 트랜스크립트/세션 레코드가 유지되더라도, 추적된 브라우저 탭/프로세스는 실행이 완료되면 최선 노력 방식으로 닫힙니다. +- 하위 에이전트 세션은 `agents.defaults.subagents.archiveAfterMinutes` 이후 자동으로 보관됩니다(기본값 `60`). +- 보관은 `sessions.delete`를 사용하며 transcript 이름을 `*.deleted.`로 변경합니다(같은 폴더). +- `cleanup: "delete"`는 알림 직후 즉시 보관합니다(transcript는 이름 변경으로 계속 보존). +- 자동 보관은 최선형입니다. Gateway가 다시 시작되면 대기 중인 타이머는 손실됩니다. +- `runTimeoutSeconds`는 자동 보관하지 않습니다. 실행만 중지합니다. 세션은 자동 보관될 때까지 남아 있습니다. +- 자동 보관은 깊이 1 및 깊이 2 세션에 동일하게 적용됩니다. +- 브라우저 정리는 보관 정리와 별개입니다. 추적되는 브라우저 탭/프로세스는 transcript/세션 레코드가 유지되더라도 실행이 끝나면 최선형으로 닫힙니다. -## 중첩된 하위 에이전트 +## 중첩 하위 에이전트 기본적으로 하위 에이전트는 자체 하위 에이전트를 생성할 수 없습니다 -(`maxSpawnDepth: 1`). 한 수준의 중첩을 활성화하려면 `maxSpawnDepth: 2`를 설정하세요. -이는 **오케스트레이터 패턴**입니다: 메인 → 오케스트레이터 하위 에이전트 → -작업자 하위-하위 에이전트. +(`maxSpawnDepth: 1`). 한 수준의 중첩을 활성화하려면 `maxSpawnDepth: 2`를 +설정하세요. 즉 **오케스트레이터 패턴**: 메인 → 오케스트레이터 하위 에이전트 → +작업자 하위-하위 에이전트입니다. ```json5 { @@ -300,103 +301,103 @@ transcript 경로를 검사하세요. ### 깊이 수준 -| 깊이 | 세션 키 형태 | 역할 | 생성 가능 여부 | -| ----- | -------------------------------------------- | --------------------------------------------- | ---------------------------- | -| 0 | `agent::main` | 메인 에이전트 | 항상 | -| 1 | `agent::subagent:` | 하위 에이전트(깊이 2가 허용되면 오케스트레이터) | `maxSpawnDepth >= 2`인 경우에만 | -| 2 | `agent::subagent::subagent:` | 하위-하위 에이전트(리프 작업자) | 불가 | +| 깊이 | 세션 키 형태 | 역할 | 생성 가능 여부 | +| ---- | --------------------------------------------- | --------------------------------------------------- | --------------------------- | +| 0 | `agent::main` | 메인 에이전트 | 항상 | +| 1 | `agent::subagent:` | 하위 에이전트(깊이 2가 허용되면 오케스트레이터) | `maxSpawnDepth >= 2`인 경우만 | +| 2 | `agent::subagent::subagent:` | 하위-하위 에이전트(리프 작업자) | 불가 | ### 알림 체인 -결과는 체인을 따라 위로 전달됩니다. +결과는 체인을 따라 다시 위로 흐릅니다. -1. 깊이 2 작업자가 완료됨 → 부모(깊이 1 오케스트레이터)에게 알립니다. -2. 깊이 1 오케스트레이터가 알림을 받고, 결과를 종합한 뒤 완료됨 → 메인에게 알립니다. -3. 메인 에이전트가 알림을 받고 사용자에게 전달합니다. +1. 깊이 2 작업자가 완료됨 → 부모(깊이 1 오케스트레이터)에게 알림. +2. 깊이 1 오케스트레이터가 알림을 받고 결과를 종합한 뒤 완료됨 → 메인에게 알림. +3. 메인 에이전트가 알림을 받고 사용자에게 전달. -각 수준은 직접적인 자식의 알림만 봅니다. +각 수준은 직접 자식의 알림만 볼 수 있습니다. -**운영 지침:** `sessions_list`, -`sessions_history`, `/subagents list` 또는 `exec` sleep 명령을 중심으로 폴링 루프를 만드는 대신, 자식 작업을 한 번 시작하고 완료 -이벤트를 기다리세요. `sessions_list`와 `/subagents list`는 자식 세션 관계를 -라이브 작업에 집중시킵니다. 라이브 자식은 연결된 상태로 유지되고, 종료된 자식은 -짧은 최근 창 동안 표시되며, 오래된 저장소 전용 자식 링크는 신선도 창 이후 -무시됩니다. 이렇게 하면 재시작 후 오래된 `spawnedBy` / -`parentSessionKey` 메타데이터가 유령 자식을 되살리는 것을 방지합니다. -이미 최종 답변을 보낸 뒤 자식 완료 이벤트가 도착하면, 올바른 후속 응답은 정확한 무음 토큰 -`NO_REPLY` / `no_reply`입니다. +**운영 지침:** `sessions_list`, `sessions_history`, `/subagents list` 또는 +`exec` sleep 명령을 중심으로 폴링 루프를 만들지 말고 자식 작업을 한 번 시작한 뒤 완료 +이벤트를 기다리세요. `sessions_list` 및 `/subagents list`는 자식 세션 관계를 +실시간 작업에 집중시킵니다. 활성 자식은 연결된 상태로 유지되고, 종료된 자식은 짧은 최근 +기간 동안 표시되며, 오래된 저장소 전용 자식 링크는 신선도 기간 이후 무시됩니다. 이렇게 하면 +다시 시작한 뒤 오래된 `spawnedBy` / `parentSessionKey` 메타데이터가 유령 자식을 +되살리는 일을 방지합니다. 이미 최종 답변을 보낸 뒤 자식 완료 이벤트가 도착했다면 올바른 +후속 응답은 정확한 무음 토큰 `NO_REPLY` / `no_reply`입니다. ### 깊이별 도구 정책 -- 역할과 제어 범위는 생성 시점에 세션 메타데이터에 기록됩니다. 이렇게 하면 평면화되었거나 복원된 세션 키가 실수로 오케스트레이터 권한을 되찾지 않습니다. +- 역할 및 제어 범위는 생성 시 세션 메타데이터에 기록됩니다. 이렇게 하면 평면화되었거나 복원된 세션 키가 실수로 오케스트레이터 권한을 다시 얻지 않습니다. - **깊이 1(오케스트레이터, `maxSpawnDepth >= 2`인 경우):** 자식을 관리할 수 있도록 `sessions_spawn`, `subagents`, `sessions_list`, `sessions_history`를 받습니다. 다른 세션/시스템 도구는 계속 거부됩니다. - **깊이 1(리프, `maxSpawnDepth == 1`인 경우):** 세션 도구 없음(현재 기본 동작). -- **깊이 2(리프 작업자):** 세션 도구 없음. `sessions_spawn`은 깊이 2에서 항상 거부됩니다. 추가 자식을 생성할 수 없습니다. +- **깊이 2(리프 작업자):** 세션 도구 없음. `sessions_spawn`은 깊이 2에서 항상 거부됩니다. 더 이상 자식을 생성할 수 없습니다. ### 에이전트별 생성 제한 각 에이전트 세션(모든 깊이)은 한 번에 최대 `maxChildrenPerAgent` -개의 활성 자식을 가질 수 있습니다(기본값 `5`). 이는 단일 오케스트레이터에서 -무제한 팬아웃이 발생하는 것을 방지합니다. +(기본값 `5`)개의 활성 자식을 가질 수 있습니다. 이는 단일 오케스트레이터에서 +무한한 팬아웃이 발생하는 것을 방지합니다. ### 연쇄 중지 깊이 1 오케스트레이터를 중지하면 모든 깊이 2 자식도 자동으로 중지됩니다. -- 메인 채팅의 `/stop`은 모든 깊이 1 에이전트를 중지하고 그 깊이 2 자식까지 연쇄 중지합니다. +- 메인 채팅의 `/stop`은 모든 깊이 1 에이전트를 중지하고 그들의 깊이 2 자식까지 연쇄 중지합니다. - `/subagents kill `는 특정 하위 에이전트를 중지하고 그 자식까지 연쇄 중지합니다. - `/subagents kill all`은 요청자의 모든 하위 에이전트를 중지하고 연쇄 중지합니다. ## 인증 -하위 에이전트 인증은 세션 유형이 아니라 **에이전트 id**로 확인됩니다. +하위 에이전트 인증은 세션 유형이 아니라 **에이전트 ID**로 결정됩니다. - 하위 에이전트 세션 키는 `agent::subagent:`입니다. - 인증 저장소는 해당 에이전트의 `agentDir`에서 로드됩니다. - 메인 에이전트의 인증 프로필은 **fallback**으로 병합됩니다. 충돌 시 에이전트 프로필이 메인 프로필을 재정의합니다. -병합은 추가 방식이므로, 메인 프로필은 항상 fallback으로 사용할 수 있습니다. +병합은 추가 방식이므로 메인 프로필은 항상 fallback으로 사용할 수 있습니다. 에이전트별 완전 격리 인증은 아직 지원되지 않습니다. ## 알림 -하위 에이전트는 알림 단계를 통해 보고합니다. +하위 에이전트는 알림 단계로 보고합니다. - 알림 단계는 요청자 세션이 아니라 하위 에이전트 세션 안에서 실행됩니다. -- 하위 에이전트가 정확히 `ANNOUNCE_SKIP`으로 응답하면 아무것도 게시되지 않습니다. -- 최신 어시스턴트 텍스트가 정확한 무음 토큰 `NO_REPLY` / `no_reply`인 경우, 이전에 표시된 진행 상황이 있었더라도 알림 출력은 억제됩니다. +- 하위 에이전트가 정확히 `ANNOUNCE_SKIP`으로 답하면 아무것도 게시되지 않습니다. +- 최신 어시스턴트 텍스트가 정확한 무음 토큰 `NO_REPLY` / `no_reply`이면, 이전에 보이는 진행 상황이 있었더라도 알림 출력은 억제됩니다. 전달은 요청자 깊이에 따라 달라집니다. -- 최상위 요청자 세션은 외부 전달(`deliver=true`)이 포함된 후속 `agent` 호출을 사용합니다. -- 중첩된 요청자 하위 에이전트 세션은 내부 후속 주입(`deliver=false`)을 받으므로 오케스트레이터가 세션 안에서 자식 결과를 종합할 수 있습니다. -- 중첩된 요청자 하위 에이전트 세션이 사라진 경우, OpenClaw는 가능한 경우 해당 세션의 요청자로 fallback합니다. +- 최상위 요청자 세션은 외부 전달(`deliver=true`)이 있는 후속 `agent` 호출을 사용합니다. +- 중첩된 요청자 하위 에이전트 세션은 내부 후속 주입(`deliver=false`)을 받아 오케스트레이터가 세션 안에서 자식 결과를 종합할 수 있게 합니다. +- 중첩된 요청자 하위 에이전트 세션이 사라진 경우, 사용 가능하면 OpenClaw는 해당 세션의 요청자로 fallback합니다. -최상위 요청자 세션의 경우, 완료 모드 직접 전달은 먼저 바인딩된 대화/스레드 경로와 훅 재정의를 해석한 뒤, 누락된 채널 대상 필드를 요청자 세션에 저장된 경로로 채웁니다. -이를 통해 완료 출처가 채널만 식별하더라도 올바른 채팅/토픽에 완료가 유지됩니다. +최상위 요청자 세션의 경우, 완료 모드 직접 전달은 먼저 바인딩된 대화/스레드 경로와 훅 +재정의를 해결한 뒤, 누락된 채널 대상 필드를 요청자 세션의 저장된 경로에서 채웁니다. +이렇게 하면 완료 출처가 채널만 식별하는 경우에도 올바른 채팅/토픽에 완료가 유지됩니다. -중첩 완료 결과를 만들 때 자식 완료 집계는 현재 요청자 실행으로 범위가 제한되어, -이전 실행의 오래된 자식 출력이 현재 알림으로 새어 들어가는 것을 방지합니다. 알림 응답은 -채널 어댑터에서 사용할 수 있을 때 스레드/토픽 라우팅을 보존합니다. +중첩 완료 결과를 만들 때 자식 완료 집계는 현재 요청자 실행 범위로 제한되어, +이전 실행의 오래된 자식 출력이 현재 알림에 새어 들어오지 않게 합니다. 알림 답장은 +채널 어댑터에서 사용 가능한 경우 스레드/토픽 라우팅을 보존합니다. ### 알림 컨텍스트 알림 컨텍스트는 안정적인 내부 이벤트 블록으로 정규화됩니다. -| 필드 | 소스 | -| -------------- | ------------------------------------------------------------------------------------------------------------- | -| 소스 | `subagent` 또는 `cron` | -| 세션 id | 자식 세션 키/id | -| 유형 | 알림 유형 + 작업 레이블 | -| 상태 | 런타임 결과(`success`, `error`, `timeout` 또는 `unknown`)에서 파생됨 — 모델 텍스트에서 추론하지 **않음** | -| 결과 콘텐츠 | 최신 표시 어시스턴트 텍스트, 없으면 정리된 최신 도구/toolResult 텍스트 | -| 후속 조치 | 응답할 때와 조용히 있을 때를 설명하는 지침 | +| 필드 | 출처 | +| ----------- | ---------------------------------------------------------------------------------------------------------------- | +| 출처 | `subagent` 또는 `cron` | +| 세션 ID | 자식 세션 키/ID | +| 유형 | 알림 유형 + 작업 레이블 | +| 상태 | 런타임 결과에서 파생(`success`, `error`, `timeout` 또는 `unknown`) — 모델 텍스트에서 추론하지 **않음** | +| 결과 내용 | 최신으로 보이는 어시스턴트 텍스트, 없으면 정리된 최신 도구/toolResult 텍스트 | +| 후속 조치 | 답장해야 할 때와 조용히 있어야 할 때를 설명하는 지침 | -종료된 실패 실행은 캡처된 응답 텍스트를 재생하지 않고 실패 상태를 보고합니다. -타임아웃 시 자식이 도구 호출까지만 진행한 경우, 알림은 원시 도구 출력을 재생하는 대신 -해당 기록을 짧은 부분 진행 요약으로 축약할 수 있습니다. +터미널에서 실패한 실행은 캡처된 답장 텍스트를 재생하지 않고 실패 상태를 보고합니다. +시간 초과 시 자식이 도구 호출까지만 진행했다면, 알림은 원시 도구 출력을 재생하는 대신 +해당 기록을 짧은 부분 진행 요약으로 접을 수 있습니다. ### 통계 줄 @@ -404,39 +405,36 @@ transcript 경로를 검사하세요. - 런타임(예: `runtime 5m12s`). - 토큰 사용량(입력/출력/전체). -- 모델 가격이 구성된 경우 예상 비용(`models.providers.*.models[].cost`). -- 메인 에이전트가 `sessions_history`를 통해 기록을 가져오거나 디스크의 파일을 검사할 수 있도록 `sessionKey`, `sessionId` 및 트랜스크립트 경로. +- 모델 가격이 구성된 경우 추정 비용(`models.providers.*.models[].cost`). +- 메인 에이전트가 `sessions_history`로 기록을 가져오거나 디스크의 파일을 검사할 수 있도록 `sessionKey`, `sessionId`, transcript 경로. -내부 메타데이터는 오케스트레이션 전용입니다. 사용자 대상 응답은 일반 어시스턴트 목소리로 다시 작성해야 합니다. +내부 메타데이터는 오케스트레이션 전용입니다. 사용자 대상 답장은 일반적인 어시스턴트 +목소리로 다시 작성해야 합니다. ### `sessions_history`를 선호하는 이유 `sessions_history`는 더 안전한 오케스트레이션 경로입니다. -- 어시스턴트 회상이 먼저 정규화됩니다. 사고 태그가 제거되고, `` / `` 스캐폴딩이 제거되며, 일반 텍스트 도구 호출 XML 페이로드 블록(``, ``, ``, ``)이 제거됩니다. 여기에는 깔끔하게 닫히지 않는 잘린 페이로드도 포함됩니다. 다운그레이드된 도구 호출/결과 스캐폴딩과 기록 컨텍스트 마커가 제거됩니다. 유출된 모델 제어 토큰(`<|assistant|>`, 기타 ASCII `<|...|>`, 전각 `<|...|>`)이 제거됩니다. 잘못된 MiniMax 도구 호출 XML이 제거됩니다. -- 자격 증명/토큰처럼 보이는 텍스트는 마스킹됩니다. +- 어시스턴트 회상이 먼저 정규화됩니다. thinking 태그 제거, `` / `` 스캐폴딩 제거, 일반 텍스트 도구 호출 XML 페이로드 블록(``, ``, ``, ``) 제거(깔끔하게 닫히지 않은 잘린 페이로드 포함), 다운그레이드된 도구 호출/결과 스캐폴딩 및 기록 컨텍스트 마커 제거, 유출된 모델 제어 토큰(`<|assistant|>`, 기타 ASCII `<|...|>`, 전각 `<|...|>`) 제거, 잘못된 MiniMax 도구 호출 XML 제거. +- credential/token처럼 보이는 텍스트는 수정됩니다. - 긴 블록은 잘릴 수 있습니다. -- 매우 큰 기록은 오래된 행을 삭제하거나 과도하게 큰 행을 `[sessions_history omitted: message too large]`로 대체할 수 있습니다. -- 전체 바이트 단위 트랜스크립트가 필요할 때는 디스크의 원시 트랜스크립트 검사가 fallback입니다. +- 매우 큰 기록은 오래된 행을 삭제하거나 너무 큰 행을 `[sessions_history omitted: message too large]`로 대체할 수 있습니다. +- 바이트 단위로 완전히 동일한 전체 transcript가 필요할 때는 디스크의 원시 transcript 검사가 fallback입니다. ## 도구 정책 -하위 에이전트는 먼저 부모 또는 대상 에이전트와 동일한 프로필 및 도구 정책 파이프라인을 사용합니다. -그 후 OpenClaw가 하위 에이전트 제한 계층을 적용합니다. +하위 에이전트는 먼저 부모 또는 대상 에이전트와 동일한 프로필 및 도구 정책 파이프라인을 사용합니다. 그 다음 OpenClaw가 하위 에이전트 제한 계층을 적용합니다. -제한적인 `tools.profile`이 없으면, 하위 에이전트는 세션 도구와 시스템 도구를 -**제외한 모든 도구**를 받습니다. +제한적인 `tools.profile`이 없으면 하위 에이전트는 **세션 도구와 시스템 도구를 제외한 모든 도구**를 받습니다. - `sessions_list` - `sessions_history` - `sessions_send` - `sessions_spawn` -여기서도 `sessions_history`는 제한되고 정리된 회상 뷰로 유지됩니다. 원시 트랜스크립트 덤프가 아닙니다. +여기에서도 `sessions_history`는 범위가 제한되고 정제된 회상 뷰로 유지됩니다. 원시 트랜스크립트 덤프가 아닙니다. -`maxSpawnDepth >= 2`인 경우, 깊이 1 오케스트레이터 하위 에이전트는 자식을 관리할 수 있도록 -추가로 `sessions_spawn`, `subagents`, `sessions_list`, -`sessions_history`를 받습니다. +`maxSpawnDepth >= 2`인 경우, 깊이 1의 오케스트레이터 하위 에이전트는 자식들을 관리할 수 있도록 추가로 `sessions_spawn`, `subagents`, `sessions_list`, `sessions_history`를 받습니다. ### 구성을 통한 재정의 @@ -462,7 +460,7 @@ transcript 경로를 검사하세요. } ``` -`tools.subagents.tools.allow`는 최종 허용 전용 필터입니다. 이미 해석된 도구 세트를 좁힐 수는 있지만, `tools.profile`에서 제거된 도구를 **다시 추가할 수는 없습니다**. 예를 들어 `tools.profile: "coding"`에는 `web_search`/`web_fetch`가 포함되지만 `browser` 도구는 포함되지 않습니다. 코딩 프로필 하위 에이전트가 브라우저 자동화를 사용하게 하려면 프로필 단계에서 browser를 추가하세요. +`tools.subagents.tools.allow`는 최종 허용 전용 필터입니다. 이미 해석된 도구 집합을 좁힐 수는 있지만, `tools.profile`로 제거된 도구를 **다시 추가할 수는 없습니다**. 예를 들어 `tools.profile: "coding"`에는 `web_search`/`web_fetch`가 포함되지만 `browser` 도구는 포함되지 않습니다. coding 프로필 하위 에이전트가 브라우저 자동화를 사용할 수 있게 하려면 프로필 단계에서 browser를 추가하세요. ```json5 { @@ -477,36 +475,36 @@ transcript 경로를 검사하세요. ## 동시성 -하위 에이전트는 전용 프로세스 내 큐 레인을 사용합니다. +하위 에이전트는 전용 인프로세스 큐 레인을 사용합니다. - **레인 이름:** `subagent` - **동시성:** `agents.defaults.subagents.maxConcurrent`(기본값 `8`) ## 활성 상태 및 복구 -OpenClaw는 `endedAt`이 없다는 사실을 하위 에이전트가 아직 살아 있다는 영구적인 증거로 간주하지 않습니다. 오래된 실행 창보다 오래된 종료되지 않은 실행은 `/subagents list`, 상태 요약, 하위 항목 완료 게이팅, 세션별 동시성 검사에서 활성/대기 중으로 계산되지 않습니다. +OpenClaw는 `endedAt`이 없다는 사실을 하위 에이전트가 아직 살아 있다는 영구적인 증거로 간주하지 않습니다. stale-run 기간보다 오래된 종료되지 않은 실행은 `/subagents list`, 상태 요약, 하위 항목 완료 게이팅, 세션별 동시성 검사에서 active/pending으로 계산되지 않습니다. -Gateway 재시작 후 오래되어 종료되지 않은 복원 실행은 해당 자식 세션이 `abortedLastRun: true`로 표시되어 있지 않으면 정리됩니다. 이렇게 재시작으로 중단된 자식 세션은 하위 에이전트 고아 복구 흐름을 통해 계속 복구할 수 있으며, 이 흐름은 중단 표시를 지우기 전에 합성 재개 메시지를 보냅니다. +Gateway를 재시작한 뒤에는, 자식 세션이 `abortedLastRun: true`로 표시되어 있지 않은 한 오래된 종료되지 않은 복원 실행이 정리됩니다. 이렇게 재시작으로 중단된 자식 세션은 하위 에이전트 고아 복구 흐름을 통해 계속 복구할 수 있으며, 이 흐름은 중단 표시를 지우기 전에 합성 resume 메시지를 보냅니다. -자동 재시작 복구는 자식 세션별로 제한됩니다. 동일한 하위 에이전트 자식이 빠른 재고착 창 안에서 반복적으로 고아 복구 대상으로 수락되면 OpenClaw는 해당 세션에 복구 툼스톤을 저장하고 이후 재시작 시 자동 재개를 중지합니다. 작업 레코드를 조정하려면 `openclaw tasks maintenance --apply`를 실행하거나, 툼스톤 처리된 세션의 오래된 중단 복구 플래그를 지우려면 `openclaw doctor --fix`를 실행하세요. +자동 재시작 복구는 자식 세션별로 제한됩니다. 동일한 하위 에이전트 자식이 rapid re-wedge 기간 내에 반복적으로 고아 복구 대상으로 승인되면, OpenClaw는 해당 세션에 복구 tombstone을 유지하고 이후 재시작에서 자동 resume을 중지합니다. 작업 레코드를 조정하려면 `openclaw tasks maintenance --apply`를 실행하거나, tombstone 처리된 세션의 오래된 중단 복구 플래그를 지우려면 `openclaw doctor --fix`를 실행하세요. -하위 에이전트 생성이 Gateway `PAIRING_REQUIRED` / `scope-upgrade`로 실패하면 페어링 상태를 편집하기 전에 RPC 호출자를 확인하세요. 내부 `sessions_spawn` 조정은 직접 루프백 공유 토큰/비밀번호 인증을 통해 `client.id: "gateway-client"` 및 `client.mode: "backend"`로 연결해야 합니다. 이 경로는 CLI의 페어링된 기기 범위 기준선에 의존하지 않습니다. 원격 호출자, 명시적 `deviceIdentity`, 명시적 기기 토큰 경로, 브라우저/Node 클라이언트에는 범위 업그레이드를 위한 일반적인 기기 승인이 여전히 필요합니다. +하위 에이전트 spawn이 Gateway `PAIRING_REQUIRED` / `scope-upgrade`로 실패하면 pairing 상태를 수정하기 전에 RPC 호출자를 확인하세요. 내부 `sessions_spawn` 조정은 직접 loopback 공유 토큰/비밀번호 인증을 통해 `client.id: "gateway-client"` 및 `client.mode: "backend"`로 연결해야 합니다. 이 경로는 CLI의 페어링된 기기 범위 기준선에 의존하지 않습니다. 원격 호출자, 명시적 `deviceIdentity`, 명시적 기기 토큰 경로, 브라우저/Node 클라이언트는 범위 업그레이드에 여전히 일반 기기 승인이 필요합니다. ## 중지 -- 요청자 채팅에서 `/stop`을 보내면 요청자 세션이 중단되고 여기서 생성된 활성 하위 에이전트 실행이 중지되며, 중첩된 자식에게도 전파됩니다. -- `/subagents kill `는 특정 하위 에이전트를 중지하고 그 자식에게도 전파합니다. +- 요청자 채팅에서 `/stop`을 보내면 요청자 세션이 중단되고 여기에서 spawn된 활성 하위 에이전트 실행이 모두 중지되며, 중첩된 자식까지 연쇄적으로 적용됩니다. +- `/subagents kill `는 특정 하위 에이전트를 중지하고 그 자식들에게 연쇄적으로 적용됩니다. ## 제한 사항 -- 하위 에이전트 알림은 **최선 노력** 방식입니다. Gateway가 재시작되면 보류 중인 "announce back" 작업은 손실됩니다. -- 하위 에이전트는 여전히 동일한 Gateway 프로세스 리소스를 공유하므로 `maxConcurrent`를 안전 밸브로 취급하세요. +- 하위 에이전트 announce는 **최선 노력 방식**입니다. Gateway가 재시작되면 보류 중인 "announce back" 작업은 손실됩니다. +- 하위 에이전트는 여전히 동일한 Gateway 프로세스 리소스를 공유합니다. `maxConcurrent`를 안전장치로 취급하세요. - `sessions_spawn`은 항상 비차단 방식입니다. 즉시 `{ status: "accepted", runId, childSessionKey }`를 반환합니다. -- 하위 에이전트 컨텍스트는 `AGENTS.md` + `TOOLS.md`만 주입합니다(`SOUL.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`는 없음). -- 최대 중첩 깊이는 5입니다(`maxSpawnDepth` 범위: 1~5). 대부분의 사용 사례에는 깊이 2를 권장합니다. -- `maxChildrenPerAgent`는 세션당 활성 자식 수를 제한합니다(기본값 `5`, 범위 `1~20`). +- 하위 에이전트 컨텍스트는 `AGENTS.md` + `TOOLS.md`만 주입합니다(`SOUL.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`는 제외). +- 최대 중첩 깊이는 5입니다(`maxSpawnDepth` 범위: 1–5). 대부분의 사용 사례에는 깊이 2가 권장됩니다. +- `maxChildrenPerAgent`는 세션당 활성 자식 수를 제한합니다(기본값 `5`, 범위 `1–20`). ## 관련 항목 diff --git a/docs/ko/web/control-ui.md b/docs/ko/web/control-ui.md index 0f7bb7397..7b43b4db6 100644 --- a/docs/ko/web/control-ui.md +++ b/docs/ko/web/control-ui.md @@ -1,210 +1,210 @@ --- read_when: - 브라우저에서 Gateway를 운영하려는 경우 - - SSH 터널 없이 Tailnet 액세스가 필요한 경우 + - SSH 터널 없이 Tailnet 액세스를 원할 때 sidebarTitle: Control UI summary: Gateway용 브라우저 기반 제어 UI(채팅, 노드, 설정) title: 제어 UI x-i18n: - generated_at: "2026-05-04T02:26:25Z" + generated_at: "2026-05-04T06:25:33Z" model: gpt-5.5 provider: openai - source_hash: c890d83da2c296b600e4b5a00a538f37e6bd54da31fbe62113ecd6177b15626e + source_hash: 07fbbe1c7fec5f67a04a231e02bdf0f7d16be9c5fe188915674d71fcd69002a5 source_path: web/control-ui.md workflow: 16 --- -Control UI는 Gateway가 제공하는 작은 **Vite + Lit** 단일 페이지 앱입니다. +Control UI는 Gateway에서 제공되는 작은 **Vite + Lit** 단일 페이지 앱입니다. - 기본값: `http://:18789/` - 선택적 접두사: `gateway.controlUi.basePath` 설정(예: `/openclaw`) -같은 포트의 **Gateway WebSocket**과 직접 통신합니다. +동일한 포트에서 **Gateway WebSocket에 직접** 연결합니다. -## 빠른 열기(로컬) +## 빠르게 열기(로컬) Gateway가 같은 컴퓨터에서 실행 중이면 다음을 여세요. - [http://127.0.0.1:18789/](http://127.0.0.1:18789/) (또는 [http://localhost:18789/](http://localhost:18789/)) -페이지가 로드되지 않으면 먼저 Gateway를 시작하세요. `openclaw gateway` +페이지가 로드되지 않으면 먼저 Gateway를 시작하세요: `openclaw gateway`. -인증은 WebSocket 핸드셰이크 중 다음을 통해 제공됩니다. +인증은 WebSocket 핸드셰이크 중에 다음을 통해 제공됩니다. - `connect.params.auth.token` - `connect.params.auth.password` - `gateway.auth.allowTailscale: true`일 때 Tailscale Serve ID 헤더 - `gateway.auth.mode: "trusted-proxy"`일 때 신뢰할 수 있는 프록시 ID 헤더 -대시보드 설정 패널은 현재 브라우저 탭 세션과 선택된 Gateway URL에 대한 토큰을 보관하며, 비밀번호는 유지하지 않습니다. 온보딩은 일반적으로 첫 연결 시 공유 비밀 인증용 Gateway 토큰을 생성하지만, `gateway.auth.mode`가 `"password"`이면 비밀번호 인증도 작동합니다. +대시보드 설정 패널은 현재 브라우저 탭 세션과 선택한 Gateway URL에 대한 토큰을 보관하며, 비밀번호는 저장하지 않습니다. 온보딩은 보통 첫 연결 시 공유 비밀 인증용 Gateway 토큰을 생성하지만, `gateway.auth.mode`가 `"password"`이면 비밀번호 인증도 사용할 수 있습니다. ## 기기 페어링(첫 연결) -새 브라우저나 기기에서 Control UI에 연결하면 Gateway는 일반적으로 **일회성 페어링 승인**을 요구합니다. 이는 무단 액세스를 방지하기 위한 보안 조치입니다. +새 브라우저나 기기에서 Control UI에 연결하면 Gateway는 일반적으로 **일회성 페어링 승인**을 요구합니다. 이는 무단 접근을 방지하기 위한 보안 조치입니다. **표시되는 내용:** "disconnected (1008): pairing required" - + ```bash openclaw devices list ``` - + ```bash openclaw devices approve ``` -브라우저가 변경된 인증 세부 정보(역할/범위/공개 키)로 페어링을 다시 시도하면 이전 대기 요청은 대체되고 새 `requestId`가 생성됩니다. 승인하기 전에 `openclaw devices list`를 다시 실행하세요. +브라우저가 변경된 인증 세부 정보(역할/범위/공개 키)로 페어링을 다시 시도하면 이전 보류 요청은 대체되고 새 `requestId`가 생성됩니다. 승인하기 전에 `openclaw devices list`를 다시 실행하세요. -브라우저가 이미 페어링되어 있고 읽기 액세스에서 쓰기/관리자 액세스로 변경하면, 이는 조용한 재연결이 아니라 승인 업그레이드로 처리됩니다. OpenClaw는 이전 승인을 활성 상태로 유지하고 더 넓은 권한의 재연결을 차단한 뒤 새 범위 세트를 명시적으로 승인하도록 요청합니다. +브라우저가 이미 페어링되어 있고 읽기 접근 권한을 쓰기/관리자 접근 권한으로 변경하는 경우, 이는 조용한 재연결이 아니라 승인 업그레이드로 처리됩니다. OpenClaw는 기존 승인을 활성 상태로 유지하고, 더 넓은 범위의 재연결을 차단하며, 새 범위 집합을 명시적으로 승인하도록 요청합니다. -승인되면 기기가 기억되며 `openclaw devices revoke --device --role `로 취소하지 않는 한 재승인이 필요하지 않습니다. 토큰 순환 및 취소는 [기기 CLI](/ko/cli/devices)를 참조하세요. +승인되면 기기가 기억되며, `openclaw devices revoke --device --role `로 취소하지 않는 한 다시 승인할 필요가 없습니다. 토큰 로테이션 및 취소는 [기기 CLI](/ko/cli/devices)를 참조하세요. - 직접 local loopback 브라우저 연결(`127.0.0.1` / `localhost`)은 자동 승인됩니다. -- `gateway.auth.allowTailscale: true`이고 Tailscale ID가 검증되며 브라우저가 기기 ID를 제시하는 경우, Tailscale Serve는 Control UI 운영자 세션의 페어링 왕복 과정을 건너뛸 수 있습니다. -- 직접 Tailnet 바인딩, LAN 브라우저 연결, 기기 ID가 없는 브라우저 프로필은 여전히 명시적 승인이 필요합니다. -- 각 브라우저 프로필은 고유한 기기 ID를 생성하므로, 브라우저를 전환하거나 브라우저 데이터를 지우면 다시 페어링해야 합니다. +- `gateway.auth.allowTailscale: true`이고, Tailscale ID가 확인되며, 브라우저가 기기 ID를 제시하면 Tailscale Serve는 Control UI 운영자 세션의 페어링 왕복 절차를 건너뛸 수 있습니다. +- 직접 Tailnet 바인드, LAN 브라우저 연결, 기기 ID가 없는 브라우저 프로필은 여전히 명시적 승인이 필요합니다. +- 각 브라우저 프로필은 고유한 기기 ID를 생성하므로 브라우저를 바꾸거나 브라우저 데이터를 지우면 다시 페어링해야 합니다. ## 개인 ID(브라우저 로컬) -Control UI는 공유 세션에서 출처 표시를 위해 보내는 메시지에 첨부되는 브라우저별 개인 ID(표시 이름 및 아바타)를 지원합니다. 이는 브라우저 저장소에 저장되고 현재 브라우저 프로필로 범위가 제한되며, 실제로 보낸 메시지의 일반적인 트랜스크립트 작성자 메타데이터를 제외하고는 다른 기기와 동기화되거나 서버 측에 유지되지 않습니다. 사이트 데이터를 지우거나 브라우저를 전환하면 빈 상태로 재설정됩니다. +Control UI는 공유 세션에서 귀속 표시를 위해 보내는 메시지에 첨부되는 브라우저별 개인 ID(표시 이름과 아바타)를 지원합니다. 이 정보는 브라우저 저장소에 있으며 현재 브라우저 프로필로 범위가 제한되고, 실제로 보낸 메시지의 일반적인 대화 기록 작성자 메타데이터를 제외하면 다른 기기로 동기화되거나 서버 측에 저장되지 않습니다. 사이트 데이터를 지우거나 브라우저를 바꾸면 비어 있는 상태로 초기화됩니다. -동일한 브라우저 로컬 패턴이 어시스턴트 아바타 재정의에도 적용됩니다. 업로드된 어시스턴트 아바타는 로컬 브라우저에서만 Gateway가 확인한 ID 위에 오버레이되며 `config.patch`를 통해 왕복하지 않습니다. 공유 `ui.assistant.avatar` 구성 필드는 해당 필드를 직접 쓰는 비 UI 클라이언트(예: 스크립트 기반 Gateway 또는 사용자 지정 대시보드)용으로 계속 사용할 수 있습니다. +동일한 브라우저 로컬 패턴은 어시스턴트 아바타 재정의에도 적용됩니다. 업로드된 어시스턴트 아바타는 로컬 브라우저에서만 Gateway가 확인한 ID 위에 오버레이되며 `config.patch`를 통해 왕복하지 않습니다. 공유 `ui.assistant.avatar` config 필드는 스크립트형 Gateway나 사용자 지정 대시보드처럼 필드를 직접 쓰는 비 UI 클라이언트에서 여전히 사용할 수 있습니다. -## 런타임 구성 엔드포인트 +## 런타임 config 엔드포인트 -Control UI는 런타임 설정을 `/__openclaw/control-ui-config.json`에서 가져옵니다. 이 엔드포인트는 HTTP 표면의 나머지 부분과 동일한 Gateway 인증으로 보호됩니다. 인증되지 않은 브라우저는 이를 가져올 수 없으며, 성공적인 가져오기를 위해서는 이미 유효한 Gateway 토큰/비밀번호, Tailscale Serve ID 또는 신뢰할 수 있는 프록시 ID 중 하나가 필요합니다. +Control UI는 `/__openclaw/control-ui-config.json`에서 런타임 설정을 가져옵니다. 해당 엔드포인트는 나머지 HTTP 표면과 동일한 Gateway 인증으로 보호됩니다. 인증되지 않은 브라우저는 이를 가져올 수 없으며, 성공적으로 가져오려면 이미 유효한 Gateway 토큰/비밀번호, Tailscale Serve ID, 또는 신뢰할 수 있는 프록시 ID가 필요합니다. ## 언어 지원 -Control UI는 첫 로드 시 브라우저 로캘을 기준으로 자체 지역화를 수행할 수 있습니다. 나중에 재정의하려면 **개요 -> Gateway 액세스 -> 언어**를 여세요. 로캘 선택기는 모양 아래가 아니라 Gateway 액세스 카드에 있습니다. +Control UI는 첫 로드 시 브라우저 로캘을 기준으로 자체 지역화를 수행할 수 있습니다. 나중에 재정의하려면 **개요 -> Gateway 접근 -> 언어**를 여세요. 로캘 선택기는 모양 아래가 아니라 Gateway 접근 카드에 있습니다. - 지원되는 로캘: `en`, `zh-CN`, `zh-TW`, `pt-BR`, `de`, `es`, `ja-JP`, `ko`, `fr`, `ar`, `it`, `tr`, `uk`, `id`, `pl`, `th`, `vi`, `nl`, `fa` - 영어가 아닌 번역은 브라우저에서 지연 로드됩니다. -- 선택한 로캘은 브라우저 저장소에 저장되고 이후 방문 시 재사용됩니다. +- 선택한 로캘은 브라우저 저장소에 저장되어 이후 방문 시 재사용됩니다. - 누락된 번역 키는 영어로 대체됩니다. -문서 번역은 동일한 비영어 로캘 세트에 대해 생성되지만, 문서 사이트에 내장된 Mintlify 언어 선택기는 Mintlify가 허용하는 로캘 코드로 제한됩니다. 태국어(`th`) 및 페르시아어(`fa`) 문서도 게시 저장소에 생성되지만, Mintlify가 해당 코드를 지원하기 전까지는 그 선택기에 표시되지 않을 수 있습니다. +문서 번역도 동일한 영어 외 로캘 집합에 대해 생성되지만, 문서 사이트에 내장된 Mintlify 언어 선택기는 Mintlify가 허용하는 로캘 코드로 제한됩니다. 태국어(`th`)와 페르시아어(`fa`) 문서는 게시 repo에 여전히 생성되지만, Mintlify가 해당 코드를 지원하기 전까지는 그 선택기에 표시되지 않을 수 있습니다. ## 모양 테마 -모양 패널은 기본 제공 Claw, Knot, Dash 테마와 브라우저 로컬 tweakcn 가져오기 슬롯 하나를 유지합니다. 테마를 가져오려면 [tweakcn themes](https://tweakcn.com/themes)를 열고 테마를 선택하거나 만든 다음 **공유**를 클릭하고 복사한 테마 링크를 모양에 붙여넣으세요. 가져오기 도구는 `https://tweakcn.com/r/themes/` 레지스트리 URL, `https://tweakcn.com/editor/theme?theme=amethyst-haze` 같은 편집기 URL, 상대 `/themes/` 경로, 원시 테마 ID, `amethyst-haze` 같은 기본 테마 이름도 허용합니다. +모양 패널은 기본 제공 Claw, Knot, Dash 테마와 브라우저 로컬 tweakcn 가져오기 슬롯 하나를 유지합니다. 테마를 가져오려면 [tweakcn editor](https://tweakcn.com/editor/theme)를 열고, 테마를 선택하거나 만든 다음, **Share**를 클릭하고 복사한 테마 링크를 모양에 붙여 넣으세요. 가져오기 도구는 `https://tweakcn.com/r/themes/` 레지스트리 URL, `https://tweakcn.com/editor/theme?theme=amethyst-haze` 같은 편집기 URL, 상대 `/themes/` 경로, 원시 테마 ID, `amethyst-haze` 같은 기본 테마 이름도 허용합니다. -가져온 테마는 현재 브라우저 프로필에만 저장됩니다. Gateway 구성에 기록되지 않으며 기기 간에 동기화되지 않습니다. 가져온 테마를 교체하면 하나의 로컬 슬롯이 업데이트됩니다. 이를 지우면 가져온 테마가 선택되어 있었던 경우 활성 테마가 Claw로 다시 전환됩니다. +가져온 테마는 현재 브라우저 프로필에만 저장됩니다. Gateway config에 쓰이지 않으며 기기 간에 동기화되지 않습니다. 가져온 테마를 교체하면 하나의 로컬 슬롯이 업데이트됩니다. 가져온 테마가 선택되어 있을 때 이를 지우면 활성 테마가 Claw로 되돌아갑니다. ## 할 수 있는 일(현재) - - - Gateway WS를 통해 모델과 채팅합니다(`chat.history`, `chat.send`, `chat.abort`, `chat.inject`). - - 브라우저 실시간 세션을 통해 대화합니다. OpenAI는 직접 WebRTC를 사용하고, Google Live는 WebSocket을 통한 제한된 일회용 브라우저 토큰을 사용하며, 백엔드 전용 실시간 음성 Plugin은 Gateway 릴레이 전송을 사용합니다. 릴레이는 제공자 자격 증명을 Gateway에 유지하고, 브라우저는 `talk.realtime.relay*` RPC를 통해 마이크 PCM을 스트리밍하며, 더 큰 구성 OpenClaw 모델을 위해 `chat.send`를 통해 `openclaw_agent_consult` 도구 호출을 다시 보냅니다. - - 채팅에서 도구 호출 + 실시간 도구 출력 카드를 스트리밍합니다(에이전트 이벤트). + + - Gateway WS(`chat.history`, `chat.send`, `chat.abort`, `chat.inject`)를 통해 모델과 채팅합니다. + - 브라우저 실시간 세션을 통해 대화합니다. OpenAI는 직접 WebRTC를 사용하고, Google Live는 WebSocket을 통한 제한된 일회용 브라우저 토큰을 사용하며, 백엔드 전용 실시간 음성 Plugin은 Gateway 릴레이 전송을 사용합니다. 릴레이는 제공자 자격 증명을 Gateway에 보관하는 동안 브라우저가 `talk.realtime.relay*` RPC를 통해 마이크 PCM을 스트리밍하고, 더 큰 구성된 OpenClaw 모델을 위해 `openclaw_agent_consult` 도구 호출을 `chat.send`를 통해 다시 보냅니다. + - Chat에서 도구 호출과 실시간 도구 출력 카드를 스트리밍합니다(에이전트 이벤트). - - - 채널: 기본 제공 및 번들/외부 Plugin 채널 상태, QR 로그인, 채널별 구성(`channels.status`, `web.login.*`, `config.patch`). - - 인스턴스: 프레즌스 목록 + 새로 고침(`system-presence`). - - 세션: 목록 + 세션별 모델/생각/빠름/자세함/추적/추론 재정의(`sessions.list`, `sessions.patch`). - - 꿈: Dreaming 상태, 활성화/비활성화 토글, Dream Diary 리더(`doctor.memory.status`, `doctor.memory.dreamDiary`, `config.patch`). + + - 채널: 기본 제공 및 번들/외부 Plugin 채널 상태, QR 로그인, 채널별 config(`channels.status`, `web.login.*`, `config.patch`). + - 인스턴스: 존재 목록 및 새로 고침(`system-presence`). + - 세션: 목록 및 세션별 모델/사고/빠름/상세/추적/추론 재정의(`sessions.list`, `sessions.patch`). + - Dreams: Dreaming 상태, 활성화/비활성화 토글, Dream Diary 읽기 도구(`doctor.memory.status`, `doctor.memory.dreamDiary`, `config.patch`). - - - Cron 작업: 목록/추가/편집/실행/활성화/비활성화 + 실행 기록(`cron.*`). + + - Cron 작업: 목록/추가/편집/실행/활성화/비활성화 및 실행 기록(`cron.*`). - Skills: 상태, 활성화/비활성화, 설치, API 키 업데이트(`skills.*`). - - Node: 목록 + 기능(`node.list`). - - 실행 승인: `exec host=gateway/node`에 대한 Gateway 또는 Node 허용 목록 + 요청 정책 편집(`exec.approvals.*`). + - 노드: 목록 및 기능(`node.list`). + - exec 승인: `exec host=gateway/node`에 대한 Gateway 또는 노드 allowlist 및 요청 정책 편집(`exec.approvals.*`). - + - `~/.openclaw/openclaw.json` 보기/편집(`config.get`, `config.set`). - - 검증과 함께 적용 + 재시작(`config.apply`)하고 마지막 활성 세션을 깨웁니다. - - 쓰기에는 동시 편집을 덮어쓰지 않도록 기본 해시 보호가 포함됩니다. - - 쓰기(`config.set`/`config.apply`/`config.patch`)는 제출된 구성 페이로드의 참조에 대해 활성 SecretRef 확인을 사전 검사합니다. 확인되지 않은 활성 제출 참조는 쓰기 전에 거부됩니다. - - 스키마 + 폼 렌더링(`config.schema` / `config.schema.lookup`, 필드 `title` / `description`, 일치한 UI 힌트, 즉시 하위 요약, 중첩 객체/와일드카드/배열/컴포지션 노드의 문서 메타데이터, 사용 가능한 경우 Plugin + 채널 스키마 포함). 원시 JSON 편집기는 스냅샷에 안전한 원시 왕복이 있을 때만 사용할 수 있습니다. - - 스냅샷이 원시 텍스트를 안전하게 왕복할 수 없으면 Control UI는 폼 모드를 강제하고 해당 스냅샷의 원시 모드를 비활성화합니다. - - 원시 JSON 편집기의 "저장된 상태로 재설정"은 평면화된 스냅샷을 다시 렌더링하는 대신 원시 작성 형태(서식, 주석, `$include` 레이아웃)를 보존하므로, 스냅샷이 안전하게 왕복할 수 있을 때 외부 편집이 재설정 후에도 유지됩니다. + - 검증과 함께 적용 및 재시작(`config.apply`)하고 마지막 활성 세션을 깨웁니다. + - 쓰기에는 동시 편집을 덮어쓰지 않도록 base-hash 가드가 포함됩니다. + - 쓰기(`config.set`/`config.apply`/`config.patch`)는 제출된 config 페이로드의 참조에 대해 활성 SecretRef 해결을 사전 확인합니다. 해결되지 않은 활성 제출 참조는 쓰기 전에 거부됩니다. + - 스키마 및 폼 렌더링(`config.schema` / `config.schema.lookup`, 필드 `title` / `description`, 일치하는 UI 힌트, 즉시 하위 요약, 중첩 객체/와일드카드/배열/컴포지션 노드의 문서 메타데이터, 사용 가능한 경우 Plugin 및 채널 스키마 포함); Raw JSON 편집기는 스냅샷이 안전한 원시 왕복을 지원할 때만 사용할 수 있습니다. + - 스냅샷이 원시 텍스트를 안전하게 왕복할 수 없으면 Control UI는 해당 스냅샷에 대해 Form 모드를 강제하고 Raw 모드를 비활성화합니다. + - Raw JSON 편집기의 "Reset to saved"는 평탄화된 스냅샷을 다시 렌더링하는 대신 원시로 작성된 형태(서식, 주석, `$include` 레이아웃)를 보존하므로, 스냅샷이 안전하게 왕복할 수 있을 때 외부 편집 내용이 초기화 후에도 유지됩니다. - 구조화된 SecretRef 객체 값은 실수로 객체가 문자열로 손상되는 것을 방지하기 위해 폼 텍스트 입력에서 읽기 전용으로 렌더링됩니다. - - - 디버그: 상태/상태 확인/모델 스냅샷 + 이벤트 로그 + 수동 RPC 호출(`status`, `health`, `models.list`). + + - 디버그: 상태/상태 확인/모델 스냅샷 및 이벤트 로그와 수동 RPC 호출(`status`, `health`, `models.list`). - 로그: 필터/내보내기가 포함된 Gateway 파일 로그의 실시간 tail(`logs.tail`). - - 업데이트: 패키지/git 업데이트 + 재시작(`update.run`)을 재시작 보고서와 함께 실행한 다음, 재연결 후 `update.status`를 폴링하여 실행 중인 Gateway 버전을 확인합니다. + - 업데이트: 재시작 보고서와 함께 패키지/git 업데이트 및 재시작을 실행(`update.run`)한 다음, 재연결 후 `update.status`를 폴링하여 실행 중인 Gateway 버전을 확인합니다. - - - 격리된 작업의 경우 전달 기본값은 요약 알림입니다. 내부 전용 실행을 원하면 없음으로 전환할 수 있습니다. - - 알림이 선택되면 채널/대상 필드가 표시됩니다. - - Webhook 모드는 `delivery.to`를 유효한 HTTP(S) Webhook URL로 설정한 `delivery.mode = "webhook"`을 사용합니다. + + - 격리된 작업의 경우 전달 기본값은 요약 공지입니다. 내부 전용 실행을 원하면 없음으로 전환할 수 있습니다. + - 공지가 선택되면 채널/대상 필드가 표시됩니다. + - Webhook 모드는 `delivery.mode = "webhook"`을 사용하고 `delivery.to`를 유효한 HTTP(S) Webhook URL로 설정합니다. - 메인 세션 작업의 경우 Webhook 및 없음 전달 모드를 사용할 수 있습니다. - - 고급 편집 컨트롤에는 실행 후 삭제, 에이전트 재정의 지우기, Cron exact/stagger 옵션, 에이전트 모델/생각 재정의, 최선 노력 전달 토글이 포함됩니다. + - 고급 편집 컨트롤에는 실행 후 삭제, 에이전트 재정의 지우기, Cron 정확/분산 옵션, 에이전트 모델/사고 재정의, 최선 노력 전달 토글이 포함됩니다. - 폼 검증은 필드 수준 오류와 함께 인라인으로 표시됩니다. 잘못된 값은 수정될 때까지 저장 버튼을 비활성화합니다. - - 전용 베어러 토큰을 보내려면 `cron.webhookToken`을 설정하세요. 생략하면 Webhook이 인증 헤더 없이 전송됩니다. - - 더 이상 권장되지 않는 폴백: `notify: true`가 있는 저장된 레거시 작업은 마이그레이션될 때까지 `cron.webhook`을 계속 사용할 수 있습니다. + - 전용 bearer 토큰을 보내려면 `cron.webhookToken`을 설정하세요. 생략하면 Webhook은 인증 헤더 없이 전송됩니다. + - 사용 중단된 대체 방식: `notify: true`가 있는 저장된 레거시 작업은 마이그레이션될 때까지 여전히 `cron.webhook`을 사용할 수 있습니다. -## 채팅 동작 +## Chat 동작 - - - `chat.send`는 **논블로킹**입니다. `{ runId, status: "started" }`로 즉시 승인하고 응답은 `chat` 이벤트를 통해 스트리밍됩니다. - - 채팅 업로드는 이미지와 동영상이 아닌 파일을 허용합니다. 이미지는 네이티브 이미지 경로를 유지하고, 다른 파일은 관리형 미디어로 저장되어 기록에 첨부 파일 링크로 표시됩니다. - - 같은 `idempotencyKey`로 다시 보내면 실행 중에는 `{ status: "in_flight" }`를 반환하고, 완료 후에는 `{ status: "ok" }`를 반환합니다. - - `chat.history` 응답은 UI 안전을 위해 크기가 제한됩니다. 대화 기록 항목이 너무 크면 Gateway가 긴 텍스트 필드를 잘라내고, 무거운 메타데이터 블록을 생략하며, 과도하게 큰 메시지를 자리표시자(`[chat.history omitted: message too large]`)로 대체할 수 있습니다. - - 어시스턴트/생성 이미지는 관리형 미디어 참조로 유지되고 인증된 Gateway 미디어 URL을 통해 다시 제공되므로, 다시 로드할 때 원시 base64 이미지 페이로드가 채팅 기록 응답에 계속 남아 있는지에 의존하지 않습니다. - - `chat.history`는 표시되는 어시스턴트 텍스트에서 표시 전용 인라인 지시문 태그(예: `[[reply_to_*]]` 및 `[[audio_as_voice]]`), 일반 텍스트 도구 호출 XML 페이로드(`...`, `...`, `...`, `...` 및 잘린 도구 호출 블록 포함), 유출된 ASCII/전각 모델 제어 토큰도 제거하며, 표시되는 전체 텍스트가 정확한 무음 토큰 `NO_REPLY` / `no_reply`뿐인 어시스턴트 항목은 생략합니다. - - 활성 전송 중 및 최종 기록 새로 고침 중에 `chat.history`가 잠시 오래된 스냅샷을 반환하더라도 채팅 보기는 로컬 낙관적 사용자/어시스턴트 메시지를 계속 표시합니다. Gateway 기록이 따라잡으면 정식 대화 기록이 해당 로컬 메시지를 대체합니다. - - 실시간 `chat` 이벤트는 전달 상태이고, `chat.history`는 내구성 있는 세션 대화 기록에서 다시 빌드됩니다. 도구 최종 이벤트 후 Control UI는 기록을 다시 로드하고 작은 낙관적 꼬리만 병합합니다. 대화 기록 경계는 [WebChat](/ko/web/webchat)에 문서화되어 있습니다. - - `chat.inject`는 어시스턴트 메모를 세션 대화 기록에 추가하고 UI 전용 업데이트용 `chat` 이벤트를 브로드캐스트합니다(에이전트 실행 없음, 채널 전달 없음). - - 채팅 헤더 모델 및 사고 선택기는 `sessions.patch`를 통해 활성 세션을 즉시 패치합니다. 이는 지속되는 세션 오버라이드이며, 한 턴에만 적용되는 전송 옵션이 아닙니다. - - Control UI에서 `/new`를 입력하면 New Chat과 같은 새 대시보드 세션이 생성되고 전환됩니다. `/reset`을 입력하면 현재 세션에 대해 Gateway의 명시적 제자리 재설정이 유지됩니다. - - 채팅 모델 선택기는 Gateway의 구성된 모델 보기를 요청합니다. `agents.defaults.models`가 있으면 해당 허용 목록이 선택기를 구동합니다. 그렇지 않으면 선택기는 명시적 `models.providers.*.models` 항목과 사용 가능한 인증이 있는 공급자를 표시합니다. 전체 카탈로그는 디버그 `models.list` RPC에서 `view: "all"`로 계속 사용할 수 있습니다. - - 새 Gateway 세션 사용량 보고서가 높은 컨텍스트 압박을 보이면 채팅 작성 영역에 컨텍스트 알림이 표시되고, 권장 Compaction 수준에서는 일반 세션 Compaction 경로를 실행하는 압축 버튼이 표시됩니다. 오래된 토큰 스냅샷은 Gateway가 새 사용량을 다시 보고할 때까지 숨겨집니다. + + - `chat.send`는 **비차단** 방식입니다. 즉시 `{ runId, status: "started" }`로 확인 응답을 반환하며, 응답은 `chat` 이벤트를 통해 스트리밍됩니다. + - 채팅 업로드는 이미지와 비동영상 파일을 허용합니다. 이미지는 네이티브 이미지 경로를 유지하고, 다른 파일은 관리형 미디어로 저장되어 기록에 첨부 파일 링크로 표시됩니다. + - 같은 `idempotencyKey`로 다시 전송하면 실행 중에는 `{ status: "in_flight" }`가 반환되고, 완료 후에는 `{ status: "ok" }`가 반환됩니다. + - `chat.history` 응답은 UI 안전성을 위해 크기가 제한됩니다. 대화 기록 항목이 너무 크면 Gateway는 긴 텍스트 필드를 잘라내고, 무거운 메타데이터 블록을 생략하며, 과도하게 큰 메시지를 자리 표시자(`[chat.history omitted: message too large]`)로 대체할 수 있습니다. + - 어시스턴트/생성 이미지가 관리형 미디어 참조로 유지되고 인증된 Gateway 미디어 URL을 통해 다시 제공되므로, 다시 로드할 때 원시 base64 이미지 페이로드가 채팅 기록 응답에 계속 남아 있을 필요가 없습니다. + - `chat.history`는 표시 가능한 어시스턴트 텍스트에서 표시 전용 인라인 지시문 태그(예: `[[reply_to_*]]`, `[[audio_as_voice]]`), 일반 텍스트 도구 호출 XML 페이로드(`...`, `...`, `...`, `...`, 잘린 도구 호출 블록 포함), 유출된 ASCII/전각 모델 제어 토큰도 제거하며, 전체 표시 텍스트가 정확한 무음 토큰 `NO_REPLY` / `no_reply`뿐인 어시스턴트 항목은 생략합니다. + - 활성 전송 중 및 최종 기록 새로 고침 중에는 `chat.history`가 잠시 오래된 스냅샷을 반환하더라도 채팅 보기는 로컬의 낙관적 사용자/어시스턴트 메시지를 계속 표시합니다. Gateway 기록이 따라잡으면 정식 대화 기록이 해당 로컬 메시지를 대체합니다. + - 실시간 `chat` 이벤트는 전달 상태이고, `chat.history`는 지속성 있는 세션 대화 기록에서 다시 빌드됩니다. 도구 최종 이벤트 후 Control UI는 기록을 다시 로드하고 작은 낙관적 꼬리 부분만 병합합니다. 대화 기록 경계는 [WebChat](/ko/web/webchat)에 문서화되어 있습니다. + - `chat.inject`는 세션 대화 기록에 어시스턴트 메모를 추가하고 UI 전용 업데이트를 위해 `chat` 이벤트를 브로드캐스트합니다(에이전트 실행 없음, 채널 전달 없음). + - 채팅 헤더 모델 및 사고 선택기는 `sessions.patch`를 통해 활성 세션을 즉시 패치합니다. 이는 한 턴에만 적용되는 전송 옵션이 아니라 지속성 있는 세션 재정의입니다. + - Control UI에서 `/new`를 입력하면 New Chat과 동일한 새 대시보드 세션을 만들고 전환합니다. `/reset`을 입력하면 현재 세션에 대해 Gateway의 명시적인 제자리 재설정이 유지됩니다. + - 채팅 모델 선택기는 Gateway의 구성된 모델 보기를 요청합니다. `agents.defaults.models`가 있으면 해당 허용 목록이 선택기를 구동합니다. 그렇지 않으면 선택기는 명시적인 `models.providers.*.models` 항목과 사용 가능한 인증이 있는 공급자를 표시합니다. 전체 카탈로그는 디버그 `models.list` RPC에서 `view: "all"`을 통해 계속 사용할 수 있습니다. + - 새 Gateway 세션 사용량 보고서에서 높은 컨텍스트 압력이 표시되면 채팅 작성 영역에 컨텍스트 알림이 표시되고, 권장 Compaction 수준에서는 일반 세션 Compaction 경로를 실행하는 압축 버튼이 표시됩니다. 오래된 토큰 스냅샷은 Gateway가 새 사용량을 다시 보고할 때까지 숨겨집니다. - - 대화 모드는 등록된 실시간 음성 공급자를 사용합니다. OpenAI는 `talk.provider: "openai"`와 `talk.providers.openai.apiKey`로 구성하거나, Google은 `talk.provider: "google"`와 `talk.providers.google.apiKey`로 구성하세요. Voice Call 실시간 공급자 구성은 여전히 폴백으로 재사용할 수 있습니다. 브라우저는 표준 공급자 API 키를 절대 받지 않습니다. OpenAI는 WebRTC용 임시 Realtime 클라이언트 시크릿을 받습니다. Google Live는 브라우저 WebSocket 세션용 일회용 제한 Live API 인증 토큰을 받으며, 지침과 도구 선언은 Gateway에 의해 토큰에 고정됩니다. 백엔드 실시간 브리지만 노출하는 공급자는 Gateway 릴레이 전송을 통해 실행되므로, 자격 증명과 벤더 소켓은 서버 측에 머물고 브라우저 오디오는 인증된 Gateway RPC를 통해 이동합니다. Realtime 세션 프롬프트는 Gateway가 조립합니다. `talk.realtime.session`은 호출자가 제공하는 지침 오버라이드를 허용하지 않습니다. + + Talk 모드는 등록된 실시간 음성 공급자를 사용합니다. OpenAI는 `talk.provider: "openai"`와 `talk.providers.openai.apiKey`로 구성하거나, Google은 `talk.provider: "google"`과 `talk.providers.google.apiKey`로 구성합니다. Voice Call 실시간 공급자 구성은 여전히 대체 구성으로 재사용할 수 있습니다. 브라우저는 표준 공급자 API 키를 절대 받지 않습니다. OpenAI는 WebRTC용 임시 Realtime 클라이언트 비밀을 받습니다. Google Live는 브라우저 WebSocket 세션용 일회용 제한 Live API 인증 토큰을 받으며, 지침과 도구 선언은 Gateway에 의해 토큰에 고정됩니다. 백엔드 실시간 브리지만 노출하는 공급자는 Gateway 릴레이 전송을 통해 실행되므로, 브라우저 오디오는 인증된 Gateway RPC를 통해 이동하는 동안 자격 증명과 공급업체 소켓은 서버 측에 유지됩니다. Realtime 세션 프롬프트는 Gateway가 조립하며, `talk.realtime.session`은 호출자 제공 지침 재정의를 허용하지 않습니다. - 채팅 작성기에서 Talk 컨트롤은 마이크 받아쓰기 버튼 옆의 파형 버튼입니다. Talk가 시작되면 작성기 상태 행에 `Connecting Talk...`가 표시된 뒤 오디오가 연결되면 `Talk live`, 실시간 도구 호출이 `chat.send`를 통해 구성된 더 큰 모델에 문의하는 동안에는 `Asking OpenClaw...`가 표시됩니다. + Chat 작성기에서 Talk 컨트롤은 마이크 받아쓰기 버튼 옆의 파형 버튼입니다. Talk가 시작되면 작성기 상태 행에 `Connecting Talk...`가 표시된 다음, 오디오가 연결되어 있는 동안 `Talk live`가 표시되거나, 실시간 도구 호출이 `chat.send`를 통해 구성된 더 큰 모델에 문의하는 동안 `Asking OpenClaw...`가 표시됩니다. - 유지관리자 실시간 스모크: `OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts`는 OpenAI 브라우저 WebRTC SDP 교환, Google Live 제한 토큰 브라우저 WebSocket 설정, 가짜 마이크 미디어를 사용하는 Gateway 릴레이 브라우저 어댑터를 검증합니다. 이 명령은 공급자 상태만 출력하고 시크릿은 기록하지 않습니다. + 메인터이너 실시간 스모크: `OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts`는 OpenAI 브라우저 WebRTC SDP 교환, Google Live 제한 토큰 브라우저 WebSocket 설정, 가짜 마이크 미디어를 사용하는 Gateway 릴레이 브라우저 어댑터를 검증합니다. 이 명령은 공급자 상태만 출력하며 비밀을 기록하지 않습니다. - + - **Stop**을 클릭합니다(`chat.abort` 호출). - - 실행이 활성 상태일 때 일반 후속 메시지는 대기열에 들어갑니다. 대기 중인 메시지에서 **Steer**를 클릭하면 해당 후속 메시지를 실행 중인 턴에 주입합니다. - - 대역 외로 중단하려면 `/stop`(또는 `stop`, `stop action`, `stop run`, `stop openclaw`, `please stop` 같은 독립 중단 문구)을 입력합니다. + - 실행이 활성 상태인 동안 일반 후속 메시지는 대기열에 들어갑니다. 대기 중인 메시지에서 **Steer**를 클릭하면 해당 후속 메시지가 실행 중인 턴에 주입됩니다. + - `/stop`을 입력하거나 `stop`, `stop action`, `stop run`, `stop openclaw`, `please stop` 같은 독립 실행 중단 문구를 입력해 대역 외로 중단합니다. - `chat.abort`는 해당 세션의 모든 활성 실행을 중단하기 위해 `{ sessionKey }`(`runId` 없음)를 지원합니다. - - - 실행이 중단되면 부분 어시스턴트 텍스트가 UI에 계속 표시될 수 있습니다. + + - 실행이 중단되어도 부분 어시스턴트 텍스트는 UI에 계속 표시될 수 있습니다. - Gateway는 버퍼링된 출력이 있을 때 중단된 부분 어시스턴트 텍스트를 대화 기록에 유지합니다. - - 유지된 항목에는 중단 메타데이터가 포함되어 대화 기록 소비자가 중단 부분과 정상 완료 출력을 구분할 수 있습니다. + - 유지된 항목에는 중단 메타데이터가 포함되어 대화 기록 소비자가 중단 부분 출력과 정상 완료 출력을 구분할 수 있습니다. ## PWA 설치 및 웹 푸시 -Control UI는 `manifest.webmanifest`와 서비스 워커를 제공하므로 최신 브라우저에서 독립 실행형 PWA로 설치할 수 있습니다. Web Push를 사용하면 탭이나 브라우저 창이 열려 있지 않아도 Gateway가 설치된 PWA를 알림으로 깨울 수 있습니다. +Control UI는 `manifest.webmanifest`와 서비스 워커를 제공하므로 최신 브라우저에서 독립 실행형 PWA로 설치할 수 있습니다. Web Push를 사용하면 탭이나 브라우저 창이 열려 있지 않아도 Gateway가 알림으로 설치된 PWA를 깨울 수 있습니다. | 표면 | 수행하는 작업 | | ----------------------------------------------------- | ------------------------------------------------------------------ | -| `ui/public/manifest.webmanifest` | PWA 매니페스트입니다. 접근 가능해지면 브라우저가 "Install app"을 제안합니다. | +| `ui/public/manifest.webmanifest` | PWA 매니페스트입니다. 브라우저는 접근 가능해지면 "Install app"을 제공합니다. | | `ui/public/sw.js` | `push` 이벤트와 알림 클릭을 처리하는 서비스 워커입니다. | -| `push/vapid-keys.json`(OpenClaw 상태 디렉터리 아래) | Web Push 페이로드에 서명하는 데 사용되는 자동 생성 VAPID 키 쌍입니다. | -| `push/web-push-subscriptions.json` | 유지되는 브라우저 구독 엔드포인트입니다. | +| `push/vapid-keys.json`(OpenClaw 상태 디렉터리 아래) | Web Push 페이로드 서명에 사용되는 자동 생성 VAPID 키 쌍입니다. | +| `push/web-push-subscriptions.json` | 유지되는 브라우저 구독 엔드포인트입니다. | -키를 고정하려는 경우(다중 호스트 배포, 시크릿 순환 또는 테스트) Gateway 프로세스의 환경 변수로 VAPID 키 쌍을 오버라이드하세요. +키를 고정하려는 경우(다중 호스트 배포, 비밀 회전 또는 테스트) Gateway 프로세스의 환경 변수를 통해 VAPID 키 쌍을 재정의합니다. - `OPENCLAW_VAPID_PUBLIC_KEY` - `OPENCLAW_VAPID_PRIVATE_KEY` @@ -221,19 +221,19 @@ Control UI는 브라우저 구독을 등록하고 테스트하기 위해 다음 Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration](/ko/gateway/configuration) 참조) 및 네이티브 모바일 페어링을 대상으로 하는 기존 `push.test` 메서드와 독립적입니다. -## 호스팅 임베드 +## 호스팅된 임베드 -어시스턴트 메시지는 `[embed ...]` 쇼트코드로 호스팅된 웹 콘텐츠를 인라인 렌더링할 수 있습니다. iframe 샌드박스 정책은 `gateway.controlUi.embedSandbox`로 제어됩니다. +어시스턴트 메시지는 `[embed ...]` 쇼트코드를 사용해 호스팅된 웹 콘텐츠를 인라인으로 렌더링할 수 있습니다. iframe 샌드박스 정책은 `gateway.controlUi.embedSandbox`로 제어됩니다. - 호스팅 임베드 내부의 스크립트 실행을 비활성화합니다. + 호스팅된 임베드 내부에서 스크립트 실행을 비활성화합니다. - 출처 격리를 유지하면서 대화형 임베드를 허용합니다. 이것이 기본값이며 일반적으로 자체 완결형 브라우저 게임/위젯에 충분합니다. + 출처 격리를 유지하면서 대화형 임베드를 허용합니다. 이것이 기본값이며, 일반적으로 자체 포함 브라우저 게임/위젯에 충분합니다. - 의도적으로 더 강한 권한이 필요한 동일 사이트 문서에 대해 `allow-scripts`에 더해 `allow-same-origin`을 추가합니다. + 의도적으로 더 강한 권한이 필요한 동일 사이트 문서를 위해 `allow-scripts` 위에 `allow-same-origin`을 추가합니다. @@ -250,14 +250,14 @@ Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration] ``` -임베드된 문서에 실제로 동일 출처 동작이 필요한 경우에만 `trusted`를 사용하세요. 대부분의 에이전트 생성 게임과 대화형 캔버스에는 `scripts`가 더 안전한 선택입니다. +임베드된 문서에 동일 출처 동작이 실제로 필요한 경우에만 `trusted`를 사용하세요. 대부분의 에이전트 생성 게임과 대화형 캔버스에는 `scripts`가 더 안전한 선택입니다. -절대 외부 `http(s)` 임베드 URL은 기본적으로 계속 차단됩니다. 의도적으로 `[embed url="https://..."]`가 서드파티 페이지를 로드하게 하려면 `gateway.controlUi.allowExternalEmbedUrls: true`를 설정하세요. +절대 외부 `http(s)` 임베드 URL은 기본적으로 계속 차단됩니다. 의도적으로 `[embed url="https://..."]`가 타사 페이지를 로드하도록 하려면 `gateway.controlUi.allowExternalEmbedUrls: true`를 설정하세요. ## 채팅 메시지 너비 -그룹화된 채팅 메시지는 읽기 쉬운 기본 최대 너비를 사용합니다. 와이드 모니터 배포에서는 번들 CSS를 패치하지 않고 `gateway.controlUi.chatMessageMaxWidth`를 설정해 오버라이드할 수 있습니다. +그룹화된 채팅 메시지는 읽기 쉬운 기본 최대 너비를 사용합니다. 와이드 모니터 배포에서는 번들 CSS를 패치하지 않고도 `gateway.controlUi.chatMessageMaxWidth`를 설정해 이를 재정의할 수 있습니다. ```json5 { @@ -269,13 +269,13 @@ Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration] } ``` -값은 브라우저에 도달하기 전에 검증됩니다. 지원되는 값에는 `960px` 또는 `82%` 같은 일반 길이와 백분율, 그리고 제한된 `min(...)`, `max(...)`, `clamp(...)`, `calc(...)`, `fit-content(...)` 너비 표현식이 포함됩니다. +이 값은 브라우저에 도달하기 전에 검증됩니다. 지원되는 값에는 `960px` 또는 `82%` 같은 일반 길이와 백분율, 그리고 제한된 `min(...)`, `max(...)`, `clamp(...)`, `calc(...)`, `fit-content(...)` 너비 표현식이 포함됩니다. ## Tailnet 접근(권장) - - Gateway를 loopback에 유지하고 Tailscale Serve가 HTTPS로 프록시하게 하세요. + + Gateway를 loopback에 유지하고 Tailscale Serve가 HTTPS로 프록시하도록 합니다. ```bash openclaw gateway --tailscale serve @@ -285,16 +285,16 @@ Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration] - `https:///`(또는 구성된 `gateway.controlUi.basePath`) - 기본적으로 `gateway.auth.allowTailscale`이 `true`이면 Control UI/WebSocket Serve 요청은 Tailscale ID 헤더(`tailscale-user-login`)를 통해 인증할 수 있습니다. OpenClaw는 `tailscale whois`로 `x-forwarded-for` 주소를 확인하고 이를 헤더와 일치시켜 ID를 검증하며, 요청이 Tailscale의 `x-forwarded-*` 헤더와 함께 loopback에 도달할 때만 이를 허용합니다. 브라우저 기기 ID가 있는 Control UI 운영자 세션의 경우, 이 검증된 Serve 경로는 기기 페어링 왕복도 건너뜁니다. 기기 없는 브라우저와 노드 역할 연결은 계속 일반 기기 검사를 따릅니다. Serve 트래픽에도 명시적 공유 시크릿 자격 증명을 요구하려면 `gateway.auth.allowTailscale: false`를 설정하세요. 그런 다음 `gateway.auth.mode: "token"` 또는 `"password"`를 사용하세요. + 기본적으로 `gateway.auth.allowTailscale`이 `true`이면 Control UI/WebSocket Serve 요청은 Tailscale ID 헤더(`tailscale-user-login`)를 통해 인증할 수 있습니다. OpenClaw는 `tailscale whois`로 `x-forwarded-for` 주소를 확인하고 이를 헤더와 일치시켜 ID를 검증하며, 요청이 Tailscale의 `x-forwarded-*` 헤더와 함께 loopback에 도달할 때만 이를 허용합니다. 브라우저 장치 ID가 있는 Control UI 운영자 세션의 경우, 이 검증된 Serve 경로는 장치 페어링 왕복도 건너뜁니다. 장치 없는 브라우저와 노드 역할 연결은 계속 일반 장치 검사를 따릅니다. Serve 트래픽에도 명시적인 공유 비밀 자격 증명을 요구하려면 `gateway.auth.allowTailscale: false`를 설정하세요. 그런 다음 `gateway.auth.mode: "token"` 또는 `"password"`를 사용합니다. - 해당 비동기 Serve ID 경로에서는 같은 클라이언트 IP와 인증 범위에 대한 실패한 인증 시도가 rate-limit 쓰기 전에 직렬화됩니다. 따라서 같은 브라우저에서 동시에 잘못된 재시도가 발생하면 두 개의 단순 불일치가 병렬로 경합하는 대신 두 번째 요청에 `retry later`가 표시될 수 있습니다. + 해당 비동기 Serve ID 경로에서는 같은 클라이언트 IP와 인증 범위에 대한 실패한 인증 시도가 속도 제한 쓰기 전에 직렬화됩니다. 따라서 같은 브라우저의 동시 잘못된 재시도는 두 개의 단순 불일치가 병렬로 경쟁하는 대신 두 번째 요청에서 `retry later`를 표시할 수 있습니다. - 토큰 없는 Serve 인증은 Gateway 호스트가 신뢰된다고 가정합니다. 신뢰할 수 없는 로컬 코드가 해당 호스트에서 실행될 수 있다면 토큰/비밀번호 인증을 요구하세요. + 토큰 없는 Serve 인증은 게이트웨이 호스트를 신뢰할 수 있다고 가정합니다. 신뢰할 수 없는 로컬 코드가 해당 호스트에서 실행될 수 있다면 토큰/비밀번호 인증을 요구하세요. - + ```bash openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)" ``` @@ -303,22 +303,22 @@ Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration] - `http://:18789/`(또는 구성된 `gateway.controlUi.basePath`) - 일치하는 공유 시크릿을 UI 설정에 붙여넣으세요(`connect.params.auth.token` 또는 `connect.params.auth.password`로 전송됨). + 일치하는 공유 비밀을 UI 설정에 붙여넣습니다(`connect.params.auth.token` 또는 `connect.params.auth.password`로 전송됨). ## 안전하지 않은 HTTP -일반 HTTP(`http://` 또는 `http://`)로 대시보드를 열면 브라우저는 **비보안 컨텍스트**에서 실행되고 WebCrypto를 차단합니다. 기본적으로 OpenClaw는 기기 ID가 없는 Control UI 연결을 **차단**합니다. +일반 HTTP(`http://` 또는 `http://`)로 대시보드를 열면 브라우저가 **비보안 컨텍스트**에서 실행되어 WebCrypto를 차단합니다. 기본적으로 OpenClaw는 장치 ID가 없는 Control UI 연결을 **차단**합니다. 문서화된 예외: -- `gateway.controlUi.allowInsecureAuth=true`를 사용한 localhost 전용 안전하지 않은 HTTP 호환성 +- `gateway.controlUi.allowInsecureAuth=true`를 사용하는 localhost 전용 안전하지 않은 HTTP 호환성 - `gateway.auth.mode: "trusted-proxy"`를 통한 성공적인 운영자 Control UI 인증 - 비상용 `gateway.controlUi.dangerouslyDisableDeviceAuth=true` -**권장 해결 방법:** HTTPS(Tailscale Serve)를 사용하거나 UI를 로컬에서 여세요. +**권장 수정:** HTTPS(Tailscale Serve)를 사용하거나 UI를 로컬에서 여세요. - `https:///` (Serve) - `http://127.0.0.1:18789/` (Gateway 호스트에서) @@ -337,9 +337,9 @@ Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration] `allowInsecureAuth`는 로컬 호환성 토글일 뿐입니다. - - 비보안 HTTP 컨텍스트에서 localhost Control UI 세션이 디바이스 ID 없이 계속 진행되도록 허용합니다. + - 보안되지 않은 HTTP 컨텍스트에서 로컬호스트 Control UI 세션이 장치 ID 없이 계속 진행되도록 허용합니다. - 페어링 검사를 우회하지 않습니다. - - 원격(non-localhost) 디바이스 ID 요구 사항을 완화하지 않습니다. + - 원격(로컬호스트가 아닌) 장치 ID 요구 사항을 완화하지 않습니다. @@ -354,52 +354,62 @@ Web Push는 iOS APNS 릴레이 경로(릴레이 기반 푸시는 [Configuration] ``` - `dangerouslyDisableDeviceAuth`는 Control UI 디바이스 ID 검사를 비활성화하며 심각한 보안 다운그레이드입니다. 긴급 사용 후에는 신속하게 되돌리세요. + `dangerouslyDisableDeviceAuth`는 Control UI 장치 ID 검사를 비활성화하며, 심각한 보안 다운그레이드입니다. 긴급 사용 후에는 빠르게 되돌리세요. - - 신뢰할 수 있는 프록시 인증에 성공하면 디바이스 ID 없이 **operator** Control UI 세션을 허용할 수 있습니다. - - 이는 노드 역할 Control UI 세션에는 확장되지 않습니다. - - 같은 호스트의 loopback 리버스 프록시는 여전히 신뢰할 수 있는 프록시 인증을 충족하지 않습니다. [신뢰할 수 있는 프록시 인증](/ko/gateway/trusted-proxy-auth)을 참고하세요. + - 성공한 신뢰할 수 있는 프록시 인증은 장치 ID 없이 **운영자** Control UI 세션을 허용할 수 있습니다. + - 이는 노드 역할 Control UI 세션에는 확장 적용되지 않습니다. + - 동일 호스트 loopback 역방향 프록시는 여전히 신뢰할 수 있는 프록시 인증을 충족하지 않습니다. [신뢰할 수 있는 프록시 인증](/ko/gateway/trusted-proxy-auth)을 참조하세요. -HTTPS 설정 지침은 [Tailscale](/ko/gateway/tailscale)을 참고하세요. +HTTPS 설정 지침은 [Tailscale](/ko/gateway/tailscale)을 참조하세요. ## 콘텐츠 보안 정책 -Control UI는 엄격한 `img-src` 정책과 함께 제공됩니다. **same-origin** 자산, `data:` URL, 로컬에서 생성된 `blob:` URL만 허용됩니다. 원격 `http(s)` 및 프로토콜 상대 이미지 URL은 브라우저에서 거부되며 네트워크 가져오기를 발생시키지 않습니다. +Control UI는 엄격한 `img-src` 정책과 함께 제공됩니다. **same-origin** 자산, `data:` URL, 로컬에서 생성된 `blob:` URL만 허용됩니다. 원격 `http(s)` 및 프로토콜 상대 이미지 URL은 브라우저에서 거부되며 네트워크 가져오기를 실행하지 않습니다. -실제로는 다음을 의미합니다. +실제로 이는 다음을 의미합니다. -- 상대 경로(예: `/avatars/`)로 제공되는 아바타와 이미지는 계속 렌더링됩니다. 여기에는 UI가 가져와 로컬 `blob:` URL로 변환하는 인증된 아바타 경로도 포함됩니다. +- 상대 경로(예: `/avatars/`) 아래에서 제공되는 아바타와 이미지는 계속 렌더링됩니다. 여기에는 UI가 가져와 로컬 `blob:` URL로 변환하는 인증된 아바타 라우트도 포함됩니다. - 인라인 `data:image/...` URL은 계속 렌더링됩니다(프로토콜 내 페이로드에 유용). - Control UI가 생성한 로컬 `blob:` URL은 계속 렌더링됩니다. -- 채널 메타데이터에서 내보낸 원격 아바타 URL은 Control UI의 아바타 헬퍼에서 제거되고 기본 제공 로고/배지로 대체되므로, 손상되었거나 악의적인 채널이 operator 브라우저에서 임의의 원격 이미지 가져오기를 강제할 수 없습니다. +- 채널 메타데이터가 내보낸 원격 아바타 URL은 Control UI의 아바타 헬퍼에서 제거되고 기본 제공 로고/배지로 대체됩니다. 따라서 손상되었거나 악의적인 채널이 운영자 브라우저에서 임의의 원격 이미지 가져오기를 강제할 수 없습니다. 이 동작을 얻기 위해 변경할 것은 없습니다. 항상 켜져 있으며 구성할 수 없습니다. -## 아바타 경로 인증 +## 아바타 라우트 인증 -Gateway 인증이 구성된 경우 Control UI 아바타 엔드포인트에는 API의 나머지 부분과 동일한 Gateway 토큰이 필요합니다. +Gateway 인증이 구성된 경우, Control UI 아바타 엔드포인트는 나머지 API와 동일한 Gateway 토큰을 요구합니다. - `GET /avatar/`는 인증된 호출자에게만 아바타 이미지를 반환합니다. `GET /avatar/?meta=1`은 동일한 규칙에 따라 아바타 메타데이터를 반환합니다. -- 두 경로 중 하나에 대한 인증되지 않은 요청은 거부됩니다(동급 assistant-media 경로와 동일). 이렇게 하면 그 외에는 보호되는 호스트에서 아바타 경로가 에이전트 ID를 유출하지 못하게 됩니다. -- Control UI 자체는 아바타를 가져올 때 Gateway 토큰을 bearer 헤더로 전달하고 인증된 blob URL을 사용하므로 이미지가 대시보드에서 계속 렌더링됩니다. +- 두 라우트 중 하나에 대한 인증되지 않은 요청은 거부됩니다(인접한 assistant-media 라우트와 일치). 이렇게 하면 다른 방식으로 보호되는 호스트에서 아바타 라우트가 에이전트 ID를 유출하지 못하게 합니다. +- Control UI 자체는 아바타를 가져올 때 Gateway 토큰을 bearer 헤더로 전달하고, 인증된 blob URL을 사용하므로 이미지가 대시보드에서 계속 렌더링됩니다. -Gateway 인증을 비활성화하면(공유 호스트에서는 권장하지 않음) Gateway의 나머지 부분과 마찬가지로 아바타 경로도 인증 없이 접근할 수 있게 됩니다. +Gateway 인증을 비활성화하면(공유 호스트에서는 권장하지 않음) 아바타 라우트도 나머지 Gateway와 마찬가지로 인증되지 않은 상태가 됩니다. + +## 어시스턴트 미디어 라우트 인증 + +Gateway 인증이 구성된 경우, 어시스턴트 로컬 미디어 미리보기는 2단계 라우트를 사용합니다. + +- `GET /__openclaw__/assistant-media?meta=1&source=`는 일반 Control UI 운영자 인증을 요구합니다. 브라우저는 사용 가능 여부를 확인할 때 Gateway 토큰을 bearer 헤더로 보냅니다. +- 성공한 메타데이터 응답에는 해당 정확한 소스 경로로 범위가 지정된 수명이 짧은 `mediaTicket`이 포함됩니다. +- 브라우저에서 렌더링되는 이미지, 오디오, 비디오, 문서 URL은 활성 Gateway 토큰이나 비밀번호 대신 `mediaTicket=`을 사용합니다. 티켓은 빠르게 만료되며 다른 소스에 권한을 부여할 수 없습니다. + +이렇게 하면 재사용 가능한 Gateway 자격 증명을 보이는 미디어 URL에 넣지 않고도 일반 미디어 렌더링이 브라우저 네이티브 미디어 요소와 호환됩니다. ## UI 빌드 -Gateway는 `dist/control-ui`에서 정적 파일을 제공합니다. 다음 명령으로 빌드하세요. +Gateway는 `dist/control-ui`에서 정적 파일을 제공합니다. 다음으로 빌드하세요. ```bash pnpm ui:build ``` -선택적 절대 base(고정 자산 URL을 원할 때): +선택적 절대 기준 경로(고정 자산 URL을 원할 때): ```bash OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build @@ -415,7 +425,7 @@ pnpm ui:dev ## 디버깅/테스트: 개발 서버 + 원격 Gateway -Control UI는 정적 파일입니다. WebSocket 대상은 구성 가능하며 HTTP 원본과 다를 수 있습니다. 로컬에서는 Vite 개발 서버를 사용하고 Gateway는 다른 곳에서 실행하려는 경우 유용합니다. +Control UI는 정적 파일입니다. WebSocket 대상은 구성 가능하며 HTTP origin과 달라도 됩니다. 로컬에서 Vite 개발 서버를 사용하고 Gateway는 다른 곳에서 실행하려는 경우 유용합니다. @@ -440,16 +450,16 @@ Control UI는 정적 파일입니다. WebSocket 대상은 구성 가능하며 HT - `gatewayUrl`은 로드 후 localStorage에 저장되고 URL에서 제거됩니다. - - `gatewayUrl`을 통해 전체 `ws://` 또는 `wss://` 엔드포인트를 전달하는 경우 브라우저가 쿼리 문자열을 올바르게 파싱하도록 `gatewayUrl` 값을 URL 인코딩하세요. - - 가능하면 `token`은 URL 프래그먼트(`#token=...`)를 통해 전달해야 합니다. 프래그먼트는 서버로 전송되지 않으므로 요청 로그와 Referer 유출을 피할 수 있습니다. 레거시 `?token=` 쿼리 매개변수는 호환성을 위해 여전히 한 번 가져오지만, fallback으로만 사용되며 bootstrap 직후 즉시 제거됩니다. + - `gatewayUrl`을 통해 전체 `ws://` 또는 `wss://` 엔드포인트를 전달하는 경우, 브라우저가 쿼리 문자열을 올바르게 파싱하도록 `gatewayUrl` 값을 URL 인코딩하세요. + - 가능하면 `token`은 URL fragment(`#token=...`)를 통해 전달해야 합니다. fragment는 서버로 전송되지 않으므로 요청 로그 및 Referer 유출을 방지합니다. 레거시 `?token=` 쿼리 매개변수는 호환성을 위해 여전히 한 번 가져오지만, fallback으로만 사용되며 bootstrap 직후 즉시 제거됩니다. - `password`는 메모리에만 유지됩니다. - - `gatewayUrl`이 설정되면 UI는 config 또는 환경 자격 증명으로 fallback하지 않습니다. `token`(또는 `password`)을 명시적으로 제공하세요. 명시적 자격 증명이 없으면 오류입니다. - - Gateway가 TLS 뒤에 있는 경우(Tailscale Serve, HTTPS 프록시 등) `wss://`를 사용하세요. - - `gatewayUrl`은 clickjacking을 방지하기 위해 최상위 창(embedded가 아닌 경우)에서만 허용됩니다. - - Non-loopback Control UI 배포는 `gateway.controlUi.allowedOrigins`를 명시적으로 설정해야 합니다(전체 origins). 여기에는 원격 개발 설정도 포함됩니다. - - Gateway 시작 시 유효한 런타임 bind 및 port에서 `http://localhost:` 및 `http://127.0.0.1:` 같은 로컬 origins를 시드할 수 있지만, 원격 브라우저 origins에는 여전히 명시적 항목이 필요합니다. - - 엄격히 통제되는 로컬 테스트를 제외하고 `gateway.controlUi.allowedOrigins: ["*"]`를 사용하지 마세요. 이는 "내가 사용하는 호스트와 일치"가 아니라 모든 브라우저 origin을 허용한다는 뜻입니다. - - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true`는 Host-header origin fallback 모드를 활성화하지만, 위험한 보안 모드입니다. + - `gatewayUrl`이 설정되면 UI는 구성 또는 환경 자격 증명으로 fallback하지 않습니다. `token`(또는 `password`)을 명시적으로 제공하세요. 명시적 자격 증명이 없으면 오류입니다. + - Gateway가 TLS(Tailscale Serve, HTTPS 프록시 등) 뒤에 있는 경우 `wss://`를 사용하세요. + - `gatewayUrl`은 clickjacking을 방지하기 위해 최상위 창(임베드되지 않음)에서만 허용됩니다. + - loopback이 아닌 Control UI 배포는 `gateway.controlUi.allowedOrigins`를 명시적으로 설정해야 합니다(전체 origin). 여기에는 원격 개발 설정도 포함됩니다. + - Gateway 시작 시 유효한 런타임 bind와 포트에서 `http://localhost:` 및 `http://127.0.0.1:` 같은 로컬 origin을 시드할 수 있지만, 원격 브라우저 origin에는 여전히 명시적 항목이 필요합니다. + - 엄격히 통제된 로컬 테스트를 제외하고 `gateway.controlUi.allowedOrigins: ["*"]`를 사용하지 마세요. 이는 "내가 사용하는 호스트와 일치"가 아니라 모든 브라우저 origin을 허용한다는 뜻입니다. + - `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true`는 Host 헤더 origin fallback 모드를 활성화하지만, 위험한 보안 모드입니다. @@ -466,7 +476,7 @@ Control UI는 정적 파일입니다. WebSocket 대상은 구성 가능하며 HT } ``` -원격 접근 설정 세부 정보: [원격 접근](/ko/gateway/remote). +원격 액세스 설정 세부 정보: [원격 액세스](/ko/gateway/remote). ## 관련 항목