Telegram (Bot API)

상태: grammY를 통한 봇 DM + 그룹에 대한 프로덕션 준비 완료. 기본적으로 롱 폴링; 웹훅 선택 사항.

빠른 설정 (초보자)

  1. @BotFather로 봇을 만들고 토큰을 복사합니다.
  2. 토큰 설정:
    • Env: TELEGRAM_BOT_TOKEN=...
    • 또는 설정: channels.telegram.botToken: "...".
    • 둘 다 설정된 경우 설정이 우선합니다 (env 대체는 기본 계정만).
  3. Gateway를 시작합니다.
  4. DM 액세스는 기본적으로 페어링입니다. 첫 연락 시 페어링 코드를 승인하세요.

최소 설정:

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123:abc",
      dmPolicy: "pairing"
    }
  }
}

개요

  • Gateway가 소유한 Telegram Bot API 채널.
  • 결정론적 라우팅: 답장은 Telegram으로 돌아갑니다. 모델은 채널을 선택하지 않습니다.
  • DM은 에이전트의 메인 세션을 공유합니다. 그룹은 격리된 상태로 유지됩니다 (agent:<agentId>:telegram:group:<chatId>).

설정 (빠른 경로)

1) 봇 토큰 생성 (BotFather)

  1. Telegram을 열고 @BotFather와 채팅합니다.
  2. /newbot를 실행한 다음 프롬프트를 따릅니다 (이름 + bot로 끝나는 사용자 이름).
  3. 토큰을 복사하고 안전하게 저장합니다.

선택적 BotFather 설정:

  • /setjoingroups — 봇을 그룹에 추가할 수 있도록 허용/거부.
  • /setprivacy — 봇이 모든 그룹 메시지를 보는지 제어.

2) 토큰 구성 (env 또는 설정)

예시:

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "123:abc",
      dmPolicy: "pairing",
      groups: { "*": { requireMention: true } }
    }
  }
}

Env 옵션: TELEGRAM_BOT_TOKEN=... (기본 계정에 작동). env와 설정이 모두 설정된 경우 설정이 우선합니다.

다중 계정 지원: 계정별 토큰과 선택적 name으로 channels.telegram.accounts를 사용합니다. 공유 패턴은 gateway/configuration을 참조하세요.

  1. Gateway를 시작합니다. 토큰이 해결되면 Telegram이 시작됩니다 (설정 우선, env 대체).
  2. DM 액세스는 기본적으로 페어링입니다. 봇에 처음 연락할 때 코드를 승인하세요.
  3. 그룹의 경우: 봇을 추가하고 개인 정보/관리자 동작을 결정한 다음 (아래) 멘션 게이팅 + 허용 목록을 제어하기 위해 channels.telegram.groups를 설정하세요.

토큰 + 개인 정보 + 권한 (Telegram 측면)

토큰 생성 (BotFather)

  • /newbot는 봇을 만들고 토큰을 반환합니다 (비밀로 유지).
  • 토큰이 유출되면 @BotFather를 통해 취소/재생성하고 설정을 업데이트하세요.

그룹 메시지 가시성 (개인 정보 모드)

Telegram 봇은 기본적으로 개인 정보 모드로 설정되어 수신하는 그룹 메시지를 제한합니다. 봇이 모든 그룹 메시지를 보아야 하는 경우 두 가지 옵션이 있습니다:

  • /setprivacy로 개인 정보 모드를 비활성화하거나 또는
  • 봇을 그룹 관리자로 추가 (관리자 봇은 모든 메시지를 받음).

참고: 개인 정보 모드를 토글하면 Telegram은 변경 사항이 적용되도록 각 그룹에서 봇을 제거 + 다시 추가해야 합니다.

그룹 권한 (관리자 권한)

관리자 상태는 그룹 내에서 설정됩니다 (Telegram UI). 관리자 봇은 항상 모든 그룹 메시지를 받으므로 전체 가시성이 필요한 경우 관리자를 사용하세요.

작동 방식 (동작)

  • 인바운드 메시지는 답장 컨텍스트 및 미디어 자리 표시자와 함께 공유 채널 봉투로 정규화됩니다.
  • 그룹 답장은 기본적으로 멘션이 필요합니다 (네이티브 @mention 또는 agents.list[].groupChat.mentionPatterns / messages.groupChat.mentionPatterns).
  • 다중 에이전트 재정의: agents.list[].groupChat.mentionPatterns에서 에이전트별 패턴을 설정하세요.
  • 답장은 항상 동일한 Telegram 채팅으로 라우팅됩니다.
  • 롱 폴링은 채팅별 시퀀싱으로 grammY 러너를 사용합니다. 전체 동시성은 agents.defaults.maxConcurrent로 제한됩니다.
  • Telegram Bot API는 읽음 확인을 지원하지 않습니다. sendReadReceipts 옵션이 없습니다.

포맷팅 (Telegram HTML)

  • 아웃바운드 Telegram 텍스트는 parse_mode: "HTML" (Telegram의 지원되는 태그 하위 집합)을 사용합니다.
  • Markdown 형식 입력은 Telegram 안전 HTML (굵게/기울임꼴/취소선/코드/링크)로 렌더링됩니다. 블록 요소는 개행/글머리 기호가 있는 텍스트로 평면화됩니다.
  • 모델의 원시 HTML은 Telegram 파싱 오류를 피하기 위해 이스케이프됩니다.
  • Telegram이 HTML 페이로드를 거부하면 OpenClaw는 동일한 메시지를 일반 텍스트로 재시도합니다.

명령 (네이티브 + 커스텀)

OpenClaw는 시작 시 Telegram의 봇 메뉴에 네이티브 명령(/status, /reset, /model 등)을 등록합니다. 설정을 통해 봇 메뉴에 커스텀 명령을 추가할 수 있습니다:

{
  channels: {
    telegram: {
      customCommands: [
        { command: "backup", description: "Git 백업" },
        { command: "generate", description: "이미지 생성" }
      ]
    }
  }
}

문제 해결

  • 로그의 setMyCommands failed는 일반적으로 api.telegram.org에 대한 아웃바운드 HTTPS/DNS가 차단되었음을 의미합니다.
  • sendMessage 또는 sendChatAction 실패가 표시되면 IPv6 라우팅 및 DNS를 확인하세요.

추가 도움말: Channel troubleshooting.

참고 사항:

  • 커스텀 명령은 메뉴 항목만입니다. 다른 곳에서 처리하지 않는 한 OpenClaw는 구현하지 않습니다.
  • 명령 이름은 정규화됩니다 (선행 / 제거, 소문자) 및 a-z, 0-9, _와 일치해야 합니다 (1–32자).
  • 커스텀 명령은 네이티브 명령을 재정의할 수 없습니다. 충돌은 무시되고 기록됩니다.
  • commands.native가 비활성화된 경우 커스텀 명령만 등록됩니다 (없으면 지워짐).

제한

  • 아웃바운드 텍스트는 channels.telegram.textChunkLimit(기본값 4000)로 청크됩니다.
  • 선택적 개행 청크: channels.telegram.chunkMode="newline"을 설정하여 길이 청크 전에 빈 줄(단락 경계)에서 분할합니다.
  • 미디어 다운로드/업로드는 channels.telegram.mediaMaxMb(기본값 5)로 제한됩니다.
  • Telegram Bot API 요청은 channels.telegram.timeoutSeconds(기본값 500, grammY를 통해) 후 시간 초과됩니다. 긴 멈춤을 피하려면 낮게 설정하세요.
  • 그룹 기록 컨텍스트는 channels.telegram.historyLimit(또는 channels.telegram.accounts.*.historyLimit)을 사용하고 messages.groupChat.historyLimit로 대체됩니다. 비활성화하려면 0으로 설정하세요 (기본값 50).
  • DM 기록은 channels.telegram.dmHistoryLimit(사용자 턴)로 제한할 수 있습니다. 사용자별 재정의: channels.telegram.dms["<user_id>"].historyLimit.

그룹 활성화 모드

기본적으로 봇은 그룹의 멘션에만 응답합니다 (@botname 또는 agents.list[].groupChat.mentionPatterns의 패턴). 이 동작을 변경하려면:

설정을 통해 (권장)

{
  channels: {
    telegram: {
      groups: {
        "-1001234567890": { requireMention: false }  // 이 그룹에서 항상 응답
      }
    }
  }
}

중요: channels.telegram.groups를 설정하면 허용 목록이 생성됩니다 - 나열된 그룹(또는 "*")만 허용됩니다. 포럼 주제는 channels.telegram.groups.<groupId>.topics.<topicId> 아래에 주제별 재정의를 추가하지 않는 한 상위 그룹 설정(allowFrom, requireMention, skills, prompts)을 상속합니다.

항상 응답하는 모든 그룹을 허용하려면:

{
  channels: {
    telegram: {
      groups: {
        "*": { requireMention: false }  // 모든 그룹, 항상 응답
      }
    }
  }
}

모든 그룹에 대해 멘션 전용을 유지하려면 (기본 동작):

{
  channels: {
    telegram: {
      groups: {
        "*": { requireMention: true }  // 또는 그룹을 완전히 생략
      }
    }
  }
}

명령을 통해 (세션 수준)

그룹에서 보내기:

  • /activation always - 모든 메시지에 응답
  • /activation mention - 멘션 필요 (기본값)

참고: 명령은 세션 상태만 업데이트합니다. 재시작 간 지속적인 동작을 위해 설정을 사용하세요.

그룹 채팅 ID 가져오기

그룹에서 메시지를 Telegram의 @userinfobot 또는 @getidsbot로 전달하여 채팅 ID를 확인하세요 (음수 번호 예: -1001234567890).

팁: 자신의 사용자 ID의 경우 봇에게 DM을 보내면 사용자 ID로 답장합니다 (페어링 메시지) 또는 명령이 활성화되면 /whoami를 사용하세요.

개인 정보 참고: @userinfobot는 타사 봇입니다. 선호하는 경우 봇을 그룹에 추가하고 메시지를 보낸 다음 openclaw logs --follow를 사용하여 chat.id를 읽거나 Bot API getUpdates를 사용하세요.

설정 쓰기

기본적으로 Telegram은 채널 이벤트 또는 /config set|unset에 의해 트리거된 설정 업데이트를 쓸 수 있습니다.

이는 다음과 같은 경우에 발생합니다:

  • 그룹이 슈퍼그룹으로 업그레이드되고 Telegram이 migrate_to_chat_id를 내보냅니다 (채팅 ID 변경). OpenClaw는 channels.telegram.groups를 자동으로 마이그레이션할 수 있습니다.
  • Telegram 채팅에서 /config set 또는 /config unset를 실행합니다 (commands.config: true 필요).

비활성화:

{
  channels: { telegram: { configWrites: false } }
}

주제 (포럼 슈퍼그룹)

Telegram 포럼 주제에는 메시지당 message_thread_id가 포함됩니다. OpenClaw:

  • Telegram 그룹 세션 키에 :topic:<threadId>를 추가하여 각 주제를 격리합니다.
  • message_thread_id로 타이핑 표시기와 답장을 보내 응답이 주제에 유지되도록 합니다.
  • 일반 주제(스레드 ID 1)는 특별합니다: 메시지 전송은 message_thread_id를 생략하지만 (Telegram이 거부) 타이핑 표시기는 여전히 포함합니다.
  • 라우팅/템플릿팅을 위해 템플릿 컨텍스트에서 MessageThreadId + IsForum을 노출합니다.
  • channels.telegram.groups.<chatId>.topics.<threadId> 아래에서 주제별 구성을 사용할 수 있습니다 (스킬, 허용 목록, 자동 답장, 시스템 프롬프트, 비활성화).
  • 주제 설정은 주제별로 재정의되지 않는 한 그룹 설정(requireMention, 허용 목록, 스킬, 프롬프트, 활성화됨)을 상속합니다.

일부 에지 케이스에서 비공개 채팅에는 message_thread_id가 포함될 수 있습니다. OpenClaw는 DM 세션 키를 변경하지 않지만 존재하는 경우 답장/초안 스트리밍에 스레드 ID를 계속 사용합니다.

인라인 버튼

Telegram은 콜백 버튼이 있는 인라인 키보드를 지원합니다.

{
  "channels": {
    "telegram": {
      "capabilities": {
        "inlineButtons": "allowlist"
      }
    }
  }
}

계정별 구성의 경우:

{
  "channels": {
    "telegram": {
      "accounts": {
        "main": {
          "capabilities": {
            "inlineButtons": "allowlist"
          }
        }
      }
    }
  }
}

범위:

  • off — 인라인 버튼 비활성화
  • dm — DM만 (그룹 대상 차단)
  • group — 그룹만 (DM 대상 차단)
  • all — DM + 그룹
  • allowlist — DM + 그룹, 그러나 allowFrom/groupAllowFrom(제어 명령과 동일한 규칙)에 의해 허용된 발신자만

기본값: allowlist. 레거시: capabilities: ["inlineButtons"] = inlineButtons: "all".

버튼 보내기

buttons 매개변수와 함께 message 도구를 사용합니다:

{
  "action": "send",
  "channel": "telegram",
  "to": "123456789",
  "message": "옵션을 선택하세요:",
  "buttons": [
    [
      {"text": "예", "callback_data": "yes"},
      {"text": "아니오", "callback_data": "no"}
    ],
    [
      {"text": "취소", "callback_data": "cancel"}
    ]
  ]
}

사용자가 버튼을 클릭하면 콜백 데이터가 다음 형식의 메시지로 에이전트에 다시 전송됩니다: callback_data: value

구성 옵션

Telegram 기능은 두 가지 수준에서 구성할 수 있습니다 (위에 표시된 객체 형식; 레거시 문자열 배열은 여전히 지원됨):

  • channels.telegram.capabilities: 재정의되지 않는 한 모든 Telegram 계정에 적용되는 전역 기본 기능 설정.
  • channels.telegram.accounts.<account>.capabilities: 특정 계정에 대한 전역 기본값을 재정의하는 계정별 기능.

모든 Telegram 봇/계정이 동일하게 동작해야 할 때 전역 설정을 사용하세요. 다른 봇이 다른 동작이 필요한 경우 계정별 구성을 사용하세요 (예: 한 계정은 DM만 처리하고 다른 계정은 그룹에서 허용됨).

접근 제어 (DM + 그룹)

DM 액세스

  • 기본값: channels.telegram.dmPolicy = "pairing". 알 수 없는 발신자는 페어링 코드를 받습니다. 승인될 때까지 메시지가 무시됩니다 (코드는 1시간 후 만료).
  • 승인 방법:
    • openclaw pairing list telegram
    • openclaw pairing approve telegram <CODE>
  • 페어링은 Telegram DM에 사용되는 기본 토큰 교환입니다. 자세한 내용: Pairing
  • channels.telegram.allowFrom은 숫자 사용자 ID(권장) 또는 @username 항목을 허용합니다. 봇 사용자 이름이 아닙니다. 사람 발신자의 ID를 사용하세요. 마법사는 @username을 허용하고 가능한 경우 숫자 ID로 해결합니다.

Telegram 사용자 ID 찾기

더 안전함 (타사 봇 없음):

  1. Gateway를 시작하고 봇에게 DM을 보냅니다.
  2. openclaw logs --follow를 실행하고 from.id를 찾습니다.

대체 (공식 Bot API):

  1. 봇에게 DM을 보냅니다.
  2. 봇 토큰으로 업데이트를 가져오고 message.from.id를 읽습니다:
    curl "https://api.telegram.org/bot<bot_token>/getUpdates"
    

타사 (덜 비공개):

  • @userinfobot 또는 @getidsbot에게 DM을 보내고 반환된 사용자 ID를 사용하세요.

그룹 액세스

두 개의 독립적인 제어:

1. 어떤 그룹이 허용되는가 (그룹 허용 목록 channels.telegram.groups를 통해):

  • groups 설정 없음 = 모든 그룹 허용
  • groups 설정 포함 = 나열된 그룹 또는 "*"만 허용
  • 예시: "groups": { "-1001234567890": {}, "*": {} }는 모든 그룹을 허용합니다

2. 어떤 발신자가 허용되는가 (channels.telegram.groupPolicy를 통한 발신자 필터링):

  • "open" = 허용된 그룹의 모든 발신자가 메시지를 보낼 수 있음
  • "allowlist" = channels.telegram.groupAllowFrom의 발신자만 메시지를 보낼 수 있음
  • "disabled" = 그룹 메시지를 전혀 수락하지 않음 기본값은 groupPolicy: "allowlist" (groupAllowFrom를 추가하지 않는 한 차단됨)입니다.

대부분의 사용자가 원하는 것: groupPolicy: "allowlist" + groupAllowFrom + channels.telegram.groups에 나열된 특정 그룹

롱 폴링 vs 웹훅

  • 기본값: 롱 폴링 (공개 URL 필요 없음).
  • 웹훅 모드: channels.telegram.webhookUrl 설정 (선택적으로 channels.telegram.webhookSecret + channels.telegram.webhookPath).
    • 로컬 리스너는 0.0.0.0:8787에 바인드하고 기본적으로 POST /telegram-webhook를 제공합니다.
    • 공개 URL이 다른 경우 역방향 프록시를 사용하고 channels.telegram.webhookUrl을 공개 엔드포인트로 지정하세요.

답장 스레딩

Telegram은 태그를 통한 선택적 스레드 답장을 지원합니다:

  • [[reply_to_current]] -- 트리거 메시지에 답장.
  • [[reply_to:<id>]] -- 특정 메시지 ID에 답장.

channels.telegram.replyToMode로 제어됨:

  • first (기본값), all, off.

오디오 메시지 (음성 vs 파일)

Telegram은 음성 노트 (둥근 버블)와 오디오 파일 (메타데이터 카드)를 구분합니다. OpenClaw는 이전 버전과의 호환성을 위해 기본적으로 오디오 파일로 설정됩니다.

에이전트 답장에서 음성 노트 버블을 강제하려면 답장 어디에나 이 태그를 포함하세요:

  • [[audio_as_voice]] — 파일 대신 음성 노트로 오디오 보내기.

태그는 전달된 텍스트에서 제거됩니다. 다른 채널은 이 태그를 무시합니다.

message 도구 전송의 경우 음성 호환 오디오 media URL과 함께 asVoice: true를 설정하세요 (message는 미디어가 있을 때 선택 사항):

{
  "action": "send",
  "channel": "telegram",
  "to": "123456789",
  "media": "https://example.com/voice.ogg",
  "asVoice": true
}

스티커

OpenClaw는 지능형 캐싱으로 Telegram 스티커 수신 및 전송을 지원합니다.

스티커 수신

사용자가 스티커를 보내면 OpenClaw는 스티커 유형에 따라 처리합니다:

  • 정적 스티커 (WEBP): 다운로드하고 비전을 통해 처리됩니다. 스티커는 메시지 콘텐츠에 <media:sticker> 자리 표시자로 나타납니다.
  • 애니메이션 스티커 (TGS): 건너뜀 (Lottie 형식은 처리를 지원하지 않음).
  • 비디오 스티커 (WEBM): 건너뜀 (비디오 형식은 처리를 지원하지 않음).

스티커 수신 시 사용 가능한 템플릿 컨텍스트 필드:

  • Sticker — 다음을 포함하는 객체:
    • emoji — 스티커와 관련된 이모지
    • setName — 스티커 세트 이름
    • fileId — Telegram 파일 ID (동일한 스티커 다시 보내기)
    • fileUniqueId — 캐시 조회를 위한 안정적인 ID
    • cachedDescription — 사용 가능한 경우 캐시된 비전 설명

스티커 캐시

스티커는 AI의 비전 기능을 통해 처리되어 설명을 생성합니다. 동일한 스티커가 반복적으로 전송되는 경우가 많기 때문에 OpenClaw는 중복 API 호출을 피하기 위해 이러한 설명을 캐시합니다.

작동 방식:

  1. 첫 만남: 스티커 이미지가 비전 분석을 위해 AI에 전송됩니다. AI는 설명을 생성합니다 (예: "열정적으로 손을 흔드는 만화 고양이").
  2. 캐시 저장: 설명이 스티커의 파일 ID, 이모지 및 세트 이름과 함께 저장됩니다.
  3. 후속 만남: 동일한 스티커가 다시 표시되면 캐시된 설명이 직접 사용됩니다. 이미지가 AI에 전송되지 않습니다.

캐시 위치: ~/.openclaw/telegram/sticker-cache.json

캐시 항목 형식:

{
  "fileId": "CAACAgIAAxkBAAI...",
  "fileUniqueId": "AgADBAADb6cxG2Y",
  "emoji": "👋",
  "setName": "CoolCats",
  "description": "열정적으로 손을 흔드는 만화 고양이",
  "cachedAt": "2026-01-15T10:30:00.000Z"
}

이점:

  • 동일한 스티커에 대한 반복적인 비전 호출을 피하여 API 비용 절감
  • 캐시된 스티커에 대한 더 빠른 응답 시간 (비전 처리 지연 없음)
  • 캐시된 설명을 기반으로 스티커 검색 기능 활성화

캐시는 스티커가 수신될 때 자동으로 채워집니다. 수동 캐시 관리가 필요하지 않습니다.

스티커 보내기

에이전트는 stickersticker-search 작업을 사용하여 스티커를 보내고 검색할 수 있습니다. 이들은 기본적으로 비활성화되어 있으며 설정에서 활성화해야 합니다:

{
  channels: {
    telegram: {
      actions: {
        sticker: true
      }
    }
  }
}

스티커 보내기:

{
  "action": "sticker",
  "channel": "telegram",
  "to": "123456789",
  "fileId": "CAACAgIAAxkBAAI..."
}

매개변수:

  • fileId (필수) — 스티커의 Telegram 파일 ID. 스티커 수신 시 Sticker.fileId에서 가져오거나 sticker-search 결과에서 가져옵니다.
  • replyTo (선택 사항) — 답장할 메시지 ID.
  • threadId (선택 사항) — 포럼 주제의 메시지 스레드 ID.

스티커 검색:

에이전트는 설명, 이모지 또는 세트 이름으로 캐시된 스티커를 검색할 수 있습니다:

{
  "action": "sticker-search",
  "channel": "telegram",
  "query": "고양이 손 흔들기",
  "limit": 5
}

캐시에서 일치하는 스티커를 반환합니다:

{
  "ok": true,
  "count": 2,
  "stickers": [
    {
      "fileId": "CAACAgIAAxkBAAI...",
      "emoji": "👋",
      "description": "열정적으로 손을 흔드는 만화 고양이",
      "setName": "CoolCats"
    }
  ]
}

검색은 설명 텍스트, 이모지 문자 및 세트 이름에서 퍼지 매칭을 사용합니다.

스레딩 예시:

{
  "action": "sticker",
  "channel": "telegram",
  "to": "-1001234567890",
  "fileId": "CAACAgIAAxkBAAI...",
  "replyTo": 42,
  "threadId": 123
}

스트리밍 (초안)

Telegram은 에이전트가 응답을 생성하는 동안 초안 버블을 스트리밍할 수 있습니다. OpenClaw는 Bot API sendMessageDraft(실제 메시지가 아님)를 사용한 다음 최종 답장을 일반 메시지로 보냅니다.

요구 사항 (Telegram Bot API 9.3+):

  • 주제가 활성화된 비공개 채팅 (봇의 포럼 주제 모드).
  • 수신 메시지에는 message_thread_id가 포함되어야 합니다 (비공개 주제 스레드).
  • 스트리밍은 그룹/슈퍼그룹/채널에 대해 무시됩니다.

설정:

  • channels.telegram.streamMode: "off" | "partial" | "block" (기본값: partial)
    • partial: 최신 스트리밍 텍스트로 초안 버블을 업데이트합니다.
    • block: 더 큰 블록으로 초안 버블을 업데이트합니다 (청크됨).
    • off: 초안 스트리밍을 비활성화합니다.
  • 선택 사항 (streamMode: "block"에만 해당):
    • channels.telegram.draftChunk: { minChars?, maxChars?, breakPreference? }
      • 기본값: minChars: 200, maxChars: 800, breakPreference: "paragraph" (channels.telegram.textChunkLimit로 고정).

참고: 초안 스트리밍은 블록 스트리밍 (채널 메시지)와 별개입니다. 블록 스트리밍은 기본적으로 꺼져 있으며 초안 업데이트 대신 초기 Telegram 메시지를 원하는 경우 channels.telegram.blockStreaming: true가 필요합니다.

추론 스트림 (Telegram만):

  • /reasoning stream은 답장이 생성되는 동안 초안 버블에 추론을 스트리밍한 다음 추론 없이 최종 답변을 보냅니다.
  • channels.telegram.streamModeoff이면 추론 스트림이 비활성화됩니다. 추가 컨텍스트: Streaming + chunking.

재시도 정책

아웃바운드 Telegram API 호출은 일시적인 네트워크/429 오류 시 지수 백오프 및 지터로 재시도합니다. channels.telegram.retry를 통해 구성합니다. Retry policy를 참조하세요.

에이전트 도구 (메시지 + 반응)

  • 도구: sendMessage 작업이 있는 telegram (to, content, 선택적 mediaUrl, replyToMessageId, messageThreadId).
  • 도구: react 작업이 있는 telegram (chatId, messageId, emoji).
  • 도구: deleteMessage 작업이 있는 telegram (chatId, messageId).
  • 반응 제거 시맨틱: /tools/reactions를 참조하세요.
  • 도구 게이팅: channels.telegram.actions.reactions, channels.telegram.actions.sendMessage, channels.telegram.actions.deleteMessage (기본값: 활성화됨) 및 channels.telegram.actions.sticker (기본값: 비활성화됨).

반응 알림

반응 작동 방식: Telegram 반응은 별도의 message_reaction 이벤트로 도착하며 메시지 페이로드의 속성이 아닙니다. 사용자가 반응을 추가하면 OpenClaw:

  1. Telegram API에서 message_reaction 업데이트를 받습니다
  2. 형식으로 시스템 이벤트로 변환합니다: "Telegram reaction added: {emoji} by {user} on msg {id}"
  3. 동일한 세션 키를 사용하여 일반 메시지로 시스템 이벤트를 대기열에 넣습니다
  4. 해당 대화에서 다음 메시지가 도착하면 시스템 이벤트가 드레인되고 에이전트의 컨텍스트에 추가됩니다

에이전트는 반응을 메시지 메타데이터가 아닌 대화 기록의 시스템 알림으로 봅니다.

구성:

  • channels.telegram.reactionNotifications: 어떤 반응이 알림을 트리거하는지 제어

    • "off" — 모든 반응 무시
    • "own" — 사용자가 봇 메시지에 반응할 때 알림 (최선 노력; 메모리 내) (기본값)
    • "all" — 모든 반응에 대해 알림
  • channels.telegram.reactionLevel: 에이전트의 반응 기능 제어

    • "off" — 에이전트가 메시지에 반응할 수 없음
    • "ack" — 봇이 확인 반응을 보냅니다 (처리 중 👀) (기본값)
    • "minimal" — 에이전트가 드물게 반응할 수 있습니다 (가이드라인: 5-10회 교환당 1회)
    • "extensive" — 에이전트가 적절한 경우 자유롭게 반응할 수 있습니다

포럼 그룹: 포럼 그룹의 반응에는 message_thread_id가 포함되며 agent:main:telegram:group:{chatId}:topic:{threadId}와 같은 세션 키를 사용합니다. 이는 동일한 주제의 반응과 메시지가 함께 유지되도록 합니다.

예시 설정:

{
  channels: {
    telegram: {
      reactionNotifications: "all",  // 모든 반응 보기
      reactionLevel: "minimal"        // 에이전트가 드물게 반응할 수 있음
    }
  }
}

요구 사항:

  • Telegram 봇은 allowed_updates에서 message_reaction을 명시적으로 요청해야 합니다 (OpenClaw에서 자동으로 구성됨)
  • 웹훅 모드의 경우 반응이 웹훅 allowed_updates에 포함됩니다
  • 폴링 모드의 경우 반응이 getUpdates allowed_updates에 포함됩니다

전달 대상 (CLI/cron)

  • 채팅 ID (123456789) 또는 사용자 이름 (@name)을 대상으로 사용합니다.
  • 예시: openclaw message send --channel telegram --target 123456789 --message "안녕".

문제 해결

봇이 그룹에서 비멘션 메시지에 응답하지 않음:

  • channels.telegram.groups.*.requireMention=false를 설정한 경우 Telegram의 Bot API 개인 정보 모드를 비활성화해야 합니다.
    • BotFather: /setprivacyDisable (그런 다음 그룹에서 봇을 제거 + 다시 추가)
  • openclaw channels status는 설정이 멘션되지 않은 그룹 메시지를 예상할 때 경고를 표시합니다.
  • openclaw channels status --probe는 명시적 숫자 그룹 ID에 대한 멤버십을 추가로 확인할 수 있습니다 (와일드카드 "*" 규칙은 감사할 수 없음).
  • 빠른 테스트: /activation always (세션만; 지속성을 위해 설정 사용)

봇이 그룹 메시지를 전혀 보지 못함:

  • channels.telegram.groups가 설정된 경우 그룹이 나열되거나 "*"를 사용해야 합니다
  • @BotFather의 개인 정보 설정 확인 → "그룹 개인 정보"가 OFF여야 합니다
  • 봇이 실제 멤버인지 확인 (읽기 액세스가 없는 관리자만이 아님)
  • Gateway 로그 확인: openclaw logs --follow ("그룹 메시지 건너뛰기" 찾기)

봇이 멘션에는 응답하지만 /activation always에는 응답하지 않음:

  • /activation 명령은 세션 상태를 업데이트하지만 설정에 유지되지 않습니다
  • 지속적인 동작을 위해 requireMention: falsechannels.telegram.groups에 그룹을 추가하세요

/status와 같은 명령이 작동하지 않음:

  • Telegram 사용자 ID가 승인되었는지 확인하세요 (페어링 또는 channels.telegram.allowFrom을 통해)
  • 명령은 groupPolicy: "open"이 있는 그룹에서도 승인이 필요합니다

롱 폴링이 Node 22+에서 즉시 중단됨 (종종 프록시/커스텀 fetch와 함께):

  • Node 22+는 AbortSignal 인스턴스에 대해 더 엄격합니다. 외부 신호는 fetch 호출을 즉시 중단할 수 있습니다.
  • 중단 신호를 정규화하는 OpenClaw 빌드로 업그레이드하거나 업그레이드할 수 있을 때까지 Node 20에서 Gateway를 실행하세요.

봇이 시작된 다음 조용히 응답을 중지함 (또는 HttpError: Network request ... failed 로그):

  • 일부 호스트는 api.telegram.org를 먼저 IPv6로 확인합니다. 서버에 작동하는 IPv6 egress가 없으면 grammY는 IPv6 전용 요청에 갇힐 수 있습니다.
  • IPv6 egress를 활성화하거나 api.telegram.org에 대한 IPv4 해상도를 강제하여 수정하세요 (예: IPv4 A 레코드를 사용하여 /etc/hosts 항목을 추가하거나 OS DNS 스택에서 IPv4를 선호) 다음 Gateway를 다시 시작하세요.
  • 빠른 확인: dig +short api.telegram.org Adig +short api.telegram.org AAAA를 실행하여 DNS가 반환하는 항목을 확인하세요.

설정 참조 (Telegram)

전체 설정: Configuration

제공자 옵션:

  • channels.telegram.enabled: 채널 시작 활성화/비활성화.
  • channels.telegram.botToken: 봇 토큰 (BotFather).
  • channels.telegram.tokenFile: 파일 경로에서 토큰 읽기.
  • channels.telegram.dmPolicy: pairing | allowlist | open | disabled (기본값: pairing).
  • channels.telegram.allowFrom: DM 허용 목록 (ID/사용자 이름). open"*" 필요.
  • channels.telegram.groupPolicy: open | allowlist | disabled (기본값: allowlist).
  • channels.telegram.groupAllowFrom: 그룹 발신자 허용 목록 (ID/사용자 이름).
  • channels.telegram.groups: 그룹별 기본값 + 허용 목록 (전역 기본값에 "*" 사용).
    • 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>.*: 주제별 재정의 (그룹과 동일한 필드).
    • channels.telegram.groups.<id>.topics.<threadId>.requireMention: 주제별 멘션 게이팅 재정의.
  • channels.telegram.capabilities.inlineButtons: off | dm | group | all | allowlist (기본값: allowlist).
  • channels.telegram.accounts.<account>.capabilities.inlineButtons: 계정별 재정의.
  • channels.telegram.replyToMode: off | first | all (기본값: first).
  • channels.telegram.textChunkLimit: 아웃바운드 청크 크기 (문자).
  • channels.telegram.chunkMode: length (기본값) 또는 newline을 설정하여 길이 청크 전에 빈 줄(단락 경계)에서 분할합니다.
  • channels.telegram.linkPreview: 아웃바운드 메시지에 대한 링크 미리보기 토글 (기본값: true).
  • channels.telegram.streamMode: off | partial | block (초안 스트리밍).
  • channels.telegram.mediaMaxMb: 인바운드/아웃바운드 미디어 상한 (MB).
  • channels.telegram.retry: 아웃바운드 Telegram API 호출에 대한 재시도 정책 (시도, minDelayMs, maxDelayMs, jitter).
  • channels.telegram.network.autoSelectFamily: Node autoSelectFamily 재정의 (true=활성화, false=비활성화). Node 22에서 Happy Eyeballs 시간 초과를 피하기 위해 기본적으로 비활성화됩니다.
  • channels.telegram.proxy: Bot API 호출용 프록시 URL (SOCKS/HTTP).
  • channels.telegram.webhookUrl: 웹훅 모드 활성화.
  • channels.telegram.webhookSecret: 웹훅 비밀 (선택 사항).
  • channels.telegram.webhookPath: 로컬 웹훅 경로 (기본값 /telegram-webhook).
  • 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).

관련 전역 옵션:

  • agents.list[].groupChat.mentionPatterns (멘션 게이팅 패턴).
  • messages.groupChat.mentionPatterns (전역 대체).
  • commands.native (기본값 "auto" → Telegram/Discord는 켜짐, Slack은 꺼짐), commands.text, commands.useAccessGroups (명령 동작). channels.telegram.commands.native로 재정의.
  • messages.responsePrefix, messages.ackReaction, messages.ackReactionScope, messages.removeAckAfterReply.