Spaces:
Runtime error
Runtime error
added files graph
Browse files
app/graph.py
CHANGED
|
@@ -1,10 +1,84 @@
|
|
| 1 |
-
from app.state.state import
|
| 2 |
from app.nodes.triage_node import *
|
| 3 |
from langgraph.prebuilt import ToolNode ,tools_condition
|
| 4 |
-
from app.
|
|
|
|
|
|
|
| 5 |
from langgraph.graph import StateGraph,END,START
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
|
|
|
| 8 |
|
| 9 |
-
#
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from app.state.state import EmailAgentState
|
| 2 |
from app.nodes.triage_node import *
|
| 3 |
from langgraph.prebuilt import ToolNode ,tools_condition
|
| 4 |
+
from app.nodes.archive_node import archive_node
|
| 5 |
+
from app.tools.email_writing_agent_tools import *
|
| 6 |
+
from app.nodes.email_writing_node import *
|
| 7 |
from langgraph.graph import StateGraph,END,START
|
| 8 |
+
from app.tools.email_writing_agent_tools import create_gmail_draft, send_draft_by_id
|
| 9 |
+
from app.nodes.safety_check_node import *
|
| 10 |
+
from app.nodes.parse_node import parse_response_node
|
| 11 |
+
from app.nodes.context_node import prepare_context_node
|
| 12 |
+
from app.nodes.store_memory_data_node import store_memory_and_data_node
|
| 13 |
+
from app.nodes.unsafe_email_node import unsafe_emails_node
|
| 14 |
+
from langgraph.types import RetryPolicy
|
| 15 |
+
from psycopg import OperationalError # Or sqlalchemy.exc.OperationalError depending on your driver
|
| 16 |
|
| 17 |
+
# Define a standard retry policy for database-heavy nodes
|
| 18 |
+
db_retry_policy = RetryPolicy(
|
| 19 |
+
retry_on=OperationalError,
|
| 20 |
+
max_attempts=3,
|
| 21 |
+
backoff_factor=2 # Waits 2s, then 4s, then 8s between retries
|
| 22 |
+
)
|
| 23 |
|
| 24 |
+
builder = StateGraph(EmailAgentState)
|
| 25 |
|
| 26 |
+
# Nodes
|
| 27 |
+
builder.add_node("safety_check_node", safety_classifier_node)
|
| 28 |
+
builder.add_node("triage_node", triage_node)
|
| 29 |
+
builder.add_node("prepare_context_node", prepare_context_node)
|
| 30 |
+
builder.add_node("email_writing_agent", email_writing_agent_node)
|
| 31 |
+
|
| 32 |
+
# --- APPLY RETRY POLICIES HERE ---
|
| 33 |
+
builder.add_node(
|
| 34 |
+
"store_memory_and_data_node",
|
| 35 |
+
store_memory_and_data_node,
|
| 36 |
+
retry=db_retry_policy
|
| 37 |
+
)
|
| 38 |
+
builder.add_node(
|
| 39 |
+
"unsafe_emails_node",
|
| 40 |
+
unsafe_emails_node,
|
| 41 |
+
retry=db_retry_policy
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
builder.add_node("archive_node", archive_node)
|
| 45 |
+
builder.add_node("parse_node", parse_response_node)
|
| 46 |
+
builder.add_node("tools", ToolNode(email_writing_agent_tools))
|
| 47 |
+
|
| 48 |
+
# Edges (Same as your original logic)
|
| 49 |
+
builder.add_edge(START, "safety_check_node")
|
| 50 |
+
|
| 51 |
+
builder.add_conditional_edges("safety_check_node", after_safety, {
|
| 52 |
+
"unsafe_emails_node": "unsafe_emails_node",
|
| 53 |
+
"triage_node": "triage_node",
|
| 54 |
+
})
|
| 55 |
+
|
| 56 |
+
builder.add_conditional_edges("triage_node", route_after_triage, {
|
| 57 |
+
"prepare_context_node": "prepare_context_node",
|
| 58 |
+
"archive_node": "archive_node",
|
| 59 |
+
})
|
| 60 |
+
|
| 61 |
+
builder.add_edge("prepare_context_node", "email_writing_agent")
|
| 62 |
+
|
| 63 |
+
builder.add_conditional_edges(
|
| 64 |
+
"email_writing_agent",
|
| 65 |
+
tools_condition,
|
| 66 |
+
{
|
| 67 |
+
"tools": "tools",
|
| 68 |
+
END: END
|
| 69 |
+
}
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
builder.add_conditional_edges(
|
| 73 |
+
"tools",
|
| 74 |
+
route_after_tools,
|
| 75 |
+
{
|
| 76 |
+
"parse_node": "parse_node",
|
| 77 |
+
"email_writing_agent": "email_writing_agent"
|
| 78 |
+
}
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
builder.add_edge("parse_node", "store_memory_and_data_node")
|
| 82 |
+
builder.add_edge("store_memory_and_data_node", END)
|
| 83 |
+
builder.add_edge("unsafe_emails_node", END)
|
| 84 |
+
builder.add_edge("archive_node", END)
|
app/nodes/{safety_classifier_node.py → safety_check_node.py}
RENAMED
|
File without changes
|
app/nodes/{unsafe_email_nodes.py → unsafe_email_node.py}
RENAMED
|
File without changes
|
app/tools/context_agent_tools.py
CHANGED
|
@@ -4,7 +4,7 @@ from langchain.tools import tool
|
|
| 4 |
search_memory_tool = create_search_memory_tool(
|
| 5 |
namespace=(
|
| 6 |
"email",
|
| 7 |
-
"{
|
| 8 |
"collection"
|
| 9 |
)
|
| 10 |
)
|
|
|
|
| 4 |
search_memory_tool = create_search_memory_tool(
|
| 5 |
namespace=(
|
| 6 |
"email",
|
| 7 |
+
"{user_id}",
|
| 8 |
"collection"
|
| 9 |
)
|
| 10 |
)
|
app/tools/email_writing_agent_tools.py
CHANGED
|
@@ -52,3 +52,9 @@ def send_draft_by_id(draft_id: str):
|
|
| 52 |
if error.resp.status == 404:
|
| 53 |
return f"ERROR: Draft ID {draft_id} was not found. Please verify the ID or check if it was already sent."
|
| 54 |
return f"ERROR: An unexpected error occurred: {error}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
if error.resp.status == 404:
|
| 53 |
return f"ERROR: Draft ID {draft_id} was not found. Please verify the ID or check if it was already sent."
|
| 54 |
return f"ERROR: An unexpected error occurred: {error}"
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
email_writing_agent_tools = [
|
| 58 |
+
create_gmail_draft,
|
| 59 |
+
send_draft_by_id
|
| 60 |
+
]
|