
Conceitos
- Alerta — a regra. Ela define o que verificar (o gatilho), com que frequência (o intervalo de avaliação), quando considerar algo quebrado (lógica composta), o nível de urgência (severidade) e quem/onde notificar (canais).
- Incidente — o que acontece quando um alerta é disparado. Um alerta tem no máximo um incidente aberto por vez. Violações repetidas atualizam as evidências do mesmo incidente. Incidentes são resolvidos por um operador; a resolução automática quando a regra para de disparar está planejada, mas ainda não está ativa.
- Canal — para onde uma notificação vai: e-mail, Slack, webhook genérico ou painel. Cada alerta pode usar qualquer combinação.
default integrada). Incidentes podem ser atribuídos a um operador individual para triagem.
Tipos de gatilho
Cinco tipos, cada um com seu próprio spec JSON. Escolha o que melhor descreve o que significa “quebrado”. O formulário novo alerta no painel constrói o mesmo spec para você, ajustando o editor de condição conforme o tipo de gatilho selecionado:
1. metric_threshold
O mais simples. Escolha uma métrica de uma lista fechada, um operador, um limite e uma janela de tempo.
| Métrica | O que conta |
|---|---|
event_count | Total de eventos na janela |
error_count | event_type = 'error' OU qualquer evento com error_type IS NOT NULL |
error_rate | error_count / event_count (0..1) |
p95_latency_ms | quantile(0.95)(duration_ms) em todos os eventos com duration_ms |
p99_latency_ms | quantile(0.99)(duration_ms) |
token_sum | SUM(input_tokens + output_tokens) |
>, >=, <, <=, == (também aceitos como gt, gte, lt, lte, eq).
Filtros opcionais: environment, event_type.
Exemplo de spec:
2. custom_sql
Para situações que as métricas predefinidas não cobrem. O SQL fornecido pelo operador passa pela mesma validação do /queries/run (somente SELECT/WITH, instrução única, limite de 10.000 linhas) antes de o dispatcher executá-lo. Dois modos:
- Modo rows (sem
op/value): o alerta dispara assim que a query retorna pelo menos uma linha. - Modo value: a query deve ter um alias de coluna chamado
metric_value; o dispatcher compara ometric_valueda primeira linha comvalueusandoop.
3. evaluation_score
Lê agenteye.evaluations e compara a média de uma pontuação nomeada ao longo de uma janela.
min_count protege contra outliers de amostra única; o dispatcher não dispara até que pelo menos N avaliações existam na janela.
4. eval_compound
Captura uma regressão de qualidade que só aparece em vários scores de avaliadores ao mesmo tempo. Enquanto evaluation_score monitora um único score nomeado, eval_compound compõe múltiplas condições de pontuação de avaliação em um único alerta e combina seus resultados com uma lógica escolhida; assim, uma regra pode expressar “disparar se a utilidade cair ou a alucinação subir”, “disparar somente se a utilidade e a eficiência de ferramentas caírem”, ou “disparar se pelo menos 2 de três verificações forem violadas”.
Cada condição lê a média de um score nomeado de agenteye.evaluations ao longo da janela compartilhada e o testa com seu próprio operador e limite. Os resultados booleanos são então combinados pelo combinator:
| Combinador | Lógica | Dispara quando |
|---|---|---|
"any" | OU | pelo menos uma condição é violada |
"all" | E | todas as condições são violadas |
{ "at_least": N } | M de N | pelo menos N condições são violadas |
combinator:"any","all"ou{ "at_least": N }.conditions[]: cada{ score_key, op, value }, usando os mesmos operadores dos outros gatilhos (>,>=,<,<=,==).window_secs: o lookback compartilhado aplicado a cada condição (padrão3600).min_count: número mínimo de avaliações por condição antes que ela possa ser violada; uma condição com amostras insuficientes na janela é contada como “não violada” (padrão1).environment: opcional; restringe todas as condições a um único ambiente.
5. per_event
Para alertas do tipo “qualquer evento que corresponda a X chegou”. Sem agregação; o dispatcher dispara assim que encontra uma correspondência na janela de lookback.
| Campo | Finalidade |
|---|---|
agent_id | Restringe a erros de um agente específico (o exibido na linha /errors). |
error_type | Restringe a uma classe de erro específica (ex: TimeoutError) em vez de todos os erros. |
message_contains | Correspondência de substring sem distinção de maiúsculas/minúsculas em payload.message. Útil para capturar um modo de falha específico (ex: prompt is too long) sem alertar sobre todos os erros do mesmo agente. Limitado a 200 caracteres; correspondido como string literal, não como padrão. |
lookback_secs para corresponder aproximadamente ao eval_interval_secs do alerta, para evitar notificações duplicadas sobre o mesmo evento.
Atalho em /errors: o botão + alert na linha representativa de cada grupo de erros na visão de erros (e no painel de detalhes de evento de sessão para um evento de erro) abre /alerts/new preenchido com um gatilho per_event associado ao event_type + ambiente daquela linha, incluindo um nome derivado do error_type do payload quando presente. Você ainda escolhe os canais e confirma o lookback, mas o matcher já vem preenchido. Operadores precisam de alerts:write para que o botão apareça.
Lógica composta (M de N)
Cada alerta tem dois controles inteiros além do gatilho:eval_window: quantas avaliações recentes considerar (padrão 1)min_breaches: quantas delas precisam violar antes que o alerta dispare (padrão 1)
1 de 1 (o padrão) significa “disparar na primeira violação”. 3 de 5 significa “disparar quando a regra tiver violado 3 das últimas 5 avaliações”, útil para sinais instáveis onde uma única medição ruim é ruído. O dispatcher mantém um buffer circular por alerta; você não precisa gerenciar o estado.
Intervalo de avaliação
eval_interval_secs controla com que frequência o dispatcher executa sua regra. Limitado ao intervalo [30, 86400]. Predefinições no painel: 1m / 5m / 15m / 1h. Escolha um intervalo compatível com a velocidade do sinal subjacente: um alerta de taxa de erros de 5 minutos avaliado a cada 15 segundos desperdiça CPU; um alerta por evento precisa de um lookback curto ou perderá eventos silenciosamente entre as execuções.
Canais
Cada alerta pode usar qualquer combinação destes quatro. Credenciais por canal (URL do webhook do Slack, URL de webhook genérico + segredo de assinatura, destinatários de e-mail padrão) são configuradas uma vez em/settings e referenciadas por chave em cada alerta. Assim, um único canal Slack pode atender muitos alertas sem que cada um armazene sua própria cópia da URL do webhook.
Os três tipos de canais externos (e-mail, Slack, webhook) também são controlados por um interruptor global da organização, alerts.enabled_channels. Quando um alerta disparado usa um tipo de canal que não está neste conjunto, o dispatcher o ignora e registra uma linha em alert_notifications com status skipped_disabled e destino <channel_disabled> (permitindo pausar globalmente, por exemplo, toda a entrega via Slack sem editar cada regra). O canal no painel sempre é permitido. Consulte Configuração.
- Substituição
recipients[]por canal (quando não vazio). - A configuração
alerts.email_default_recipients(um array de strings de e-mail).
alert_notifications com destino <smtp_unconfigured> para que a trilha de auditoria torne visível a configuração incorreta.
Slack
Envia uma mensagem Block Kit para uma URL de webhook de entrada.- URL padrão:
alerts.slack_default_webhook(definida em/settings). - Substituição por alerta: defina o
webhook_setting_keydo canal para qualquer outra chave de configuração do tipo URL, ex:alerts.slack_oncall,alerts.slack_costs.
:rotating_light: / :warning: / :bell:), e a mensagem traz um botão com link direto para a página do incidente.
Webhook genérico
Uma integração JSON-POST para PagerDuty, Opsgenie ou seu próprio endpoint de ingestão. Formato do corpo:alerts.webhook_signing_secret está definido, a requisição inclui um cabeçalho X-AgentEye-Signature: sha256=<hex>, o HMAC-SHA256 do corpo usando o segredo. Verifique-o no lado receptor antes de confiar no payload.
O cabeçalho X-AgentEye-Event carrega alert.firing / alert.test. (alert.resolved está reservado para o recurso de auto-resolução planejado e não é emitido atualmente.)
No painel
Sem entrega externa: o alerta apenas escreve uma linha emalert_notifications que a página de incidentes do painel exibe. Útil enquanto você está ajustando uma regra e não quer sobrecarregar um sistema externo, ou para alertas de baixa urgência que os operadores verificam durante a triagem normal.
Ciclo de vida do incidente
- firing — o dispatcher acabou de abrir o incidente ou detectou outra violação. A notificação de disparo é enviada exatamente uma vez (controlada pelo timestamp
notified_firing_atno incidente). - acknowledged — um operador pressionou ack em
/incidents/:id. O incidente ainda é considerado aberto; violações subsequentes atualizarão suas evidências sem re-notificar. - resolved — um operador pressionou resolve. A resolução automática quando a regra para de violar está planejada, mas ainda não está ativa, portanto um incidente aberto permanece aberto até que um operador o resolva.


Permissões necessárias
A criação de regras de alerta e a triagem de incidentes são responsabilidades separadas com concessões distintas, para que você possa dar a uma rotação de plantão acesso a incidentes sem também conceder a capacidade de reescrever as regras.alerts:read: visualizar regras de alerta.alerts:write: criar, editar, excluir regras de alerta e acionar uma notificação de teste.incidents:read: visualizar incidentes.incidents:write: abrir incidentes manuais (ad-hoc) que não estão vinculados a um alerta.incidents:ack: reconhecer, atribuir, comentar e resolver incidentes.
Conceda em chaves de API (alerts:acklegado. Chaves e operadores que receberam o tokenalerts:ackantigo continuam funcionando: ele é aceito comoincidents:ack(e implicaincidents:read), para que os plantões existentes mantenham o acesso sem precisar reemitir credenciais. Emita novas concessões com a famíliaincidents:*.
POST /keys) e operadores (PUT /users/:id). O PermGate do painel bloqueia os botões relevantes quando uma permissão está ausente; você verá // 403 ao lado da ação.
Seletor de destinatários de e-mail. O seletor de destinatários do editor de alertas lista os membros da sua organização para que você possa selecioná-los pelo nome. Ele carrega para qualquer operador que possuaalerts:readoualerts:write; visualizar o diretório da sua equipe para esse fim não requerusers:read, e o seletor retorna apenas endereços de e-mail dos membros, nunca registros completos de usuário.
Configuração
Variáveis de ambiente consumidas pelo dispatcher:| Variável | Padrão | Finalidade |
|---|---|---|
ALERT_WORKERS | 1 | Tarefas de worker por instância de servidor. A maioria das implantações precisa apenas de uma. |
ALERT_CLAIM_BATCH | 16 | Máximo de alertas processados em um único tick do worker. |
ALERT_POLL_IDLE_SECS | 5 | Tempo de espera do worker quando a fila está vazia. |
ALERT_REQUEST_TIMEOUT_MS | 15000 | Tempo limite de avaliação por gatilho. |
DASHBOARD_URL | https://app.befailproof.ai | Origem usada para construir o link mágico do incidente nas notificações. Defina para o host do seu painel. |
/settings, não via env):
alerts.email_default_recipients(email_list): array JSON de strings de e-mail — os destinatários padrão para canais de e-mail.alerts.slack_default_webhook(url): URL padrão do webhook de entrada do Slack.alerts.webhook_default_url(url): URL padrão do webhook genérico.alerts.webhook_signing_secret(secret): chave HMAC-SHA256. Sempre retornada como""na resposta GET; digite um novo valor para rotacionar.alerts.enabled_channels(channel_set): o conjunto global de tipos de canais externos que são despachados quando um alerta dispara; o padrão inclui todos os três (email,slack,webhook). Remover um tipo aqui suprime globalmente esse canal para todos os alertas sem editar cada regra. O canal no painel sempre é entregue e não é afetado por essa configuração.
Verificar um novo alerta
Antes de confiar em um novo alerta:- Salve-o como habilitado com pelo menos um canal de notificação.
- Selecione test na página de detalhes do alerta e confirme que cada destino configurado recebe a notificação sintética.
- Após a primeira violação real, confirme que o incidente aparece em Incidents e que o valor medido corresponde à query do painel correspondente.
Solução de problemas
| Sintoma | Causa provável |
|---|---|
| O alerta nunca dispara | enabled = false, nenhum canal anexado ou a query CH subjacente retorna 0 linhas. Use test para confirmar os canais; use /queries/run para confirmar a métrica. |
| Notificação do Slack ausente | alerts.slack_default_webhook (ou a chave de substituição por alerta) não está definida: verifique alert_notifications.target por linhas <unset:…>; ou o tipo slack está desabilitado globalmente em alerts.enabled_channels: verifique linhas em alert_notifications com status skipped_disabled e destino <channel_disabled>. |
| Webhook genérico retorna 401 | O destinatário está exigindo uma assinatura, mas alerts.webhook_signing_secret não está definido. Verifique no destinatário se o HMAC corresponde a hmac_sha256(secret, body). |
| E-mail “from all sends failed” | Credenciais SMTP incorretas ou o endereço from é rejeitado pelo seu relay. A mesma superfície que envia e-mails OTP: se esses funcionam, o transporte SMTP está correto. |
| Incidente reabre repetidamente | Os controles compostos estão muito agressivos: tente aumentar min_breaches ou eval_window para que picos transitórios não reabram incidentes que você resolveu. |

