MÓDULO 1.2

🔀 O caminho de uma mensagem

Do Telegram ao resultado, passo a passo: quem recebe, quem decide, quem responde, quem paga a conta e o que fica guardado no fim.

6
Tópicos
55
Minutos
Essencial
Nível
Fundamento
Tipo
Progresso do módulo 1.2 0%
0 de 0
1

📥 O adaptador do canal publica no bus

Nada no v3 fala diretamente com o Telegram, com o terminal ou com a porta HTTP. Cada canal tem um adaptador, e o trabalho dele é um só: traduzir o que chegou para um aviso no bus, chamado mensagem.recebida. Daí em diante, o resto do sistema não sabe nem se importa de onde veio.

🆕 Novo aqui?

  • Bus (barramento): o correio interno do programa. Um pedaço publica um aviso, outro escuta. Serve para o canal não precisar conhecer o cérebro.
  • Adaptador: o tradutor de um canal específico. O do Telegram usa a biblioteca grammy, lê texto e legenda de foto ou vídeo, e guarda quem falou.
  • Ollama: o programa que roda modelos de IA dentro da sua própria máquina, sem internet e sem custo por uso.
  • Chat autorizado: o Telegram do v3 só responde ao identificador em ALLOWED_CHAT_ID. Qualquer outro chat vira uma linha no log, não uma resposta.
canal adaptador bus orquestrador collect 2 s · roteador comando: responde na hora direto: Ollama responde agente: job na fila guarda redige segredos

O que olhar: existem três saídas possíveis, e todas as três voltam a se juntar no mesmo ponto azul do fim. Nenhum texto sai para você sem passar pela guarda.

Conceito principal

No Telegram existem dois tipos de chat. Os de TELEGRAM_CHATS_RESPONDER conversam com você. Os de TELEGRAM_CHATS_OBSERVAR só alimentam o cérebro: entram no conversation_log com agent_id = 'observado' e nunca recebem resposta. A cada 30 minutos o cron ingestao-observados transforma o que chegou em memória.

⚠️ Atenção

Grupo observado é conversa de outras pessoas, e elas não sabem que um bot está guardando o que dizem. Observe só onde isso for combinado.

2

⏱️ A janela de 2 segundos e os outros modos

Quando a mensagem não começa com barra, o orquestrador espera. O modo padrão se chama collect: mensagens seguidas dentro de uma janela de 2 segundos viram uma só. É isso que evita três respostas quando você escreve em três balões.

🆕 Novo aqui?

  • Lane (faixa da fila): uma pista com quantos trabalhos podem correr juntos nela. chat aceita 2, agente aceita 1, ollama 1, cron 1 e io 4.
  • Modo de fila: o que fazer com uma mensagem que chega enquanto outra ainda está sendo respondida. Vale por chat e se troca com /fila.

✓ Os quatro modos, honestamente

  • collect: junta 2 segundos e responde uma vez. É o padrão.
  • followup: sem janela. Se estiver ocupado, entra na fila e responde depois.
  • steer: substitui o que estava na fila daquele chat pela mensagem nova, com prioridade alta.
  • interrupt: cancela fila e agentes daquele chat e responde à nova agora.

✗ O que esses modos não fazem

  • steer não injeta a mensagem no agente que já está rodando: o claude -p é um subprocesso, então a nova só entra quando o atual terminar.
  • interrupt não aborta uma resposta direta já em voo no Ollama: ela termina e é descartada por um contador de geração.
  • Cancelar não é instantâneo: um claude -p em execução morre na batida seguinte do worker, em até 30 segundos.

Conceito principal

O modo escolhido fica gravado na tabela prefs, que é um par chave e valor por chat, com '*' valendo como global. Por isso ele sobrevive a um restart do serviço.

Dica prática

Se você costuma pensar em voz alta e mandar cinco balões seguidos, collect é o seu modo. Se costuma corrigir o pedido no meio, experimente /fila steer naquele chat.

3

🧭 O roteador decide direto ou agente

Antes de gastar qualquer centavo, um modelo pequeno e local decide o que fazer. É o roteador: o papel roteador em config/ollama.yaml usa llama3.2, responde em cerca de 2 segundos, ocupa 4 GB e devolve um JSON com quatro campos, {rota, agente, tier, motivo}.

🆕 Novo aqui?

  • Roteador: um classificador, não um conversador. Ele não responde a você, só diz por onde a mensagem deve seguir.
  • Ollama: o programa que roda modelos de IA na sua máquina. O v3 conversa com ele só por HTTP, na porta 11434 do serviço systemd, que é o gerenciador de serviços do Linux, nunca subindo um processo paralelo.
  • Tier: a faixa de custo escolhida para a chamada. local custa zero, barato e premium custam dinheiro.
1

Rota direto

Conversa, pergunta curta, resumo, tradução. Segue para o gateway de custo no tier local e volta como resposta, sem passar pela fila de agentes.

2

Rota agente

Precisa de ferramenta: arquivo, shell, repositório, web, skill, calendário. Vira um job na lane agente, que roda um de cada vez.

3

Indicação de consultar

Até dois agentes só leitura, por exemplo o research, rodam antes e entregam as saídas deles ao agente lead. Só o lead escreve.

Conceito principal

Decidir com um modelo local e grátis antes de chamar um modelo pago é a economia central do projeto. O campo motivo do JSON existe para que a decisão fique auditável depois, e não só executada.

⌨️ Copie e rode

Objetivo: ver o caminho da mensagem acontecendo em tempo real, do adaptador até a resposta.

journalctl --user -u openpcbotv3 -f -o cat

Como verificar: com o log aberto, mande uma mensagem ao bot no Telegram. As linhas em JSON aparecem na hora. Para sair, aperte Ctrl+C.

4

💬 Resposta direta: o prompt em camadas

Na rota direta, o que chega ao modelo não é só a sua frase. É um bolo montado em camadas: a identidade do bot, a persona escolhida para aquele chat, o USER.md do vault, o contexto de memória e o histórico recente da conversa.

🆕 Novo aqui?

  • FTS5: a busca por palavra que já vem dentro do SQLite. Acha memórias que contêm as palavras da sua pergunta.
  • Embedding (vetor): a mesma frase virada em uma lista de números que aproxima significados parecidos. O v3 usa o modelo bge-m3, com 1024 números por memória, e compara por cosseno.
  • Salience (importância): uma nota de cada memória. Começa em 1.0, sobe 0,1 a cada uso e cai um pouco por dia sem uso.
  • Vault: dois arquivos em Markdown que você controla, MEMORY.md e USER.md. Nada é escrito neles sem a sua aprovação.
FTS5: palavra-chave vetor bge-m3 importância e recência memória teto de 600 tokens IDENTIDADE.md persona do chat USER.md do vault memória e insights histórico + sua mensagem

O que olhar: à esquerda, os três caminhos de busca que alimentam uma só caixa de memória. À direita, a pilha na ordem em que entra no prompt, com a sua frase por último.

Conceito principal

O contexto de memória tem teto de 600 tokens e é montado assim: 3 memórias por palavra-chave, 3 por vetor, 3 mais importantes, 3 mais recentes, sem repetir, mais 3 insights. Teto existe porque cada token dessas camadas é pago em toda mensagem, mesmo quando a pergunta é curta.

Dica prática

O comando /context mede quanto cada camada está ocupando, sem chamar modelo de chat. Ele roda o retrieval em modo somente leitura, então consultar não infla a importância das memórias.

5

🤖 Agente: um job na fila, um processo, um resultado

Quando a rota é agente, a mensagem não é respondida na hora: ela vira um job gravado na fila, na lane agente, que executa um por vez porque cada processo consome cerca de 500 MB de memória. O worker então roda claude -p --output-format json com o prompt em camadas.

🆕 Novo aqui?

  • Job: uma linha na tabela da fila descrevendo um trabalho a fazer. Jobs nunca são apagados: eles são o histórico do sistema.
  • Lease (aluguel): a marca de "este job é meu agora", renovada por um sinal de vida a cada 30 segundos. Se o processo morre, o aluguel vence e outro worker pode pegar o job de volta.
  • Skill: uma receita em skills/<id>/SKILL.md. Só o resumo entra no prompt, para não gastar token à toa.
  • Sessão retomada: o agente continua a conversa anterior em vez de começar do zero.

✓ O que a fila garante

  • Pegar um job é atômico, então dois workers nunca pegam o mesmo.
  • Falhou, tenta de novo com espera crescente entre as tentativas.
  • A mesma tarefa com a mesma idem_key não dispara duas vezes.
  • Todo job com chat_id avisa o chat ao terminar, dando certo ou errado. Se o envio falhar, uma varredura a cada 20 segundos reentrega.

✗ O que continua sendo limite

  • Um agente por vez: o segundo pedido espera o primeiro acabar.
  • Job enfileirado antes de um /parar falha ao ser pego, com o motivo, sem gastar token.
  • Um job que passar de duas vezes o tempo limite de 20 minutos é tratado como zumbi e cancelado pelo heartbeat.

Conceito principal

O padrão dos especialistas vale a pena entender: até dois agentes só leitura rodam em paralelo, o lead recebe as saídas deles no prompt, e só o lead escreve. Leitura em paralelo é barata e segura; escrita concorrente é que faz estrago.

⌨️ Copie e rode

Objetivo: mandar uma mensagem pela porta HTTP e ver o caminho inteiro sem abrir o Telegram.

curl -X POST http://127.0.0.1:3142/mensagem \
  -H 'Content-Type: application/json' \
  -d '{"texto":"resuma <o-assunto-que-voce-quiser> em tres linhas"}'

Como verificar: a mensagem aparece no journalctl do bloco anterior. Se o pedido virar trabalho de agente, /status no chat mostra o job e a lane em que ele caiu.

6

🧾 Depois da resposta: o que fica gravado

A mensagem respondida não acaba na resposta. Quatro coisas acontecem depois dela, e é esse rastro que faz o assistente melhorar em vez de esquecer tudo a cada conversa.

1

O turno é logado

Pergunta e resposta entram no conversation_log. É desse log que sai o histórico recente que volta ao prompt na próxima mensagem.

2

A memória é classificada em português

Toda mensagem sua com mais de 20 caracteres vira uma memória. Uma regex em PT-BR e inglês decide se é semantic, ou seja durável, quando aparecem marcas como "meu", "prefiro", "sempre", "nunca", "moro em", ou episodic. Pergunta nunca vira fato, e frases repetidas são descartadas por hash.

3

O vault pode receber uma proposta

Se o fato parece durável, o bot propõe uma entrada para o MEMORY.md ou o USER.md. Proposta não é escrita: nada entra sem /memoria aprovar <id>.

4

O custo é registrado

O gateway grava a chamada em chamadas_llm com latência e custo. Na rota de agente, o valor não é estimado: o custo real vem do próprio CLI claude. O /usage lê essa tabela por dia, por tier e por agente.

Conceito principal

Antes de qualquer texto sair para você, ele passa pela guarda de exfiltração: uma varredura que procura tokens, chaves, JWT e valores do .env e troca o que achar por [REDIGIDO]. Vale para as três rotas, inclusive para o que um agente escreveu.

Dica prática

De madrugada, às 4h, a consolidação junta memórias duplicadas, marca contradições com superseded_by em vez de apagar, e gera até três insights por chat. Roda no Ollama, então custa zero. Para rodar na hora, use /consolidar.

Resumo do Módulo

O adaptador só traduz - o canal publica no bus e some do caminho
Janela de 2 segundos - collect junta balões seguidos em uma resposta
O roteador é local e grátis - decide rota, agente, tier e motivo em JSON
Prompt em camadas - identidade, persona, USER.md, memória e histórico
Agente é job na fila - um por vez, com lease, retry e aviso no fim
O rastro fica - turno, memória, proposta de vault, custo e guarda de saída

Próximo módulo:

2.1 - Subir o v3