yashAI007 commited on
Commit
b8c0485
·
1 Parent(s): 45f00f2

add tool calling and user wise chat

Browse files
Files changed (3) hide show
  1. app.py +173 -40
  2. app_backup.py +321 -0
  3. memory_chatbot.py +86 -1
app.py CHANGED
@@ -1,67 +1,144 @@
1
  import gradio as gr
2
  import uuid
3
  from langchain_core.messages import HumanMessage
4
- # from chatbot import chatbot
5
- from memory_chatbot import chatbot
6
 
7
 
8
  # -----------------------
9
- # Generate Thread ID
10
  # -----------------------
11
  def new_thread_id():
12
- return str(uuid.uuid4())[:8]
 
 
 
13
 
14
 
15
  # -----------------------
16
- # First Thread
17
  # -----------------------
 
18
  first_thread = new_thread_id()
19
 
20
 
21
  # -----------------------
22
  # Chat Function
23
  # -----------------------
24
- def chat_fn(message, chat_history, thread_id, all_threads):
25
 
26
- config = {"configurable": {"thread_id": thread_id, "user_id": "user_id"}}
 
 
 
 
 
27
 
28
  res = chatbot.invoke(
29
  {"messages": [HumanMessage(content=message)]},
30
  config=config
31
  )
32
 
33
- ai_message = res["messages"][-1].content
 
34
 
35
- # Append in NEW format
36
  chat_history.append({"role": "user", "content": message})
37
  chat_history.append({"role": "assistant", "content": ai_message})
38
 
39
- all_threads[thread_id] = chat_history
 
 
 
40
 
41
- return "", chat_history, all_threads
42
 
43
 
44
  # -----------------------
45
  # Create New Thread
46
  # -----------------------
47
- def create_new_thread(all_threads):
48
- new_id = new_thread_id()
49
- all_threads[new_id] = []
 
 
 
 
 
50
 
51
  return (
52
  all_threads,
53
- gr.update(choices=list(all_threads.keys()), value=new_id),
54
- new_id,
55
- []
 
56
  )
57
 
58
 
59
  # -----------------------
60
  # Switch Thread
61
  # -----------------------
62
- def switch_thread(thread_id, all_threads):
63
- history = all_threads.get(thread_id, [])
64
- return thread_id, history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
 
67
  # -----------------------
@@ -69,13 +146,31 @@ def switch_thread(thread_id, all_threads):
69
  # -----------------------
70
  with gr.Blocks() as demo:
71
 
 
72
  thread_state = gr.State(first_thread)
73
- threads_state = gr.State({first_thread: []})
 
 
 
 
 
 
74
 
75
  with gr.Row():
76
 
77
  # Sidebar
78
  with gr.Column(scale=1):
 
 
 
 
 
 
 
 
 
 
 
79
  gr.Markdown("## 🧵 Threads")
80
 
81
  thread_radio = gr.Radio(
@@ -86,36 +181,74 @@ with gr.Blocks() as demo:
86
 
87
  new_chat_btn = gr.Button("➕ New Chat")
88
 
89
- # Main Chat
90
- with gr.Column(scale=4):
91
 
92
  chatbot_ui = gr.Chatbot()
93
  msg_box = gr.Textbox(placeholder="Type message and press Enter")
 
94
 
95
  msg_box.submit(
96
  chat_fn,
97
- inputs=[msg_box, chatbot_ui, thread_state, threads_state],
98
- outputs=[msg_box, chatbot_ui, threads_state],
99
  )
100
 
101
- # New Chat Button
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  new_chat_btn.click(
103
- create_new_thread,
104
- inputs=threads_state,
105
- outputs=[
106
- threads_state,
107
- thread_radio,
108
- thread_state,
109
- chatbot_ui
110
- ]
111
- )
112
-
 
 
113
  # Switch Thread
 
114
  thread_radio.change(
115
- switch_thread,
116
- inputs=[thread_radio, threads_state],
117
- outputs=[thread_state, chatbot_ui]
118
- )
119
 
120
 
121
  demo.launch()
 
1
  import gradio as gr
2
  import uuid
3
  from langchain_core.messages import HumanMessage
4
+ from memory_chatbot import chatbot,get_last_ai_message,extract_tool_logs
 
5
 
6
 
7
  # -----------------------
8
+ # Generate IDs
9
  # -----------------------
10
  def new_thread_id():
11
+ return "thread_" + str(uuid.uuid4())[:8]
12
+
13
+ def new_user_id():
14
+ return "user_" + str(uuid.uuid4())[:6]
15
 
16
 
17
  # -----------------------
18
+ # Initial User + Thread
19
  # -----------------------
20
+ first_user = new_user_id()
21
  first_thread = new_thread_id()
22
 
23
 
24
  # -----------------------
25
  # Chat Function
26
  # -----------------------
27
+ def chat_fn(message, chat_history, thread_id, user_id, all_threads):
28
 
29
+ config = {
30
+ "configurable": {
31
+ "thread_id": thread_id,
32
+ "user_id": user_id
33
+ }
34
+ }
35
 
36
  res = chatbot.invoke(
37
  {"messages": [HumanMessage(content=message)]},
38
  config=config
39
  )
40
 
41
+ ai_message = get_last_ai_message(res["messages"])
42
+ tool_logs = extract_tool_logs(res["messages"], message)
43
 
44
+ chat_history = chat_history or []
45
  chat_history.append({"role": "user", "content": message})
46
  chat_history.append({"role": "assistant", "content": ai_message})
47
 
48
+ all_threads[(user_id, thread_id)] = {
49
+ "chat": chat_history,
50
+ "tools": tool_logs
51
+ }
52
 
53
+ return "", chat_history, all_threads, tool_logs
54
 
55
 
56
  # -----------------------
57
  # Create New Thread
58
  # -----------------------
59
+
60
+ def create_new_thread(user_id, all_threads):
61
+
62
+ new_tid = new_thread_id()
63
+ all_threads[(user_id, new_tid)] = {
64
+ "chat": [],
65
+ "tools": "_No tools used yet._"
66
+ }
67
 
68
  return (
69
  all_threads,
70
+ gr.update(choices=[t for (u, t) in all_threads if u == user_id], value=new_tid),
71
+ new_tid,
72
+ [],
73
+ "_No tools used yet._"
74
  )
75
 
76
 
77
  # -----------------------
78
  # Switch Thread
79
  # -----------------------
80
+
81
+ def switch_thread(thread_id, user_id, all_threads):
82
+
83
+ data = all_threads.get(
84
+ (user_id, thread_id),
85
+ {"chat": [], "tools": "_No tools used yet._"}
86
+ )
87
+
88
+ return thread_id, data["chat"], data["tools"]
89
+
90
+ # -----------------------
91
+ # Create New User
92
+ # -----------------------
93
+ def create_new_user(all_threads):
94
+
95
+ new_uid = new_user_id()
96
+ new_tid = new_thread_id()
97
+
98
+ all_threads[(new_uid, new_tid)] = {
99
+ "chat": [],
100
+ "tools": "_No tools used yet._"
101
+ }
102
+
103
+ return (
104
+ all_threads,
105
+ gr.update(choices=list(set([u for (u, _) in all_threads])), value=new_uid),
106
+ new_uid,
107
+ gr.update(choices=[new_tid], value=new_tid),
108
+ new_tid,
109
+ [],
110
+ "_No tools used yet._"
111
+ )
112
+
113
+
114
+ # -----------------------
115
+ # Switch User
116
+ # -----------------------
117
+ def switch_user(user_id, all_threads):
118
+
119
+ user_threads = [t for (u, t) in all_threads if u == user_id]
120
+
121
+ if not user_threads:
122
+ new_tid = new_thread_id()
123
+ all_threads[(user_id, new_tid)] = {
124
+ "chat": [],
125
+ "tools": "_No tools used yet._"
126
+ }
127
+ user_threads = [new_tid]
128
+
129
+ first_thread = user_threads[0]
130
+ data = all_threads.get(
131
+ (user_id, first_thread),
132
+ {"chat": [], "tools": "_No tools used yet._"}
133
+ )
134
+
135
+ return (
136
+ user_id,
137
+ gr.update(choices=user_threads, value=first_thread),
138
+ first_thread,
139
+ data["chat"],
140
+ data["tools"]
141
+ )
142
 
143
 
144
  # -----------------------
 
146
  # -----------------------
147
  with gr.Blocks() as demo:
148
 
149
+ user_state = gr.State(first_user)
150
  thread_state = gr.State(first_thread)
151
+
152
+ threads_state = gr.State({
153
+ (first_user, first_thread): {
154
+ "chat": [],
155
+ "tools": "_No tools used yet._"
156
+ }
157
+ })
158
 
159
  with gr.Row():
160
 
161
  # Sidebar
162
  with gr.Column(scale=1):
163
+
164
+ gr.Markdown("## 👤 Users")
165
+
166
+ user_dropdown = gr.Dropdown(
167
+ choices=[first_user],
168
+ value=first_user,
169
+ label="Select User"
170
+ )
171
+
172
+ new_user_btn = gr.Button("➕ New User")
173
+
174
  gr.Markdown("## 🧵 Threads")
175
 
176
  thread_radio = gr.Radio(
 
181
 
182
  new_chat_btn = gr.Button("➕ New Chat")
183
 
184
+ # Chat Area
185
+ with gr.Column(scale=7):
186
 
187
  chatbot_ui = gr.Chatbot()
188
  msg_box = gr.Textbox(placeholder="Type message and press Enter")
189
+ tool_panel = gr.Markdown("## 🛠 Tool Activity\n_No tools used yet._")
190
 
191
  msg_box.submit(
192
  chat_fn,
193
+ inputs=[msg_box, chatbot_ui, thread_state, user_state, threads_state],
194
+ outputs=[msg_box, chatbot_ui, threads_state, tool_panel],
195
  )
196
 
197
+ # -----------------------
198
+ # New User
199
+ # -----------------------
200
+ new_user_btn.click(
201
+ create_new_user,
202
+ inputs=threads_state,
203
+ outputs=[
204
+ threads_state,
205
+ user_dropdown,
206
+ user_state,
207
+ thread_radio,
208
+ thread_state,
209
+ chatbot_ui,
210
+ tool_panel
211
+ ]
212
+ )
213
+
214
+ # -----------------------
215
+ # Switch User
216
+ # -----------------------
217
+ user_dropdown.change(
218
+ switch_user,
219
+ inputs=[user_dropdown, threads_state],
220
+ outputs=[
221
+ user_state,
222
+ thread_radio,
223
+ thread_state,
224
+ chatbot_ui,
225
+ tool_panel
226
+ ]
227
+ )
228
+
229
+ # -----------------------
230
+ # New Thread
231
+ # -----------------------
232
  new_chat_btn.click(
233
+ create_new_thread,
234
+ inputs=[user_state, threads_state],
235
+ outputs=[
236
+ threads_state,
237
+ thread_radio,
238
+ thread_state,
239
+ chatbot_ui,
240
+ tool_panel
241
+ ]
242
+ )
243
+
244
+ # -----------------------
245
  # Switch Thread
246
+ # -----------------------
247
  thread_radio.change(
248
+ switch_thread,
249
+ inputs=[thread_radio, user_state, threads_state],
250
+ outputs=[thread_state, chatbot_ui, tool_panel]
251
+ )
252
 
253
 
254
  demo.launch()
app_backup.py ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import uuid
3
+ from langchain_core.messages import HumanMessage
4
+ from memory_chatbot import chatbot
5
+
6
+
7
+ # -----------------------
8
+ # Generate IDs
9
+ # -----------------------
10
+ def new_thread_id():
11
+ return "thread_" + str(uuid.uuid4())[:8]
12
+
13
+ def new_user_id():
14
+ return "user_" + str(uuid.uuid4())[:6]
15
+
16
+
17
+ # -----------------------
18
+ # Initial User + Thread
19
+ # -----------------------
20
+ first_user = new_user_id()
21
+ first_thread = new_thread_id()
22
+
23
+
24
+ # -----------------------
25
+ # Chat Function
26
+ # -----------------------
27
+ def chat_fn(message, chat_history, thread_id, user_id, all_threads):
28
+
29
+ # tool_logs = []
30
+
31
+ config = {
32
+ "configurable": {
33
+ "thread_id": thread_id,
34
+ "user_id": user_id
35
+ }
36
+ }
37
+
38
+ res = chatbot.invoke(
39
+ {"messages": [HumanMessage(content=message)]},
40
+ config=config
41
+ )
42
+
43
+ ai_message = res["messages"][-1].content
44
+
45
+
46
+ chat_history.append({"role": "user", "content": message})
47
+ chat_history.append({"role": "assistant", "content": ai_message})
48
+
49
+ all_threads[(user_id, thread_id)] = chat_history
50
+
51
+ return "", chat_history, all_threads
52
+
53
+
54
+ # -----------------------
55
+ # Create New Thread
56
+ # -----------------------
57
+ def create_new_thread(user_id, all_threads):
58
+
59
+ new_tid = new_thread_id()
60
+ all_threads[(user_id, new_tid)] = []
61
+
62
+ return (
63
+ all_threads,
64
+ gr.update(choices=[t for (u, t) in all_threads if u == user_id], value=new_tid),
65
+ new_tid,
66
+ []
67
+ )
68
+
69
+
70
+ # -----------------------
71
+ # Switch Thread
72
+ # -----------------------
73
+ def switch_thread(thread_id, user_id, all_threads):
74
+
75
+ history = all_threads.get((user_id, thread_id), [])
76
+ return thread_id, history
77
+
78
+
79
+ # -----------------------
80
+ # Create New User
81
+ # -----------------------
82
+ def create_new_user(all_threads):
83
+
84
+ new_uid = new_user_id()
85
+ new_tid = new_thread_id()
86
+
87
+ all_threads[(new_uid, new_tid)] = []
88
+
89
+ return (
90
+ all_threads,
91
+ gr.update(choices=list(set([u for (u, _) in all_threads])), value=new_uid),
92
+ new_uid,
93
+ gr.update(choices=[new_tid], value=new_tid),
94
+ new_tid,
95
+ []
96
+ )
97
+
98
+
99
+ # -----------------------
100
+ # Switch User
101
+ # -----------------------
102
+ def switch_user(user_id, all_threads):
103
+
104
+ user_threads = [t for (u, t) in all_threads if u == user_id]
105
+
106
+ if not user_threads:
107
+ new_tid = new_thread_id()
108
+ all_threads[(user_id, new_tid)] = []
109
+ user_threads = [new_tid]
110
+
111
+ first_thread = user_threads[0]
112
+ history = all_threads.get((user_id, first_thread), [])
113
+
114
+ return (
115
+ user_id,
116
+ gr.update(choices=user_threads, value=first_thread),
117
+ first_thread,
118
+ history
119
+ )
120
+
121
+
122
+ # -----------------------
123
+ # UI
124
+ # -----------------------
125
+ with gr.Blocks() as demo:
126
+
127
+ user_state = gr.State(first_user)
128
+ thread_state = gr.State(first_thread)
129
+
130
+ threads_state = gr.State({
131
+ (first_user, first_thread): []
132
+ })
133
+
134
+ with gr.Row():
135
+
136
+ # Sidebar
137
+ with gr.Column(scale=1):
138
+
139
+ gr.Markdown("## 👤 Users")
140
+
141
+ user_dropdown = gr.Dropdown(
142
+ choices=[first_user],
143
+ value=first_user,
144
+ label="Select User"
145
+ )
146
+
147
+ new_user_btn = gr.Button("➕ New User")
148
+
149
+ gr.Markdown("## 🧵 Threads")
150
+
151
+ thread_radio = gr.Radio(
152
+ choices=[first_thread],
153
+ value=first_thread,
154
+ label="Select Thread"
155
+ )
156
+
157
+ new_chat_btn = gr.Button("➕ New Chat")
158
+
159
+ # Chat Area
160
+ with gr.Column(scale=4):
161
+
162
+ chatbot_ui = gr.Chatbot()
163
+ msg_box = gr.Textbox(placeholder="Type message and press Enter")
164
+
165
+ msg_box.submit(
166
+ chat_fn,
167
+ inputs=[msg_box, chatbot_ui, thread_state, user_state, threads_state],
168
+ outputs=[msg_box, chatbot_ui, threads_state],
169
+ )
170
+
171
+ # -----------------------
172
+ # New User
173
+ # -----------------------
174
+ new_user_btn.click(
175
+ create_new_user,
176
+ inputs=threads_state,
177
+ outputs=[
178
+ threads_state,
179
+ user_dropdown,
180
+ user_state,
181
+ thread_radio,
182
+ thread_state,
183
+ chatbot_ui
184
+ ]
185
+ )
186
+
187
+ # -----------------------
188
+ # Switch User
189
+ # -----------------------
190
+ user_dropdown.change(
191
+ switch_user,
192
+ inputs=[user_dropdown, threads_state],
193
+ outputs=[
194
+ user_state,
195
+ thread_radio,
196
+ thread_state,
197
+ chatbot_ui
198
+ ]
199
+ )
200
+
201
+ # -----------------------
202
+ # New Thread
203
+ # -----------------------
204
+ new_chat_btn.click(
205
+ create_new_thread,
206
+ inputs=[user_state, threads_state],
207
+ outputs=[
208
+ threads_state,
209
+ thread_radio,
210
+ thread_state,
211
+ chatbot_ui
212
+ ]
213
+ )
214
+
215
+ # -----------------------
216
+ # Switch Thread
217
+ # -----------------------
218
+ thread_radio.change(
219
+ switch_thread,
220
+ inputs=[thread_radio, user_state, threads_state],
221
+ outputs=[thread_state, chatbot_ui]
222
+ )
223
+
224
+
225
+ demo.launch()
226
+
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+ # import gradio as gr
236
+ # import uuid
237
+ # from langchain_core.messages import HumanMessage
238
+ # from memory_chatbot import chatbot
239
+
240
+
241
+ # # -----------------------
242
+ # # Generate IDs
243
+ # # -----------------------
244
+ # def new_thread_id():
245
+ # return "thread_" + str(uuid.uuid4())[:8]
246
+
247
+ # def new_user_id():
248
+ # return "user_" + str(uuid.uuid4())[:6]
249
+
250
+
251
+ # # -----------------------
252
+ # # Chat Function
253
+ # # -----------------------
254
+ # def chat_fn(message, chat_history, thread_id, user_id):
255
+
256
+ # config = {
257
+ # "configurable": {
258
+ # "thread_id": thread_id,
259
+ # "user_id": user_id
260
+ # }
261
+ # }
262
+
263
+ # res = chatbot.invoke(
264
+ # {"messages": [HumanMessage(content=message)]},
265
+ # config=config
266
+ # )
267
+
268
+ # ai_message = res["messages"][-1].content
269
+
270
+ # chat_history.append({"role": "user", "content": message})
271
+ # chat_history.append({"role": "assistant", "content": ai_message})
272
+
273
+ # return "", chat_history
274
+
275
+
276
+ # # -----------------------
277
+ # # New Chat (Reset Thread)
278
+ # # -----------------------
279
+ # def new_chat():
280
+ # return new_thread_id(), []
281
+
282
+
283
+ # # -----------------------
284
+ # # UI
285
+ # # -----------------------
286
+ # with gr.Blocks() as demo:
287
+
288
+ # # Hidden states
289
+ # user_state = gr.State(new_user_id())
290
+ # thread_state = gr.State(new_thread_id())
291
+
292
+ # gr.Markdown("# 🤖 AI Chatbot")
293
+
294
+ # chatbot_ui = gr.Chatbot(height=500)
295
+ # msg_box = gr.Textbox(placeholder="Type your message...")
296
+
297
+ # with gr.Row():
298
+ # send_btn = gr.Button("Send")
299
+ # new_chat_btn = gr.Button("🧹 New Chat")
300
+
301
+ # # Send message
302
+ # send_btn.click(
303
+ # chat_fn,
304
+ # inputs=[msg_box, chatbot_ui, thread_state, user_state],
305
+ # outputs=[msg_box, chatbot_ui],
306
+ # )
307
+
308
+ # msg_box.submit(
309
+ # chat_fn,
310
+ # inputs=[msg_box, chatbot_ui, thread_state, user_state],
311
+ # outputs=[msg_box, chatbot_ui],
312
+ # )
313
+
314
+ # # New chat (reset thread)
315
+ # new_chat_btn.click(
316
+ # new_chat,
317
+ # outputs=[thread_state, chatbot_ui]
318
+ # )
319
+
320
+
321
+ # demo.launch()
memory_chatbot.py CHANGED
@@ -2,7 +2,7 @@ import json
2
  from typing import TypedDict, Annotated
3
 
4
  from dotenv import load_dotenv
5
- from langchain_core.messages import BaseMessage, HumanMessage
6
  from langchain_groq import ChatGroq
7
 
8
  from langgraph.graph import START, END, StateGraph
@@ -44,6 +44,59 @@ llm = ChatGroq(
44
  # State
45
  # -----------------------------
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  class ChatState(TypedDict):
48
  messages: Annotated[list[BaseMessage], add_messages]
49
 
@@ -147,6 +200,38 @@ def memory_retrieval(state: ChatState, config, store):
147
 
148
  return {"messages": state["messages"]}
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  # -----------------------------
151
  # Chat Node
152
  # -----------------------------
 
2
  from typing import TypedDict, Annotated
3
 
4
  from dotenv import load_dotenv
5
+ from langchain_core.messages import BaseMessage, HumanMessage,ToolMessage,AIMessage
6
  from langchain_groq import ChatGroq
7
 
8
  from langgraph.graph import START, END, StateGraph
 
44
  # State
45
  # -----------------------------
46
 
47
+ def get_last_ai_message(messages):
48
+ """Get the final AI response safely"""
49
+ for msg in reversed(messages):
50
+ if isinstance(msg, AIMessage) and msg.content:
51
+ return msg.content if isinstance(msg.content, str) else str(msg.content)
52
+ return "No response"
53
+
54
+
55
+ def extract_tool_logs(messages, current_user_message):
56
+ """
57
+ Extract tool calls and tool outputs from the latest turn only
58
+ """
59
+ latest_turn = []
60
+ found_user_message = False
61
+
62
+ # Walk backwards until we find the current user message
63
+ for msg in reversed(messages):
64
+ latest_turn.append(msg)
65
+ if isinstance(msg, HumanMessage) and msg.content == current_user_message:
66
+ found_user_message = True
67
+ break
68
+
69
+ if found_user_message:
70
+ latest_turn = list(reversed(latest_turn))
71
+ else:
72
+ latest_turn = messages
73
+
74
+ logs = []
75
+
76
+ for msg in latest_turn:
77
+ # AI asked to call tool
78
+ if isinstance(msg, AIMessage) and getattr(msg, "tool_calls", None):
79
+ for call in msg.tool_calls:
80
+ tool_name = call.get("name", "unknown_tool")
81
+ tool_args = call.get("args", {})
82
+
83
+ logs.append(
84
+ f"### 🔧 Calling `{tool_name}`\n"
85
+ f"```json\n{json.dumps(tool_args, indent=2)}\n```"
86
+ )
87
+
88
+ # Tool returned output
89
+ elif isinstance(msg, ToolMessage):
90
+ tool_name = getattr(msg, "name", "unknown_tool")
91
+ tool_output = msg.content if isinstance(msg.content, str) else str(msg.content)
92
+
93
+ logs.append(
94
+ f"### ✅ Output from `{tool_name}`\n"
95
+ f"```\n{tool_output[:1000]}\n```"
96
+ )
97
+
98
+ return "\n\n".join(logs) if logs else "_No tools used in this response._"
99
+
100
  class ChatState(TypedDict):
101
  messages: Annotated[list[BaseMessage], add_messages]
102
 
 
200
 
201
  return {"messages": state["messages"]}
202
 
203
+
204
+ # def memory_retrieval(state: ChatState, config, store):
205
+
206
+ # user_id = config["configurable"]["user_id"]
207
+ # query = state["messages"][-1].content
208
+
209
+ # categories = [
210
+ # "preferences",
211
+ # "profile",
212
+ # "interests",
213
+ # "project"
214
+ # ]
215
+
216
+ # all_memories = []
217
+
218
+ # for category in categories:
219
+ # namespace = (user_id, category)
220
+ # results = store.search(namespace, query=query, limit=3)
221
+ # all_memories.extend(results)
222
+
223
+ # memory_text = "\n".join([f"{m.namespace[1]}: {m.value}" for m in all_memories])
224
+
225
+ # # FIX: Only return the new message(s) added in this step, not the whole state.
226
+ # if memory_text:
227
+ # return {
228
+ # "messages": [
229
+ # HumanMessage(content=f"Relevant user memories:\n{memory_text}")
230
+ # ]
231
+ # }
232
+
233
+ # return {}
234
+
235
  # -----------------------------
236
  # Chat Node
237
  # -----------------------------