O que é uma Lesson
UmaLesson é um registro de quatro linhas:
memory.Fact, o Content fica:
lesson e as tags incluem reflexion + trigger:<x> + os tags específicos do domínio. Isso permite queries precisas: “me mostre todas as lições sobre edit-file” se torna uma pesquisa normal da memória.
Quatro gatilhos
- OnError
- OnHallucination
- OnLowQuality
- Manual via /reflect
Error != nil. Exemplos: timeout, tool call inválido, crash do provedor.
Default: ON.Fluxo — modo durável (default)
ComCHATCLI_QUALITY_REFLEXION_QUEUE_ENABLED=true (default), o trigger vai pra uma fila persistente. O hook não bloqueia o turn e o processo pode crashar sem perder a lição:
PostRun inspeciona o trigger
ReflexionHook.PostRun(ctx, hc, result) olha result.Metadata + result.Error — se nenhum gate bate, retorna em μs.WAL Append (síncrono, sub-ms)
enqueuer.Enqueue(req). O Runner calcula um JobID = sha256(task|trigger|attempt)[:16], escreve um record no WAL (~/.chatcli/reflexion/wal/<id>.wal) via tmp → fsync → atomic rename → dir fsync, então empilha em memory.Retorno imediato ao pipeline
Worker pool processa async
GenerateLesson com timeout per-job (default 2 min) e persiste em memory.Fact se o LLM não emitir <skip>.Classificação do outcome
Replay on boot
Runner.Replay() roda async e reenfileira todo record pendente do WAL (descartando os mais velhos que StaleAfter, default 7 dias).Fallback: modo legado (goroutine detached)
SeCHATCLI_QUALITY_REFLEXION_QUEUE_ENABLED=false, o hook volta ao comportamento original:
Fila Durável — WAL + Worker Pool + DLQ
A fila é implementada emcli/agent/quality/lessonq/ com garantias enterprise:
WAL (Write-Ahead Log)
Cada lição pendente é um arquivo.wal em ~/.chatcli/reflexion/wal/ — um por Job ID. Layout binário:
- CRC duplo detecta torn writes (crash no meio do fsync). Records corruptos são descartados no replay +
chatcli_lessonq_wal_corruption_totalincrementa. - Atomic rename: escrita em
<id>.tmp.<pid>.<seq>→ fsync → rename → dir fsync. Nunca um leitor vê record parcial. - O(1) ACK: um único
unlinkremove o record. Sem compactação em background.
Worker Pool
- Dequeue bloqueante (espera por NextAttemptAt ≤ now).
- Per-job timeout bounded (não herda ctx do turn — reflexion outlive o turn por design).
- Panic recovery: se o processor panica, vai direto pra DLQ (retry não ajuda bug).
- Métrica
chatcli_lessonq_processing_duration_seconds{outcome}emitida.
Dead Letter Queue
Failures permanentes ou exaustão de retries vão pra~/.chatcli/reflexion/dlq/ (mesmo formato WAL, read-only pro processo). Operador inspeciona e decide:
Retry com Jitter
Transient errors (ctx timeout, provider 429/503, temp fs error) viram reschedule:Idempotência
JobID é conteúdo-endereçado: sha256(normalized(task) | trigger | attempt | outcome)[:16]. Re-trigger da mesma situação enquanto o job está in-flight é no-op (WAL existe → Runner pula queue insert). Whitespace é normalizado pra evitar inflação por churn trivial.
Drain + Graceful Shutdown
Na saída (cli.cleanup()), o Runner fica em DrainAndShutdown(30s):
- Queue fecha — sem novos dequeues.
- Workers terminam in-flight (ou são cancelados no timeout).
- WAL/DLQ fecham.
/reflect — Comandos
/reflect retry e /reflect purge listam IDs reais vivos da DLQ com preview da task + último erro.Arquivos e layout
CHATCLI_QUALITY_REFLEXION_QUEUE_BASE_DIR (default: <workspace>/.chatcli/reflexion).
Protocolo do lesson generator
O system prompt instrui o modelo a ser geral, não one-off:/reflect — caminho manual sem LLM
Quando você sabe a lição e não precisa do LLM destilando:
memory.Fact:
["reflexion", "trigger:manual", "user-supplied"].
Como a lição “volta”
Uma vez persistida, a lesson é um fact normal no índice. Ela emerge via:- Retrieval por hints: se a próxima task mencionar keywords em
Tags, o scorer relevance-based a surfaceia. - HyDE amplifica: com
CHATCLI_QUALITY_HYDE_ENABLED=true, a hipótese gerada cobre conceitos semelhantes, aumentando chance de match. - Vector search: com embeddings configurados, a lesson é buscada por proximidade cosseno.
## Long-term Memory com o texto da lesson, e o modelo tem todas as pistas para não repetir o erro.
Variáveis de ambiente
Gates (quando disparar)
Fila durável (WAL + worker pool + DLQ)
Métricas Prometheus
A fila emite 10 métricas emchatcli_lessonq_*:
Exemplo de ciclo completo
Usuário pede task que falha
/coder refactor pkg/engine to extract Close methodCoderAgent tenta rewrite total
PostRun detecta result.Error != nil
goroutine: GenerateLesson
Persiste em memory.Fact
lesson, workspace=current project.Próxima semana, usuário pede refactor similar
/coder refactor pkg/auth/manager.go split into smaller filesRAG+HyDE traz a lesson
refactor + large-file matchem. Lesson aparece no system prompt.Coder escolhe abordagem correta de primeira
@coder patch ao invés de write. Task concluída sem timeout.Inspecionar lições armazenadas
Prometheus snapshots úteis
Leia também
#4 RAG + HyDE
#6 CoVe
verified_with_discrepancy que Reflexion consome.Bootstrap Memory
Memory Commands
/memory load, /memory show, /memory longterm.Configuração quality
CHATCLI_QUALITY_REFLEXION_QUEUE_* + presets.