new feature: External guardrails/judges

This commit is contained in:
2026-08-24 11:26:08 -03:00
parent a472daa1e4
commit 63d0fb51c4
343 changed files with 37952 additions and 970 deletions

View File

@@ -0,0 +1,76 @@
# Observability Code Mapping
## Objetivo
O framework separa o **identificador semântico interno** do **identificador contratual externo** usado por observabilidade. Cada agente/deployment pode declarar sua própria tabela sem alterar guardrails, judges ou publishers.
Exemplo:
```yaml
version: "1"
mappings:
guardrail.dlex_in: GRL.004
guardrail.tox: GRL.005
```
Nesse exemplo, o componente continua internamente conhecido como `guardrail.dlex_in`, mas Langfuse/OTEL/EventBus recebem `GRL.004` como nome da observation/span/generation.
## Configuração
```dotenv
OBSERVABILITY_CODE_MAPPING_ENABLED=true
OBSERVABILITY_CODE_MAPPING_PATH=./config/observability_mapping.yaml
```
O core não contém mappings de cliente.
## Pontos de aplicação
O mapper atua antes do fan-out nos pontos comuns do framework:
1. `Telemetry.span()` — normaliza o nome antes do span OTEL, observation Langfuse e EventBus.
2. `Telemetry.generation_span()` — normaliza o nome antes da generation Langfuse e EventBus.
3. `Telemetry.event()` — normaliza o nome do evento antes de EventBus/Langfuse.
4. `AgentObserver.emit()` — normaliza `event_type` antes de Analytics, NOC/OTEL e EventBus.
Assim, o mapping não precisa ser duplicado em cada exporter/provider.
## Preservação do identificador interno
Para spans/generations mapeados:
- `observability_name_internal`: nome semântico original;
- `observability_name_mapped`: nome contratual;
- `observability_code_mapped: true`.
Para eventos estruturados:
- `event_code_internal`;
- `event_code_mapped`;
- `observability_code_mapped: true`.
Isso permite que o cliente filtre pelo contrato externo sem eliminar a informação útil para troubleshooting.
## Compatibilidade
- recurso opt-in;
- mapping desconhecido = passthrough;
- YAML ausente/inválido = passthrough com log;
- nenhuma substituição textual em payloads/prompts;
- o código interno de guardrails e judges não é renomeado;
- mappings pertencem ao agente/deployment, nunca ao core.
## Registry v2: ações e aliases
Além da forma escalar histórica, uma entrada pode declarar `label`, `action` e `aliases`.
```yaml
mappings:
guardrail.revprec:
action: retry
aliases: [REVPREC, TIM_REVPREC]
```
`OutputSupervisor` e `ParallelRailExecutor` consultam a mesma instância de `ObservabilityCodeMapper` para resolver a ação de uma negação que não tenha ação mais específica. Precedência: `terminal_action` do rail, `on_deny` do rail, `action` do registry e por fim `BLOCK`.
A ausência de `label` torna a entrada action-only e não renomeia a observabilidade. A sintaxe `guardrail.x: GRL.004` continua suportada.

View File

@@ -0,0 +1,81 @@
# Observability default registry + agent overlay
## Objetivo
O `agent_framework_oci` carrega um registry default de observabilidade e políticas de guardrail **sempre por padrão**. Esse registry reproduz o comportamento histórico que antes estava codificado em Python (`GRL.001..GRL.009`, decisões de `REVPREC/CMP/SCO/GND`, handover e rewrite de `FRASEOLOGIA`).
Com isso, um agente legado pode substituir apenas a versão do framework e continuar funcionando sem criar `observability_mapping.yaml` nem declarar novas variáveis.
## Fontes e precedência
1. `agent_framework/config/observability_mapping.yaml` — default interno do framework, carregado por padrão.
2. `OBSERVABILITY_CODE_MAPPING_PATH` — mapping opcional do agente/deployment, aplicado como overlay quando `OBSERVABILITY_CODE_MAPPING_ENABLED=true`.
O overlay é feito por chave canônica. Uma chave declarada pelo agente substitui a entrada default com a mesma chave; todas as demais entradas default continuam disponíveis.
### Exemplo
Default do framework:
```yaml
guardrail.dlex_in:
label: GRL.DLEX_IN
aliases: [DLEX_IN]
```
Contas:
```yaml
guardrail.dlex_in:
label: GRL.004
aliases: [DLEX_IN]
```
Registry efetivo do Contas:
- `guardrail.dlex_in` / `DLEX_IN` -> `GRL.004` (override do agente)
- `REVPREC` -> `retry` (herdado do framework)
- `CMP` -> `retry` (herdado do framework)
- `guardrail.result.block` -> `GRL.004` (herdado do framework)
## Compatibilidade de agentes antigos
Sem qualquer configuração nova:
```text
agente legado + framework novo
|
+-- default registry interno
+-- GRL.001..GRL.009
+-- REVPREC/CMP/SCO/GND -> retry
+-- HANDOVER/ATH/HUMAN -> handover
+-- FRASEOLOGIA -> remediation rewrite
```
Assim `OBSERVABILITY_CODE_MAPPING_ENABLED` controla apenas o overlay customizado do agente. Ele não desliga o registry base de compatibilidade.
## Escape hatch
Somente deployments que desejarem explicitamente remover a compatibilidade base podem usar:
```env
OBSERVABILITY_DEFAULT_MAPPING_ENABLED=false
```
Também é possível substituir o arquivo default para testes/deployments especiais:
```env
OBSERVABILITY_DEFAULT_MAPPING_PATH=/caminho/default.yaml
```
Essas opções não são necessárias para agentes normais.
## Packaging
O YAML default fica dentro do pacote Python em:
```text
agent_framework/config/observability_mapping.yaml
```
O `pyproject.toml` inclui explicitamente esse arquivo como package data, portanto ele também está presente quando o framework é instalado como wheel.

View File

@@ -0,0 +1,26 @@
# Correção do merge Default + Overlay de Observabilidade
## Problema
O default do framework estava ativo, porém em alguns caminhos o overlay do agente não era carregado. O efeito observado no Langfuse era `GRL.DLEX_IN`/`GRL.TOX` (default) em vez de `GRL.004`/`GRL.005` (Contas).
## Correção
O framework agora monta um único registry efetivo antes de qualquer resolução:
1. carrega `agent_framework/config/observability_mapping.yaml`;
2. localiza o overlay do agente;
3. faz merge por chave canônica, com o agente sobrescrevendo o default;
4. reconstrói os aliases somente depois do merge;
5. usa esse único registry em LLM provider, Telemetry, Analytics, OutputSupervisor e ParallelRailExecutor.
## Descoberta do overlay
Além de `OBSERVABILITY_CODE_MAPPING_PATH`, o framework autodetecta `config/observability_mapping.yaml` no cwd e nos roots de importação Python. O arquivo default empacotado do framework é excluído dessa descoberta.
Assim um agente com arquivo convencional de overlay não depende de alterar seu launcher ou `.env` para que a customização seja aplicada.
## Resultado esperado no Contas
- `guardrail.dlex_in` -> `GRL.004`
- `guardrail.tox` -> `GRL.005`
- componentes não sobrescritos continuam herdando o default do framework.
## Compatibilidade
Agentes antigos sem overlay continuam usando apenas o default do framework e preservam a taxonomia/ações históricas.

View File

@@ -0,0 +1,83 @@
# OutputSupervisor sem taxonomia contratual hardcoded
## Objetivo
O `OutputSupervisor` do framework trabalha somente com eventos semânticos e ações de runtime. Códigos contratuais externos/numerados pertencem exclusivamente ao `ObservabilityCodeMapper` configurado pelo agente/deployment.
## Eventos internos
Exemplos de eventos internos:
```text
guardrail.output_supervisor.started
guardrail.result.allow
guardrail.result.block
guardrail.result.retry
guardrail.output.<rail>.completed
guardrail.output_supervisor.completed
```
Se um cliente exigir códigos próprios, configure `config/observability_mapping.yaml`. O supervisor não conhece a taxonomia externa.
## Ação quando um rail nega
O framework não decide mais a ação procurando nomes específicos de rails. A ação pode vir do próprio resultado:
```python
metadata={"terminal_action": "retry"}
```
ou do YAML:
```yaml
output:
- code: MY_VALIDATION
enabled: true
on_deny: retry
```
Valores suportados são os valores de `RailAction`, como `block`, `retry` e `handover`.
## Remediação por rewrite
Rewrite também é uma capacidade genérica. O rail/policy declara a remediação:
```yaml
output:
- code: MY_WORDING_POLICY
enabled: true
on_block:
type: rewrite
max_attempts: 1
prompt_id: FALLBACK
profile_name: grl
component_name: guardrail.wording.rewrite
```
O supervisor não verifica se o código é `FRASEOLOGIA` ou qualquer outro nome. Um guardrail externo do agente pode usar exatamente o mesmo contrato.
## Mensagens de UX
Mensagens de fallback/handover pertencem ao agente:
```yaml
output_supervisor:
max_retries: 3
fallback_message: "..."
handover_message: "..."
```
Assim o framework não precisa conhecer idioma, marca ou fraseologia do atendimento.
## Contas
O Contas preserva seu comportamento atual:
- `TIM_REVPREC` declara `terminal_action=retry` no próprio rail externo;
- `CMP` está configurado com `on_deny: retry`;
- `TIM_FRASEOLOGIA`, quando habilitado, declara remediação `rewrite` no agente;
- textos de fallback/handover ficam no `config/guardrails.yaml` do Contas.
## Compatibilidade
Rails que retornam apenas `allowed=false` e não declaram policy continuam em `block`, que é o fail-closed genérico. Não há mais inferência de ação pelo nome do rail.