new feature: frontend with separated responses

This commit is contained in:
2026-09-11 11:59:51 -03:00
parent 82ae25b85b
commit 2ac3e4e702
21 changed files with 697 additions and 34 deletions

View File

@@ -435,6 +435,34 @@ class AgentWorkflow:
"PAUSED",
"WAITING_INPUT",
}
# The most recent MCP result is authoritative for a transaction
# promoted after another transaction completed in the same
# multi-intent turn. Checkpoint merge order can otherwise leave
# the previous COMPLETED status at the top level and cause input
# guardrails to reject the new transaction's short confirmation.
latest_mcp_transaction = next(
(
result
for result in reversed(list(state.get("mcp_results") or []))
if isinstance(result, dict)
and str(result.get("transaction_status") or "").strip().upper()
in nonterminal_tx_statuses
),
None,
)
if latest_mcp_transaction:
latest_status = str(latest_mcp_transaction.get("transaction_status") or "").strip().upper()
tx_status = latest_status
state["transaction_status"] = latest_status
if not active_tx or active_tx_status not in nonterminal_tx_statuses:
active_tx = {
"transaction_id": str(latest_mcp_transaction.get("transaction_id") or ""),
"tool_name": str(latest_mcp_transaction.get("tool_name") or ""),
"arguments": dict(latest_mcp_transaction.get("arguments") or {}),
"status": latest_status,
}
state["active_transaction"] = active_tx
active_tx_status = latest_status
# A new active transaction has precedence over terminal evidence from
# the previous transaction in the same session. Without this guard,
# a stale state["transaction_status"] == COMPLETED can tombstone an
@@ -549,6 +577,7 @@ class AgentWorkflow:
"transaction_status": state.get("transaction_status"),
"missing_parameters": list(state.get("missing_parameters") or []),
"active_transaction": state.get("active_transaction") or {},
"mcp_results": list(state.get("mcp_results") or []),
},
)
for _decision in decisions:
@@ -729,7 +758,8 @@ class AgentWorkflow:
} 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 []
if (decision.metadata or {}).get("multi_intent_plan")
else list(state.get("pending_topics") or [])
),
}
@@ -953,6 +983,7 @@ class AgentWorkflow:
"output_guardrails_already_applied": False,
"supervisor_action": "disabled",
"supervisor_attempt": int(state.get("supervisor_attempt", 0)),
**drained.state_patch,
}
context = {
**self._output_guardrail_context({
@@ -1033,6 +1064,7 @@ class AgentWorkflow:
"agent_responses": drained.agent_responses,
"mcp_results": drained.mcp_results,
"rag_results": drained.rag_results,
**drained.state_patch,
}
async def output_guardrails(self, state):