Zalo Personal (não-oficial)

Status: experimental. Esta integração automatiza uma conta pessoal do Zalo via zca-js nativo dentro do OpenClaw.

Aviso: Esta é uma integração não-oficial e pode resultar em suspensão/banimento da conta. Use por sua conta e risco.

Plugin necessário

O Zalo Personal é distribuído como plugin e não vem incluído na instalação padrão.

  • Instalação via CLI: openclaw plugins install @openclaw/zalouser
  • Ou a partir de um checkout de código: openclaw plugins install ./extensions/zalouser
  • Detalhes: Plugins

Nenhum binário CLI externo zca/openzca é necessário.

Configuração rápida (iniciante)

  1. Instale o plugin (veja acima).
  2. Login (QR, na máquina do Gateway):
    • openclaw channels login --channel zalouser
    • Escaneie o código QR com o app Zalo no celular.
  3. Habilite o canal:
{
  channels: {
    zalouser: {
      enabled: true,
      dmPolicy: "pairing",
    },
  },
}
  1. Reinicie o Gateway (ou finalize o onboarding).
  2. O acesso a DM usa pareamento por padrão; aprove o código de pareamento no primeiro contato.

O que é

  • Roda inteiramente in-process via zca-js.
  • Usa listeners de evento nativos para receber mensagens de entrada.
  • Envia respostas diretamente pela API JS (texto/mídia/link).
  • Projetado para casos de uso de “conta pessoal” onde a Zalo Bot API não está disponível.

Nomenclatura

O ID do canal é zalouser para deixar explícito que isto automatiza uma conta pessoal de usuário Zalo (não-oficial). Mantemos zalo reservado para uma potencial futura integração oficial da API Zalo.

Encontrando IDs (diretório)

Use o CLI de diretório para descobrir peers/grupos e seus IDs:

openclaw directory self --channel zalouser
openclaw directory peers list --channel zalouser --query "nome"
openclaw directory groups list --channel zalouser --query "trabalho"

Limites

  • Texto de saída é dividido em ~2000 caracteres (limites do cliente Zalo).
  • Streaming é bloqueado por padrão.

Controle de acesso (DMs)

channels.zalouser.dmPolicy suporta: pairing | allowlist | open | disabled (padrão: pairing).

channels.zalouser.allowFrom aceita IDs de usuário ou nomes. Durante o onboarding, nomes são resolvidos para IDs usando a busca de contatos in-process do plugin.

Aprove via:

  • openclaw pairing list zalouser
  • openclaw pairing approve zalouser <code>

Acesso a grupos (opcional)

  • Padrão: channels.zalouser.groupPolicy = "open" (grupos permitidos). Use channels.defaults.groupPolicy para sobrescrever o padrão quando não definido.
  • Restrinja com allowlist:
    • channels.zalouser.groupPolicy = "allowlist"
    • channels.zalouser.groups (chaves devem ser IDs estáveis de grupo; nomes são resolvidos para IDs na inicialização quando possível)
    • channels.zalouser.groupAllowFrom (controla quais remetentes em grupos permitidos podem acionar o bot)
  • Bloquear todos os grupos: channels.zalouser.groupPolicy = "disabled".
  • O wizard de configuração pode solicitar allowlists de grupo.
  • Na inicialização, o OpenClaw resolve nomes de grupo/usuário em allowlists para IDs e registra o mapeamento.
  • Correspondência de allowlist de grupo é apenas por ID por padrão. Nomes não resolvidos são ignorados para auth a menos que channels.zalouser.dangerouslyAllowNameMatching: true esteja habilitado.
  • channels.zalouser.dangerouslyAllowNameMatching: true é um modo de compatibilidade de emergência que reabilita correspondência mutável por nome de grupo.
  • Se groupAllowFrom não está definido, o runtime faz fallback para allowFrom para verificações de remetente de grupo.
  • Verificações de remetente se aplicam tanto a mensagens normais de grupo quanto a comandos de controle (por exemplo /new, /reset).

Exemplo:

{
  channels: {
    zalouser: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["1471383327500481391"],
      groups: {
        "123456789": { allow: true },
        "Chat de Trabalho": { allow: true },
      },
    },
  },
}

Gating de menção em grupo

  • channels.zalouser.groups.<group>.requireMention controla se respostas de grupo requerem menção.
  • Ordem de resolução: ID/nome exato do grupo -> slug normalizado do grupo -> * -> padrão (true).
  • Isso se aplica tanto a grupos na allowlist quanto no modo de grupo aberto.
  • Comandos de controle autorizados (por exemplo /new) podem contornar o gating de menção.
  • Quando uma mensagem de grupo é ignorada porque menção é necessária, o OpenClaw a armazena como histórico pendente de grupo e a inclui na próxima mensagem de grupo processada.
  • O limite de histórico de grupo padrão é messages.groupChat.historyLimit (fallback 50). Você pode sobrescrever por conta com channels.zalouser.historyLimit.

Exemplo:

{
  channels: {
    zalouser: {
      groupPolicy: "allowlist",
      groups: {
        "*": { allow: true, requireMention: true },
        "Chat de Trabalho": { allow: true, requireMention: false },
      },
    },
  },
}

Múltiplas contas

As contas mapeiam para perfis zalouser no estado do OpenClaw. Exemplo:

{
  channels: {
    zalouser: {
      enabled: true,
      defaultAccount: "default",
      accounts: {
        work: { enabled: true, profile: "work" },
      },
    },
  },
}

Digitação, reações e confirmações de entrega

  • O OpenClaw envia um evento de digitação antes de despachar uma resposta (melhor esforço).
  • A ação de reação a mensagem react é suportada para zalouser em ações de canal.
    • Use remove: true para remover um emoji de reação específico de uma mensagem.
    • Semântica de reações: Reações
  • Para mensagens de entrada que incluem metadados de evento, o OpenClaw envia confirmações de entrega + visualização (melhor esforço).

Resolução de problemas

Login não persiste:

  • openclaw channels status --probe
  • Re-login: openclaw channels logout --channel zalouser && openclaw channels login --channel zalouser

Allowlist/nome de grupo não resolveu:

  • Use IDs numéricos em allowFrom/groupAllowFrom/groups, ou nomes exatos de amigos/grupos.

Atualizou de setup antigo baseado em CLI:

  • Remova quaisquer suposições de processo zca externo antigo.
  • O canal agora roda totalmente no OpenClaw sem binários CLI externos.