From ecfbfbf8e1882bd519e39ef8a2701473dafcf421 Mon Sep 17 00:00:00 2001 From: "cristiano.hoshikawa" Date: Fri, 11 Sep 2026 09:33:55 -0300 Subject: [PATCH] new feature: frontend with separated responses --- .../.env.example | 24 + .../app/main.py | 2 + .../app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../.env.example | 24 + .../app/main.py | 2 + .../app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../.env.example | 24 + .../app/main.py | 2 + .../app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../agent_template_backend/.env.example | 24 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 11 + .../apps/agent_frontend/app.js | 468 ++++++------------ .../apps/agent_frontend/styles.css | 2 +- .../src/agent_framework/config/settings.py | 3 + .../src/agent_framework/rag/kbdb_service.py | 8 + .../agent_framework/routing/pending_topics.py | 33 +- .../scripts/sync_pending_topics_to_tuning.py | 41 +- .../agent_template_backend/.env.example | 3 + .../agent_template_backend/app/main.py | 2 + .../agent_template_backend/app/state.py | 1 + .../app/workflows/agent_graph.py | 3 + .../.env.example | 5 +- .../app/main.py | 2 + .../app/state.py | 1 + .../app/workflows/agent_graph.py | 3 + .../unit/test_pending_topics_isolation.py | 3 + .../tests/unit/test_rag_kbdb_provider.py | 12 +- .../unit/test_tuning_pending_topics_sync.py | 18 + app/main.py | 2 + app/state.py | 1 + app/workflows/agent_graph.py | 3 + 60 files changed, 657 insertions(+), 337 deletions(-) diff --git a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/.env.example b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/.env.example index 310a33c9..ae6a1f5f 100644 --- a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/.env.example +++ b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/.env.example @@ -37,3 +37,27 @@ AGENT_AUTH_BASIC_REALM=agent-contas # AGENT_AUTH_PROXY_SUBJECT_HEADER=x-authenticated-subject # AGENT_AUTH_PROXY_SHARED_SECRET_HEADER=x-internal-auth # 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 diff --git a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/main.py b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/main.py index b2d27c25..5908b5fb 100644 --- a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/main.py @@ -369,6 +369,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/state.py b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/state.py index 27d4f7b9..9533ad02 100644 --- a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/workflows/agent_graph.py index 197d16ec..0dcd6b49 100644 --- a/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Authentication/agent_template_backend_authentication/app/workflows/agent_graph.py @@ -490,6 +490,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -569,6 +570,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -654,6 +664,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/.env.example index f41c0ed7..03d5cbbb 100644 --- a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/.env.example @@ -67,6 +67,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/main.py index e8383282..9c9eca42 100644 --- a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/main.py @@ -363,6 +363,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/state.py index 27d4f7b9..9533ad02 100644 --- a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/workflows/agent_graph.py index 197d16ec..0dcd6b49 100644 --- a/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Deterministic_Transactional_Workflow/agent_template_backend/app/workflows/agent_graph.py @@ -490,6 +490,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -569,6 +570,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -654,6 +664,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/.env.example index e93eccab..50c3109f 100644 --- a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/main.py index 7e9401f6..451574df 100644 --- a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/main.py @@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/state.py index 9ec69485..288e79c3 100644 --- a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/workflows/agent_graph.py index 1f9954cb..8be1347c 100644 --- a/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/External_Guardrails_Judges/agent_template_backend/app/workflows/agent_graph.py @@ -488,6 +488,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -567,6 +568,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -652,6 +662,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/.env.example index 116eb7d3..f724b51e 100644 --- a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/.env.example @@ -67,6 +67,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/main.py index e8383282..9c9eca42 100644 --- a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/main.py @@ -363,6 +363,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/state.py index 27d4f7b9..9533ad02 100644 --- a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/workflows/agent_graph.py index 197d16ec..0dcd6b49 100644 --- a/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Long_Term_Memory/templates/agent_template_backend/app/workflows/agent_graph.py @@ -490,6 +490,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -569,6 +570,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -654,6 +664,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/.env.example index e93eccab..50c3109f 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/main.py index 7e9401f6..451574df 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/main.py @@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/state.py index 9ec69485..288e79c3 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/workflows/agent_graph.py index 1f9954cb..8be1347c 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend/app/workflows/agent_graph.py @@ -488,6 +488,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -567,6 +568,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -652,6 +662,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/.env.example b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/.env.example index 34118b9a..3fb43004 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/.env.example +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/main.py b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/main.py index 7e9401f6..451574df 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/main.py @@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/state.py b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/state.py index 9ec69485..288e79c3 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py index 1f9954cb..8be1347c 100644 --- a/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Normal/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py @@ -488,6 +488,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -567,6 +568,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -652,6 +662,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/.env.example index a8a666c3..be7467eb 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/main.py index 7e9401f6..451574df 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/main.py @@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/state.py index 9ec69485..288e79c3 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/workflows/agent_graph.py index 1f9954cb..8be1347c 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend/app/workflows/agent_graph.py @@ -488,6 +488,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -567,6 +568,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -652,6 +662,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/.env.example b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/.env.example index 31aa694f..83ae1d7f 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/.env.example +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/main.py b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/main.py index 7e9401f6..451574df 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/main.py @@ -358,6 +358,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/state.py b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/state.py index 9ec69485..288e79c3 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/state.py @@ -36,6 +36,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py index 1f9954cb..8be1347c 100644 --- a/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Route_Stickness/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py @@ -488,6 +488,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -567,6 +568,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -652,6 +662,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/.env.example index a8a666c3..be7467eb 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/main.py index 52585276..f594f59e 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/main.py @@ -457,6 +457,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/state.py index fbb54b63..970df839 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/state.py @@ -39,6 +39,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/workflows/agent_graph.py index 87389012..cd16da66 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Transaction_Evidence/agent_template_backend/app/workflows/agent_graph.py @@ -490,6 +490,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -569,6 +570,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -654,6 +664,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example index e93eccab..50c3109f 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example +++ b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/.env.example @@ -66,6 +66,30 @@ EMBEDDING_PROVIDER=mock OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0 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 ############################################################################### diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/main.py b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/main.py index 891f0e06..eab131ec 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/main.py +++ b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/main.py @@ -457,6 +457,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/state.py b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/state.py index aee4d926..e048cf13 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/state.py +++ b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/state.py @@ -40,6 +40,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/workflows/agent_graph.py index 87389012..cd16da66 100644 --- a/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/Tuning-Performance/Transaction_Pre_Validation/agent_template_backend/app/workflows/agent_graph.py @@ -490,6 +490,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -569,6 +570,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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_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, + "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"), "agent_id": state.get("agent_id"), "session_id": state.get("conversation_key") or state.get("session_id"), @@ -654,6 +664,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/apps/agent_frontend/app.js b/agent_framework_oci/apps/agent_frontend/app.js index b9bb182b..f18024a2 100644 --- a/agent_framework_oci/apps/agent_frontend/app.js +++ b/agent_framework_oci/apps/agent_frontend/app.js @@ -1,364 +1,176 @@ -const chat=document.getElementById('chat'); -const form=document.getElementById('form'); -let eventSource=null; +const chat = document.getElementById("chat"); +const form = document.getElementById("form"); +let eventSource = null; let currentSessionId = null; +const renderedResponses = new Set(); -function add(role,text){ - const d=document.createElement('div'); - d.className='msg '+role; - d.textContent=text; - chat.appendChild(d); - chat.scrollTop=chat.scrollHeight; +function status(text) { const el = document.getElementById("status"); if (el) el.textContent = text; } +function val(id) { return (document.getElementById(id)?.value || "").trim(); } +function uuid() { return crypto.randomUUID(); } +function humanizeAgentName(value) { + return String(value || "agent").trim().replace(/([a-zà-ÿ])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase()); } -function status(text){const el=document.getElementById('status'); if(el) el.textContent=text;} -function val(id){return (document.getElementById(id)?.value || '').trim();} -function uuid(){return crypto.randomUUID();} - -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 responseText(value) { + if (typeof value === "string") return value; + if (value == null) return ""; + return JSON.stringify(value, null, 2); } - -function syncDomainAliases(payload, businessContext){ - const agent=val('agent'); - if(agent === 'retail_orders'){ - payload.customer_id = businessContext.customer_key; - payload.order_id = businessContext.contract_key; - } else { - payload.msisdn = businessContext.customer_key; - payload.invoice_id = businessContext.contract_key; - payload.ura_call_id = businessContext.interaction_key; - payload.asset_id = businessContext.resource_key; - } +function splitTaggedAgentMessages(value) { + const text = responseText(value).trim(); + if (!text) return []; + const marker = /^\[([^\]\r\n]*Agent)\]\s*/gim; + const matches = [...text.matchAll(marker)]; + if (!matches.length || matches[0].index !== 0) return []; + return matches.map((match, index) => { + const start = match.index + match[0].length; + const end = index + 1 < matches.length ? matches[index + 1].index : text.length; + return { agent: match[1].trim(), text: text.slice(start, end).trim() }; + }).filter((item) => item.agent && item.text); } - -function adicionarMensagem(role, text) { - const chat = - document.getElementById("chat") || - document.getElementById("messages") || - document.querySelector(".chat") || - document.querySelector(".messages") || - document.querySelector("[data-chat]"); - - if (!chat) { - console.error("Não encontrei o container do chat no HTML."); - console.log("Mensagem que seria exibida:", role, text); - return; - } - +function stripOwnAgentMarker(value, agent) { + const text = responseText(value).trim(); + const marker = text.match(/^\[([^\]\r\n]*Agent)\]\s*/i); + if (!marker) return text; + const normalize = (name) => String(name || "").replace(/[_\s-]+/g, "").toLowerCase(); + return normalize(marker[1]) === normalize(agent) ? text.slice(marker[0].length).trim() : text; +} +function addUserMessage(text) { const div = document.createElement("div"); - - if (role === "user") { - div.className = "msg user chat-bubble--user"; - } else { - div.className = "msg assistant chat-bubble--agent"; - } - - div.textContent = text || ""; - + div.className = "msg user chat-bubble--user"; + div.textContent = text; chat.appendChild(div); chat.scrollTop = chat.scrollHeight; } - -function abrirSSE(sessionId) { - if (!sessionId) { - console.error("Não vou abrir SSE sem sessionId."); - return; +function addAgentMessage(agentId, text, group) { + const article = document.createElement("article"); + article.className = "agent-message"; + article.dataset.agentId = agentId || "agent"; + 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; } - - if (eventSource) { - eventSource.close(); - eventSource = null; - } - - const url = `${backend}/gateway/events/${sessionId}`; - - eventSource = new EventSource(url); - - eventSource.onopen = () => { - console.log("SSE OPEN"); + const text = data?.text ?? data?.speak ?? data?.message ?? data?.response ?? data?.content ?? data?.output; + const taggedMessages = splitTaggedAgentMessages(text); + if (taggedMessages.length) return taggedMessages; + const agent = metadata.active_agent || metadata.route || data?.agent_id || metadata.agent_id || val("agent") || "agent"; + return responseText(text).trim() ? [{ agent, text }] : []; +} +function responseKey(data) { + const stableId = data?.metadata?.message_id || data?.message_id; + return stableId ? `id:${stableId}` : JSON.stringify(getAgentMessages(data)); +} +function renderAgentResponse(data) { + 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) => { - console.error("SSE ERROR:", err); - }; - - const eventos = [ - "connected", - "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 syncDomainAliases(payload, businessContext) { + if (val("agent") === "retail_orders") { + payload.customer_id = businessContext.customer_key; payload.order_id = businessContext.contract_key; + } else { + payload.msisdn = businessContext.customer_key; payload.invoice_id = businessContext.contract_key; + payload.ura_call_id = businessContext.interaction_key; payload.asset_id = businessContext.resource_key; } } - function normalizeSessionId(value) { if (!value) return uuid(); - - const parts = value.split(":"); - return parts[parts.length - 1]; // mantém só o UUID final + const parts = value.split(":"); return parts[parts.length - 1]; } - function connectSSE(backend, sessionId) { - if (!sessionId) { - console.warn("SSE não aberto: sessionId ausente."); - 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; - } - + if (!backend || !sessionId) return; + if (eventSource) eventSource.close(); const url = `${backend.replace(/\/$/, "")}/gateway/events/${encodeURIComponent(sessionId)}`; - - console.log("Abrindo SSE:", url); - eventSource = new EventSource(url); - eventSource._sessionId = sessionId; - - eventSource.onopen = () => { - console.log("SSE OPEN:", url); - status("SSE conectado"); + eventSource.onopen = () => status("SSE conectado"); + eventSource.onerror = () => { + if (eventSource?.readyState === EventSource.CONNECTING) status("SSE aguardando/reconectando"); + else if (eventSource?.readyState === EventSource.CLOSED) status("SSE fechado"); + else status("SSE com erro"); }; - - eventSource.onerror = (err) => { - 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); - } - }); - + 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" }; + Object.entries(statuses).forEach(([eventName, label]) => eventSource.addEventListener(eventName, () => status(label))); eventSource.addEventListener("message.responded", (event) => { - try { - const data = JSON.parse(event.data); - - 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"); - } + try { renderAgentResponse(JSON.parse(event.data)); } catch { renderAgentResponse(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) => { - console.error("SSE server.error:", event.data); - add("assistant", `Erro SSE: ${event.data || "erro informado pelo servidor"}`); + renderAgentResponse({ text: `Erro SSE: ${event.data || "erro informado pelo servidor"}`, agent_id: "sistema" }); status("Erro no fluxo SSE"); }); } -form.addEventListener('submit', async (e) => { - e.preventDefault(); - - const input = document.getElementById('message'); +form.addEventListener("submit", async (event) => { + event.preventDefault(); + const input = document.getElementById("message"); const text = input.value.trim(); - if (!text) return; - - adicionarMensagem('user', text); - input.value = ''; - - const backend = val('backend').replace(/\/$/, ''); - const channel = val('channel'); - // const session = val('session') || uuid(); - const session = normalizeSessionId(val('session')); + addUserMessage(text); input.value = ""; + const backend = val("backend").replace(/\/$/, ""); + const channel = val("channel"); + const session = normalizeSessionId(val("session")); const messageId = uuid(); - const tenantId = val('tenant') || 'default'; - const agentId = val('agent') || 'telecom_contas'; - - document.getElementById('session').value = session; - + const tenantId = val("tenant") || "default"; + const agentId = val("agent") || "telecom_contas"; + document.getElementById("session").value = session; const businessContext = buildBusinessContext(session, messageId); - - const commonContext = { - channel_id: 'browser', - tenant_id: tenantId, - 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 - }; - + const commonContext = { channel_id: "browser", tenant_id: tenantId, 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, session_id: session, user_id: businessContext.customer_key || "web-user", message_id: messageId, tenant_id: tenantId, agent_id: agentId, context: commonContext }; syncDomainAliases(payload, businessContext); - + if (document.getElementById("useSse")?.checked) connectSSE(backend, session); try { - status('Enviando mensagem'); - - const res = await fetch(`${backend}/gateway/message`, { - method: 'POST', - 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(); - + 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 }) }); + if (!response.ok) throw new Error(`${response.status} ${response.statusText}`); + const data = await response.json(); const returnedSessionId = data.session_id || session; currentSessionId = returnedSessionId; - document.getElementById('session').value = returnedSessionId; - - const resposta = - data.text || - data.speak || - data.message || - 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'); + document.getElementById("session").value = returnedSessionId; + renderAgentResponse(data); + status("Resposta recebida"); + } catch (error) { + renderAgentResponse({ text: `Erro ao chamar backend: ${error.message}`, agent_id: "sistema" }); + status("Erro de conexão"); } -}); \ No newline at end of file +}); diff --git a/agent_framework_oci/apps/agent_frontend/styles.css b/agent_framework_oci/apps/agent_frontend/styles.css index caf85923..7fd84306 100644 --- a/agent_framework_oci/apps/agent_frontend/styles.css +++ b/agent_framework_oci/apps/agent_frontend/styles.css @@ -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%}} diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/config/settings.py b/agent_framework_oci/libs/agent_framework/src/agent_framework/config/settings.py index 5cab2f19..2225c282 100644 --- a/agent_framework_oci/libs/agent_framework/src/agent_framework/config/settings.py +++ b/agent_framework_oci/libs/agent_framework/src/agent_framework/config/settings.py @@ -124,6 +124,9 @@ class Settings(BaseSettings): KBDB_DOCUMENT_TYPE: str | None = 'customer_safe' KBDB_METADATA_JSON: str | None = None KBDB_MIN_SCORE: float | None = None + KBDB_IDENTIFY_DOCUMENT: bool = True + KBDB_STORE_QUERY: bool = True + KBDB_IDENTIFY_TOP_N: int = 3 # MCP só pula retrieval quando declarar explicitamente rag_sufficient/knowledge_sufficient. SKIP_RAG_WHEN_MCP_SUFFICIENT: bool = True # Preserva comportamento legado do RAG standard; KBDB enterprise é grounded-only por padrão. diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/rag/kbdb_service.py b/agent_framework_oci/libs/agent_framework/src/agent_framework/rag/kbdb_service.py index 423b805d..568cdda6 100644 --- a/agent_framework_oci/libs/agent_framework/src/agent_framework/rag/kbdb_service.py +++ b/agent_framework_oci/libs/agent_framework/src/agent_framework/rag/kbdb_service.py @@ -148,6 +148,9 @@ class KbdbRagService: int(self.settings.KBDB_MAX_CROSS_REF_HOPS), self.settings.KBDB_DOCUMENT_TYPE or None, metadata or None, + bool(getattr(self.settings, "KBDB_IDENTIFY_DOCUMENT", True)), + bool(getattr(self.settings, "KBDB_STORE_QUERY", True)), + int(getattr(self.settings, "KBDB_IDENTIFY_TOP_N", 3)), ] named_inputs = { "SEARCH_TYPE": self.settings.KBDB_SEARCH_TYPE, @@ -166,6 +169,9 @@ class KbdbRagService: "DOCUMENT_TYPE": self.settings.KBDB_DOCUMENT_TYPE or None, "METADATA_JSON": metadata or None, "METADATA": metadata or None, + "IDENTIFY_DOCUMENT": bool(getattr(self.settings, "KBDB_IDENTIFY_DOCUMENT", True)), + "STORE_QUERY": bool(getattr(self.settings, "KBDB_STORE_QUERY", True)), + "IDENTIFY_TOP_N": int(getattr(self.settings, "KBDB_IDENTIFY_TOP_N", 3)), } input_index = 0 binds: list[Any] = [] @@ -188,6 +194,8 @@ class KbdbRagService: input_index += 1 if argument["data_type"] == "NUMBER" and isinstance(value, bool): value = 1 if value else 0 + elif argument["data_type"] in {"VARCHAR", "VARCHAR2", "CHAR", "NCHAR"} and isinstance(value, bool): + value = "true" if value else "false" binds.append(value) if out is None: raise RuntimeError("Assinatura KBDB não possui parâmetro OUT visível") diff --git a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/pending_topics.py b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/pending_topics.py index 8996e88f..37693c48 100644 --- a/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/pending_topics.py +++ b/agent_framework_oci/libs/agent_framework/src/agent_framework/routing/pending_topics.py @@ -11,6 +11,7 @@ AgentHandler = Callable[[dict[str, Any]], Awaitable[dict[str, Any]]] @dataclass(frozen=True) class PendingTopicDrain: answer: str + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] mcp_results: list[dict[str, Any]] @@ -33,6 +34,23 @@ async def drain_pending_topics( combined_mcp_results = list(state.get("mcp_results") or []) combined_rag_results = list(state.get("rag_results") or []) secondary_answers: list[str] = [] + agent_responses = list(state.get("agent_responses") or []) + if not agent_responses and str(candidate or "").strip(): + primary_agent = str( + state.get("active_agent") + or state.get("route") + or route.get("agent") + or route.get("route") + or state.get("agent_id") + or "agent" + ) + agent_responses.append({ + "agent": primary_agent, + "intent": state.get("intent") or route.get("intent"), + "answer": str(candidate).strip(), + "primary": True, + "status": "completed", + }) for topic in topics: disposition = topic.get("disposition") if disposition == "defer": @@ -105,6 +123,14 @@ async def drain_pending_topics( if rag_evidence not in combined_rag_results: combined_rag_results.append(rag_evidence) secondary_answers.append(answer) + agent_responses.append({ + "operation_id": topic.get("operation_id"), + "agent": topic.get("agent"), + "intent": topic.get("intent"), + "answer": answer, + "primary": False, + "status": "completed", + }) handled.append({**topic, "status": "completed"}) secondary_answers.extend(MultiIntentPlanner.public_messages(plan)) @@ -116,5 +142,10 @@ async def drain_pending_topics( secondary = "\n\n".join(unique) candidate = f"{candidate.rstrip()}\n\n{secondary}".strip() return PendingTopicDrain( - candidate, remaining, handled, combined_mcp_results, combined_rag_results + answer=candidate, + agent_responses=agent_responses, + pending_topics=remaining, + handled_topics=handled, + mcp_results=combined_mcp_results, + rag_results=combined_rag_results, ) diff --git a/agent_framework_oci/scripts/sync_pending_topics_to_tuning.py b/agent_framework_oci/scripts/sync_pending_topics_to_tuning.py index e6e812a3..26158899 100644 --- a/agent_framework_oci/scripts/sync_pending_topics_to_tuning.py +++ b/agent_framework_oci/scripts/sync_pending_topics_to_tuning.py @@ -183,12 +183,49 @@ def update_rag_telemetry(path: Path) -> None: 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: tuning = ROOT / "Tuning-Performance" states = sorted(tuning.glob("**/app/state.py")) graphs = sorted(tuning.glob("**/app/workflows/agent_graph.py")) agents = sorted(tuning.glob("**/app/agents/*.py")) mains = sorted(tuning.glob("**/app/main.py")) + envs = sorted(tuning.glob("**/.env.example")) for path in states: update_state(path) for path in graphs: @@ -201,7 +238,9 @@ def main() -> None: update_rag_agents(path) for path in mains: 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__": diff --git a/agent_framework_oci/templates/agent_template_backend/.env.example b/agent_framework_oci/templates/agent_template_backend/.env.example index 16527cf8..dfca44a0 100644 --- a/agent_framework_oci/templates/agent_template_backend/.env.example +++ b/agent_framework_oci/templates/agent_template_backend/.env.example @@ -230,6 +230,9 @@ 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 grounding RAG_GROUNDED_ONLY=false diff --git a/agent_framework_oci/templates/agent_template_backend/app/main.py b/agent_framework_oci/templates/agent_template_backend/app/main.py index 891f0e06..eab131ec 100644 --- a/agent_framework_oci/templates/agent_template_backend/app/main.py +++ b/agent_framework_oci/templates/agent_template_backend/app/main.py @@ -457,6 +457,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/templates/agent_template_backend/app/state.py b/agent_framework_oci/templates/agent_template_backend/app/state.py index aee4d926..e048cf13 100644 --- a/agent_framework_oci/templates/agent_template_backend/app/state.py +++ b/agent_framework_oci/templates/agent_template_backend/app/state.py @@ -40,6 +40,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/templates/agent_template_backend/app/workflows/agent_graph.py b/agent_framework_oci/templates/agent_template_backend/app/workflows/agent_graph.py index f76c2c7d..33f65688 100644 --- a/agent_framework_oci/templates/agent_template_backend/app/workflows/agent_graph.py +++ b/agent_framework_oci/templates/agent_template_backend/app/workflows/agent_graph.py @@ -490,6 +490,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -569,6 +570,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "output_guardrails_already_applied": False, @@ -650,6 +652,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/templates/agent_template_backend_day_zero/.env.example b/agent_framework_oci/templates/agent_template_backend_day_zero/.env.example index eeb71309..1668c3d3 100644 --- a/agent_framework_oci/templates/agent_template_backend_day_zero/.env.example +++ b/agent_framework_oci/templates/agent_template_backend_day_zero/.env.example @@ -215,7 +215,7 @@ LONG_TERM_MEMORY_INJECT_CONTEXT=true # kbdb = KBDB enterprise via PKG_KB_SERVING.SEARCH_KNOWLEDGE_BASE 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_PASSWORD= KBDB_DB_DSN= @@ -229,3 +229,6 @@ 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 diff --git a/agent_framework_oci/templates/agent_template_backend_day_zero/app/main.py b/agent_framework_oci/templates/agent_template_backend_day_zero/app/main.py index 0b9f0a6e..1128d7c2 100644 --- a/agent_framework_oci/templates/agent_template_backend_day_zero/app/main.py +++ b/agent_framework_oci/templates/agent_template_backend_day_zero/app/main.py @@ -452,6 +452,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/agent_framework_oci/templates/agent_template_backend_day_zero/app/state.py b/agent_framework_oci/templates/agent_template_backend_day_zero/app/state.py index a0016e73..b27c56ad 100644 --- a/agent_framework_oci/templates/agent_template_backend_day_zero/app/state.py +++ b/agent_framework_oci/templates/agent_template_backend_day_zero/app/state.py @@ -37,6 +37,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/agent_framework_oci/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py b/agent_framework_oci/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py index aa4726f6..bcc4e6a6 100644 --- a/agent_framework_oci/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py +++ b/agent_framework_oci/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py @@ -488,6 +488,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -567,6 +568,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "output_guardrails_already_applied": False, @@ -648,6 +650,7 @@ class AgentWorkflow: "output_guardrails_already_applied": True, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "guardrail_decisions": state.get("guardrail_decisions", []) diff --git a/agent_framework_oci/tests/unit/test_pending_topics_isolation.py b/agent_framework_oci/tests/unit/test_pending_topics_isolation.py index e2dbb948..618fad2a 100644 --- a/agent_framework_oci/tests/unit/test_pending_topics_isolation.py +++ b/agent_framework_oci/tests/unit/test_pending_topics_isolation.py @@ -56,6 +56,9 @@ async def test_secondary_topic_does_not_inherit_primary_transaction_state(): assert captured["domain"] == "telecom_contas" assert result.answer.startswith("Você confirma o cancelamento") 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.mcp_results == [ {"tool_name": "consultar_vas"}, diff --git a/agent_framework_oci/tests/unit/test_rag_kbdb_provider.py b/agent_framework_oci/tests/unit/test_rag_kbdb_provider.py index 75192dbc..48f77b75 100644 --- a/agent_framework_oci/tests/unit/test_rag_kbdb_provider.py +++ b/agent_framework_oci/tests/unit/test_rag_kbdb_provider.py @@ -17,6 +17,7 @@ def _settings(**overrides): KBDB_NODE_MAX_RELATED=8, KBDB_GRAPH_CROSS_REF=False, KBDB_MAX_CROSS_REF_HOPS=1, KBDB_DOCUMENT_TYPE="customer_safe", KBDB_METADATA_JSON=None, KBDB_MIN_SCORE=None, + KBDB_IDENTIFY_DOCUMENT=True, KBDB_STORE_QUERY=True, KBDB_IDENTIFY_TOP_N=3, ) data.update(overrides) return SimpleNamespace(**data) @@ -139,12 +140,13 @@ def test_kbdb_discovers_number_flags_and_clob_output(monkeypatch): names = [ ("P_SEARCH_TYPE", "VARCHAR2"), ("P_QUERY", "VARCHAR2"), ("P_TOP_K", "NUMBER"), ("P_NODE_EXPANSION", "NUMBER"), - ("P_NODE_MAX_RELATED", "NUMBER"), ("P_GRAPH_CROSS_REF", "NUMBER"), - ("P_MAX_CROSS_REF_HOPS", "NUMBER"), ("P_DOCUMENT_TYPE", "VARCHAR2"), - ("P_METADATA_JSON", "CLOB"), ("P_RESULT", "CLOB"), + ("P_NODE_MAX_RELATED", "NUMBER"), ("P_DOCUMENT_TYPE", "VARCHAR2"), + ("P_METADATA", "CLOB"), ("P_IDENTIFY_DOCUMENT", "NUMBER"), + ("P_STORE_QUERY", "NUMBER"), ("P_IDENTIFY_TOP_N", "NUMBER"), + ("P_RESULT", "CLOB"), ] 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) ] @@ -179,5 +181,5 @@ def test_kbdb_discovers_number_flags_and_clob_output(monkeypatch): assert result == {"units": [], "seeds": []} assert captured["procedure"] == "PKG_KB_SERVING.search_knowledge_base" assert captured["binds"][3] == 1 - assert captured["binds"][5] == 0 + assert captured["binds"][7:10] == [1, 1, 3] assert captured["out_type"] == "CLOB" diff --git a/agent_framework_oci/tests/unit/test_tuning_pending_topics_sync.py b/agent_framework_oci/tests/unit/test_tuning_pending_topics_sync.py index dbe1abb7..b0f8e50c 100644 --- a/agent_framework_oci/tests/unit/test_tuning_pending_topics_sync.py +++ b/agent_framework_oci/tests/unit/test_tuning_pending_topics_sync.py @@ -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 for path in graphs: 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) diff --git a/app/main.py b/app/main.py index f1764d4a..c3eeac04 100644 --- a/app/main.py +++ b/app/main.py @@ -480,6 +480,8 @@ async def _process_gateway_message(req: GatewayRequest, emit_sse: bool = False) "route": result.get("route"), "intent": result.get("intent"), "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"), "mcp_tools": result.get("mcp_tools"), "mcp_results": result.get("mcp_results"), diff --git a/app/state.py b/app/state.py index 14fb9328..08f14611 100644 --- a/app/state.py +++ b/app/state.py @@ -43,6 +43,7 @@ class AgentState(TypedDict, total=False): missing_parameters: list[str] supervisor_plan: dict[str, Any] supervisor_results: list[dict[str, Any]] + agent_responses: list[dict[str, Any]] pending_topics: list[dict[str, Any]] handled_topics: list[dict[str, Any]] active_agent: str diff --git a/app/workflows/agent_graph.py b/app/workflows/agent_graph.py index 8b2a971c..0d6ef84d 100644 --- a/app/workflows/agent_graph.py +++ b/app/workflows/agent_graph.py @@ -827,6 +827,7 @@ class AgentWorkflow: return { "answer": answer, "supervisor_results": partials, + "agent_responses": partials, "mcp_results": mcp_results, "next_state": "SUPERVISOR_ACTIVE", } @@ -946,6 +947,7 @@ class AgentWorkflow: "final_answer": candidate, "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, "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", [])], "pending_topics": drained.pending_topics, "handled_topics": drained.handled_topics, + "agent_responses": drained.agent_responses, "mcp_results": drained.mcp_results, "rag_results": drained.rag_results, }