Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions RAGManager/app/agents/nodes/agent_host.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
"""Nodo 1: Agent Host - Entry point that saves initial context."""

import logging
from uuid import UUID, uuid4

from app.agents.state import AgentState
from app.core.config import settings
from app.core.database_connection import SessionLocal
from app.models.chat import ChatMessage, ChatSession

logger = logging.getLogger(__name__)

Expand All @@ -29,7 +25,7 @@ def agent_host(state: AgentState) -> AgentState:
Updated state with chat_session_id, chat_messages, and initial_context set
"""
updated_state = state.copy()
initial_message = state["messages"][-1]
initial_message = state["messages"][-1] if state["messages"] else None
updated_state["initial_context"] = (
initial_message.content if initial_message else ""
)
Expand Down
21 changes: 14 additions & 7 deletions RAGManager/app/agents/nodes/context_builder.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
"""Nodo 6: Context Builder - Enriches query with retrieved context."""

from app.agents.state import AgentState
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-5-nano")
from app.agents.state import AgentState

_llm: ChatOpenAI | None = None


def _get_llm() -> ChatOpenAI:
"""Lazy initialization of LLM instance."""
global _llm
if _llm is None:
_llm = ChatOpenAI(model="gpt-5-nano")
return _llm


def context_builder(state: AgentState) -> dict:
Expand All @@ -21,7 +30,7 @@ def context_builder(state: AgentState) -> dict:
state: Agent state containing paraphrased_text and relevant_chunks

Returns:
Updated state with enriched_query and primary_response set
dict: A dictionary with a "messages" key containing the LLM response
"""
# TODO: Implement context building and primary LLM call
# This should:
Expand All @@ -31,13 +40,11 @@ def context_builder(state: AgentState) -> dict:
# 4. Store the LLM response in primary_response

# Placeholder: For now, we'll create a simple enriched query
updated_state = state.copy()
paraphrased = state.get("paraphrased_text", "")
chunks = state.get("relevant_chunks", [])

# Build enriched query with context
context_section = "\n\n".join(chunks) if chunks else "No relevant context found."

system_content = f"""You are a helpful assistant. Use the following context to answer the user's question.
If the answer is not in the context, say you don't know.

Expand All @@ -47,6 +54,6 @@ def context_builder(state: AgentState) -> dict:
messages = [SystemMessage(content=system_content)] + state["messages"]

# Call Primary LLM
response = llm.invoke(messages)
response = _get_llm().invoke(messages)

return {"messages": [response]}
40 changes: 24 additions & 16 deletions RAGManager/app/agents/nodes/fallback.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
"""Nodo 3: Fallback Inicial - Initial fallback processing."""
"""Nodo 3: Fallback - Fallback processing for malicious prompts and risky content."""

import logging

from app.agents.state import AgentState
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI

from app.agents.state import AgentState

logger = logging.getLogger(__name__)

llm = ChatOpenAI(
model="gpt-5-nano",
)
_llm: ChatOpenAI | None = None


def _get_llm() -> ChatOpenAI:
"""Lazy initialization of LLM instance."""
global _llm
if _llm is None:
_llm = ChatOpenAI(
model="gpt-5-nano",
)
return _llm


# TO DO: implementar clase nodo fallback y inicializar el llm en el init
def fallback(state: AgentState) -> AgentState:
def fallback(state: AgentState) -> dict:
"""
Fallback node - Performs fallback processing.

This node:
1. Alerts about malicious prompt or PII detection
2. Generates an error_message from llm to show the user
2. Generates an error message from llm to show the user

Args:
state: Agent state containing the prompt or initial context

Returns:
error_message
dict: A dictionary with a "messages" key containing a list with the generated error message from the LLM.
"""

# Check for PII/Risky content (from guard_final)
if state.get("is_risky"):
logger.warning(
Expand All @@ -38,17 +46,17 @@ def fallback(state: AgentState) -> AgentState:
"Your job is to generate an error message in user's language explaining "
"that the response cannot be provided because it contains sensitive or private information."
)

# Check for Malicious prompt (from guard_inicial)
elif state.get("is_malicious"):
logger.warning(
"Defensive check triggered: Malicious prompt detected"
"Defensive check triggered: Malicious prompt detected"
)
system_message_content = (
"Your job is to generate an error message in user's language for the user "
"explaining the database doesn't have the information to answer the user's question"
)

# Generic Fallback (neither risky nor malicious)
else:
logger.info(
Expand All @@ -58,11 +66,11 @@ def fallback(state: AgentState) -> AgentState:
"Your job is to generate an error message in user's language for the user "
"explaining the database doesn't have the information to answer the user's question"
)

messages = [
SystemMessage(content=system_message_content)
] + state["messages"]
error_message = llm.invoke(messages)

error_message = _get_llm().invoke(messages)
return {"messages": [error_message]}

10 changes: 7 additions & 3 deletions RAGManager/app/agents/nodes/guard_inicial.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ def guard_inicial(state: AgentState) -> AgentState:
Updated state with is_malicious and error_message set
"""
updated_state = state.copy()
last_message = state["messages"][-1]
prompt = last_message.content if last_message else ""
if state["messages"]:
last_message = state["messages"][-1]
prompt = last_message.content if last_message else ""
else:
last_message = None
prompt = ""

if not prompt:
# Empty prompt is considered safe
Expand Down Expand Up @@ -77,7 +81,7 @@ def guard_inicial(state: AgentState) -> AgentState:
except Exception as e:
# Log error details for monitoring
logger.error("Error during jailbreak detection", exc_info=True)

# Check if fail-closed mode is enabled
if settings.guardrails_fail_closed:
# Fail-closed: treat errors as malicious to prevent bypassing detection
Expand Down
19 changes: 14 additions & 5 deletions RAGManager/app/agents/nodes/parafraseo.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
"""Nodo 4: Parafraseo - Paraphrases user input."""

from app.agents.state import AgentState
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-5-nano")
from app.agents.state import AgentState

_llm: ChatOpenAI | None = None


def _get_llm() -> ChatOpenAI:
"""Lazy initialization of LLM instance."""
global _llm
if _llm is None:
_llm = ChatOpenAI(model="gpt-5-nano")
return _llm


def parafraseo(state: AgentState) -> AgentState:
Expand All @@ -29,14 +38,14 @@ def parafraseo(state: AgentState) -> AgentState:
# 3. Set paraphrased_text with the result

# Paraphrase the last message using history

system_instruction = """You are an expert at paraphrasing user questions to be standalone and clear, given the conversation history.
Reformulate the last user message to be a self-contained query that includes necessary context from previous messages.
Do not answer the question, just rewrite it."""

messages = [SystemMessage(content=system_instruction)] + state["messages"]
response = llm.invoke(messages)

response = _get_llm().invoke(messages)
updated_state = state.copy() # Create a copy of the state to update
updated_state["paraphrased_text"] = response.content

Expand Down
Loading