Telegram (Bot API)

상태: grammY 기반의 봇 DM + 그룹 프로덕션 레벨. 롱 폴링이 기본 모드이며, 웹훅 모드도 선택 가능합니다.

빠른 설정

1단계: BotFather에서 봇 토큰 생성

Telegram을 열고 **@BotFather**와 채팅합니다 (핸들이 정확히 `@BotFather`인지 확인).

`/newbot`을 실행하고 안내에 따라 토큰을 저장합니다.

2단계: 토큰 및 DM 정책 설정

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123:abc",
      dmPolicy: "pairing",
      groups: { "*": { requireMention: true } },
    },
  },
}
환경 변수 폴백: `TELEGRAM_BOT_TOKEN=...` (기본 계정만).
Telegram은 `openclaw channels login telegram`을 사용하지 **않습니다**. 설정/환경 변수에 토큰을 설정한 후 게이트웨이를 시작합니다.

3단계: 게이트웨이 시작 및 첫 DM 승인

openclaw gateway
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>
페어링 코드는 1시간 후 만료됩니다.

4단계: 그룹에 봇 추가

그룹에 봇을 추가한 다음 접근 모델에 맞게 `channels.telegram.groups`와 `groupPolicy`를 설정합니다.

참고: 토큰 해석 순서는 계정을 인식합니다. 실제로 설정 값이 환경 변수 폴백보다 우선하며 TELEGRAM_BOT_TOKEN은 기본 계정에만 적용됩니다.

Telegram 측 설정

프라이버시 모드 및 그룹 가시성
Telegram 봇은 기본적으로 **프라이버시 모드**로 되어 있어 수신하는 그룹 메시지가 제한됩니다.

봇이 모든 그룹 메시지를 볼 수 있어야 하는 경우:

- `/setprivacy`로 프라이버시 모드를 비활성화하거나,
- 봇을 그룹 관리자로 지정합니다.

프라이버시 모드를 전환할 때 Telegram이 변경 사항을 적용하도록 각 그룹에서 봇을 제거 + 다시 추가합니다.
그룹 권한
관리자 상태는 Telegram 그룹 설정에서 제어됩니다.

관리자 봇은 모든 그룹 메시지를 수신하므로 항상 켜진 그룹 동작에 유용합니다.
유용한 BotFather 토글
- `/setjoingroups`로 그룹 추가 허용/거부
- `/setprivacy`로 그룹 가시성 동작

접근 제어 및 활성화

DM 정책

`channels.telegram.dmPolicy`로 다이렉트 메시지 접근을 제어합니다:

- `pairing` (기본값)
- `allowlist` (`allowFrom`에 최소 하나의 발신자 ID 필요)
- `open` (`allowFrom`에 `"*"` 필요)
- `disabled`

`channels.telegram.allowFrom`은 숫자형 Telegram 사용자 ID를 허용합니다. `telegram:` / `tg:` 접두사가 허용되며 정규화됩니다.
`dmPolicy: "allowlist"`에서 빈 `allowFrom`은 모든 DM을 차단하며 설정 검증에서 거부됩니다.
온보딩 마법사는 `@username` 입력을 받아 숫자 ID로 해석합니다.
업그레이드 후 설정에 `@username` 허용 목록 항목이 있으면 `openclaw doctor --fix`를 실행하여 해석합니다 (최선의 노력; Telegram 봇 토큰 필요).
이전에 페어링 저장소 허용 목록 파일에 의존했다면 `openclaw doctor --fix`가 허용 목록 흐름에서 항목을 `channels.telegram.allowFrom`으로 복구할 수 있습니다 (예: `dmPolicy: "allowlist"`에 명시적 ID가 아직 없는 경우).

단일 소유자 봇의 경우 접근 정책이 설정에서 지속되도록 명시적 숫자 `allowFrom` ID가 포함된 `dmPolicy: "allowlist"`를 권장합니다 (이전 페어링 승인에 의존하지 않음).

### Telegram 사용자 ID 찾기

안전한 방법 (타사 봇 없이):

1. 봇에게 DM을 보냅니다.
2. `openclaw logs --follow`를 실행합니다.
3. `from.id`를 읽습니다.

공식 Bot API 방법:
curl "https://api.telegram.org/bot<bot_token>/getUpdates"
타사 방법 (덜 프라이빗): `@userinfobot` 또는 `@getidsbot`.

그룹 정책 및 허용 목록

두 가지 제어가 함께 적용됩니다:

1. **허용되는 그룹** (`channels.telegram.groups`)
   - `groups` 설정 없음:
     - `groupPolicy: "open"`: 모든 그룹이 그룹 ID 검사를 통과
     - `groupPolicy: "allowlist"` (기본값): `groups` 항목을 추가하기 전까지 그룹 차단 (또는 `"*"`)
   - `groups` 설정됨: 허용 목록으로 동작 (명시적 ID 또는 `"*"`)

2. **그룹에서 허용되는 발신자** (`channels.telegram.groupPolicy`)
   - `open`
   - `allowlist` (기본값)
   - `disabled`

`groupAllowFrom`은 그룹 발신자 필터링에 사용됩니다. 미설정이면 Telegram은 `allowFrom`으로 폴백합니다.
`groupAllowFrom` 항목은 숫자형 Telegram 사용자 ID여야 합니다 (`telegram:` / `tg:` 접두사는 정규화됨).
`groupAllowFrom`에 Telegram 그룹 또는 슈퍼그룹 채팅 ID를 넣지 마세요. 음수 채팅 ID는 `channels.telegram.groups` 아래에 둡니다.
비숫자 항목은 발신자 인가에서 무시됩니다.
보안 경계 (`2026.2.25+`): 그룹 발신자 인증은 DM 페어링 저장소 승인을 상속하지 **않습니다**.
페어링은 DM 전용으로 유지됩니다. 그룹의 경우 `groupAllowFrom` 또는 그룹별/토픽별 `allowFrom`을 설정합니다.
런타임 참고: `channels.telegram`이 완전히 누락되면 `channels.defaults.groupPolicy`가 명시적으로 설정되지 않는 한 런타임은 실패 폐쇄 `groupPolicy="allowlist"`로 기본 설정됩니다.

예시: 특정 그룹에서 모든 멤버 허용:
{
  channels: {
    telegram: {
      groups: {
        "-1001234567890": {
          groupPolicy: "open",
          requireMention: false,
        },
      },
    },
  },
}
예시: 특정 그룹에서 특정 사용자만 허용:
{
  channels: {
    telegram: {
      groups: {
        "-1001234567890": {
          requireMention: true,
          allowFrom: ["8734062810", "745123456"],
        },
      },
    },
  },
}
> **경고:**

흔한 실수: groupAllowFrom은 Telegram 그룹 허용 목록이 아닙니다.

  - `-1001234567890`과 같은 음수 Telegram 그룹 또는 슈퍼그룹 채팅 ID는 `channels.telegram.groups`에 넣으세요.
  - `8734062810`과 같은 Telegram 사용자 ID는 허용된 그룹 내에서 봇을 트리거할 수 있는 사람을 제한하려면 `groupAllowFrom`에 넣으세요.
  - 허용된 그룹의 모든 멤버가 봇과 대화할 수 있게 하려면 `groupAllowFrom: ["*"]`을 사용하세요.

멘션 동작

그룹 응답은 기본적으로 멘션이 필요합니다.

멘션은 다음에서 올 수 있습니다:

- 네이티브 `@botusername` 멘션, 또는
- 멘션 패턴:
  - `agents.list[].groupChat.mentionPatterns`
  - `messages.groupChat.mentionPatterns`

세션 수준 명령 토글:

- `/activation always`
- `/activation mention`

세션 상태만 업데이트됩니다. 지속성에는 설정을 사용합니다.

영구 설정 예시:
{
  channels: {
    telegram: {
      groups: {
        "*": { requireMention: false },
      },
    },
  },
}
그룹 채팅 ID 가져오기:

- 그룹 메시지를 `@userinfobot` / `@getidsbot`에 전달
- 또는 `openclaw logs --follow`에서 `chat.id` 읽기
- 또는 Bot API `getUpdates` 확인

런타임 동작

  • Telegram은 게이트웨이 프로세스가 소유합니다.
  • 라우팅은 결정론적: Telegram 인바운드는 Telegram으로 응답합니다 (모델이 채널을 선택하지 않음).
  • 인바운드 메시지는 답장 메타데이터와 미디어 플레이스홀더가 포함된 공유 채널 봉투로 정규화됩니다.
  • 그룹 세션은 그룹 ID별로 격리됩니다. 포럼 토픽은 토픽을 격리하기 위해 :topic:<threadId>를 추가합니다.
  • DM 메시지에 message_thread_id가 포함될 수 있으며, OpenClaw는 스레드 인식 세션 키로 라우팅하고 응답에 스레드 ID를 유지합니다.
  • 롱 폴링은 채팅/스레드별 시퀀싱이 있는 grammY runner를 사용합니다. 전체 runner 싱크 동시성은 agents.defaults.maxConcurrent를 사용합니다.
  • Telegram Bot API에는 읽음 확인 지원이 없습니다 (sendReadReceipts는 적용되지 않음).

기능 참조

실시간 스트림 미리보기 (메시지 편집)
OpenClaw는 부분 응답을 실시간으로 스트리밍할 수 있습니다:

- 다이렉트 채팅: 미리보기 메시지 + `editMessageText`
- 그룹/토픽: 미리보기 메시지 + `editMessageText`

요구 사항:

- `channels.telegram.streaming`은 `off | partial | block | progress` (기본: `partial`)
- `progress`는 Telegram에서 `partial`로 매핑됩니다 (크로스 채널 네이밍 호환)
- 레거시 `channels.telegram.streamMode` 및 불리언 `streaming` 값은 자동 매핑됩니다

텍스트 전용 응답:

- DM: OpenClaw가 동일한 미리보기 메시지를 유지하고 제자리에서 최종 편집 수행 (두 번째 메시지 없음)
- 그룹/토픽: OpenClaw가 동일한 미리보기 메시지를 유지하고 제자리에서 최종 편집 수행 (두 번째 메시지 없음)

복합 응답 (예: 미디어 페이로드)의 경우 OpenClaw는 일반 최종 전달로 폴백하고 미리보기 메시지를 정리합니다.

미리보기 스트리밍은 블록 스트리밍과 별개입니다. Telegram에 블록 스트리밍이 명시적으로 활성화되면 OpenClaw는 이중 스트리밍을 방지하기 위해 미리보기 스트림을 건너뜁니다.

네이티브 초안 전송이 불가능/거부되면 OpenClaw는 자동으로 `sendMessage` + `editMessageText`로 폴백합니다.

Telegram 전용 추론 스트림:

- `/reasoning stream`은 생성 중 실시간 미리보기에 추론을 전송합니다
- 최종 답변은 추론 텍스트 없이 전송됩니다
서식 및 HTML 폴백
아웃바운드 텍스트는 Telegram `parse_mode: "HTML"`을 사용합니다.

- 마크다운 스타일 텍스트는 Telegram 안전 HTML로 렌더링됩니다.
- 원시 모델 HTML은 Telegram 파싱 실패를 줄이기 위해 이스케이프됩니다.
- Telegram이 파싱된 HTML을 거부하면 OpenClaw는 일반 텍스트로 재시도합니다.

링크 미리보기는 기본적으로 활성화되며 `channels.telegram.linkPreview: false`로 비활성화할 수 있습니다.
네이티브 명령 및 사용자 정의 명령
Telegram 명령 메뉴 등록은 시작 시 `setMyCommands`로 처리됩니다.

네이티브 명령 기본값:

- `commands.native: "auto"`는 Telegram에서 네이티브 명령을 활성화합니다

사용자 정의 명령 메뉴 항목 추가:
{
  channels: {
    telegram: {
      customCommands: [
        { command: "backup", description: "Git backup" },
        { command: "generate", description: "Create an image" },
      ],
    },
  },
}
규칙:

- 이름은 정규화됩니다 (앞의 `/` 제거, 소문자)
- 유효한 패턴: `a-z`, `0-9`, `_`, 길이 `1..32`
- 사용자 정의 명령은 네이티브 명령을 재정의할 수 없음
- 충돌/중복은 건너뛰고 로깅됨

참고:

- 사용자 정의 명령은 메뉴 항목만이며 동작을 자동 구현하지 않음
- 플러그인/스킬 명령은 Telegram 메뉴에 표시되지 않아도 입력하면 작동 가능

네이티브 명령이 비활성화되면 내장 명령이 제거됩니다. 사용자 정의/플러그인 명령은 설정된 경우 여전히 등록될 수 있습니다.

일반적인 설정 실패:

- `BOT_COMMANDS_TOO_MUCH`로 `setMyCommands failed`는 트리밍 후에도 Telegram 메뉴가 오버플로되었음을 의미합니다. 플러그인/스킬/사용자 정의 명령을 줄이거나 `channels.telegram.commands.native`를 비활성화합니다.
- 네트워크/fetch 오류로 `setMyCommands failed`는 일반적으로 `api.telegram.org`로의 아웃바운드 DNS/HTTPS가 차단되었음을 의미합니다.

### 기기 페어링 명령 (`device-pair` 플러그인)

`device-pair` 플러그인이 설치된 경우:

1. `/pair`로 설정 코드 생성
2. iOS 앱에 코드 붙여넣기
3. `/pair approve`로 최신 대기 중 요청 승인

자세히: [Pairing](/docs/channels/pairing#pair-via-telegram-recommended-for-ios).
인라인 버튼
인라인 키보드 범위 설정:
{
  channels: {
    telegram: {
      capabilities: {
        inlineButtons: "allowlist",
      },
    },
  },
}
계정별 재정의:
{
  channels: {
    telegram: {
      accounts: {
        main: {
          capabilities: {
            inlineButtons: "allowlist",
          },
        },
      },
    },
  },
}
범위:

- `off`
- `dm`
- `group`
- `all`
- `allowlist` (기본값)

레거시 `capabilities: ["inlineButtons"]`는 `inlineButtons: "all"`로 매핑됩니다.

메시지 액션 예시:
{
  action: "send",
  channel: "telegram",
  to: "123456789",
  message: "Choose an option:",
  buttons: [
    [
      { text: "Yes", callback_data: "yes" },
      { text: "No", callback_data: "no" },
    ],
    [{ text: "Cancel", callback_data: "cancel" }],
  ],
}
콜백 클릭은 에이전트에게 텍스트로 전달됩니다:
`callback_data: <value>`
에이전트 및 자동화를 위한 Telegram 메시지 액션
Telegram 도구 액션 포함:

- `sendMessage` (`to`, `content`, 선택 `mediaUrl`, `replyToMessageId`, `messageThreadId`)
- `react` (`chatId`, `messageId`, `emoji`)
- `deleteMessage` (`chatId`, `messageId`)
- `editMessage` (`chatId`, `messageId`, `content`)
- `createForumTopic` (`chatId`, `name`, 선택 `iconColor`, `iconCustomEmojiId`)

채널 메시지 액션은 편의 별칭을 노출합니다 (`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`).

게이팅 제어:

- `channels.telegram.actions.sendMessage`
- `channels.telegram.actions.deleteMessage`
- `channels.telegram.actions.reactions`
- `channels.telegram.actions.sticker` (기본: 비활성화)

참고: `edit`과 `topic-create`는 현재 기본적으로 활성화되어 있으며 별도의 `channels.telegram.actions.*` 토글이 없습니다.
런타임 전송은 활성 설정/시크릿 스냅샷(시작/리로드)을 사용하므로 액션 경로는 전송마다 임시 SecretRef 재해석을 수행하지 않습니다.

리액션 제거 의미: [/tools/reactions](/docs/tools/reactions)
응답 스레딩 태그
Telegram은 생성된 출력에서 명시적 응답 스레딩 태그를 지원합니다:

- `[[reply_to_current]]`는 트리거 메시지에 응답
- `[[reply_to:<id>]]`는 특정 Telegram 메시지 ID에 응답

`channels.telegram.replyToMode`로 처리를 제어합니다:

- `off` (기본값)
- `first`
- `all`

참고: `off`는 암묵적 응답 스레딩을 비활성화합니다. 명시적 `[[reply_to_*]]` 태그는 여전히 적용됩니다.
포럼 토픽 및 스레드 동작
포럼 슈퍼그룹:

- 토픽 세션 키에 `:topic:<threadId>` 추가
- 응답 및 입력 표시가 토픽 스레드를 대상으로 함
- 토픽 설정 경로:
  `channels.telegram.groups.<chatId>.topics.<threadId>`

일반 토픽 (`threadId=1`) 특수 케이스:

- 메시지 전송 시 `message_thread_id` 생략 (Telegram이 `sendMessage(...thread_id=1)`을 거부)
- 입력 중 액션에는 여전히 `message_thread_id` 포함

토픽 상속: 토픽 항목은 재정의하지 않는 한 그룹 설정을 상속합니다 (`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`).
`agentId`는 토픽 전용이며 그룹 기본값을 상속하지 않습니다.

**토픽별 에이전트 라우팅**: 각 토픽은 토픽 설정에서 `agentId`를 설정하여 다른 에이전트로 라우팅할 수 있습니다. 이를 통해 각 토픽이 자체 격리된 작업 공간, 메모리, 세션을 갖게 됩니다. 예시:

```json5
{
  channels: {
    telegram: {
      groups: {
        "-1001234567890": {
          topics: {
            "1": { agentId: "main" },      // 일반 토픽 -> main 에이전트
            "3": { agentId: "zu" },        // Dev 토픽 -> zu 에이전트
            "5": { agentId: "coder" }      // 코드 리뷰 -> coder 에이전트
          }
        }
      }
    }
  }
}
```

각 토픽은 자체 세션 키를 갖습니다: `agent:zu:telegram:group:-1001234567890:topic:3`

**영구 ACP 토픽 바인딩**: 포럼 토픽은 최상위 타입 ACP 바인딩을 통해 ACP 하네스 세션을 고정할 수 있습니다:

- `bindings[]`에 `type: "acp"` 및 `match.channel: "telegram"`

예시:

```json5
{
  agents: {
    list: [
      {
        id: "codex",
        runtime: {
          type: "acp",
          acp: {
            agent: "codex",
            backend: "acpx",
            mode: "persistent",
            cwd: "/workspace/openclaw",
          },
        },
      },
    ],
  },
  bindings: [
    {
      type: "acp",
      agentId: "codex",
      match: {
        channel: "telegram",
        accountId: "default",
        peer: { kind: "group", id: "-1001234567890:topic:42" },
      },
    },
  ],
  channels: {
    telegram: {
      groups: {
        "-1001234567890": {
          topics: {
            "42": {
              requireMention: false,
            },
          },
        },
      },
    },
  },
}
```

현재 그룹 및 슈퍼그룹의 포럼 토픽에만 적용됩니다.

**채팅에서 스레드 바인딩 ACP 생성**:

- `/acp spawn <agent> --thread here|auto`는 현재 Telegram 토픽을 새 ACP 세션에 바인딩할 수 있습니다.
- 후속 토픽 메시지는 바인딩된 ACP 세션으로 직접 라우팅됩니다 (`/acp steer` 불필요).
- OpenClaw는 바인딩 성공 후 토픽 내에서 생성 확인 메시지를 고정합니다.
- `channels.telegram.threadBindings.spawnAcpSessions=true`가 필요합니다.

템플릿 컨텍스트 포함:

- `MessageThreadId`
- `IsForum`

DM 스레드 동작:

- `message_thread_id`가 있는 비공개 채팅은 DM 라우팅을 유지하지만 스레드 인식 세션 키/응답 대상을 사용합니다.
오디오, 비디오, 스티커
### 오디오 메시지

Telegram은 음성 메모와 오디오 파일을 구분합니다.

- 기본: 오디오 파일 동작
- 에이전트 응답에 `[[audio_as_voice]]` 태그로 음성 메모 전송 강제

메시지 액션 예시:
{
  action: "send",
  channel: "telegram",
  to: "123456789",
  media: "https://example.com/voice.ogg",
  asVoice: true,
}
### 비디오 메시지

Telegram은 비디오 파일과 비디오 노트를 구분합니다.

메시지 액션 예시:
{
  action: "send",
  channel: "telegram",
  to: "123456789",
  media: "https://example.com/video.mp4",
  asVideoNote: true,
}
비디오 노트는 캡션을 지원하지 않습니다. 제공된 메시지 텍스트는 별도로 전송됩니다.

### 스티커

인바운드 스티커 처리:

- 정적 WEBP: 다운로드 및 처리됨 (플레이스홀더 `<media:sticker>`)
- 애니메이션 TGS: 건너뜀
- 비디오 WEBM: 건너뜀

스티커 컨텍스트 필드:

- `Sticker.emoji`
- `Sticker.setName`
- `Sticker.fileId`
- `Sticker.fileUniqueId`
- `Sticker.cachedDescription`

스티커 캐시 파일:

- `~/.openclaw/telegram/sticker-cache.json`

스티커는 한 번 설명되고(가능한 경우) 캐시되어 반복적인 비전 호출을 줄입니다.

스티커 액션 활성화:
{
  channels: {
    telegram: {
      actions: {
        sticker: true,
      },
    },
  },
}
스티커 전송 액션:
{
  action: "sticker",
  channel: "telegram",
  to: "123456789",
  fileId: "CAACAgIAAxkBAAI...",
}
캐시된 스티커 검색:
{
  action: "sticker-search",
  channel: "telegram",
  query: "cat waving",
  limit: 5,
}
리액션 알림
Telegram 리액션은 `message_reaction` 업데이트로 도착합니다 (메시지 페이로드와 별도).

활성화되면 OpenClaw가 다음과 같은 시스템 이벤트를 큐에 넣습니다:

- `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`)으로 라우팅됩니다

폴링/웹훅의 `allowed_updates`에 `message_reaction`이 자동으로 포함됩니다.
수신 확인 리액션
`ackReaction`은 OpenClaw가 인바운드 메시지를 처리하는 동안 확인 이모지를 전송합니다.

해석 순서:

- `channels.telegram.accounts.<accountId>.ackReaction`
- `channels.telegram.ackReaction`
- `messages.ackReaction`
- 에이전트 ID 이모지 폴백 (`agents.list[].identity.emoji`, 없으면 "👀")

참고:

- Telegram은 유니코드 이모지를 사용합니다 (예: "👀").
- `""`를 사용하여 채널 또는 계정에서 리액션을 비활성화합니다.
Telegram 이벤트 및 명령으로부터의 설정 쓰기
채널 설정 쓰기는 기본적으로 활성화됩니다 (`configWrites !== false`).

Telegram에서 트리거되는 쓰기:

- 그룹 마이그레이션 이벤트 (`migrate_to_chat_id`)로 `channels.telegram.groups` 업데이트
- `/config set` 및 `/config unset` (명령 활성화 필요)

비활성화:
{
  channels: {
    telegram: {
      configWrites: false,
    },
  },
}
롱 폴링 vs 웹훅
기본: 롱 폴링.

웹훅 모드:

- `channels.telegram.webhookUrl` 설정
- `channels.telegram.webhookSecret` 설정 (웹훅 URL 설정 시 필수)
- 선택 `channels.telegram.webhookPath` (기본 `/telegram-webhook`)
- 선택 `channels.telegram.webhookHost` (기본 `127.0.0.1`)
- 선택 `channels.telegram.webhookPort` (기본 `8787`)

웹훅 모드의 기본 로컬 리스너는 `127.0.0.1:8787`에 바인딩됩니다.

공개 엔드포인트가 다른 경우 리버스 프록시를 앞에 두고 `webhookUrl`을 공개 URL로 지정합니다.
의도적으로 외부 인그레스가 필요한 경우 `webhookHost`를 설정합니다 (예: `0.0.0.0`).
제한, 재시도, CLI 대상
- `channels.telegram.textChunkLimit` 기본값은 4000입니다.
- `channels.telegram.chunkMode="newline"`은 길이 분할 전에 단락 경계(빈 줄)를 우선합니다.
- `channels.telegram.mediaMaxMb` (기본 100)는 인바운드 및 아웃바운드 Telegram 미디어 크기를 제한합니다.
- `channels.telegram.timeoutSeconds`는 Telegram API 클라이언트 타임아웃을 재정의합니다 (미설정이면 grammY 기본값 적용).
- 그룹 컨텍스트 히스토리는 `channels.telegram.historyLimit` 또는 `messages.groupChat.historyLimit` (기본 50)을 사용합니다. `0`으로 비활성화.
- DM 히스토리 제어:
  - `channels.telegram.dmHistoryLimit`
  - `channels.telegram.dms["<user_id>"].historyLimit`
- `channels.telegram.retry` 설정은 복구 가능한 아웃바운드 API 오류에 대한 Telegram 전송 헬퍼(CLI/도구/액션)에 적용됩니다.

CLI 전송 대상은 숫자 채팅 ID 또는 사용자 이름일 수 있습니다:
openclaw message send --channel telegram --target 123456789 --message "hi"
openclaw message send --channel telegram --target @name --message "hi"
Telegram 설문조사는 `openclaw message poll`을 사용하며 포럼 토픽을 지원합니다:
openclaw message poll --channel telegram --target 123456789 \
  --poll-question "Ship it?" --poll-option "Yes" --poll-option "No"
openclaw message poll --channel telegram --target -1001234567890:topic:42 \
  --poll-question "Pick a time" --poll-option "10am" --poll-option "2pm" \
  --poll-duration-seconds 300 --poll-public
Telegram 전용 설문조사 플래그:

- `--poll-duration-seconds` (5-600)
- `--poll-anonymous`
- `--poll-public`
- `--thread-id` 포럼 토픽용 (또는 `:topic:` 대상 사용)

액션 게이팅:

- `channels.telegram.actions.sendMessage=false`는 설문조사를 포함한 아웃바운드 Telegram 메시지를 비활성화합니다
- `channels.telegram.actions.poll=false`는 일반 전송을 유지하면서 Telegram 설문조사 생성을 비활성화합니다
Telegram에서의 실행 승인
Telegram은 승인자 DM에서 실행 승인을 지원하며 원본 채팅 또는 토픽에 승인 프롬프트를 선택적으로 게시할 수 있습니다.

설정 경로:

- `channels.telegram.execApprovals.enabled`
- `channels.telegram.execApprovals.approvers`
- `channels.telegram.execApprovals.target` (`dm` | `channel` | `both`, 기본: `dm`)
- `agentFilter`, `sessionFilter`

승인자는 숫자형 Telegram 사용자 ID여야 합니다. `enabled`가 false이거나 `approvers`가 비어있으면 Telegram은 실행 승인 클라이언트로 작동하지 않습니다. 승인 요청은 다른 설정된 승인 경로 또는 실행 승인 폴백 정책으로 폴백됩니다.

전달 규칙:

- `target: "dm"`은 설정된 승인자 DM에만 승인 프롬프트 전송
- `target: "channel"`은 원본 Telegram 채팅/토픽에 프롬프트 전송
- `target: "both"`는 승인자 DM과 원본 채팅/토픽 모두에 전송

설정된 승인자만 승인 또는 거부할 수 있습니다. 비승인자는 `/approve`를 사용할 수 없으며 Telegram 승인 버튼도 사용할 수 없습니다.

채널 전달은 채팅에 명령 텍스트를 표시하므로 신뢰할 수 있는 그룹/토픽에서만 `channel` 또는 `both`를 활성화합니다. 포럼 토픽에 프롬프트가 도착하면 OpenClaw는 승인 프롬프트와 승인 후 후속 조치 모두에서 토픽을 유지합니다.

인라인 승인 버튼도 `channels.telegram.capabilities.inlineButtons`가 대상 표면 (`dm`, `group`, 또는 `all`)을 허용하는지에 따라 달라집니다.

관련 문서: [Exec approvals](/docs/tools/exec-approvals)

문제 해결

멘션 없는 그룹 메시지에 봇이 응답하지 않음
- `requireMention=false`인 경우 Telegram 프라이버시 모드가 전체 가시성을 허용해야 합니다.
  - BotFather: `/setprivacy` -> Disable
  - 그런 다음 그룹에서 봇을 제거 + 다시 추가
- `openclaw channels status`는 설정이 멘션 없는 그룹 메시지를 기대할 때 경고합니다.
- `openclaw channels status --probe`는 명시적 숫자 그룹 ID를 확인할 수 있습니다. 와일드카드 `"*"`는 멤버십 프로빙이 불가능합니다.
- 빠른 세션 테스트: `/activation always`.
봇이 그룹 메시지를 전혀 보지 못함
- `channels.telegram.groups`가 있으면 그룹이 나열되어야 합니다 (또는 `"*"` 포함)
- 그룹에서 봇 멤버십 확인
- 로그 확인: 건너뛰는 이유는 `openclaw logs --follow`에서 확인
명령이 부분적으로 또는 전혀 작동하지 않음
- 발신자 ID를 인가합니다 (페어링 및/또는 숫자 `allowFrom`)
- 그룹 정책이 `open`이어도 명령 인가는 여전히 적용됩니다
- `BOT_COMMANDS_TOO_MUCH`로 `setMyCommands failed`는 네이티브 메뉴에 항목이 너무 많음을 의미합니다. 플러그인/스킬/사용자 정의 명령을 줄이거나 네이티브 메뉴를 비활성화합니다
- 네트워크/fetch 오류로 `setMyCommands failed`는 일반적으로 `api.telegram.org`에 대한 DNS/HTTPS 접근성 문제를 나타냅니다
폴링 또는 네트워크 불안정
- Node 22+ + 사용자 정의 fetch/프록시는 AbortSignal 타입 불일치 시 즉시 중단 동작을 트리거할 수 있습니다.
- 일부 호스트는 `api.telegram.org`를 IPv6로 먼저 해석합니다. 깨진 IPv6 이그레스는 간헐적인 Telegram API 실패를 유발할 수 있습니다.
- 로그에 `TypeError: fetch failed` 또는 `Network request for 'getUpdates' failed!`가 포함되면 OpenClaw는 이를 복구 가능한 네트워크 오류로 재시도합니다.
- 직접 이그레스/TLS가 불안정한 VPS 호스트에서는 `channels.telegram.proxy`를 통해 Telegram API 호출을 라우팅합니다:
channels:
  telegram:
    proxy: socks5://<user>:<password>@proxy-host:1080
- Node 22+는 `autoSelectFamily=true` (WSL2 제외) 및 `dnsResultOrder=ipv4first`가 기본입니다.
- 호스트가 WSL2이거나 IPv4 전용 동작이 더 잘 작동하는 경우 패밀리 선택을 강제합니다:
channels:
  telegram:
    network:
      autoSelectFamily: false
- 환경 변수 재정의 (임시):
  - `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1`
  - `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1`
  - `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first`
- DNS 응답 확인:
dig +short api.telegram.org A
dig +short api.telegram.org AAAA

추가 도움말: Channel troubleshooting.

Telegram 설정 참조 포인터

기본 참조:

  • channels.telegram.enabled: 채널 시작 활성화/비활성화.

  • channels.telegram.botToken: 봇 토큰 (BotFather).

  • channels.telegram.tokenFile: 일반 파일 경로에서 토큰 읽기. 심볼릭 링크는 거부됩니다.

  • channels.telegram.dmPolicy: pairing | allowlist | open | disabled (기본: pairing).

  • channels.telegram.allowFrom: DM 허용 목록 (숫자형 Telegram 사용자 ID). allowlist는 최소 하나의 발신자 ID 필요. open"*" 필요. openclaw doctor --fix는 레거시 @username 항목을 ID로 해석하고 허용 목록 마이그레이션 흐름에서 페어링 저장소 파일의 항목을 복구할 수 있습니다.

  • channels.telegram.actions.poll: Telegram 설문조사 생성 활성화/비활성화 (기본: 활성화; 여전히 sendMessage 필요).

  • channels.telegram.defaultTo: CLI --deliver에서 명시적 --reply-to가 제공되지 않을 때 사용되는 기본 Telegram 대상.

  • channels.telegram.groupPolicy: open | allowlist | disabled (기본: allowlist).

  • channels.telegram.groupAllowFrom: 그룹 발신자 허용 목록 (숫자형 Telegram 사용자 ID). openclaw doctor --fix는 레거시 @username 항목을 ID로 해석할 수 있습니다. 비숫자 항목은 인증 시점에 무시됩니다. 그룹 인증은 DM 페어링 저장소 폴백을 사용하지 않습니다 (2026.2.25+).

  • 멀티 계정 우선순위:

    • 두 개 이상의 계정 ID가 설정된 경우 channels.telegram.defaultAccount를 설정하거나 (channels.telegram.accounts.default 포함) 기본 라우팅을 명시적으로 설정합니다.
    • 둘 다 설정되지 않으면 OpenClaw는 첫 번째 정규화된 계정 ID로 폴백하고 openclaw doctor가 경고합니다.
    • channels.telegram.accounts.default.allowFromchannels.telegram.accounts.default.groupAllowFromdefault 계정에만 적용됩니다.
    • 이름이 지정된 계정은 계정 수준 값이 미설정이면 channels.telegram.allowFromchannels.telegram.groupAllowFrom을 상속합니다.
    • 이름이 지정된 계정은 channels.telegram.accounts.default.allowFrom / groupAllowFrom을 상속하지 않습니다.
  • channels.telegram.groups: 그룹별 기본값 + 허용 목록 (전역 기본값에는 "*" 사용).

    • channels.telegram.groups.<id>.groupPolicy: 그룹별 groupPolicy 재정의 (open | allowlist | disabled).
    • channels.telegram.groups.<id>.requireMention: 멘션 게이팅 기본값.
    • channels.telegram.groups.<id>.skills: 스킬 필터 (생략 = 모든 스킬, 빈 값 = 없음).
    • channels.telegram.groups.<id>.allowFrom: 그룹별 발신자 허용 목록 재정의.
    • channels.telegram.groups.<id>.systemPrompt: 그룹용 추가 시스템 프롬프트.
    • channels.telegram.groups.<id>.enabled: false일 때 그룹 비활성화.
    • channels.telegram.groups.<id>.topics.<threadId>.*: 토픽별 재정의 (그룹 필드 + 토픽 전용 agentId).
    • channels.telegram.groups.<id>.topics.<threadId>.agentId: 이 토픽을 특정 에이전트로 라우팅 (그룹 수준 및 바인딩 라우팅 재정의).
  • channels.telegram.groups.<id>.topics.<threadId>.groupPolicy: 토픽별 groupPolicy 재정의 (open | allowlist | disabled).

  • channels.telegram.groups.<id>.topics.<threadId>.requireMention: 토픽별 멘션 게이팅 재정의.

  • 최상위 bindings[]type: "acp" 및 정규 토픽 id chatId:topic:topicIdmatch.peer.id에: 영구 ACP 토픽 바인딩 필드 (ACP Agents 참조).

  • channels.telegram.direct.<id>.topics.<threadId>.agentId: DM 토픽을 특정 에이전트로 라우팅 (포럼 토픽과 동일한 동작).

  • channels.telegram.execApprovals.enabled: 이 계정에 대해 Telegram을 채팅 기반 실행 승인 클라이언트로 활성화.

  • channels.telegram.execApprovals.approvers: 실행 요청을 승인 또는 거부할 수 있는 Telegram 사용자 ID. 실행 승인 활성화 시 필수.

  • channels.telegram.execApprovals.target: dm | channel | both (기본: dm). channelboth는 원본 Telegram 토픽이 있으면 유지.

  • channels.telegram.execApprovals.agentFilter: 전달된 승인 프롬프트의 선택적 에이전트 ID 필터.

  • channels.telegram.execApprovals.sessionFilter: 전달된 승인 프롬프트의 선택적 세션 키 필터 (부분 문자열 또는 정규식).

  • channels.telegram.accounts.<account>.execApprovals: Telegram 실행 승인 라우팅 및 승인자 인가의 계정별 재정의.

  • channels.telegram.capabilities.inlineButtons: off | dm | group | all | allowlist (기본: allowlist).

  • channels.telegram.accounts.<account>.capabilities.inlineButtons: 계정별 재정의.

  • channels.telegram.commands.nativeSkills: Telegram 네이티브 스킬 명령 활성화/비활성화.

  • channels.telegram.replyToMode: off | first | all (기본: off).

  • channels.telegram.textChunkLimit: 아웃바운드 청크 크기 (문자).

  • channels.telegram.chunkMode: length (기본) 또는 newline (길이 청킹 전에 빈 줄(단락 경계)로 분할).

  • channels.telegram.linkPreview: 아웃바운드 메시지의 링크 미리보기 전환 (기본: true).

  • channels.telegram.streaming: off | partial | block | progress (실시간 스트림 미리보기; 기본: partial; progresspartial로 매핑; block은 레거시 미리보기 모드 호환). Telegram 미리보기 스트리밍은 제자리에서 편집되는 단일 미리보기 메시지를 사용합니다.

  • channels.telegram.mediaMaxMb: 인바운드/아웃바운드 Telegram 미디어 상한 (MB, 기본: 100).

  • channels.telegram.retry: 복구 가능한 아웃바운드 API 오류에 대한 Telegram 전송 헬퍼(CLI/도구/액션)의 재시도 정책 (attempts, minDelayMs, maxDelayMs, jitter).

  • channels.telegram.network.autoSelectFamily: Node autoSelectFamily 재정의 (true=활성화, false=비활성화). Node 22+에서 기본 활성화, WSL2는 기본 비활성화.

  • channels.telegram.network.dnsResultOrder: DNS 결과 순서 재정의 (ipv4first 또는 verbatim). Node 22+에서 ipv4first 기본값.

  • channels.telegram.proxy: Bot API 호출용 프록시 URL (SOCKS/HTTP).

  • channels.telegram.webhookUrl: 웹훅 모드 활성화 (channels.telegram.webhookSecret 필요).

  • channels.telegram.webhookSecret: 웹훅 시크릿 (webhookUrl 설정 시 필수).

  • channels.telegram.webhookPath: 로컬 웹훅 경로 (기본 /telegram-webhook).

  • channels.telegram.webhookHost: 로컬 웹훅 바인드 호스트 (기본 127.0.0.1).

  • channels.telegram.webhookPort: 로컬 웹훅 바인드 포트 (기본 8787).

  • channels.telegram.actions.reactions: Telegram 도구 리액션 게이트.

  • channels.telegram.actions.sendMessage: Telegram 도구 메시지 전송 게이트.

  • channels.telegram.actions.deleteMessage: Telegram 도구 메시지 삭제 게이트.

  • channels.telegram.actions.sticker: Telegram 스티커 액션 게이트 — 전송 및 검색 (기본: false).

  • channels.telegram.reactionNotifications: off | own | all — 시스템 이벤트를 트리거하는 리액션 제어 (미설정 시 기본: own).

  • channels.telegram.reactionLevel: off | ack | minimal | extensive — 에이전트의 리액션 기능 제어 (미설정 시 기본: minimal).

  • Configuration reference - Telegram

Telegram 전용 주요 필드:

  • 시작/인증: enabled, botToken, tokenFile, accounts.* (tokenFile은 일반 파일을 가리켜야 함; 심볼릭 링크 거부)
  • 접근 제어: dmPolicy, allowFrom, groupPolicy, groupAllowFrom, groups, groups.*.topics.*, 최상위 bindings[] (type: "acp")
  • 실행 승인: execApprovals, accounts.*.execApprovals
  • 명령/메뉴: commands.native, commands.nativeSkills, customCommands
  • 스레딩/응답: replyToMode
  • 스트리밍: streaming (미리보기), blockStreaming
  • 서식/전달: textChunkLimit, chunkMode, linkPreview, responsePrefix
  • 미디어/네트워크: mediaMaxMb, timeoutSeconds, retry, network.autoSelectFamily, proxy
  • 웹훅: webhookUrl, webhookSecret, webhookPath, webhookHost
  • 액션/기능: capabilities.inlineButtons, actions.sendMessage|editMessage|deleteMessage|reactions|sticker
  • 리액션: reactionNotifications, reactionLevel
  • 쓰기/히스토리: configWrites, historyLimit, dmHistoryLimit, dms.*.historyLimit

관련 문서