Tools
Detecção de loop de ferramentas
O OpenClaw possui duas proteções complementares contra padrões repetitivos de chamadas de ferramentas,
ambas configuradas em tools.loopDetection:
- Detecção de loops (
enabled) - desabilitada por padrão. Monitora o histórico contínuo de chamadas de ferramentas em busca de padrões repetidos e novas tentativas com ferramentas desconhecidas. - Proteção pós-Compaction (
postCompactionGuard) - habilitada sempre queenablednão for explicitamentefalse. É armada após cada nova tentativa decorrente de Compaction e interrompe a execução se o agente repetir a mesma tripla(tool, args, result)dentro da janela.
Defina tools.loopDetection.enabled: false para desativar as duas proteções.
Por que isso existe
- Detectar sequências repetitivas que não produzem progresso.
- Detectar loops de alta frequência sem resultados (mesma ferramenta, mesmas entradas e erros repetidos).
- Detectar padrões específicos de chamadas repetidas para ferramentas de sondagem conhecidas.
- Interromper ciclos de estouro de contexto -> Compaction -> mesmo loop, em vez de permitir que continuem indefinidamente.
Bloco de configuração
Padrões globais, com todos os campos documentados:
{ tools: { loopDetection: { enabled: false, // master switch for the rolling-history detectors historySize: 30, warningThreshold: 10, criticalThreshold: 20, unknownToolThreshold: 10, globalCircuitBreakerThreshold: 30, detectors: { genericRepeat: true, knownPollNoProgress: true, pingPong: true, }, postCompactionGuard: { windowSize: 3, // armed after compaction-retry; runs unless enabled is explicitly false }, }, },}Substituição por agente (opcional, em agents.list[].tools.loopDetection):
{ agents: { list: [ { id: "safe-runner", tools: { loopDetection: { enabled: true, warningThreshold: 8, criticalThreshold: 16, }, }, }, ], },}As configurações por agente são sobrepostas ao bloco global campo por campo (incluindo
detectors e postCompactionGuard aninhados), portanto um agente precisa definir apenas os
campos que deseja alterar.
Comportamento dos campos
| Campo | Padrão | Efeito |
|---|---|---|
enabled |
false |
Chave principal dos detectores de histórico contínuo. false também desabilita a proteção pós-Compaction. |
historySize |
30 |
Número de chamadas de ferramentas recentes mantidas para análise. |
warningThreshold |
10 |
Contagem de repetições antes que um padrão seja classificado apenas como aviso. |
criticalThreshold |
20 |
Contagem de repetições para bloquear um padrão de loop sem progresso. Em caso de configuração incorreta, o runtime limita esse valor para que fique acima de warningThreshold. |
unknownToolThreshold |
10 |
Bloqueia chamadas repetidas à mesma ferramenta indisponível após essa quantidade de falhas. Não é controlado por detectors. |
globalCircuitBreakerThreshold |
30 |
Disjuntor global de ausência de progresso para todos os detectores. Em caso de configuração incorreta, o runtime limita esse valor para que fique acima de criticalThreshold. Não é controlado por detectors. |
detectors.genericRepeat |
true |
Emite avisos sobre chamadas repetidas com a mesma ferramenta e os mesmos argumentos; bloqueia quando essas chamadas também retornam resultados idênticos. |
detectors.knownPollNoProgress |
true |
Detecta padrões conhecidos de sondagem sem progresso (process com action: "poll"/"log", command_status). |
detectors.pingPong |
true |
Detecta padrões alternados de vaivém sem progresso entre duas chamadas. |
postCompactionGuard.windowSize |
3 |
Quantidade de tentativas durante as quais a proteção permanece armada após a Compaction e número de triplas idênticas que interrompe a execução. |
Para exec, o hash de ausência de progresso compara resultados estáveis do comando (status,
código de saída, indicador de tempo limite e saída) e ignora metadados voláteis do runtime, como
duração, PID, ID da sessão e diretório de trabalho. Os hashes dos resultados de envio de mensagens
removem IDs voláteis específicos de cada chamada (ID da mensagem, ID do arquivo e carimbo de data e hora),
para que um resultado de "envio concluído" não pareça idêntico a outro resultado de "envio concluído".
Quando um ID de execução está disponível, o histórico é avaliado somente dentro dessa execução,
portanto ciclos agendados de Heartbeat e novas execuções não herdam contagens obsoletas de loops
de execuções anteriores.
Configuração recomendada
- Para modelos menores, defina
enabled: truee mantenha os valores padrão dos limites. Modelos de ponta raramente precisam da detecção por histórico contínuo e podem manter a chave principal comofalse, ainda se beneficiando da proteção pós-Compaction. - Mantenha os limites na ordem
warningThreshold < criticalThreshold < globalCircuitBreakerThreshold; o runtime aumentacriticalThresholdeglobalCircuitBreakerThresholdse você os definir com valor igual ou inferior ao limite que eles precisam exceder. - Se ocorrerem falsos positivos:
- Aumente
warningThresholde/oucriticalThreshold. - Opcionalmente, aumente
globalCircuitBreakerThreshold. - Desabilite somente o detector específico que está causando problemas (
detectors.<name>: false). - Reduza
historySizepara usar uma janela histórica mais curta.
- Aumente
- Para desabilitar tudo, incluindo a proteção pós-Compaction, defina
explicitamente
tools.loopDetection.enabled: false.
Proteção pós-Compaction
Após uma nova tentativa de Compaction decorrente de um estouro de contexto, o executor arma uma
proteção de janela curta para as próximas chamadas de ferramentas. Se o agente emitir a mesma
tripla (toolName, argsHash, resultHash) postCompactionGuard.windowSize
vezes dentro dessa janela, a proteção conclui que a Compaction não interrompeu o
loop e encerra a execução com um erro compaction_loop_persisted.
A proteção é controlada pela chave principal tools.loopDetection.enabled, com uma
particularidade: ela permanece habilitada quando a chave não está definida ou é true e somente é
desativada quando a chave é explicitamente false. Isso é intencional: a proteção
existe para interromper loops de Compaction que, de outra forma, consumiriam tokens sem limite,
portanto até mesmo um usuário sem configuração recebe essa proteção.
{ tools: { loopDetection: { // master switch; set false to disable the guard along with the rolling detectors enabled: true, postCompactionGuard: { windowSize: 3, // default }, }, },}- Um
windowSizemenor é mais rigoroso (menos tentativas antes da interrupção). - Um
windowSizemaior oferece ao agente mais tentativas de recuperação. - A proteção nunca interrompe a execução enquanto os resultados estiverem mudando; somente resultados idênticos byte a byte ao longo da janela a acionam.
- Ela é armada somente imediatamente após uma nova tentativa de Compaction, e não em outros pontos de uma execução.
Logs e comportamento esperado
Quando um loop é detectado, o OpenClaw registra um evento de loop e emite um aviso ou bloqueia o próximo ciclo de ferramenta, dependendo da gravidade, protegendo contra o consumo descontrolado de tokens e travamentos sem impedir o acesso normal às ferramentas.
- Os avisos ocorrem primeiro.
- O bloqueio ocorre quando um padrão persiste além do limite de aviso.
- Os limites críticos bloqueiam o próximo ciclo de ferramenta e apresentam um motivo claro de detecção de loop no registro da execução.
- A proteção pós-Compaction emite erros
compaction_loop_persistedque identificam a ferramenta responsável e a contagem de chamadas idênticas.
Conteúdo relacionado
Política de permissão e negação para execução no shell.
Níveis de esforço de raciocínio e interação com a política do provedor.
Criação de agentes isolados para limitar comportamentos descontrolados.
Esquema completo de tools.loopDetection e semântica de mesclagem.