new feature: frontend with separated responses

This commit is contained in:
2026-09-11 09:33:55 -03:00
parent 6c81b21aaa
commit ecfbfbf8e1
60 changed files with 657 additions and 337 deletions

View File

@@ -124,6 +124,9 @@ class Settings(BaseSettings):
KBDB_DOCUMENT_TYPE: str | None = 'customer_safe'
KBDB_METADATA_JSON: str | None = None
KBDB_MIN_SCORE: float | None = None
KBDB_IDENTIFY_DOCUMENT: bool = True
KBDB_STORE_QUERY: bool = True
KBDB_IDENTIFY_TOP_N: int = 3
# MCP só pula retrieval quando declarar explicitamente rag_sufficient/knowledge_sufficient.
SKIP_RAG_WHEN_MCP_SUFFICIENT: bool = True
# Preserva comportamento legado do RAG standard; KBDB enterprise é grounded-only por padrão.

View File

@@ -148,6 +148,9 @@ class KbdbRagService:
int(self.settings.KBDB_MAX_CROSS_REF_HOPS),
self.settings.KBDB_DOCUMENT_TYPE or None,
metadata or None,
bool(getattr(self.settings, "KBDB_IDENTIFY_DOCUMENT", True)),
bool(getattr(self.settings, "KBDB_STORE_QUERY", True)),
int(getattr(self.settings, "KBDB_IDENTIFY_TOP_N", 3)),
]
named_inputs = {
"SEARCH_TYPE": self.settings.KBDB_SEARCH_TYPE,
@@ -166,6 +169,9 @@ class KbdbRagService:
"DOCUMENT_TYPE": self.settings.KBDB_DOCUMENT_TYPE or None,
"METADATA_JSON": metadata or None,
"METADATA": metadata or None,
"IDENTIFY_DOCUMENT": bool(getattr(self.settings, "KBDB_IDENTIFY_DOCUMENT", True)),
"STORE_QUERY": bool(getattr(self.settings, "KBDB_STORE_QUERY", True)),
"IDENTIFY_TOP_N": int(getattr(self.settings, "KBDB_IDENTIFY_TOP_N", 3)),
}
input_index = 0
binds: list[Any] = []
@@ -188,6 +194,8 @@ class KbdbRagService:
input_index += 1
if argument["data_type"] == "NUMBER" and isinstance(value, bool):
value = 1 if value else 0
elif argument["data_type"] in {"VARCHAR", "VARCHAR2", "CHAR", "NCHAR"} and isinstance(value, bool):
value = "true" if value else "false"
binds.append(value)
if out is None:
raise RuntimeError("Assinatura KBDB não possui parâmetro OUT visível")

View File

@@ -11,6 +11,7 @@ AgentHandler = Callable[[dict[str, Any]], Awaitable[dict[str, Any]]]
@dataclass(frozen=True)
class PendingTopicDrain:
answer: str
agent_responses: list[dict[str, Any]]
pending_topics: list[dict[str, Any]]
handled_topics: list[dict[str, Any]]
mcp_results: list[dict[str, Any]]
@@ -33,6 +34,23 @@ async def drain_pending_topics(
combined_mcp_results = list(state.get("mcp_results") or [])
combined_rag_results = list(state.get("rag_results") or [])
secondary_answers: list[str] = []
agent_responses = list(state.get("agent_responses") or [])
if not agent_responses and str(candidate or "").strip():
primary_agent = str(
state.get("active_agent")
or state.get("route")
or route.get("agent")
or route.get("route")
or state.get("agent_id")
or "agent"
)
agent_responses.append({
"agent": primary_agent,
"intent": state.get("intent") or route.get("intent"),
"answer": str(candidate).strip(),
"primary": True,
"status": "completed",
})
for topic in topics:
disposition = topic.get("disposition")
if disposition == "defer":
@@ -105,6 +123,14 @@ async def drain_pending_topics(
if rag_evidence not in combined_rag_results:
combined_rag_results.append(rag_evidence)
secondary_answers.append(answer)
agent_responses.append({
"operation_id": topic.get("operation_id"),
"agent": topic.get("agent"),
"intent": topic.get("intent"),
"answer": answer,
"primary": False,
"status": "completed",
})
handled.append({**topic, "status": "completed"})
secondary_answers.extend(MultiIntentPlanner.public_messages(plan))
@@ -116,5 +142,10 @@ async def drain_pending_topics(
secondary = "\n\n".join(unique)
candidate = f"{candidate.rstrip()}\n\n{secondary}".strip()
return PendingTopicDrain(
candidate, remaining, handled, combined_mcp_results, combined_rag_results
answer=candidate,
agent_responses=agent_responses,
pending_topics=remaining,
handled_topics=handled,
mcp_results=combined_mcp_results,
rag_results=combined_rag_results,
)