new feature: Multi-Intent
This commit is contained in:
@@ -185,6 +185,7 @@ O framework deve concentrar os motores reutilizáveis:
|
||||
- Telemetria Langfuse/OpenTelemetry.
|
||||
- Analytics IC/NOC/GRL.
|
||||
- MCP Tool Router.
|
||||
- Planejamento multi-intent e fila persistente de `pending_topics`.
|
||||
- Cache.
|
||||
- RAG genérico.
|
||||
|
||||
@@ -230,6 +231,8 @@ Input Guardrails
|
||||
↓
|
||||
Enterprise Router ou Supervisor
|
||||
↓
|
||||
Planejamento multi-intent / pending_topics
|
||||
↓
|
||||
Agente especializado
|
||||
↓
|
||||
MCP Tool Router / RAG / Cache / LLM
|
||||
@@ -11486,6 +11489,8 @@ O conteúdo desta pasta deve ser tratado como uma extensão adicional do framewo
|
||||
| Um exemplo antigo não compila | documentação histórica versus API atual | [Validação README x Código](docs/developer/pt/VALIDATION_README_ALIGNMENT.md) |
|
||||
| Preciso criar um agente novo do zero | fluxo completo | [`README.md`](README.md) |
|
||||
| Preciso saber onde colocar uma nova feature | arquitetura e boundaries | [Arquitetura e Conceitos](docs/developer/pt/01_architecture_and_concepts.md) |
|
||||
| Duas solicitações na mesma mensagem acionam apenas uma intent | decomposição multi-intent, `pending_topics`, allowlist de tools | [Planejamento Multi-Intent](docs/features/pt-BR/16_multi_intent_planning.md) |
|
||||
| O agent secundário repete a transação ou confirmação primária | isolamento de `active_transaction`, `mcp_tools` e estado operacional | [Planejamento Multi-Intent](docs/features/pt-BR/16_multi_intent_planning.md) |
|
||||
|
||||
### 34. Funcionalidades Avançadas
|
||||
|
||||
@@ -11561,9 +11566,31 @@ O conteúdo desta pasta deve ser tratado como uma extensão adicional do framewo
|
||||
|
||||
**Use quando:** um `COER`/guardrail de entrada gera mensagem genérica, `route=blocked` carrega resultados antigos ou há dúvida sobre a precedência entre input guardrails, routing e tools.
|
||||
|
||||
### Guias de features implementadas
|
||||
|
||||
Os manuais `01` a `12` acima organizam os assuntos por área de desenvolvimento. Os guias abaixo documentam cada feature executável individualmente:
|
||||
|
||||
1. [Autenticação](docs/features/pt-BR/01_authentication.md)
|
||||
2. [Workflow Transacional Determinístico](docs/features/pt-BR/02_deterministic_transactional_workflow.md)
|
||||
3. [Composição por LLM Solicitada pelo Domínio](docs/features/pt-BR/03_domain_requested_llm_composition.md)
|
||||
4. [RAG Solicitado pelo Domínio](docs/features/pt-BR/04_domain_requested_rag.md)
|
||||
5. [Memória de Longo Prazo](docs/features/pt-BR/05_long_term_memory.md)
|
||||
6. [Regressão Offline de Workflow](docs/features/pt-BR/06_offline_workflow_regression.md)
|
||||
7. [Pause e Resume de Workflow](docs/features/pt-BR/07_pause_resume_workflow.md)
|
||||
8. [Route Stickiness](docs/features/pt-BR/08_route_stickiness.md)
|
||||
9. [Replay em Interrupções de Voz](docs/features/pt-BR/09_voice_interruption_replay.md)
|
||||
10. [Recuperação de Erro em Workflow](docs/features/pt-BR/10_workflow_error_recovery.md)
|
||||
11. [Clarificação](docs/features/pt-BR/11_clarification.md)
|
||||
12. [Idempotência Durável](docs/features/pt-BR/12_durable_idempotency.md)
|
||||
13. [Estados Transacionais Dinâmicos](docs/features/pt-BR/13_dynamic_transaction_states.md)
|
||||
14. [Replay Após Finalização](docs/features/pt-BR/14_post_finalization_replay.md)
|
||||
15. [Guardrails de Retrieval e Tools](docs/features/pt-BR/15_retrieval_tool_guardrails.md)
|
||||
16. [Planejamento Multi-Intent e Pending Topics](docs/features/pt-BR/16_multi_intent_planning.md)
|
||||
|
||||
O [índice de features em português](docs/features/pt-BR/README.md) deve ser atualizado sempre que um novo guia for adicionado.
|
||||
|
||||
### 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`.
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ Details the evaluation and certification framework, including evaluation archite
|
||||
|
||||
Defines the platform operational readiness and SRE model, including managed components, health checks, readiness, SLOs, metrics, dashboards, alerts, runbooks, incident management, capacity planning, and production checklists.
|
||||
|
||||
### [IMPORTANT: Disclaimer Auth and Security](specs/Disclaimer%20Auth%20and%20Security_EN.md)
|
||||
### [IMPORTANT: Disclaimer Auth and Security](specs/Disclaimer_Auth_and_Security_EN.md)
|
||||
|
||||
Oracle Cloud Infrastructure Security Best Practice Recommendations.
|
||||
|
||||
@@ -186,6 +186,7 @@ The framework should concentrate the reusable engines:
|
||||
- Langfuse/OpenTelemetry Telemetry.
|
||||
- Analytics IC/NOC/GRL.
|
||||
- MCP Tool Router.
|
||||
- Multi-intent planning and the persistent `pending_topics` queue.
|
||||
- Cache.
|
||||
- Generic RAG.
|
||||
|
||||
@@ -231,6 +232,8 @@ Input Guardrails
|
||||
↓
|
||||
Enterprise Router or Supervisor
|
||||
↓
|
||||
Multi-intent planning / pending_topics
|
||||
↓
|
||||
Specialized agent
|
||||
↓
|
||||
MCP Tool Router / RAG / Cache / LLM
|
||||
@@ -11388,6 +11391,8 @@ The content of this folder should be treated as an additional framework extensio
|
||||
| Logs/traces do not correlate the same agent | labels, IDs, observability mapping | [Observability](docs/developer/en/11_observability_persistence_and_operational_readiness.md) |
|
||||
| Historical example no longer compiles | stale docs vs current API | [README Alignment Validation](docs/developer/en/VALIDATION_README_ALIGNMENT.md) |
|
||||
| Need to create a new agent from scratch | complete flow | [`README_en.md`](README_en.md) |
|
||||
| Two requests in one message trigger only one intent | multi-intent decomposition, `pending_topics`, tool allowlist | [Multi-Intent Planning](docs/features/en/16_multi_intent_planning.md) |
|
||||
| A secondary agent repeats the primary transaction or confirmation | isolation of `active_transaction`, `mcp_tools`, and operational state | [Multi-Intent Planning](docs/features/en/16_multi_intent_planning.md) |
|
||||
|
||||
### 34. Advanced Features
|
||||
|
||||
@@ -11463,6 +11468,29 @@ The content of this folder should be treated as an additional framework extensio
|
||||
|
||||
**Use it when:** `COER`/input guardrails generate generic messages, `route=blocked` carries stale results, or you need to reason about precedence between input guardrails, routing, and tools.
|
||||
|
||||
### Implemented feature guides
|
||||
|
||||
The `01` through `12` manuals above organize documentation by development area. The guides below document each executable feature individually:
|
||||
|
||||
1. [Authentication](docs/features/en/01_authentication.md)
|
||||
2. [Deterministic Transactional Workflow](docs/features/en/02_deterministic_transactional_workflow.md)
|
||||
3. [Domain-Requested LLM Composition](docs/features/en/03_domain_requested_llm_composition.md)
|
||||
4. [Domain-Requested RAG](docs/features/en/04_domain_requested_rag.md)
|
||||
5. [Long-Term Memory](docs/features/en/05_long_term_memory.md)
|
||||
6. [Offline Workflow Regression](docs/features/en/06_offline_workflow_regression.md)
|
||||
7. [Pause and Resume Workflow](docs/features/en/07_pause_resume_workflow.md)
|
||||
8. [Route Stickiness](docs/features/en/08_route_stickiness.md)
|
||||
9. [Voice Interruption Replay](docs/features/en/09_voice_interruption_replay.md)
|
||||
10. [Workflow Error Recovery](docs/features/en/10_workflow_error_recovery.md)
|
||||
11. [Clarification](docs/features/en/11_clarification.md)
|
||||
12. [Durable Idempotency](docs/features/en/12_durable_idempotency.md)
|
||||
13. [Dynamic Transaction States](docs/features/en/13_dynamic_transaction_states.md)
|
||||
14. [Post-Finalization Replay](docs/features/en/14_post_finalization_replay.md)
|
||||
15. [Retrieval and Tool Guardrails](docs/features/en/15_retrieval_tool_guardrails.md)
|
||||
16. [Multi-Intent Planning and Pending Topics](docs/features/en/16_multi_intent_planning.md)
|
||||
|
||||
The [English feature index](docs/features/en/README.md) must be updated whenever a new feature guide is added.
|
||||
|
||||
### Main tutorial
|
||||
|
||||
[`README_en.md`](README_en.md) remains the complete step-by-step guide.
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -409,6 +410,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -547,14 +552,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -623,6 +642,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -409,6 +410,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -547,14 +552,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -623,6 +642,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -407,6 +408,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -545,14 +550,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -621,6 +640,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -409,6 +410,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -547,14 +552,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -623,6 +642,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -407,6 +408,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -545,14 +550,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -621,6 +640,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Este template suporta confirmação transacional em duas camadas: primeiro um pa
|
||||
|
||||
A configuração `router.transaction_confirmation.semantic_fallback` usa três classes: `SIM`, `NAO` e `CONTINUAR`. O prompt pode usar `{{ pending_prompt }}`, `{{ relevant_conversation_context }}`, `{{ user_input }}` e `{{ allowed_values }}`. O histórico injetado é apenas contexto de interpretação; não substitui validação de negócio ou evidência MCP.
|
||||
|
||||
Exemplo: após `Você confirma o cancelamento do serviço Tamboro Mensal?`, a frase `isso mesmo, pode confirmar` pode ser classificada como `SIM`. Já `mas qual é o valor?` deve ser `CONTINUAR`, portanto não executa a ação por confirmação.
|
||||
Exemplo: após `Você confirma o cancelamento do serviço adicional selecionado?`, a frase `isso mesmo, pode confirmar` pode ser classificada como `SIM`. Já `mas qual é o valor?` deve ser `CONTINUAR`, portanto não executa a ação por confirmação.
|
||||
|
||||
Entradas explícitas já suportadas continuam no caminho determinístico e não geram custo adicional de LLM. Em observabilidade, o fallback usa `transaction.confirmation.semantic_classifier` e o `route_decision.metadata` informa `transaction_confirmation_source: semantic`.
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -407,6 +408,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -545,14 +550,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -621,6 +640,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Este template suporta confirmação transacional em duas camadas: primeiro um pa
|
||||
|
||||
A configuração `router.transaction_confirmation.semantic_fallback` usa três classes: `SIM`, `NAO` e `CONTINUAR`. O prompt pode usar `{{ pending_prompt }}`, `{{ relevant_conversation_context }}`, `{{ user_input }}` e `{{ allowed_values }}`. O histórico injetado é apenas contexto de interpretação; não substitui validação de negócio ou evidência MCP.
|
||||
|
||||
Exemplo: após `Você confirma o cancelamento do serviço Tamboro Mensal?`, a frase `isso mesmo, pode confirmar` pode ser classificada como `SIM`. Já `mas qual é o valor?` deve ser `CONTINUAR`, portanto não executa a ação por confirmação.
|
||||
Exemplo: após `Você confirma o cancelamento do serviço adicional selecionado?`, a frase `isso mesmo, pode confirmar` pode ser classificada como `SIM`. Já `mas qual é o valor?` deve ser `CONTINUAR`, portanto não executa a ação por confirmação.
|
||||
|
||||
Entradas explícitas já suportadas continuam no caminho determinístico e não geram custo adicional de LLM. Em observabilidade, o fallback usa `transaction.confirmation.semantic_classifier` e o `route_decision.metadata` informa `transaction_confirmation_source: semantic`.
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -407,6 +408,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -545,14 +550,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -621,6 +640,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -407,6 +408,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -545,14 +550,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -621,6 +640,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -409,6 +410,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -547,14 +552,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -623,6 +642,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ class AgentState(TypedDict, total=False):
|
||||
missing_parameters: list[str]
|
||||
supervisor_plan: dict[str, Any]
|
||||
supervisor_results: list[dict[str, Any]]
|
||||
pending_topics: list[dict[str, Any]]
|
||||
handled_topics: list[dict[str, Any]]
|
||||
active_agent: str
|
||||
route_bypassed: bool
|
||||
continuity_signal: dict[str, Any]
|
||||
|
||||
@@ -7,6 +7,7 @@ from agent_framework.guardrails.rail_action import RailAction
|
||||
from agent_framework.guardrails.rail_result import RailResult
|
||||
from agent_framework.judges.judge import JudgePipeline
|
||||
from agent_framework.routing.enterprise_router import EnterpriseRouter
|
||||
from agent_framework.routing.pending_topics import drain_pending_topics
|
||||
from agent_framework.supervisor.supervisor import Supervisor
|
||||
from agent_framework.observability.workflow_events import WorkflowTelemetry
|
||||
from agent_framework.observability.guardrail_events import GuardrailTelemetry
|
||||
@@ -409,6 +410,10 @@ class AgentWorkflow:
|
||||
"reason": decision.reason if decision.method == "continuity" else None,
|
||||
"profile": (decision.metadata or {}).get("continuity_profile"),
|
||||
} if decision.method == "continuity" else {},
|
||||
"pending_topics": (
|
||||
(decision.metadata or {}).get("multi_intent_plan", {}).get("operations", [])[1:]
|
||||
if (decision.metadata or {}).get("multi_intent_plan") else []
|
||||
),
|
||||
}
|
||||
|
||||
async def billing_agent(self, state):
|
||||
@@ -547,14 +552,28 @@ class AgentWorkflow:
|
||||
agente gerar `answer` e antes dos judges/persistência, produzindo campos
|
||||
supervisor_* no state e eventos GRL.001..GRL.009 via AgentObserver.
|
||||
"""
|
||||
drained = await drain_pending_topics(
|
||||
state,
|
||||
str(state.get("answer") or ""),
|
||||
{
|
||||
"billing_agent": self.billing.run,
|
||||
"product_agent": self.product.run,
|
||||
"orders_agent": self.orders.run,
|
||||
"support_agent": self.support.run,
|
||||
},
|
||||
)
|
||||
candidate = drained.answer
|
||||
if not bool(getattr(self.settings, "ENABLE_OUTPUT_SUPERVISOR", True)):
|
||||
return {
|
||||
"answer": candidate,
|
||||
"final_answer": candidate,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"output_guardrails_already_applied": False,
|
||||
"supervisor_action": "disabled",
|
||||
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
|
||||
}
|
||||
|
||||
candidate = state.get("answer") or ""
|
||||
context = {
|
||||
**(state.get("context") or {}),
|
||||
"tenant_id": state.get("tenant_id"),
|
||||
@@ -623,6 +642,8 @@ class AgentWorkflow:
|
||||
for r in decision.results
|
||||
],
|
||||
"output_guardrails_already_applied": True,
|
||||
"pending_topics": drained.pending_topics,
|
||||
"handled_topics": drained.handled_topics,
|
||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||
+ [item for r in decision.results for item in (r.metadata or {}).get("legacy_decisions", [])],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Multi-Intent Planning
|
||||
|
||||
`MultiIntentPlanner` recognizes independent requests in one utterance and
|
||||
builds a plan constrained to the intents, agents, and tools declared in
|
||||
`config/routing.yaml`. It does not execute operations or let the LLM invent a
|
||||
sequence: the router selects the primary operation and the domain workflow
|
||||
continues to own the transaction.
|
||||
|
||||
## Configuration and execution
|
||||
|
||||
No additional configuration is required. The planner uses the intents already
|
||||
declared in `routing.yaml`, selects the single transactional operation from
|
||||
`tool_policies.yaml`, and persists the remaining requests as `pending_topics`.
|
||||
|
||||
Known read-only topics execute through their own agent. A second mutation stays
|
||||
pending for its own confirmation, while an unknown clause becomes off-context.
|
||||
|
||||
The router resolves clauses from registered intent keywords and routes the
|
||||
transactional operation first. The graph drains read-only pending topics before
|
||||
output supervision. During an open transaction,
|
||||
`yes, and send me the invoice` confirms the transaction and records the
|
||||
secondary request instead of causing an intent shift.
|
||||
|
||||
For multiple side-effecting actions, implement a transactional coordinator
|
||||
that persists the plan, confirms it, executes idempotently, and records partial
|
||||
failure or compensation. See `tests/unit/test_multi_intent_planner.py`. No
|
||||
special Tuning-Performance template is needed because the behavior is native.
|
||||
@@ -17,3 +17,4 @@ Documentation for the main `agent_framework_oci` features.
|
||||
- [Dynamic Transaction States](13_dynamic_transaction_states.md)
|
||||
- [Post Finalization Replay](14_post_finalization_replay.md)
|
||||
- [Retrieval / Tool Guardrails](15_retrieval_tool_guardrails.md)
|
||||
- [Multi-Intent Planning](16_multi_intent_planning.md)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Planejamento Multi-Intent
|
||||
|
||||
O `MultiIntentPlanner` reconhece solicitações independentes na mesma mensagem e
|
||||
cria um plano limitado às intents, agents e tools declarados em
|
||||
`config/routing.yaml`. O planejador não executa operações nem permite que o LLM
|
||||
invente uma sequência: o roteador escolhe a operação primária e o workflow do
|
||||
domínio continua responsável pela transação.
|
||||
|
||||
## Configuração
|
||||
|
||||
Não existe configuração adicional. O planejador usa as intents do `routing.yaml`
|
||||
e lê `tool_policies.yaml` para priorizar automaticamente a única operação
|
||||
transacional. Pedidos secundários são persistidos em `pending_topics`.
|
||||
|
||||
- intent conhecida e read-only: executada pelo agent correspondente;
|
||||
- intent conhecida e transacional: mantida pendente para confirmação própria;
|
||||
- trecho sem capability correspondente: respondido como `off_context`.
|
||||
|
||||
Consultas secundárias com `execute` podem ser executadas pelo agent correspondente
|
||||
e consolidadas. Uma segunda mutação é marcada como `defer`, pois exige um
|
||||
workflow transacional coordenador.
|
||||
|
||||
## Fluxo de execução
|
||||
|
||||
1. O `EnterpriseRouter` separa a entrada em cláusulas e resolve cada uma pelas
|
||||
keywords das intents cadastradas.
|
||||
2. `tool_policies.yaml` identifica a operação transacional e a torna primária.
|
||||
3. A primeira operação é roteada normalmente para seu agent/workflow.
|
||||
4. O `agent_graph` compõe as mensagens públicas antes do supervisor de saída.
|
||||
5. Durante uma confirmação, uma frase como `sim e me manda a segunda via`
|
||||
confirma a transação aberta e registra a solicitação secundária, sem causar
|
||||
troca indevida de intent.
|
||||
|
||||
## Operações mutáveis
|
||||
|
||||
Para executar mais de uma ação com efeito colateral, implemente um workflow
|
||||
transacional coordenador. Ele deve persistir o plano, pedir confirmação quando
|
||||
necessário, executar cada passo com idempotência e registrar sucesso parcial,
|
||||
falha e compensação. O planejador fornece o contrato; a política de negócio e a
|
||||
orquestração permanecem no domínio.
|
||||
|
||||
## Referência executável
|
||||
|
||||
Veja os testes genéricos em `tests/unit/test_multi_intent_planner.py`. Como a
|
||||
feature é padrão do runtime, não existe uma cópia especial do
|
||||
`agent_template_backend` em `Tuning-Performance`.
|
||||
@@ -17,3 +17,4 @@ Documentação das principais features do `agent_framework_oci`.
|
||||
- [Estados Transacionais Dinâmicos](13_dynamic_transaction_states.md)
|
||||
- [Replay Após Finalização](14_post_finalization_replay.md)
|
||||
- [Guardrails de Retrieval e Tools](15_retrieval_tool_guardrails.md)
|
||||
- [Planejamento Multi-Intent](16_multi_intent_planning.md)
|
||||
|
||||
@@ -201,6 +201,8 @@ src/agent_framework/routing/config_loader.py
|
||||
src/agent_framework/routing/continuity.py
|
||||
src/agent_framework/routing/enterprise_router.py
|
||||
src/agent_framework/routing/models.py
|
||||
src/agent_framework/routing/multi_intent.py
|
||||
src/agent_framework/routing/pending_topics.py
|
||||
src/agent_framework/runtime/__init__.py
|
||||
src/agent_framework/runtime/agent_runtime.py
|
||||
src/agent_framework/runtime/transaction_input.py
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user