Visão geral dos pacotes
Struct principal: ChatCLI
A structChatCLI em cli/cli.go é o coração do sistema. Seus campos mais importantes estão organizados por responsabilidade:
LLM e Provider
| Campo | Tipo | Descrição |
|---|---|---|
Client | client.LLMClient | Cliente ativo do provedor LLM |
manager | manager.LLMManager | Gerenciador de provedores (cria clientes, lista disponíveis) |
Provider | string | Nome do provedor ativo (ex: "ANTHROPIC", "OPENAI") |
Model | string | Modelo ativo (ex: "claude-sonnet-4-20250514") |
Histórico e Compactação
| Campo | Tipo | Descrição |
|---|---|---|
history | []models.Message | Histórico unificado de conversa (compartilhado entre todos os modos) |
historyCompactor | *HistoryCompactor | Pipeline de compactação em 3 níveis |
historyManager | *HistoryManager | Persistência de histórico de comandos em disco |
Controle de Execução
| Campo | Tipo | Descrição |
|---|---|---|
isExecuting | atomic.Bool | Flag atômica: true enquanto aguarda resposta do LLM |
operationCancel | context.CancelFunc | Cancela a operação LLM em andamento (Ctrl+C) |
processingDone | chan struct{} | Sinaliza fim do processamento para o loop principal |
interactionState | InteractionState | Estado da interação: Normal, SwitchingProvider, Processing, AgentMode |
executionProfile | ExecutionProfile | Perfil de execução: Normal, Agent, Coder |
Subsistemas
| Campo | Tipo | Descrição |
|---|---|---|
agentMode | *AgentMode | Instância do modo agente (loop ReAct) |
pluginManager | *plugins.Manager | Gerenciador de plugins (built-in + externos) |
commandHandler | *CommandHandler | Roteador de comandos / |
contextHandler | *ContextHandler | Gerenciador de contextos (/context) |
personaHandler | *PersonaHandler | Gerenciador de personas/agents |
skillHandler | *SkillHandler | Registro e execução de skills |
contextBuilder | *workspace.ContextBuilder | Combina bootstrap + memória no system prompt |
memoryStore | *workspace.MemoryStore | Facade para o sistema de memória estruturada |
memWorker | *memoryWorker | Worker background de extração de memória |
Estado Auxiliar
| Campo | Tipo | Descrição |
|---|---|---|
checkpoints | []conversationCheckpoint | Pontos de restauração do histórico (max 20) |
messageQueue | []string | Fila FIFO de mensagens digitadas durante processamento (type-ahead) |
lastEscTime | time.Time | Detecção de Esc+Esc para menu de rewind |
sessionManager | *SessionManager | Salvar/carregar sessões em disco |
Fluxo de inicialização
O diagrama abaixo mostra a sequência completa de boot, demain.go até o loop interativo:
detectProjectDir()
Caminha do diretório atual até a raiz procurando marcadores de projeto:.agent/(marcador explícito do ChatCLI) — prioridade.git/(convencao comum)
"" se nenhum marcador for encontrado.
Fluxo de mensagens: modo chat
No modo interativo normal, cada mensagem do usuário segue este pipeline:Type-ahead (messageQueue)
Mensagens digitadas enquanto o LLM processa são armazenadas em uma fila FIFO (messageQueue). Após cada resposta, o sistema drena a fila e processa cada mensagem sequencialmente, sem necessidade de re-digitação. O modo coder tem sua própria fila com indicador visual em tempo real (▼ N msg fila) quando há mensagens enfileiradas.
Input guard (anti-typeahead em prompts de segurança)
Distinto do typeahead “bom” acima, quando uma security box aparece no meio de um turn — três camadas descartam input em queue para evitar consumir bytes comoy/n:
- TTY flush —
TCIFLUSH(Linux),TIOCFLUSH(BSD/Darwin),FlushConsoleInputBuffer(Windows). - Drain channel — esvazia o buffer non-blocking do reader.
- 250ms debounce — descarta input nos primeiros 250ms após a box renderizar.
stty sane no /dev/tty controlador para recuperar de um teardown anterior do go-prompt que pudesse ter deixado o terminal em raw mode.
Fluxo de mensagens: modo Agent/Coder
A entrada no modo agente usa um mecanismo depanic/recover para sair do loop do go-prompt:
Anchor Reminder
A cada turno, o agente injeta um lembrete curto no histórico para manter o LLM focado na tarefa original. Isso evita drift em conversas longas.Parsing de tool calls
O parser emcli/agent/toolcall_parser.go usa um scanner stateful (não regex) para robustez:
Formatos suportados
Algoritmo do scanner
- Busca
<tool_callcase-insensitive - Verifica que o próximo char é whitespace ou
>(não parte de outra tag) scanTagEnd(): avança respeitando aspas (single e double quotes)- Dentro de aspas,
>é tratado como texto literal - Suporta entidades HTML (
>,", etc.)
- Dentro de aspas,
- Extrai atributos
nameeargsindependente da ordem - Se self-closing falha, tenta paired tags com
</tool_call> - Fallback para JSON: tenta
parseJSONToolCalls()em paralelo
Por que não regex?
Argumentos de tools frequentemente contêm>, ", e JSON aninhado. Regex não consegue distinguir > dentro de um atributo quoted de > que fecha a tag. O scanner stateful resolve isso rastreando o estado de quote.
Pipeline de sanitização de argumentos
Após o parsing, cada tool call passa por um pipeline de 7 etapas emagent_tool_sanitizer.go:
Compactação de histórico (3 níveis)
OHistoryCompactor em cli/history_compactor.go gerencia o tamanho do histórico através de um pipeline progressivo:
Trigger no modo agente
No modo agente, a compactação é verificada a cada turno do loop ReAct. O trigger ocorre quando o uso de tokens ultrapassa 60% do budget do modelo.Sistema de checkpoint/rewind
Orewind.go implementa um sistema de snapshots do histórico:
Estrutura
Comportamento
- Quando salva: Antes de cada chamada ao LLM (
saveCheckpoint()) - Limite: Máximo de 20 checkpoints (FIFO — os mais antigos são descartados)
- Deep copy: Cada checkpoint contém uma cópia completa e independente do histórico
- Trigger: Pressionar Esc+Esc (dois Esc em menos de 500ms) abre o menu de rewind
- Restauração: O usuário escolhe um checkpoint, e o histórico é substituído pela cópia salva
Registry de provedores
Padrão de auto-registro
Cada provedor LLM se registra automaticamente viainit() no pacote llm/registry:
ProviderInfo
Fluxo de descoberta
switch/case. Para adicionar um novo provedor, basta criar o pacote com register.go e implementar a interface LLMClient.
Memory Worker (processo background)
OmemoryWorker em cli/memory_worker.go extrai memórias da conversa em background:
Parâmetros
| Constante | Valor | Descrição |
|---|---|---|
memoryMinNewMessages | 4 | Mínimo de novas mensagens para trigger |
memoryCooldown | 2 min | Tempo mínimo entre extrações |
memoryExtractTimeout | 60s | Timeout da chamada LLM de extração |
compactionCheckInterval | 6h | Frequência de checagem de compactação |
dailyCleanupInterval | 24h | Frequência de limpeza de notas diárias |
Triggers
- nudge(): Chamado após cada resposta do LLM. Se houver >= 4 novas mensagens e cooldown expirado, executa extração
- Ticker de 3 minutos: O loop background verifica periodicamente (para sessões longas onde o usuário digita pouco)
- Compaction ticker (6h): Consolida fatos antigos com scores baixos
- Cleanup ticker (24h): Remove notas diárias expiradas
Pipeline de extracao
Componentes principais
CLI e Modos
A structChatCLI em cli/cli.go é o ponto central (~923 linhas após decomposição). O método Start() inicia o modo interativo usando Bubble Tea (Charmbracelet). Métodos auxiliares, gerenciamento de histórico, troca de modos, formatação de saída, construção de prompts, gerenciamento de sessões e tratamento de tools foram extraídos para arquivos dedicados (cli_helpers.go, cli_history.go, cli_mode.go, cli_output.go, cli_prompt.go, cli_session.go, cli_tools.go).
| Modo | Arquivo | Descrição |
|---|---|---|
| Interativo | cli/cli.go | Prompt interativo com auto-completação |
| Agente | cli/agent_mode.go | Planejamento e execução de tarefas |
| Coder | cli/cli.go + cli/agent_mode.go | Loop de engenharia com tool calls |
| One-shot | cli/cli.go (flag -p) | Execução única sem TUI |
panic/recover para sair do loop do go-prompt.
O ChatCLI usa um histórico unificado (cli.history) compartilhado entre todos os modos. Ao trocar de modo, o contexto completo é preservado. Os comandos /compact e /rewind operam diretamente sobre esse histórico único.
Message Bus
O pacotecli/bus implementa um barramento de mensagens tipado com:
- Pub/sub com filtros por canal e tipo
- Request-reply com correlation IDs
- Métricas atômicas de throughput
Multi-Agent
O sistema de orquestração emcli/agent/workers gerencia 12 agents especialistas que executam em goroutines paralelas com semáforo configurável. Cada worker possui:
- Mini ReAct loop isolado (observe -> reason -> act)
- Skills próprias (scripts aceleradores e descritivas)
- File locks (mutex per-filepath)
- Timeout e max turns configuráveis
Tecnologias
| Categoria | Biblioteca |
|---|---|
| TUI | Bubble Tea (Charmbracelet) |
| Markdown | Glamour (Charmbracelet) |
| Cores | Lipgloss (Charmbracelet) |
| Logger | Zap (Uber) |
| Log rotation | Lumberjack |
| Env files | Godotenv |
| i18n | golang.org/x/text |
| gRPC | google.golang.org/grpc |
| Kubernetes | k8s.io/client-go |
| Operator | controller-runtime (Kubebuilder) |
| Protobuf | google.golang.org/protobuf |
Padrões de design
- Auto-registro via
init()— Provedores se registram automaticamente - Interface-driven —
LLMClienteToolAwareClientpara polimorfismo - Fallback chain — Classificacao inteligente de erros + cooldown exponencial
- Stateful parser — Parsing de XML com atributos escapados (mais robusto que regex)
- embed.FS — Arquivos i18n embarcados no binário (sempre usa
/, nuncafilepath.Join) - Panic/recover — Troca de modos no go-prompt sem reiniciar o processo
- Histórico unificado — Um único array de mensagens compartilhado entre chat, agent e coder
- Checkpoint/rewind — Deep copy do histórico antes de cada chamada LLM, com restauração seletiva
- Compactação em 3 níveis — Trimming near-lossless, sumarização estruturada, truncamento de emergência
- Type-ahead queue — Mensagens digitadas durante processamento são enfileiradas e drenadas automaticamente
- Workspace context injection — Bootstrap + memória injetados automaticamente em todo system prompt
- Context injection via system prompt — Contextos attached (
/context attach) são injetados comoSystemPartscomCacheControlno modelo de mensagem, permitindo cache automático por provider (Anthropiccache_control: ephemeral, OpenAI prompt caching, Google context caching) - Background memory extraction — Worker em goroutine extrai e consolida memórias da conversa sem bloquear o fluxo principal