adjustments: manual v2

This commit is contained in:
2026-09-12 08:05:39 -03:00
parent 04a8f31744
commit 4f703402db
21 changed files with 1174 additions and 76 deletions

View File

@@ -159,34 +159,15 @@ _, decisions = await pipeline.run_tool(
### SPI for external guardrails and judges
> Content consolidated from `docs/EXTERNAL_GUARDRAILS_JUDGES.md`.
Use extensions when a policy or quality criterion belongs to the agent domain. A guardrail implements `evaluate(text, context) -> RailDecision` and can run at `input`, `retrieval`, `tool`, or `output`. A judge implements `evaluate(question, answer, context) -> JudgeResult` and scores rather than rewrites a response.
`agent_framework_oci` supports agent-owned guardrails and judges without importing domain code into the core.
The [external guardrails and judges guide](../../EXTERNAL_GUARDRAILS_JUDGES_en.md) covers directory layout, imports, copyable implementations, YAML, constructor injection, failure policy, observability, and executable verification.
```yaml
output:
- code: ACME_POLICY
type: external
class: app.extensions.guardrails:AcmePolicyRail
```
Key constraints: `type: external` plus `class: package.module:Class` enables dynamic import; `kwargs` populate the constructor; judges may receive injected `llm` and `settings`; guardrails receive a shared LLM through context only when the pipeline was built with `llm=...`; synchronous implementations run in worker threads; and external judge exceptions should be handled by the implementation.
```yaml
judges:
- name: acme_quality
type: external
class: app.extensions.judges:AcmeQualityJudge
threshold: 0.7
```
> **Current limitation:** `agent_template_backend` creates a global pipeline pair at startup. Registry fields `guardrails_config_path` and `judges_config_path` do not automatically select a configuration per request. LLM-backed extensions also require the composition to pass `llm` and `settings` as documented in the full guide.
Native entries remain unchanged. External synchronous `evaluate()` methods execute in worker threads via `asyncio.to_thread`; asynchronous methods execute concurrently on the framework event loop. Judges run concurrently with `asyncio.gather`, preserving YAML result order. Agent plugins should reuse the LLM supplied by the framework rather than instantiate a separate provider.
The core must not reference a concrete agent package, company, product, telecom identifier, or domain-specific policy. Domain-specific variants belong to the agent and should receive distinct public codes/names.
### Compatibility rule
Domain policies must not be replaced by cosmetically generic text inside the core while losing the original policy. The generic core implementation and the agent-specific implementation may coexist; the embedding agent explicitly selects its own code/name in YAML.
Legacy business validators should migrate to the agent domain. A temporary compatibility shim is acceptable for old imports, but new application code must import the agent-owned implementation.
Verify the published examples with `pytest -q tests/test_external_guardrails_judges_documentation.py`.
### Mandatory judge execution for transactions

View File

@@ -0,0 +1,90 @@
### Advanced transactional workflows
### Goal
This chapter turns a sensitive tool into a deterministic transaction with parameter collection, pre-validation, confirmation, versioned workflow, pause/resume, idempotency, and recovery. Business rules and actions belong to the agent; the execution engine belongs to the framework.
### Actual flow
1. `routing.yaml` selects the agent and limits candidate tools.
2. `tools.yaml` describes arguments, prompts, and response behavior.
3. `mcp_parameter_mapping.yaml` resolves identity, defaults, and extraction.
4. `tool_policies.yaml` classifies the operation and requires confirmation.
5. Optional pre-validation checks whether execution may continue without producing an effect.
6. After unambiguous confirmation, execution is direct or delegated to `WorkflowToolExecutor`.
7. `WorkflowRuntime` loads the active version, runs actions, persists pauses, and returns `COMPLETED`, `PAUSED`, or `FAILED`.
8. An idempotency key prevents duplicate external effects.
### Catalog and policy are different contracts
```yaml
# config/tools.yaml
tools:
request_return:
description: Opens an order return.
mcp_server: retail
enabled: true
tool_type: action
confirmation_required: true
requires: [order_id, reason]
args_schema:
order_id:
type: string
label: the order number
user_prompt: Provide the order number.
reason:
type: string
label: the return reason
user_prompt: What is the return reason?
```
```yaml
# config/tool_policies.yaml
version: 1
defaults:
operation_type: read_only
require_confirmation: false
tool_policies:
request_return:
operation_type: transactional
require_confirmation: true
requires: [order_id, reason]
pre_validation:
enabled: true
tool: validate_return
fail_open: false
execution:
mode: workflow
workflow: order_return
version: active
```
`tools.yaml` is the public catalog; `tool_policies.yaml` governs effects. Do not rely only on catalog `confirmation_required`: effective policy must declare `operation_type` and `require_confirmation`. A pre-validation tool must be read-only and never perform the transaction early. Prefer `fail_open: false` for sensitive operations.
### Versioned workflow and actions
Store definitions under `workflows/<name>.vN.yaml` and maintain a valid active definition. Node IDs must be unique; `start`, destinations, and `resume_from` must exist; `retry` accepts 0 through 10. Paths under `$.input.*` read workflow input and `$.nodes.<id>.*` read earlier results.
Agent actions use `@workflow_action("name")`, matching `node.action`, and implement `(params: dict, state: dict) -> dict`. Import the action module during startup so decorators register. Return serializable data only—never an HTTP client, connection, exception, or coroutine. Complete executable YAML and Python are available in the matching [Portuguese chapter](../pt/13_workflows_transacionais_avancados.md).
### Idempotent external effects
Create one `create_idempotency_store(...)` instance at startup and inject it into actions. Build the key from stable business identity, operation, resource, and contract version—not merely a timestamp. `IDEMPOTENCY_PROVIDER` takes precedence over checkpoint, session, and cache providers. For production transactions, enable `IDEMPOTENCY_REQUIRE_DURABLE=true` and select an appropriate `oracle`, `redis`, or `sqlite` provider. Memory does not protect across pods or restarts. Persist the outcome only after the external system confirms the effect.
### Pause, expected input, and resume
A node may declare `pause.expected_input` with `key`, `allowed_values`, normalization, `reprompt`, and a semantic classifier. Explicit confirmation remains deterministic; the classifier handles only inconclusive replies and must return an allowed option. `contextual_reentry` releases the workflow and returns the utterance to normal routing without confirming user facts.
Resume with the same `execution_id`; a new execution creates a separate transaction. The checkpoint must contain serializable data sufficient to rebuild the pause. Duplicate replies must check idempotency before repeating an effect.
### Intent shift, recovery, and replay
When a user abandons a transaction, clear pending call, collected arguments, confirmation, and related transaction state. Do not reuse parameters from a closed transaction. A contextual question may be answered and return to the pause; a genuine intent change explicitly closes or suspends the flow according to agent policy.
- `PAUSED`: persist execution ID, prompt, and expected-input contract.
- `FAILED`: keep technical details in telemetry and return a safe message.
- timeout after sending: query idempotency or external status before resending.
- replay after `COMPLETED`: return the persisted result without execution.
- new version: in-flight runs retain their version; `active` applies to new runs.
Test invalid graphs, valid/invalid paths, retry, pause/resume, unmatched answers, intent shift, duplicates, idempotency-provider failure, and post-finalization replay. Run `pytest -q tests/test_advanced_developer_documentation.py`.

View File

@@ -0,0 +1,31 @@
### Advanced routing, parameters, and state
### Decision precedence
Routing is not a keyword list. Safe precedence is: explicit block/finalization; pending collection or transaction through `state_policies`; deterministic confirmation; deterministic intent; optional LLM fallback; and finally fallback/handoff. Pending state must win so short replies and isolated parameters do not jump to another agent.
The complete executable YAML is in the matching [Portuguese chapter](../pt/14_routing_parametros_e_estado_avancados.md). In `routing.yaml`, lower `priority` values win ties in the current template. `mcp_tools` limits candidates but does not authorize sensitive effects. `confidence_threshold` gates semantic results, `allow_handoff` permits an explicit agent change, and `domain` supplies scope metadata rather than replacing `agent`.
### Semantic confirmation
Constrain semantic confirmation with `allowed_values`, plus explicit confirm, reject, and continue sets. The prompt must include the allowed values and prohibit execution or invented facts. `include_relevant_context` contributes bounded context related to the pause. If model output does not match an allowed option, keep the transaction pending. Explicit yes/no remains deterministic; the LLM handles inconclusive language only.
### Identity, mapping, and extraction
`identity.yaml` resolves canonical customer, contract, interaction, account, resource, and session keys from the payload, prior `business_context`, or previous context. Validate required identity before MCP execution. A session identifier is not customer identity.
Recommended argument precedence is: already confirmed transaction value, explicit current value, canonical identity mapping, deterministic extraction, LLM/hybrid extraction, and default. A new explicit value may correct an old one; an inferred value must never overwrite a confirmed value.
For `strategy: hybrid`, test both regex and LLM paths. `pattern` and `group` require positive and negative tests. `description` is an operational extraction instruction, not decorative documentation. Type conversion must fail safely when ambiguous.
### Temporal reconciliation
Temporal reconciliation is a fallback only after ordinary collection leaves missing fields. Search relevant messages newest-first and bind values only to fields described by the tool schema/mapping. It must not cross tenant/agent/session, revive a closed transaction, recover a user-invalidated value, replace safe exact matching with dangerous fuzzy matching, or overwrite a confirmed field. Record value origin and correlation without retaining unnecessary sensitive text.
### Dynamic states and multi-agent behavior
Declare new collection and confirmation state fields only when they carry extra data; otherwise reuse generic transaction keys. Every new state needs a matching `state_policies` entry, cleanup on success/cancellation/intent shift, and routing tests. A new state without policy commonly loses route stickiness.
Router mode selects one agent. Supervisor mode coordinates multiple agents and changes cost, latency, state, and telemetry. Do not enable it merely to improve classification. Give subagents minimum context and authorized tools, scoped by `tenant_id:agent_id:session_id`; never share raw memory across agents.
Test keyword overlap, priority ties, below-threshold output, fallback, pending states, short confirmations, ambiguity, parameter correction, regex/LLM extraction, temporal history, and isolation. Run `pytest -q tests/test_advanced_developer_documentation.py`.

View File

@@ -0,0 +1,25 @@
### Presentation, recovery, and observability
### Deterministic renderers
Use `response.mode: renderer` for trusted structured tool results whose values must not be changed by an LLM. Register each renderer once at startup. Its keyword-only contract accepts `tool_name`, `result`, `state`, and `agent_label`; return `None` when required fields are absent so the configured fallback can run. Select, format, and mask allowed fields—never interpolate the complete payload. The executable YAML and implementation are in the matching [Portuguese chapter](../pt/15_apresentacao_recuperacao_e_observabilidade.md).
### Output supervision and recovery
The Output Supervisor may allow, sanitize, retry, block, hand over, or observe candidate output. Keep retries bounded, provide objective retry guidance, and revalidate rewritten output. Permanent authorization or dependency failure is not a content retry.
Distinguish validation, transient dependency, permanent dependency, persistence, and programming failures. Before an external send, bounded retry may be safe. After an ambiguous send, query status/idempotency before resending. After external confirmation, persist the outcome before replying. A new user message must not erase evidence of uncertain execution. Checkpoint retry, integrity checks, compaction, and recovery do not make an external action idempotent.
### Voice interruption and replay
On barge-in, preserve confirmed transcript, mark interrupted output, and discard stale audio. An interrupted utterance is not transaction confirmation. Replay uses interaction/message identity and the same scoped session; resume only after revalidating pending state, confirmation, and idempotency.
### Events, mappings, and Pub/Sub
Emit functional behavior as IC, operational dependency/latency as NOC, and guardrail/supervisor decisions as GRL through the observer abstraction. Include tenant, agent, session, transaction/execution, component, and duration where available. Never record credentials, complete prompts, PII, or raw financial payloads.
Map legacy consumer labels through a default registry plus agent overlay. Keep internal events semantic; do not hardcode historical external labels in runtime code.
Pub/Sub publication occurs after the functional decision and must not change its outcome. Ordering requires explicit `sequence`, correlation, and a stable partition key; multiple pods do not provide global ordering. Define retention/TTL, duplicate handling, filters, and failure policy. A Pub/Sub filter does not remove the event from other telemetry destinations.
Validate payload masking, supervisor revalidation, bounded retry, uncertain effects, correlation, mapping, multi-consumer ordering, and voice behavior. Run `pytest -q tests/test_advanced_developer_documentation.py`.

View File

@@ -0,0 +1,31 @@
### Multi-agent composition and lifecycle
### Effective isolation
An `agent_id` is not merely a label. Real isolation includes prompt, routing, tools, MCP servers, guardrails, judges, memory, checkpoints, cache, telemetry, and identity, normally scoped as `tenant_id:agent_id:session_id`. The complete registry and runtime-bundle code are in the matching [Portuguese chapter](../pt/16_multiagente_composicao_e_ciclo_de_vida.md).
Every configured path must exist and be validated at startup. A system prefix guides the model but is not a security boundary; code must enforce tool authorization, persistence namespaces, and pipeline selection.
### Current template limitation
Although `agents.yaml` accepts per-agent paths, the template currently builds one router, one tool/RAG composition, and one global guardrail/judge pair. YAML alone does not provide per-request isolation. Use one global profile per deployment or implement an explicit cached runtime bundle per `agent_id`. Cache immutable/expensive objects rather than constructing LLM clients, routers, or pipelines for every message. Never silently fall back to another agent's bundle.
### Subagents and LLM composition
A subagent is a bounded capability with declared purpose, input/output, authorized tools, timeout/budget, and return conditions. A supervisor consolidates structured results and passes minimum relevant context with correlation and maximum delegation depth. Use routing for one-specialty turns; use supervision only for genuine decomposition. Handoff transfers conversation ownership; subagent delegation leaves final-response ownership with the supervisor.
Reuse framework LLM profiles and clients rather than creating provider SDKs inside domain components. Explicit, observable profile fallback preserves authentication, rate limits, retries, cache, and telemetry; configuration failure must not become an apparently valid answer.
### RAG, memory, and security
`RAG_PROVIDER=kbdb` works only when the execution's `RagService` uses the intended settings. A simple intent should still retrieve knowledge when agent policy requires it. Scope RAG collections, long-term memory, and checkpoints by tenant and agent. Long-term memory stores permitted summarized facts; checkpoints store execution state; neither may mix another agent's identity.
Authentication establishes a principal; authorization controls tenant, agent, route, and tool. Production secrets require hashing/rotation and TLS. Trusted-proxy headers are safe only behind an authenticated edge that removes client-supplied values.
### Startup and delivery lifecycle
At startup validate registry/paths, create providers, register actions/renderers, load workflows, construct bundles, and check mandatory dependencies. `/health` reports process liveness; `/ready` must reject traffic when a required dependency is unusable. Invalid configuration should fail before the first conversation.
Development order: copy the canonical template; create domain agent/configuration; register node and route; implement tools, mappings, policies, actions, and renderers; configure controls/RAG/memory/telemetry; run unit, loader, graph, conversational, and failure tests; run offline evaluation, load, and readiness checks; publish with version, compatibility, and rollback.
The definition of done includes isolation, confirmation, idempotency, recovery, grounding, controls, correlated telemetry, no data leakage, dependency-failure behavior, and PT/EN documentation parity. Run `pytest -q tests/test_advanced_developer_documentation.py`.

View File

@@ -125,11 +125,35 @@ If something is not working, use **Search by problem** below.
**Use when:** block messages are generic, `COER` should ask for clarification, or blocked-turn metadata contains stale routing/tool results.
### [13 — Advanced Transactional Workflows](./13_advanced_transactional_workflows.md)
**What it is:** pre-validation, versioned workflow actions, pause/resume, idempotency, replay, and recovery.
**Use when:** a sensitive tool requires a deterministic and recoverable process.
### [14 — Advanced Routing, Parameters, and State](./14_advanced_routing_parameters_and_state.md)
**What it is:** routing precedence, semantic confirmation, hybrid extraction, temporal reconciliation, dynamic states, and subagents.
**Use when:** routing or collection works on the happy path but fails in real conversations.
### [15 — Presentation, Recovery, and Observability](./15_presentation_recovery_and_observability.md)
**What it is:** renderers, Output Supervisor, recovery, voice replay, events, mappings, and ordered Pub/Sub.
**Use when:** output changes evidence, an effect may repeat, or telemetry cannot reconstruct execution.
### [16 — Multi-Agent Composition and Lifecycle](./16_multi_agent_composition_and_lifecycle.md)
**What it is:** actual isolation, per-agent bundles, supervisor/subagents, LLM/RAG/memory, and readiness.
**Use when:** multiple agents share one deployment or a new capability must reach production.
### Main tutorial
[`README_en.md`](README_en.md) remains the reference for the complete step-by-step flow:
`architecture → configuration → agent creation → registration → state → routing → tools → MCP → identity → execution → tests → gateways → memory → RAG`.
`architecture → configuration → agent creation → registration → state → routing → tools → MCP → identity → workflows → idempotency → execution → tests → gateways → memory → RAG → operations`.
### Maintenance
@@ -141,4 +165,3 @@ When evolving a feature:
- update the specialized manual with behavior, configuration, examples, and troubleshooting;
- update SPECs if the contract changed;
- keep release notes as history, not as the only current documentation.

View File

@@ -160,33 +160,23 @@ _, decisions = await pipeline.run_tool(
### SPI de guardrails e judges externos
> Conteúdo consolidado a partir de `docs/EXTERNAL_GUARDRAILS_JUDGES.md`.
Use extensões quando a política ou o critério de qualidade pertencer ao domínio do agente. Um guardrail implementa `evaluate(text, context) -> RailDecision` e pode atuar em `input`, `retrieval`, `tool` ou `output`. Um judge implementa `evaluate(question, answer, context) -> JudgeResult` e avalia a resposta sem reescrevê-la.
`agent_framework_oci` supports agent-owned guardrails and judges without importing domain code into the core.
O guia [Guardrails e judges externos](../../EXTERNAL_GUARDRAILS_JUDGES.md) contém a estrutura de diretórios, imports, classes completas para copiar, YAML, explicação de cada declaração, fail-open/fail-closed, observabilidade e teste executável.
```yaml
output:
- code: ACME_POLICY
type: external
class: app.extensions.guardrails:AcmePolicyRail
```
Pontos indispensáveis:
```yaml
judges:
- name: acme_quality
type: external
class: app.extensions.judges:AcmeQualityJudge
threshold: 0.7
```
- `type: external` e `class: pacote.modulo:Classe` ativam o import dinâmico;
- `kwargs` são argumentos do construtor; judges também podem receber `llm` e `settings` injetados;
- guardrails externos não recebem `llm` no construtor: o pipeline o disponibiliza no contexto somente quando criado com `llm=...`;
- métodos síncronos rodam em worker thread; métodos assíncronos rodam no event loop;
- judges são concorrentes e preservam a ordem declarada no YAML;
- exceções esperadas de judges externos devem ser tratadas pela implementação;
- códigos, regras e vocabulário de negócio ficam no pacote do agente, nunca importados pelo core.
Native entries remain unchanged. External synchronous `evaluate()` methods execute in worker threads via `asyncio.to_thread`; asynchronous methods execute concurrently on the framework event loop. Judges run concurrently with `asyncio.gather`, preserving YAML result order. Agent plugins should reuse the LLM supplied by the framework rather than instantiate a separate provider.
> **Limitação atual:** o `agent_template_backend` instancia um par global de pipelines no startup. Os campos `guardrails_config_path` e `judges_config_path` do registro não selecionam automaticamente configurações por requisição. Extensões dependentes de LLM também exigem que a composição passe `llm` e `settings` aos pipelines, conforme o guia completo.
The core must not reference a concrete agent package, company, product, telecom identifier or domain-specific policy. Domain-specific variants belong to the agent and should receive distinct public codes/names.
### Compatibility rule
Domain policies must not be replaced by cosmetically generic text inside the core while losing the original policy. The generic core implementation and the agent-specific implementation may coexist; the embedding agent explicitly selects its own code/name in YAML.
Legacy business validators should migrate to the agent domain. A temporary compatibility shim is acceptable for old imports, but new application code must import the agent-owned implementation.
Valide o exemplo publicado com `pytest -q tests/test_external_guardrails_judges_documentation.py`.
### Execução obrigatória de judges em transações

View File

@@ -0,0 +1,152 @@
### Workflows transacionais avançados
### Objetivo
Este capítulo ensina a transformar uma tool sensível em uma transação determinística, com coleta de parâmetros, pré-validação, confirmação, workflow versionado, pausa/retomada, idempotência e recuperação. A regra de negócio e as actions ficam no agente; o motor de execução fica no framework.
### Fluxo real
1. `routing.yaml` escolhe o agente e restringe as tools candidatas.
2. `tools.yaml` descreve argumentos, prompts e resposta.
3. `mcp_parameter_mapping.yaml` resolve identidade, defaults e extrações.
4. `tool_policies.yaml` classifica a operação e exige confirmação.
5. A pré-validação opcional verifica se a operação pode prosseguir sem causar efeito.
6. Após confirmação inequívoca, a execução é direta ou encaminhada ao `WorkflowToolExecutor`.
7. O `WorkflowRuntime` carrega a versão ativa, executa actions, persiste pausa e devolve `COMPLETED`, `PAUSED` ou `FAILED`.
8. A chave idempotente impede a repetição do efeito externo.
### Catálogo e política são contratos diferentes
```yaml
# config/tools.yaml
tools:
solicitar_devolucao:
description: Abre uma devolução de pedido.
mcp_server: retail
enabled: true
tool_type: action
confirmation_required: true
requires: [order_id, reason]
args_schema:
order_id:
type: string
label: o número do pedido
user_prompt: Informe o número do pedido.
reason:
type: string
label: o motivo da devolução
user_prompt: Qual é o motivo da devolução?
```
```yaml
# config/tool_policies.yaml
version: 1
defaults:
operation_type: read_only
require_confirmation: false
tool_policies:
solicitar_devolucao:
operation_type: transactional
require_confirmation: true
requires: [order_id, reason]
pre_validation:
enabled: true
tool: validar_devolucao
fail_open: false
execution:
mode: workflow
workflow: devolucao_pedido
version: active
```
`tools.yaml` é o catálogo público. `tool_policies.yaml` governa efeitos. Não confie somente em `confirmation_required` do catálogo: a política efetiva deve declarar `operation_type` e `require_confirmation`. `pre_validation.tool` deve ser read-only e nunca executar a transação antecipadamente. Para segurança, use `fail_open: false`.
### Definição versionada do workflow
```yaml workflow-definition-example
name: devolucao_pedido
version: 1
start: validar_pedido
nodes:
- id: validar_pedido
action: validar_pedido
input:
order_id: $.input.order_id
- id: registrar_devolucao
action: registrar_devolucao
retry: 1
input:
order_id: $.input.order_id
reason: $.input.reason
edges:
- from: validar_pedido
to: registrar_devolucao
when:
path: $.nodes.validar_pedido.valid
equals: true
- from: validar_pedido
to: END
when:
path: $.nodes.validar_pedido.valid
equals: false
- from: registrar_devolucao
to: END
```
Salve como `workflows/devolucao_pedido.v1.yaml`. O arquivo `devolucao_pedido.active.yaml` deve apontar para uma definição válida da versão ativa. IDs de nós não podem repetir; `start`, destinos e `resume_from` precisam existir. `retry` aceita de 0 a 10. Paths `$.input.*` leem a entrada e `$.nodes.<id>.*` leem resultados anteriores.
### Actions pertencentes ao agente
```python workflow-actions-example
from agent_framework.workflows import workflow_action
@workflow_action("validar_pedido")
async def validar_pedido(params: dict, state: dict) -> dict:
return {"valid": bool(params.get("order_id"))}
@workflow_action("registrar_devolucao")
async def registrar_devolucao(params: dict, state: dict) -> dict:
order_id = str(params["order_id"])
return {"protocol": f"DEV-{order_id}", "status": "REQUESTED"}
```
O nome do decorator deve ser igual a `node.action`. A assinatura obrigatória é `(params: dict, state: dict) -> dict`. O módulo precisa ser importado no startup para registrar decorators. Actions devem devolver dados serializáveis; não devolva cliente HTTP, conexão, exception ou coroutine.
### Idempotência do efeito externo
```python idempotency-example
async def execute_once(store, customer_key: str, order_id: str, invoke):
key = store.canonical_key(customer_key, order_id, "solicitar_devolucao", "v1")
previous = await store.get(key)
if previous is not None:
return previous
result = await invoke()
await store.set(key, result)
return result
```
Crie uma única instância no startup com `create_idempotency_store(settings, namespace="return-request", require_durable=True)` e injete-a nas actions. Use componentes de negócio estáveis na chave; nunca use apenas timestamp. `IDEMPOTENCY_PROVIDER` tem precedência sobre checkpoint, session e cache. Em produção transacional, configure `IDEMPOTENCY_REQUIRE_DURABLE=true` e um provider `oracle`, `redis` ou `sqlite` apropriado. `memory` não protege entre pods ou reinícios. Grave o resultado somente depois de o efeito ter sido confirmado pelo sistema externo.
### Pausa, entrada esperada e retomada
Um nó pode declarar `pause.expected_input` com `key`, `allowed_values`, normalização, `reprompt` e classificador semântico. A confirmação explícita continua determinística; o classificador só trata respostas inconclusivas e deve retornar uma das opções permitidas. `contextual_reentry` libera o workflow e devolve a fala ao roteamento normal, sem confirmar fatos automaticamente.
Ao retomar, use o mesmo `execution_id`. Uma nova execução cria outra transação. O checkpoint deve conter somente dados serializáveis e suficientes para reconstruir a pausa. Respostas duplicadas precisam consultar idempotência antes de repetir qualquer efeito.
### Intent shift e limpeza
Quando o usuário abandona a transação, limpe `pending_tool_call`, argumentos coletados, confirmação e estado transacional relacionado. Não reutilize parâmetros de uma transação encerrada. Uma pergunta contextual durante a pausa pode ser respondida e retornar ao workflow; uma mudança real de intenção encerra ou suspende explicitamente o fluxo conforme a política do agente.
### Recuperação e post-finalization replay
- `PAUSED`: persistir `execution_id`, prompt e contrato da entrada esperada.
- `FAILED`: manter detalhes técnicos na telemetria e uma mensagem segura ao usuário.
- timeout após envio: consultar idempotência ou status externo antes de reenviar.
- replay depois de `COMPLETED`: devolver o resultado persistido; nunca executar novamente.
- versão nova: execuções em andamento continuam com sua versão; `active` vale para novas execuções.
### Como testar
Teste grafo inválido, caminho válido/inválido, retry, pause/resume, resposta não reconhecida, intent shift, duplicidade, falha do provider de idempotência e replay após finalização. O contrato copiável deste capítulo é validado por `tests/test_advanced_developer_documentation.py`.

View File

@@ -0,0 +1,122 @@
### Routing, parâmetros e estado avançados
### Precedência de decisão
O desenvolvedor não deve tratar `routing.yaml` como uma lista de palavras. A decisão combina estado pendente, regras determinísticas e fallback semântico. A ordem segura é:
1. bloqueio ou finalização explícita;
2. transação/coleção pendente por `state_policies`;
3. confirmação determinística;
4. intenção determinística por keywords/examples/priority;
5. fallback LLM, quando habilitado;
6. `fallback_agent` ou handoff.
O estado pendente tem precedência para que “sim”, “não” ou um parâmetro isolado não sejam roteados para outro agente.
### Contrato comentado do `routing.yaml`
```yaml routing-advanced-example
router:
mode: router
fallback_agent: billing_agent
confidence_threshold: 0.65
allow_handoff: true
transaction_confirmation:
semantic_fallback:
enabled: true
allowed_values: [SIM, NAO, CONTINUAR]
confirm_values: [SIM]
reject_values: [NAO]
continue_values: [CONTINUAR]
include_relevant_context: true
profile_name: router
prompt: |
Classifique somente como {{ allowed_values }}.
Pergunta pendente: {{ pending_prompt }}
Histórico relevante: {{ relevant_conversation_context }}
Resposta atual: {{ user_input }}
state_policies:
- state: COLLECTING_FINANCIAL_PARAMETERS
agent: financeiro_agent
description: Mantém respostas curtas na coleta financeira.
- state: WAITING_FINANCIAL_CONFIRMATION
agent: financeiro_agent
description: Mantém a confirmação no fluxo financeiro.
intents:
- name: financial_analysis
domain: financial
agent: financeiro_agent
description: Consulta saldo, posição e movimentações.
priority: 10
mcp_tools: [consultar_saldo, consultar_movimentacoes]
keywords: [saldo, extrato, movimentação]
examples:
- Qual é meu saldo?
- Mostre minhas movimentações.
```
`priority` desempata intenções; menor valor tem precedência no template atual. `mcp_tools` restringe capacidades candidatas, mas não autoriza efeito sensível. `confidence_threshold` define quando aceitar o resultado semântico. `allow_handoff` permite troca explícita de agente. `domain` é metadado de escopo e não substitui `agent`.
O prompt semântico deve conter `allowed_values` e instruir o modelo a não executar ações nem inventar fatos. `include_relevant_context` inclui somente contexto limitado relacionado à pausa. Se a saída não corresponder a uma opção permitida, mantenha a transação pendente.
### Identidade antes da extração
`identity.yaml` resolve chaves canônicas (`customer_key`, `contract_key`, `interaction_key`, `account_key`, `resource_key`, `session_key`) a partir do payload, do `business_context` ou do contexto anterior. A validação de `required` deve ocorrer antes de chamar MCP. Nunca use `session_id` como identidade de cliente.
### Mapeamento e extração
```yaml parameter-mapping-example
mcp_parameter_mapping:
defaults:
use_mock: false
tools:
consultar_movimentacoes:
map:
customer_key: customer_id
account_key: account_id
session_key: session_id
defaults:
limit: 20
extract:
month:
from: message
type: int
strategy: month_name_pt
description: Converta o mês mencionado em número de 1 a 12.
transaction_id:
from: message
type: string
strategy: hybrid
pattern: '(?i)\\b(?:transação|transaction)\\s*[:#-]?\\s*([A-Z0-9-]+)\\b'
group: 1
description: Extraia somente um identificador explicitamente informado.
```
Precedência recomendada para argumentos: valor já confirmado na transação, argumento explícito atual, identidade canônica mapeada, extração determinística, extração LLM/híbrida e default. Um valor novo explícito pode corrigir o anterior; um valor inferido nunca deve sobrescrever um valor confirmado.
`strategy: hybrid` tenta a parte determinística e usa LLM quando necessário. `pattern` e `group` devem ser testados com casos positivos e negativos. `description` é instrução operacional do extrator, não documentação decorativa. `type` deve falhar de forma controlada se a conversão não for segura.
### Reconciliação temporal
A reconciliação temporal é fallback da coleta tradicional. Quando ainda faltarem campos, percorra mensagens relevantes da mais recente para a mais antiga e associe valores somente aos campos descritos no `args_schema`/mapeamento. Ela não deve:
- reabrir transação encerrada;
- misturar agentes, tenants ou sessões;
- recuperar valor invalidado pelo usuário;
- trocar correspondência exata por aproximação perigosa;
- substituir parâmetro já confirmado.
Registre a origem (`current_message`, `business_context`, `history`, `default`), a mensagem correlacionada e a confiança, sem persistir conteúdo sensível desnecessário.
### Estados dinâmicos
Para um agente novo, declare os estados de coleta e confirmação em `AgentState` somente quando eles carregarem campos adicionais; caso contrário, use as chaves transacionais genéricas. Registre ambos em `state_policies`, implemente a limpeza em sucesso/cancelamento/intent shift e inclua os estados nos testes de roteamento. Estado novo sem política correspondente costuma causar perda de stickiness.
### Router versus supervisor
No modo `router`, uma decisão escolhe um agente. No modo `supervisor`, o supervisor pode coordenar vários agentes e consolidar resultados. Não habilite supervisor apenas para melhorar classificação: ele muda custo, latência, estado e observabilidade. Um subagente deve receber contexto mínimo, ferramentas autorizadas e namespace `tenant_id:agent_id:session_id`; nunca compartilhe memória bruta entre agentes.
### Testes obrigatórios
Teste sobreposição de keywords, empate de prioridade, abaixo do threshold, agente fallback, estado pendente, confirmação curta, resposta ambígua, correção de parâmetro, extração regex/LLM, histórico temporal e isolamento entre agentes. Os YAMLs deste capítulo são analisados por `tests/test_advanced_developer_documentation.py`.

View File

@@ -0,0 +1,87 @@
### Apresentação, recuperação e observabilidade
### Renderers de resposta
Quando uma tool retorna dados estruturados confiáveis, `response.mode: renderer` produz uma resposta determinística e evita que o LLM altere valores, protocolos ou status.
```yaml
tools:
consultar_saldo:
description: Consulta saldo da conta.
mcp_server: financial
enabled: true
response:
mode: renderer
renderer: financial.balance
```
```python renderer-example
from typing import Any
from agent_framework.presentation import register_tool_response_renderer
def render_balance(*, tool_name: str, result: dict[str, Any],
state: dict[str, Any], agent_label: str) -> str | None:
account = result.get("account_masked")
balance = result.get("balance")
currency = result.get("currency", "BRL")
if account is None or balance is None:
return None
return f"[{agent_label}] Conta {account}: saldo {currency} {float(balance):.2f}."
def register_financial_renderers() -> None:
register_tool_response_renderer("financial.balance", render_balance)
```
Importe e execute `register_financial_renderers()` uma vez no startup. A assinatura é keyword-only e deve aceitar `tool_name`, `result`, `state` e `agent_label`. Retorne `None` quando faltarem campos obrigatórios para permitir o fallback previsto pelo runtime. Nunca interpolar o payload inteiro: selecione campos permitidos, mascare identidade e formate valores explicitamente.
### Output Supervisor
O Output Supervisor valida a resposta candidata antes da saída final. Ele pode permitir, sanitizar, solicitar retry, bloquear, entregar a humano ou observar. `OUTPUT_SUPERVISOR_MAX_RETRIES` deve ter limite pequeno; cada retry precisa de orientação objetiva e a resposta reescrita deve passar novamente pelos controles. Não use retry para erro permanente de autorização ou indisponibilidade.
### Recuperação de workflow
Classifique falhas em: validação, dependência temporária, dependência permanente, persistência e erro de programação. O usuário recebe mensagem segura; a telemetria recebe classe, fase, tentativa, workflow/version/execution ID e correlação. Para efeitos externos:
- antes do envio, um retry controlado é aceitável;
- depois de envio com resultado incerto, consulte status/idempotência;
- após confirmação externa, persista o resultado antes de responder;
- uma nova mensagem do usuário não deve apagar evidência de uma execução incerta.
Checkpoints resilientes podem repetir operações de armazenamento, validar integridade, compactar histórico e recuperar o último checkpoint válido. Isso não torna automaticamente uma action externa idempotente.
### Interrupção de voz e replay
No barge-in, preserve o texto confirmado, marque a resposta interrompida e não reapresente áudio obsoleto. O replay deve usar identificadores de interação/mensagem e a mesma sessão escopada. Se uma transação estava pendente, a fala interrompida não conta como confirmação. Ao retomar, revalide estado, confirmação e idempotência.
### Eventos IC, NOC e GRL
- IC: comportamento funcional, decisão, tool, cache e workflow;
- NOC: disponibilidade, timeout, dependência e latência operacional;
- GRL: decisão e ação de guardrail/supervisor.
Use o `AgentObserver`/adapter do template em vez de chamar diretamente um backend de telemetria. Inclua `tenant_id`, `agent_id`, `session_id`, `transaction_id`/`execution_id`, componente e duração quando disponíveis. Nunca inclua credenciais, prompt integral, PII ou payload financeiro bruto.
### Mapeamento e compatibilidade
Quando consumidores históricos exigirem códigos diferentes, use um registry/overlay como `observability_mapping.yaml`: evento semântico interno → label externo. O default é compartilhado e o overlay pertence ao agente. Não hardcode labels históricas no executor nem renomeie o evento interno de forma que perca semântica.
### Pub/Sub e sequência
Publicação deve ocorrer após a decisão funcional e não pode alterar seu resultado. Configure provider, tópicos/streams, filtros e política de falha. Quando o consumidor exigir ordem, publique `sequence`, chave de partição estável e correlação; múltiplos pods não garantem ordem global. Defina TTL/retenção e comportamento para duplicatas. Eventos filtrados no Pub/Sub continuam disponíveis nos outros destinos de observabilidade.
### Checklist operacional
- renderer não expõe payload bruto;
- resposta sanitizada é revalidada;
- retries têm limite e distinguem erro transitório;
- efeitos incertos consultam idempotência/status;
- evento contém correlação e não contém segredo;
- labels externas são mapeadas por configuração;
- sequência e chave de partição são testadas com múltiplos consumidores;
- interrupção de voz não confirma nem repete transação.
O exemplo de renderer é compilado e executado por `tests/test_advanced_developer_documentation.py`.

View File

@@ -0,0 +1,93 @@
### Multiagente, composição e ciclo de vida
### O que constitui um agente isolado
Um `agent_id` não é apenas um label. O isolamento real precisa abranger prompt, routing, tools, MCP servers, guardrails, judges, memória, checkpoints, cache, telemetria e identidade. A chave operacional recomendada é `tenant_id:agent_id:session_id`.
```yaml agents-registry-example
default_agent_id: financial
agents:
- agent_id: financial
name: Agente Financeiro
description: Consultas e operações financeiras.
prompt_policy_path: ./config/agents/financial/prompt_policy.yaml
routing_config_path: ./config/agents/financial/routing.yaml
guardrails_config_path: ./config/agents/financial/guardrails.yaml
judges_config_path: ./config/agents/financial/judges.yaml
mcp_servers_config_path: ./config/agents/financial/mcp_servers.yaml
tools_config_path: ./config/agents/financial/tools.yaml
metadata:
domain: financial
system_prefix: |
Execute somente políticas e recursos do agent_id financial.
```
Todos os caminhos devem existir e ser validados no startup. O prefixo ajuda o LLM, mas não é barreira de segurança. Autorização de tools, namespaces de persistência e seleção de pipelines devem ser impostas pelo código.
### Limitação real do template atual
O registry aceita esses caminhos, mas o `AgentWorkflow` corrente ainda constrói um único router, um único conjunto de tools/RAG e um par global de guardrails/judges. Portanto, copiar o YAML acima não cria isolamento completo por requisição. Até existir uma factory/cache por perfil, use uma configuração global por deployment ou implemente a seleção explícita antes de invocar o grafo.
Uma composição correta mantém, por `agent_id`, os objetos imutáveis/caros em cache e injeta dependências na execução:
```python agent-runtime-bundle-example
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class AgentRuntimeBundle:
router: Any
tool_router: Any
rag_service: Any
guardrails: Any
judges: Any
def select_bundle(registry: dict[str, AgentRuntimeBundle], agent_id: str) -> AgentRuntimeBundle:
if agent_id not in registry:
raise KeyError(f"agent_id não registrado: {agent_id}")
return registry[agent_id]
```
Não construa LLM, conexão, router ou pipeline a cada mensagem. Não use fallback silencioso para o bundle de outro agente; falhe de forma explícita ou use somente o `default_agent_id` autorizado na borda.
### Subagentes e supervisor
Subagente é uma capacidade delimitada, não apenas uma função Python. Declare objetivo, entradas, saídas, tools autorizadas, orçamento/timeout e condições de retorno. O supervisor recebe resultados estruturados e consolida; ele não deve compartilhar todo o histórico por padrão. Uma delegação deve carregar correlação e profundidade máxima para evitar ciclos.
Use router quando uma única especialidade resolve o turno. Use supervisor quando a tarefa realmente exigir decomposição ou combinação de duas ou mais capacidades. Para handoff, transfira propriedade da conversa; para subagente, mantenha o supervisor como proprietário da resposta final.
### Composição de LLM por domínio
Use `llm_profiles.yaml` e o cliente criado pelo framework. Componentes recebem `profile_name` ou o LLM compartilhado; não criam SDK/provedor com credenciais próprias. Isso preserva autenticação, rate limits, retries, cache e telemetria. Fallback entre profiles precisa ser explícito e observável; nunca converta falha de configuração em resposta aparentemente válida.
### RAG e memória por agente
`RAG_PROVIDER=kbdb` seleciona KBDB apenas quando o `RagService` daquela execução usa as settings corretas. A intenção simples também deve acionar RAG quando a política do agente exigir conhecimento. Separe coleção/namespace por tenant e agente. Memória de longo prazo guarda fatos permitidos e resumidos; checkpoint guarda execução. Nenhum dos dois deve misturar identidade de outro agente.
### Autenticação e autorização
Autenticação prova o principal; autorização decide agente, tenant, rota e tool. Basic, API key, bearer, JWT, introspection e trusted proxy são providers possíveis, mas produção deve usar segredo com hash/rotação e TLS. Headers de trusted proxy só são confiáveis quando a borda autenticada remove valores enviados pelo cliente.
### Inicialização e readiness
No startup: validar registry e caminhos; criar providers; registrar actions/renderers; carregar workflows; construir bundles; verificar conexões essenciais. `/ready` deve falhar quando uma dependência obrigatória não estiver utilizável; `/health` indica processo vivo. Configuração inválida deve falhar cedo, antes da primeira conversa.
### Ciclo de desenvolvimento e certificação
1. Copiar o template canônico sem copiar `.venv` ou caches.
2. Criar agente, estado somente se necessário, configurações e recursos de domínio.
3. Registrar nó/rota e decidir router ou supervisor.
4. Implementar tools, mappings, políticas, actions e renderers.
5. Configurar guardrails, judges, RAG, memória e observabilidade.
6. Testar unidade, loader/config, grafo, regressão conversacional e falhas.
7. Executar avaliação offline, carga e readiness.
8. Publicar com versão, compatibilidade e rollback documentados.
### Definition of done
Um agente não está pronto apenas porque responde ao happy path. Ele precisa provar isolamento, confirmação antes de efeito, idempotência, recuperação, grounding, bloqueio/sanitização, telemetria correlacionada, ausência de vazamento, comportamento sob dependência indisponível e compatibilidade PT/EN dos manuais.
Os contratos deste capítulo são validados por `tests/test_advanced_developer_documentation.py`.

View File

@@ -126,11 +126,35 @@ Se algo não está funcionando, use **Buscar pelo problema** abaixo.
**Use quando:** mensagens de bloqueio são genéricas, `COER` deveria pedir esclarecimento ou o metadata de um turno bloqueado contém routing/tools antigos.
### [13 — Workflows Transacionais Avançados](./13_workflows_transacionais_avancados.md)
**O que é:** implementação de pré-validação, workflow versionado, actions, pausa/retomada, idempotência, replay e recuperação.
**Use quando:** uma tool sensível precisa executar um processo determinístico e recuperável.
### [14 — Routing, Parâmetros e Estado Avançados](./14_routing_parametros_e_estado_avancados.md)
**O que é:** precedência do router, confirmação semântica, extração híbrida, reconciliação temporal, estados dinâmicos e subagentes.
**Use quando:** routing, coleta ou retomada funcionam no happy path, mas falham em conversas reais.
### [15 — Apresentação, Recuperação e Observabilidade](./15_apresentacao_recuperacao_e_observabilidade.md)
**O que é:** renderers, Output Supervisor, recuperação, voice replay, eventos, mappings e Pub/Sub ordenado.
**Use quando:** a resposta altera evidências, um efeito pode repetir ou a telemetria não permite reconstruir o fluxo.
### [16 — Multiagente, Composição e Ciclo de Vida](./16_multiagente_composicao_e_ciclo_de_vida.md)
**O que é:** isolamento efetivo, bundles por agente, supervisor/subagentes, LLM/RAG/memória e readiness.
**Use quando:** vários agentes compartilham o deployment ou uma nova capacidade precisa chegar à produção.
### Tutorial principal
[`README.md`](../../../README.md) continua sendo a referência para o passo a passo completo:
`arquitetura → configuração → criação do agente → registro → estado → routing → tools → MCP → identidade → execução → testes → gateways → memória → RAG`.
`arquitetura → configuração → criação do agente → registro → estado → routing → tools → MCP → identidade → workflows → idempotência → execução → testes → gateways → memória → RAG → operação`.
### Manutenção