File size: 4,772 Bytes
b99e403
c6421b9
7b3f35e
b99e403
 
7b3f35e
57d78b2
b99e403
 
 
 
 
21f1bdf
b99e403
0c0b2ef
 
b99e403
aa34f6b
21f1bdf
44c6641
 
d9012b6
 
 
 
d8647d4
7b3f35e
b99e403
 
 
21f1bdf
 
 
 
 
 
 
 
 
b99e403
7b3f35e
21f1bdf
b99e403
7b3f35e
4d860a2
 
 
b99e403
 
21f1bdf
0c0b2ef
 
b99e403
 
 
 
0c0b2ef
b99e403
 
 
 
 
 
 
 
 
 
 
21f1bdf
b99e403
d8647d4
4d860a2
 
b99e403
 
0c0b2ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b99e403
 
21f1bdf
b99e403
 
 
21f1bdf
 
 
 
 
 
 
 
b99e403
 
21f1bdf
b99e403
 
 
 
 
 
 
 
 
 
 
 
 
4d860a2
b99e403
 
 
 
4d860a2
b99e403
 
21f1bdf
76a007c
d9012b6
d8647d4
814aa17
44c6641
 
 
76a007c
 
 
44c6641
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
from app.state.state import EmailAgentState
from app.nodes.triage_node import *
from langgraph.prebuilt import ToolNode ,tools_condition
from app.nodes.archive_node import  archive_node
from app.nodes.email_writing_node import *
from langgraph.graph import StateGraph,END,START
from app.tools.email_writing_agent_tools import create_gmail_draft, send_draft
from app.nodes.safety_check_node import *
from app.nodes.parse_node import parse_response_node
from app.nodes.context_node import prepare_context_node
from app.nodes.store_memory_data_node import store_memory_and_data_node
from app.nodes.unsafe_email_node import unsafe_emails_node
from app.nodes.check_email_exist_node import *
from langgraph.types import RetryPolicy
from app.nodes.summarise_email_body_node import summarise_email_body_node
from app.nodes.check_token_count_node import *
from psycopg import OperationalError # Or sqlalchemy.exc.OperationalError depending on your driver
from app.tools.email_writing_agent_tools import email_writing_agent_tools 
from IPython.display import Image, display
from app.persistance.memory_store_checkpointer_config import memory_store, checkpointer
from langchain_google_community import GmailToolkit
from app.database.connection import pool
from app.utils.embeddings import remote_embeddings
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.store.postgres import PostgresStore
from app.tools.email_writing_agent_tools import email_writing_agent_tools

# Define a standard retry policy for database-heavy nodes
db_retry_policy = RetryPolicy(
    retry_on=OperationalError,
    max_attempts=4,
    backoff_factor=1 # Waits 2s, then 4s, then 8s between retries
)

tool_node_retry_policy = RetryPolicy(
    max_attempts=4,
    initial_interval=1.0,
    backoff_factor=2.0,
    jitter=True
)


builder = StateGraph(EmailAgentState)

# Nodes
builder = StateGraph(EmailAgentState)

# Nodes
builder.add_node("safety_check_node", safety_classifier_node)  
builder.add_node("check_previous_email_exist_node", check_previous_email_exist_node)
builder.add_node("check_token_count_node", check_token_count_node)
builder.add_node("summarise_email_body_node", summarise_email_body_node)
builder.add_node("triage_node", triage_node)
builder.add_node("prepare_context_node", prepare_context_node)
builder.add_node("email_writing_agent", email_writing_agent_node)

# --- APPLY RETRY POLICIES HERE ---
builder.add_node(
    "store_memory_and_data_node", 
    store_memory_and_data_node, 
    retry=db_retry_policy
)         
builder.add_node(
    "unsafe_emails_node", 
    unsafe_emails_node, 
    retry=db_retry_policy
)

builder.add_node("archive_node", archive_node,retry=db_retry_policy)   

builder.add_node("tools", ToolNode(email_writing_agent_tools), retry=tool_node_retry_policy)

# Edges (Same as your original logic)
builder.add_edge(START, "safety_check_node")

builder.add_conditional_edges(
    "safety_check_node", 
    after_safety, 
    {
        "unsafe": "unsafe_emails_node",
        "safe": "check_token_count_node" 
    }
)

builder.add_conditional_edges(
    "check_token_count_node", 
    check_token_limit_router, 
    {
        "summarize": "summarise_email_body_node",
        "triage": "triage_node" 
    }
)

builder.add_edge("summarise_email_body_node", "triage_node")



builder.add_conditional_edges("triage_node", route_after_triage, {
    "check_previous_email_exist_node": "check_previous_email_exist_node", 
    "archive_node": "archive_node",
})

builder.add_conditional_edges(
    "check_previous_email_exist_node",
    after_mail_check,
    {
        "email_writing_agent": "email_writing_agent", 
        "prepare_context_node": "prepare_context_node" 
    }
)
builder.add_edge("prepare_context_node", "email_writing_agent")


builder.add_conditional_edges(
    "email_writing_agent",
    tools_condition,
    {
        "tools": "tools", 
        END: END
    }
)

builder.add_conditional_edges(
    "tools",
    route_after_tools,
    {
        "store_memory_and_data_node": "store_memory_and_data_node",
        "email_writing_agent": "email_writing_agent"
    }
)


builder.add_edge("store_memory_and_data_node", END)
builder.add_edge("unsafe_emails_node", END)
builder.add_edge("archive_node", END)


toolkit = GmailToolkit()
graph=builder.compile(checkpointer=checkpointer, store=memory_store,debug=True)






# try:
#     # This creates a PNG and saves it to your project folder
#     graph_png = graph.get_graph().draw_mermaid_png()
#     with open("graph.png", "wb") as f:
#         f.write(graph_png)
#     print("--- Graph image saved as 'graph.png' ---")
# except Exception as e:
#     # This happens if you don't have the 'pypydot' or 'graphviz' dependencies
#     print(f"Could not generate graph image: {e}")