new feature: frontend with separated responses
This commit is contained in:
@@ -37,3 +37,27 @@ AGENT_AUTH_BASIC_REALM=agent-contas
|
|||||||
# AGENT_AUTH_PROXY_SUBJECT_HEADER=x-authenticated-subject
|
# AGENT_AUTH_PROXY_SUBJECT_HEADER=x-authenticated-subject
|
||||||
# AGENT_AUTH_PROXY_SHARED_SECRET_HEADER=x-internal-auth
|
# AGENT_AUTH_PROXY_SHARED_SECRET_HEADER=x-internal-auth
|
||||||
# AGENT_AUTH_PROXY_SHARED_SECRET_HASH=sha256:replace-hex
|
# AGENT_AUTH_PROXY_SHARED_SECRET_HASH=sha256:replace-hex
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|||||||
@@ -369,6 +369,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -569,6 +570,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -586,6 +588,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -654,6 +664,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -67,6 +67,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -569,6 +570,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -586,6 +588,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -654,6 +664,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -567,6 +568,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -584,6 +586,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -652,6 +662,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -67,6 +67,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -569,6 +570,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -586,6 +588,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -654,6 +664,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -567,6 +568,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -584,6 +586,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -652,6 +662,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -567,6 +568,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -584,6 +586,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -652,6 +662,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -567,6 +568,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -584,6 +586,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -652,6 +662,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -567,6 +568,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -584,6 +586,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -652,6 +662,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -457,6 +457,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -569,6 +570,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -586,6 +588,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -654,6 +664,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock
|
|||||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||||
|
|
||||||
|
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Observabilidade
|
# Observabilidade
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
@@ -457,6 +457,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -569,6 +570,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -586,6 +588,14 @@ class AgentWorkflow:
|
|||||||
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
|
"evidence": (list(drained.mcp_results) + list(drained.rag_results)) or (state.get("context") or {}).get("evidence"),
|
||||||
|
"tool_result": drained.mcp_results or (state.get("context") or {}).get("tool_result"),
|
||||||
|
"tool_executed": any(isinstance(item, dict) and item.get("ok") for item in drained.mcp_results),
|
||||||
|
"mcp_results": drained.mcp_results,
|
||||||
"tenant_id": state.get("tenant_id"),
|
"tenant_id": state.get("tenant_id"),
|
||||||
"agent_id": state.get("agent_id"),
|
"agent_id": state.get("agent_id"),
|
||||||
"session_id": state.get("conversation_key") or state.get("session_id"),
|
"session_id": state.get("conversation_key") or state.get("session_id"),
|
||||||
@@ -654,6 +664,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -1,364 +1,176 @@
|
|||||||
const chat=document.getElementById('chat');
|
const chat = document.getElementById("chat");
|
||||||
const form=document.getElementById('form');
|
const form = document.getElementById("form");
|
||||||
let eventSource=null;
|
let eventSource = null;
|
||||||
let currentSessionId = null;
|
let currentSessionId = null;
|
||||||
|
const renderedResponses = new Set();
|
||||||
|
|
||||||
function add(role,text){
|
function status(text) { const el = document.getElementById("status"); if (el) el.textContent = text; }
|
||||||
const d=document.createElement('div');
|
function val(id) { return (document.getElementById(id)?.value || "").trim(); }
|
||||||
d.className='msg '+role;
|
function uuid() { return crypto.randomUUID(); }
|
||||||
d.textContent=text;
|
function humanizeAgentName(value) {
|
||||||
chat.appendChild(d);
|
return String(value || "agent").trim().replace(/([a-zà-ÿ])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
||||||
chat.scrollTop=chat.scrollHeight;
|
|
||||||
}
|
}
|
||||||
function status(text){const el=document.getElementById('status'); if(el) el.textContent=text;}
|
function responseText(value) {
|
||||||
function val(id){return (document.getElementById(id)?.value || '').trim();}
|
if (typeof value === "string") return value;
|
||||||
function uuid(){return crypto.randomUUID();}
|
if (value == null) return "";
|
||||||
|
return JSON.stringify(value, null, 2);
|
||||||
function buildBusinessContext(session, messageId){
|
|
||||||
return {
|
|
||||||
customer_key: val('customerKey') || null,
|
|
||||||
contract_key: val('contractKey') || null,
|
|
||||||
interaction_key: val('interactionKey') || messageId,
|
|
||||||
account_key: val('accountKey') || null,
|
|
||||||
resource_key: val('resourceKey') || null,
|
|
||||||
session_key: session || null,
|
|
||||||
metadata: {frontend: 'agent_frontend', version: 'business-context-v2'}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
function splitTaggedAgentMessages(value) {
|
||||||
function syncDomainAliases(payload, businessContext){
|
const text = responseText(value).trim();
|
||||||
const agent=val('agent');
|
if (!text) return [];
|
||||||
if(agent === 'retail_orders'){
|
const marker = /^\[([^\]\r\n]*Agent)\]\s*/gim;
|
||||||
payload.customer_id = businessContext.customer_key;
|
const matches = [...text.matchAll(marker)];
|
||||||
payload.order_id = businessContext.contract_key;
|
if (!matches.length || matches[0].index !== 0) return [];
|
||||||
} else {
|
return matches.map((match, index) => {
|
||||||
payload.msisdn = businessContext.customer_key;
|
const start = match.index + match[0].length;
|
||||||
payload.invoice_id = businessContext.contract_key;
|
const end = index + 1 < matches.length ? matches[index + 1].index : text.length;
|
||||||
payload.ura_call_id = businessContext.interaction_key;
|
return { agent: match[1].trim(), text: text.slice(start, end).trim() };
|
||||||
payload.asset_id = businessContext.resource_key;
|
}).filter((item) => item.agent && item.text);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
function stripOwnAgentMarker(value, agent) {
|
||||||
function adicionarMensagem(role, text) {
|
const text = responseText(value).trim();
|
||||||
const chat =
|
const marker = text.match(/^\[([^\]\r\n]*Agent)\]\s*/i);
|
||||||
document.getElementById("chat") ||
|
if (!marker) return text;
|
||||||
document.getElementById("messages") ||
|
const normalize = (name) => String(name || "").replace(/[_\s-]+/g, "").toLowerCase();
|
||||||
document.querySelector(".chat") ||
|
return normalize(marker[1]) === normalize(agent) ? text.slice(marker[0].length).trim() : text;
|
||||||
document.querySelector(".messages") ||
|
}
|
||||||
document.querySelector("[data-chat]");
|
function addUserMessage(text) {
|
||||||
|
|
||||||
if (!chat) {
|
|
||||||
console.error("Não encontrei o container do chat no HTML.");
|
|
||||||
console.log("Mensagem que seria exibida:", role, text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
|
div.className = "msg user chat-bubble--user";
|
||||||
if (role === "user") {
|
div.textContent = text;
|
||||||
div.className = "msg user chat-bubble--user";
|
|
||||||
} else {
|
|
||||||
div.className = "msg assistant chat-bubble--agent";
|
|
||||||
}
|
|
||||||
|
|
||||||
div.textContent = text || "";
|
|
||||||
|
|
||||||
chat.appendChild(div);
|
chat.appendChild(div);
|
||||||
chat.scrollTop = chat.scrollHeight;
|
chat.scrollTop = chat.scrollHeight;
|
||||||
}
|
}
|
||||||
|
function addAgentMessage(agentId, text, group) {
|
||||||
function abrirSSE(sessionId) {
|
const article = document.createElement("article");
|
||||||
if (!sessionId) {
|
article.className = "agent-message";
|
||||||
console.error("Não vou abrir SSE sem sessionId.");
|
article.dataset.agentId = agentId || "agent";
|
||||||
return;
|
const header = document.createElement("header");
|
||||||
|
header.className = "agent-message__header";
|
||||||
|
const avatar = document.createElement("span");
|
||||||
|
avatar.className = "agent-message__avatar";
|
||||||
|
avatar.textContent = humanizeAgentName(agentId).charAt(0) || "A";
|
||||||
|
avatar.setAttribute("aria-hidden", "true");
|
||||||
|
const name = document.createElement("span");
|
||||||
|
name.className = "agent-message__name";
|
||||||
|
name.textContent = humanizeAgentName(agentId);
|
||||||
|
const body = document.createElement("div");
|
||||||
|
body.className = "agent-message__body";
|
||||||
|
body.textContent = responseText(text);
|
||||||
|
header.append(avatar, name);
|
||||||
|
article.append(header, body);
|
||||||
|
group.appendChild(article);
|
||||||
|
}
|
||||||
|
function getAgentMessages(data) {
|
||||||
|
const metadata = data?.metadata || {};
|
||||||
|
const candidates = data?.supervisor_results || metadata.supervisor_results || data?.agent_responses || metadata.agent_responses || (Array.isArray(data?.messages) ? data.messages : null);
|
||||||
|
if (Array.isArray(candidates)) {
|
||||||
|
const messages = candidates.map((item) => ({
|
||||||
|
agent: item?.agent || item?.agent_id || item?.agentId || item?.name,
|
||||||
|
text: stripOwnAgentMarker(item?.answer ?? item?.text ?? item?.message ?? item?.response ?? item?.content, item?.agent || item?.agent_id || item?.agentId || item?.name),
|
||||||
|
})).filter((item) => item.agent && responseText(item.text).trim());
|
||||||
|
if (messages.length) return messages;
|
||||||
}
|
}
|
||||||
|
const text = data?.text ?? data?.speak ?? data?.message ?? data?.response ?? data?.content ?? data?.output;
|
||||||
if (eventSource) {
|
const taggedMessages = splitTaggedAgentMessages(text);
|
||||||
eventSource.close();
|
if (taggedMessages.length) return taggedMessages;
|
||||||
eventSource = null;
|
const agent = metadata.active_agent || metadata.route || data?.agent_id || metadata.agent_id || val("agent") || "agent";
|
||||||
}
|
return responseText(text).trim() ? [{ agent, text }] : [];
|
||||||
|
}
|
||||||
const url = `${backend}/gateway/events/${sessionId}`;
|
function responseKey(data) {
|
||||||
|
const stableId = data?.metadata?.message_id || data?.message_id;
|
||||||
eventSource = new EventSource(url);
|
return stableId ? `id:${stableId}` : JSON.stringify(getAgentMessages(data));
|
||||||
|
}
|
||||||
eventSource.onopen = () => {
|
function renderAgentResponse(data) {
|
||||||
console.log("SSE OPEN");
|
const normalized = typeof data === "string" ? { text: data } : (data || {});
|
||||||
|
const messages = getAgentMessages(normalized);
|
||||||
|
if (!messages.length) return false;
|
||||||
|
const key = responseKey(normalized);
|
||||||
|
if (renderedResponses.has(key)) return false;
|
||||||
|
renderedResponses.add(key);
|
||||||
|
const group = document.createElement("section");
|
||||||
|
group.className = "agent-response-group";
|
||||||
|
group.setAttribute("aria-label", "Respostas dos agentes");
|
||||||
|
messages.forEach((message) => addAgentMessage(message.agent, message.text, group));
|
||||||
|
chat.appendChild(group);
|
||||||
|
chat.scrollTop = chat.scrollHeight;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function buildBusinessContext(session, messageId) {
|
||||||
|
return {
|
||||||
|
customer_key: val("customerKey") || null, contract_key: val("contractKey") || null,
|
||||||
|
interaction_key: val("interactionKey") || messageId, account_key: val("accountKey") || null,
|
||||||
|
resource_key: val("resourceKey") || null, session_key: session || null,
|
||||||
|
metadata: { frontend: "agent_frontend", version: "business-context-v2" },
|
||||||
};
|
};
|
||||||
|
}
|
||||||
eventSource.onerror = (err) => {
|
function syncDomainAliases(payload, businessContext) {
|
||||||
console.error("SSE ERROR:", err);
|
if (val("agent") === "retail_orders") {
|
||||||
};
|
payload.customer_id = businessContext.customer_key; payload.order_id = businessContext.contract_key;
|
||||||
|
} else {
|
||||||
const eventos = [
|
payload.msisdn = businessContext.customer_key; payload.invoice_id = businessContext.contract_key;
|
||||||
"connected",
|
payload.ura_call_id = businessContext.interaction_key; payload.asset_id = businessContext.resource_key;
|
||||||
"waiting",
|
|
||||||
"backend.selected",
|
|
||||||
"flow.start",
|
|
||||||
"workflow.started",
|
|
||||||
"message.responded",
|
|
||||||
"workflow.completed",
|
|
||||||
"flow.end",
|
|
||||||
"error"
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const nome of eventos) {
|
|
||||||
eventSource.addEventListener(nome, (event) => {
|
|
||||||
|
|
||||||
if (nome === "message.responded") {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
|
|
||||||
const text =
|
|
||||||
data.text ||
|
|
||||||
data.message ||
|
|
||||||
data.response ||
|
|
||||||
data.content ||
|
|
||||||
data.output ||
|
|
||||||
event.data;
|
|
||||||
|
|
||||||
adicionarMensagem("assistant", text);
|
|
||||||
} catch {
|
|
||||||
adicionarMensagem("assistant", event.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nome === "error") {
|
|
||||||
adicionarMensagem("assistant", `Erro SSE: ${event.data}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeSessionId(value) {
|
function normalizeSessionId(value) {
|
||||||
if (!value) return uuid();
|
if (!value) return uuid();
|
||||||
|
const parts = value.split(":"); return parts[parts.length - 1];
|
||||||
const parts = value.split(":");
|
|
||||||
return parts[parts.length - 1]; // mantém só o UUID final
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectSSE(backend, sessionId) {
|
function connectSSE(backend, sessionId) {
|
||||||
if (!sessionId) {
|
if (!backend || !sessionId) return;
|
||||||
console.warn("SSE não aberto: sessionId ausente.");
|
if (eventSource) eventSource.close();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backend) {
|
|
||||||
console.warn("SSE não aberto: backend ausente.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventSource) {
|
|
||||||
console.log("Fechando SSE anterior:", eventSource.url);
|
|
||||||
eventSource.close();
|
|
||||||
eventSource = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = `${backend.replace(/\/$/, "")}/gateway/events/${encodeURIComponent(sessionId)}`;
|
const url = `${backend.replace(/\/$/, "")}/gateway/events/${encodeURIComponent(sessionId)}`;
|
||||||
|
|
||||||
console.log("Abrindo SSE:", url);
|
|
||||||
|
|
||||||
eventSource = new EventSource(url);
|
eventSource = new EventSource(url);
|
||||||
eventSource._sessionId = sessionId;
|
eventSource.onopen = () => status("SSE conectado");
|
||||||
|
eventSource.onerror = () => {
|
||||||
eventSource.onopen = () => {
|
if (eventSource?.readyState === EventSource.CONNECTING) status("SSE aguardando/reconectando");
|
||||||
console.log("SSE OPEN:", url);
|
else if (eventSource?.readyState === EventSource.CLOSED) status("SSE fechado");
|
||||||
status("SSE conectado");
|
else status("SSE com erro");
|
||||||
};
|
};
|
||||||
|
const statuses = { waiting: "SSE aguardando backend", "backend.selected": "Backend selecionado", "flow.start": "Fluxo iniciado", "workflow.started": "Workflow em execução", "workflow.completed": "Workflow concluído", "flow.end": "Fluxo finalizado" };
|
||||||
eventSource.onerror = (err) => {
|
Object.entries(statuses).forEach(([eventName, label]) => eventSource.addEventListener(eventName, () => status(label)));
|
||||||
console.error("SSE ERROR raw:", err);
|
|
||||||
console.error("SSE readyState:", eventSource?.readyState);
|
|
||||||
console.error("SSE url:", eventSource?.url);
|
|
||||||
|
|
||||||
if (eventSource?.readyState === EventSource.CONNECTING) {
|
|
||||||
status("SSE aguardando/reconectando");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventSource?.readyState === EventSource.CLOSED) {
|
|
||||||
status("SSE fechado");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
status("SSE com erro");
|
|
||||||
};
|
|
||||||
|
|
||||||
eventSource.addEventListener("connected", (event) => {
|
|
||||||
console.log("SSE connected:", event.data);
|
|
||||||
status("SSE conectado");
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("waiting", (event) => {
|
|
||||||
console.log("SSE waiting:", event.data);
|
|
||||||
status("SSE aguardando backend");
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("backend.selected", (event) => {
|
|
||||||
console.log("SSE backend.selected:", event.data);
|
|
||||||
status("Backend selecionado");
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("flow.start", (event) => {
|
|
||||||
console.log("SSE flow.start:", event.data);
|
|
||||||
status("Fluxo iniciado");
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("workflow.started", (event) => {
|
|
||||||
console.log("SSE workflow.started:", event.data);
|
|
||||||
status("Workflow em execução");
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("session.upserted", (event) => {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
if (data.business_context) {
|
|
||||||
console.debug("business_context", data.business_context);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Não consegui interpretar session.upserted:", event.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("message.responded", (event) => {
|
eventSource.addEventListener("message.responded", (event) => {
|
||||||
try {
|
try { renderAgentResponse(JSON.parse(event.data)); } catch { renderAgentResponse(event.data); }
|
||||||
const data = JSON.parse(event.data);
|
status("Resposta recebida");
|
||||||
|
|
||||||
const text =
|
|
||||||
data.text ||
|
|
||||||
data.message ||
|
|
||||||
data.response ||
|
|
||||||
data.content ||
|
|
||||||
data.output ||
|
|
||||||
event.data;
|
|
||||||
|
|
||||||
if (text) {
|
|
||||||
add("assistant", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.metadata?.business_context) {
|
|
||||||
console.debug("metadata.business_context", data.metadata.business_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
status("Resposta recebida");
|
|
||||||
} catch (e) {
|
|
||||||
add("assistant", event.data);
|
|
||||||
status("Resposta recebida");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
eventSource.addEventListener("workflow.completed", (event) => {
|
|
||||||
console.log("SSE workflow.completed:", event.data);
|
|
||||||
status("Workflow concluído");
|
|
||||||
});
|
|
||||||
|
|
||||||
eventSource.addEventListener("flow.end", (event) => {
|
|
||||||
console.log("SSE flow.end:", event.data);
|
|
||||||
status("Fluxo finalizado");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use um nome diferente de "error" para erro enviado pelo servidor.
|
|
||||||
// "error" é reservado/conflituoso com erro nativo do EventSource.
|
|
||||||
eventSource.addEventListener("server.error", (event) => {
|
eventSource.addEventListener("server.error", (event) => {
|
||||||
console.error("SSE server.error:", event.data);
|
renderAgentResponse({ text: `Erro SSE: ${event.data || "erro informado pelo servidor"}`, agent_id: "sistema" });
|
||||||
add("assistant", `Erro SSE: ${event.data || "erro informado pelo servidor"}`);
|
|
||||||
status("Erro no fluxo SSE");
|
status("Erro no fluxo SSE");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
form.addEventListener('submit', async (e) => {
|
form.addEventListener("submit", async (event) => {
|
||||||
e.preventDefault();
|
event.preventDefault();
|
||||||
|
const input = document.getElementById("message");
|
||||||
const input = document.getElementById('message');
|
|
||||||
const text = input.value.trim();
|
const text = input.value.trim();
|
||||||
|
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
|
addUserMessage(text); input.value = "";
|
||||||
adicionarMensagem('user', text);
|
const backend = val("backend").replace(/\/$/, "");
|
||||||
input.value = '';
|
const channel = val("channel");
|
||||||
|
const session = normalizeSessionId(val("session"));
|
||||||
const backend = val('backend').replace(/\/$/, '');
|
|
||||||
const channel = val('channel');
|
|
||||||
// const session = val('session') || uuid();
|
|
||||||
const session = normalizeSessionId(val('session'));
|
|
||||||
const messageId = uuid();
|
const messageId = uuid();
|
||||||
const tenantId = val('tenant') || 'default';
|
const tenantId = val("tenant") || "default";
|
||||||
const agentId = val('agent') || 'telecom_contas';
|
const agentId = val("agent") || "telecom_contas";
|
||||||
|
document.getElementById("session").value = session;
|
||||||
document.getElementById('session').value = session;
|
|
||||||
|
|
||||||
const businessContext = buildBusinessContext(session, messageId);
|
const businessContext = buildBusinessContext(session, messageId);
|
||||||
|
const commonContext = { channel_id: "browser", tenant_id: tenantId, agent_id: agentId, business_context: businessContext };
|
||||||
const commonContext = {
|
const payload = channel === "voice"
|
||||||
channel_id: 'browser',
|
? { transcript: text, session_id: session, ani: businessContext.customer_key, message_id: messageId, tenant_id: tenantId, agent_id: agentId, context: commonContext }
|
||||||
tenant_id: tenantId,
|
: { message: text, text, session_id: session, user_id: businessContext.customer_key || "web-user", message_id: messageId, tenant_id: tenantId, agent_id: agentId, context: commonContext };
|
||||||
agent_id: agentId,
|
|
||||||
business_context: businessContext
|
|
||||||
};
|
|
||||||
|
|
||||||
const payload = channel === 'voice'
|
|
||||||
? {
|
|
||||||
transcript: text,
|
|
||||||
session_id: session,
|
|
||||||
ani: businessContext.customer_key,
|
|
||||||
message_id: messageId,
|
|
||||||
tenant_id: tenantId,
|
|
||||||
agent_id: agentId,
|
|
||||||
context: commonContext
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
message: text,
|
|
||||||
text: text,
|
|
||||||
session_id: session,
|
|
||||||
user_id: businessContext.customer_key || 'web-user',
|
|
||||||
message_id: messageId,
|
|
||||||
tenant_id: tenantId,
|
|
||||||
agent_id: agentId,
|
|
||||||
context: commonContext
|
|
||||||
};
|
|
||||||
|
|
||||||
syncDomainAliases(payload, businessContext);
|
syncDomainAliases(payload, businessContext);
|
||||||
|
if (document.getElementById("useSse")?.checked) connectSSE(backend, session);
|
||||||
try {
|
try {
|
||||||
status('Enviando mensagem');
|
status("Enviando mensagem");
|
||||||
|
const response = await fetch(`${backend}/gateway/message`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ channel, tenant_id: tenantId, agent_id: agentId, payload }) });
|
||||||
const res = await fetch(`${backend}/gateway/message`, {
|
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
|
||||||
method: 'POST',
|
const data = await response.json();
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
channel,
|
|
||||||
tenant_id: tenantId,
|
|
||||||
agent_id: agentId,
|
|
||||||
payload
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`${res.status} ${res.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
const returnedSessionId = data.session_id || session;
|
const returnedSessionId = data.session_id || session;
|
||||||
currentSessionId = returnedSessionId;
|
currentSessionId = returnedSessionId;
|
||||||
document.getElementById('session').value = returnedSessionId;
|
document.getElementById("session").value = returnedSessionId;
|
||||||
|
renderAgentResponse(data);
|
||||||
const resposta =
|
status("Resposta recebida");
|
||||||
data.text ||
|
} catch (error) {
|
||||||
data.speak ||
|
renderAgentResponse({ text: `Erro ao chamar backend: ${error.message}`, agent_id: "sistema" });
|
||||||
data.message ||
|
status("Erro de conexão");
|
||||||
data.response ||
|
|
||||||
data.content ||
|
|
||||||
data.output ||
|
|
||||||
JSON.stringify(data);
|
|
||||||
|
|
||||||
adicionarMensagem('assistant', resposta);
|
|
||||||
status('Resposta recebida');
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
adicionarMensagem('assistant', `Erro ao chamar backend: ${err.message}`);
|
|
||||||
status('Erro de conexão');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1 +1 @@
|
|||||||
body{font-family:system-ui,Arial,sans-serif;background:#f6f7fb;margin:0}.app{max-width:900px;margin:0 auto;padding:24px}header{margin-bottom:16px}.config{display:grid;grid-template-columns:1fr 160px 1fr;gap:12px;margin-bottom:16px}.config input,.config select,#message{width:100%;padding:10px;border:1px solid #ccc;border-radius:8px}.chat{background:#fff;border:1px solid #ddd;border-radius:12px;min-height:420px;padding:16px;overflow:auto}.msg{padding:10px 12px;border-radius:10px;margin:8px 0;max-width:75%}.user{background:#e8f0ff;margin-left:auto}.assistant{background:#f0f0f0}form{display:flex;gap:8px;margin-top:12px}button{padding:10px 16px;border:0;border-radius:8px;background:#111;color:#fff;cursor:pointer}
|
body{font-family:system-ui,Arial,sans-serif;background:#f6f7fb;margin:0;color:#202124}.app{max-width:900px;margin:0 auto;padding:24px}header{margin-bottom:16px}.config{display:grid;grid-template-columns:1fr 160px 1fr;gap:12px;margin-bottom:16px}.config input,.config select,#message{box-sizing:border-box;width:100%;padding:10px;border:1px solid #ccc;border-radius:8px}.chat{background:#fff;border:1px solid #ddd;border-radius:12px;min-height:420px;max-height:65vh;padding:16px;overflow:auto}.msg{padding:10px 12px;border-radius:10px;margin:8px 0;max-width:75%;white-space:pre-wrap}.user{background:#e8f0ff;margin-left:auto}.agent-response-group{display:grid;gap:10px;margin:12px 0;max-width:82%}.agent-message{overflow:hidden;border:1px solid #dfe3eb;border-radius:12px;background:#f8f9fb;box-shadow:0 1px 2px rgba(20,30,50,.05)}.agent-message__header{display:flex;align-items:center;gap:8px;margin:0;padding:8px 12px;border-bottom:1px solid #e5e8ee;background:#eef1f6}.agent-message__avatar{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;background:#263f73;color:#fff;font-size:12px;font-weight:700}.agent-message__name{font-size:13px;font-weight:700;color:#34425e}.agent-message__body{padding:11px 12px;white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.45}form{display:flex;gap:8px;margin-top:12px}button{padding:10px 16px;border:0;border-radius:8px;background:#111;color:#fff;cursor:pointer}@media(max-width:720px){.app{padding:12px}.config{grid-template-columns:1fr}.agent-response-group,.msg{max-width:92%}}
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ class Settings(BaseSettings):
|
|||||||
KBDB_DOCUMENT_TYPE: str | None = 'customer_safe'
|
KBDB_DOCUMENT_TYPE: str | None = 'customer_safe'
|
||||||
KBDB_METADATA_JSON: str | None = None
|
KBDB_METADATA_JSON: str | None = None
|
||||||
KBDB_MIN_SCORE: float | 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.
|
# MCP só pula retrieval quando declarar explicitamente rag_sufficient/knowledge_sufficient.
|
||||||
SKIP_RAG_WHEN_MCP_SUFFICIENT: bool = True
|
SKIP_RAG_WHEN_MCP_SUFFICIENT: bool = True
|
||||||
# Preserva comportamento legado do RAG standard; KBDB enterprise é grounded-only por padrão.
|
# Preserva comportamento legado do RAG standard; KBDB enterprise é grounded-only por padrão.
|
||||||
|
|||||||
@@ -148,6 +148,9 @@ class KbdbRagService:
|
|||||||
int(self.settings.KBDB_MAX_CROSS_REF_HOPS),
|
int(self.settings.KBDB_MAX_CROSS_REF_HOPS),
|
||||||
self.settings.KBDB_DOCUMENT_TYPE or None,
|
self.settings.KBDB_DOCUMENT_TYPE or None,
|
||||||
metadata 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 = {
|
named_inputs = {
|
||||||
"SEARCH_TYPE": self.settings.KBDB_SEARCH_TYPE,
|
"SEARCH_TYPE": self.settings.KBDB_SEARCH_TYPE,
|
||||||
@@ -166,6 +169,9 @@ class KbdbRagService:
|
|||||||
"DOCUMENT_TYPE": self.settings.KBDB_DOCUMENT_TYPE or None,
|
"DOCUMENT_TYPE": self.settings.KBDB_DOCUMENT_TYPE or None,
|
||||||
"METADATA_JSON": metadata or None,
|
"METADATA_JSON": metadata or None,
|
||||||
"METADATA": 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
|
input_index = 0
|
||||||
binds: list[Any] = []
|
binds: list[Any] = []
|
||||||
@@ -188,6 +194,8 @@ class KbdbRagService:
|
|||||||
input_index += 1
|
input_index += 1
|
||||||
if argument["data_type"] == "NUMBER" and isinstance(value, bool):
|
if argument["data_type"] == "NUMBER" and isinstance(value, bool):
|
||||||
value = 1 if value else 0
|
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)
|
binds.append(value)
|
||||||
if out is None:
|
if out is None:
|
||||||
raise RuntimeError("Assinatura KBDB não possui parâmetro OUT visível")
|
raise RuntimeError("Assinatura KBDB não possui parâmetro OUT visível")
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ AgentHandler = Callable[[dict[str, Any]], Awaitable[dict[str, Any]]]
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class PendingTopicDrain:
|
class PendingTopicDrain:
|
||||||
answer: str
|
answer: str
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
mcp_results: 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_mcp_results = list(state.get("mcp_results") or [])
|
||||||
combined_rag_results = list(state.get("rag_results") or [])
|
combined_rag_results = list(state.get("rag_results") or [])
|
||||||
secondary_answers: list[str] = []
|
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:
|
for topic in topics:
|
||||||
disposition = topic.get("disposition")
|
disposition = topic.get("disposition")
|
||||||
if disposition == "defer":
|
if disposition == "defer":
|
||||||
@@ -105,6 +123,14 @@ async def drain_pending_topics(
|
|||||||
if rag_evidence not in combined_rag_results:
|
if rag_evidence not in combined_rag_results:
|
||||||
combined_rag_results.append(rag_evidence)
|
combined_rag_results.append(rag_evidence)
|
||||||
secondary_answers.append(answer)
|
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"})
|
handled.append({**topic, "status": "completed"})
|
||||||
|
|
||||||
secondary_answers.extend(MultiIntentPlanner.public_messages(plan))
|
secondary_answers.extend(MultiIntentPlanner.public_messages(plan))
|
||||||
@@ -116,5 +142,10 @@ async def drain_pending_topics(
|
|||||||
secondary = "\n\n".join(unique)
|
secondary = "\n\n".join(unique)
|
||||||
candidate = f"{candidate.rstrip()}\n\n{secondary}".strip()
|
candidate = f"{candidate.rstrip()}\n\n{secondary}".strip()
|
||||||
return PendingTopicDrain(
|
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,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -183,12 +183,49 @@ def update_rag_telemetry(path: Path) -> None:
|
|||||||
path.write_text(text, encoding="utf-8")
|
path.write_text(text, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def update_rag_env(path: Path) -> None:
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
if "KBDB_IDENTIFY_DOCUMENT=" in text:
|
||||||
|
return
|
||||||
|
marker = "RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json\n"
|
||||||
|
settings_block = """
|
||||||
|
# RAG / KBDB
|
||||||
|
# RAG provider: standard (local) ou kbdb (PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE)
|
||||||
|
RAG_PROVIDER=standard
|
||||||
|
# KBDB usa credenciais próprias; não há fallback para ADB_*.
|
||||||
|
KBDB_DB_USER=
|
||||||
|
KBDB_DB_PASSWORD=
|
||||||
|
KBDB_DB_DSN=
|
||||||
|
KBDB_DB_WALLET_LOCATION=
|
||||||
|
KBDB_DB_WALLET_PASSWORD=
|
||||||
|
KBDB_SEARCH_TYPE=hybrid
|
||||||
|
KBDB_NODE_EXPANSION=true
|
||||||
|
KBDB_NODE_MAX_RELATED=8
|
||||||
|
KBDB_GRAPH_CROSS_REF=false
|
||||||
|
KBDB_MAX_CROSS_REF_HOPS=1
|
||||||
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
|
KBDB_METADATA_JSON=
|
||||||
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
RAG_GROUNDED_ONLY=false
|
||||||
|
KBDB_GROUNDED_ONLY=true
|
||||||
|
"""
|
||||||
|
if marker in text:
|
||||||
|
text = text.replace(marker, marker + "\n" + settings_block, 1)
|
||||||
|
else:
|
||||||
|
text = text.rstrip() + "\n\n" + settings_block
|
||||||
|
path.write_text(text, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
tuning = ROOT / "Tuning-Performance"
|
tuning = ROOT / "Tuning-Performance"
|
||||||
states = sorted(tuning.glob("**/app/state.py"))
|
states = sorted(tuning.glob("**/app/state.py"))
|
||||||
graphs = sorted(tuning.glob("**/app/workflows/agent_graph.py"))
|
graphs = sorted(tuning.glob("**/app/workflows/agent_graph.py"))
|
||||||
agents = sorted(tuning.glob("**/app/agents/*.py"))
|
agents = sorted(tuning.glob("**/app/agents/*.py"))
|
||||||
mains = sorted(tuning.glob("**/app/main.py"))
|
mains = sorted(tuning.glob("**/app/main.py"))
|
||||||
|
envs = sorted(tuning.glob("**/.env.example"))
|
||||||
for path in states:
|
for path in states:
|
||||||
update_state(path)
|
update_state(path)
|
||||||
for path in graphs:
|
for path in graphs:
|
||||||
@@ -201,7 +238,9 @@ def main() -> None:
|
|||||||
update_rag_agents(path)
|
update_rag_agents(path)
|
||||||
for path in mains:
|
for path in mains:
|
||||||
update_rag_http_response(path)
|
update_rag_http_response(path)
|
||||||
print(f"pending_topics/RAG sincronizado: {len(states)} states, {len(graphs)} graphs, {len(agents)} agents, {len(mains)} APIs")
|
for path in envs:
|
||||||
|
update_rag_env(path)
|
||||||
|
print(f"pending_topics/RAG sincronizado: {len(states)} states, {len(graphs)} graphs, {len(agents)} agents, {len(mains)} APIs, {len(envs)} envs")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -230,6 +230,9 @@ KBDB_MAX_CROSS_REF_HOPS=1
|
|||||||
KBDB_DOCUMENT_TYPE=customer_safe
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
KBDB_METADATA_JSON=
|
KBDB_METADATA_JSON=
|
||||||
KBDB_MIN_SCORE=
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
|
||||||
# RAG grounding
|
# RAG grounding
|
||||||
RAG_GROUNDED_ONLY=false
|
RAG_GROUNDED_ONLY=false
|
||||||
|
|||||||
@@ -457,6 +457,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -569,6 +570,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -650,6 +652,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ LONG_TERM_MEMORY_INJECT_CONTEXT=true
|
|||||||
# kbdb = KBDB enterprise via PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE
|
# kbdb = KBDB enterprise via PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE
|
||||||
RAG_PROVIDER=standard
|
RAG_PROVIDER=standard
|
||||||
|
|
||||||
# Somente usados quando RAG_PROVIDER=kbdb. Se vazios, credenciais caem para ADB_*.
|
# Somente usados quando RAG_PROVIDER=kbdb; não há fallback para ADB_*.
|
||||||
KBDB_DB_USER=
|
KBDB_DB_USER=
|
||||||
KBDB_DB_PASSWORD=
|
KBDB_DB_PASSWORD=
|
||||||
KBDB_DB_DSN=
|
KBDB_DB_DSN=
|
||||||
@@ -229,3 +229,6 @@ KBDB_MAX_CROSS_REF_HOPS=1
|
|||||||
KBDB_DOCUMENT_TYPE=customer_safe
|
KBDB_DOCUMENT_TYPE=customer_safe
|
||||||
KBDB_METADATA_JSON=
|
KBDB_METADATA_JSON=
|
||||||
KBDB_MIN_SCORE=
|
KBDB_MIN_SCORE=
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=true
|
||||||
|
KBDB_STORE_QUERY=true
|
||||||
|
KBDB_IDENTIFY_TOP_N=3
|
||||||
|
|||||||
@@ -452,6 +452,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -567,6 +568,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -648,6 +650,7 @@ class AgentWorkflow:
|
|||||||
"output_guardrails_already_applied": True,
|
"output_guardrails_already_applied": True,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"guardrail_decisions": state.get("guardrail_decisions", [])
|
"guardrail_decisions": state.get("guardrail_decisions", [])
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ async def test_secondary_topic_does_not_inherit_primary_transaction_state():
|
|||||||
assert captured["domain"] == "telecom_contas"
|
assert captured["domain"] == "telecom_contas"
|
||||||
assert result.answer.startswith("Você confirma o cancelamento")
|
assert result.answer.startswith("Você confirma o cancelamento")
|
||||||
assert result.answer.endswith("Aqui está a sua segunda via.")
|
assert result.answer.endswith("Aqui está a sua segunda via.")
|
||||||
|
assert [item["agent"] for item in result.agent_responses] == ["agent", "faturas_agent"]
|
||||||
|
assert result.agent_responses[0]["primary"] is True
|
||||||
|
assert result.agent_responses[1]["primary"] is False
|
||||||
assert result.pending_topics == []
|
assert result.pending_topics == []
|
||||||
assert result.mcp_results == [
|
assert result.mcp_results == [
|
||||||
{"tool_name": "consultar_vas"},
|
{"tool_name": "consultar_vas"},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ def _settings(**overrides):
|
|||||||
KBDB_NODE_MAX_RELATED=8, KBDB_GRAPH_CROSS_REF=False,
|
KBDB_NODE_MAX_RELATED=8, KBDB_GRAPH_CROSS_REF=False,
|
||||||
KBDB_MAX_CROSS_REF_HOPS=1, KBDB_DOCUMENT_TYPE="customer_safe",
|
KBDB_MAX_CROSS_REF_HOPS=1, KBDB_DOCUMENT_TYPE="customer_safe",
|
||||||
KBDB_METADATA_JSON=None, KBDB_MIN_SCORE=None,
|
KBDB_METADATA_JSON=None, KBDB_MIN_SCORE=None,
|
||||||
|
KBDB_IDENTIFY_DOCUMENT=True, KBDB_STORE_QUERY=True, KBDB_IDENTIFY_TOP_N=3,
|
||||||
)
|
)
|
||||||
data.update(overrides)
|
data.update(overrides)
|
||||||
return SimpleNamespace(**data)
|
return SimpleNamespace(**data)
|
||||||
@@ -139,12 +140,13 @@ def test_kbdb_discovers_number_flags_and_clob_output(monkeypatch):
|
|||||||
names = [
|
names = [
|
||||||
("P_SEARCH_TYPE", "VARCHAR2"), ("P_QUERY", "VARCHAR2"),
|
("P_SEARCH_TYPE", "VARCHAR2"), ("P_QUERY", "VARCHAR2"),
|
||||||
("P_TOP_K", "NUMBER"), ("P_NODE_EXPANSION", "NUMBER"),
|
("P_TOP_K", "NUMBER"), ("P_NODE_EXPANSION", "NUMBER"),
|
||||||
("P_NODE_MAX_RELATED", "NUMBER"), ("P_GRAPH_CROSS_REF", "NUMBER"),
|
("P_NODE_MAX_RELATED", "NUMBER"), ("P_DOCUMENT_TYPE", "VARCHAR2"),
|
||||||
("P_MAX_CROSS_REF_HOPS", "NUMBER"), ("P_DOCUMENT_TYPE", "VARCHAR2"),
|
("P_METADATA", "CLOB"), ("P_IDENTIFY_DOCUMENT", "NUMBER"),
|
||||||
("P_METADATA_JSON", "CLOB"), ("P_RESULT", "CLOB"),
|
("P_STORE_QUERY", "NUMBER"), ("P_IDENTIFY_TOP_N", "NUMBER"),
|
||||||
|
("P_RESULT", "CLOB"),
|
||||||
]
|
]
|
||||||
return [
|
return [
|
||||||
(name, index, "OUT" if index == 10 else "IN", data_type, None)
|
(name, index, "OUT" if index == 11 else "IN", data_type, None)
|
||||||
for index, (name, data_type) in enumerate(names, start=1)
|
for index, (name, data_type) in enumerate(names, start=1)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -179,5 +181,5 @@ def test_kbdb_discovers_number_flags_and_clob_output(monkeypatch):
|
|||||||
assert result == {"units": [], "seeds": []}
|
assert result == {"units": [], "seeds": []}
|
||||||
assert captured["procedure"] == "PKG_KB_SERVING.search_knowledge_base"
|
assert captured["procedure"] == "PKG_KB_SERVING.search_knowledge_base"
|
||||||
assert captured["binds"][3] == 1
|
assert captured["binds"][3] == 1
|
||||||
assert captured["binds"][5] == 0
|
assert captured["binds"][7:10] == [1, 1, 3]
|
||||||
assert captured["out_type"] == "CLOB"
|
assert captured["out_type"] == "CLOB"
|
||||||
|
|||||||
@@ -70,3 +70,21 @@ def test_templates_and_tuning_expose_rag_results_in_api_and_telemetry():
|
|||||||
assert '"rag_results": result.get("rag_results")' in path.read_text(encoding="utf-8"), path
|
assert '"rag_results": result.get("rag_results")' in path.read_text(encoding="utf-8"), path
|
||||||
for path in graphs:
|
for path in graphs:
|
||||||
assert '"rag_results": state.get("rag_results", [])' in path.read_text(encoding="utf-8"), path
|
assert '"rag_results": state.get("rag_results", [])' in path.read_text(encoding="utf-8"), path
|
||||||
|
|
||||||
|
|
||||||
|
def test_all_tuning_envs_expose_complete_kbdb_configuration():
|
||||||
|
envs = sorted((ROOT / "Tuning-Performance").glob("**/.env.example"))
|
||||||
|
assert envs
|
||||||
|
required = (
|
||||||
|
"RAG_PROVIDER=standard",
|
||||||
|
"KBDB_DB_USER=",
|
||||||
|
"KBDB_DB_DSN=",
|
||||||
|
"KBDB_IDENTIFY_DOCUMENT=true",
|
||||||
|
"KBDB_STORE_QUERY=true",
|
||||||
|
"KBDB_IDENTIFY_TOP_N=3",
|
||||||
|
"KBDB_GROUNDED_ONLY=true",
|
||||||
|
)
|
||||||
|
for path in envs:
|
||||||
|
source = path.read_text(encoding="utf-8")
|
||||||
|
for setting in required:
|
||||||
|
assert setting in source, (path, setting)
|
||||||
|
|||||||
@@ -480,6 +480,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False)
|
|||||||
"route": result.get("route"),
|
"route": result.get("route"),
|
||||||
"intent": result.get("intent"),
|
"intent": result.get("intent"),
|
||||||
"route_decision": result.get("route_decision"),
|
"route_decision": result.get("route_decision"),
|
||||||
|
"supervisor_results": result.get("supervisor_results") or [],
|
||||||
|
"agent_responses": result.get("agent_responses") or result.get("supervisor_results") or [],
|
||||||
"domain": result.get("domain"),
|
"domain": result.get("domain"),
|
||||||
"mcp_tools": result.get("mcp_tools"),
|
"mcp_tools": result.get("mcp_tools"),
|
||||||
"mcp_results": result.get("mcp_results"),
|
"mcp_results": result.get("mcp_results"),
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class AgentState(TypedDict, total=False):
|
|||||||
missing_parameters: list[str]
|
missing_parameters: list[str]
|
||||||
supervisor_plan: dict[str, Any]
|
supervisor_plan: dict[str, Any]
|
||||||
supervisor_results: list[dict[str, Any]]
|
supervisor_results: list[dict[str, Any]]
|
||||||
|
agent_responses: list[dict[str, Any]]
|
||||||
pending_topics: list[dict[str, Any]]
|
pending_topics: list[dict[str, Any]]
|
||||||
handled_topics: list[dict[str, Any]]
|
handled_topics: list[dict[str, Any]]
|
||||||
active_agent: str
|
active_agent: str
|
||||||
|
|||||||
@@ -827,6 +827,7 @@ class AgentWorkflow:
|
|||||||
return {
|
return {
|
||||||
"answer": answer,
|
"answer": answer,
|
||||||
"supervisor_results": partials,
|
"supervisor_results": partials,
|
||||||
|
"agent_responses": partials,
|
||||||
"mcp_results": mcp_results,
|
"mcp_results": mcp_results,
|
||||||
"next_state": "SUPERVISOR_ACTIVE",
|
"next_state": "SUPERVISOR_ACTIVE",
|
||||||
}
|
}
|
||||||
@@ -946,6 +947,7 @@ class AgentWorkflow:
|
|||||||
"final_answer": candidate,
|
"final_answer": candidate,
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
"output_guardrails_already_applied": False,
|
"output_guardrails_already_applied": False,
|
||||||
@@ -1028,6 +1030,7 @@ class AgentWorkflow:
|
|||||||
+ [item for r in decision.results for item in (r.metadata or {}).get("framework_decisions", [])],
|
+ [item for r in decision.results for item in (r.metadata or {}).get("framework_decisions", [])],
|
||||||
"pending_topics": drained.pending_topics,
|
"pending_topics": drained.pending_topics,
|
||||||
"handled_topics": drained.handled_topics,
|
"handled_topics": drained.handled_topics,
|
||||||
|
"agent_responses": drained.agent_responses,
|
||||||
"mcp_results": drained.mcp_results,
|
"mcp_results": drained.mcp_results,
|
||||||
"rag_results": drained.rag_results,
|
"rag_results": drained.rag_results,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user