2020
2121
2222def main ():
23+ """Main Streamlit application for LangGraph Agent Chat."""
2324 st .title ("LangGraph Agent Chat" )
2425 initialize_checkpoint ()
2526
27+ # === Sidebar: Conversation and Agent Management ===
2628 with st .sidebar :
2729 st .header ("💬 Conversations" )
2830
29- # Thread management
31+ # Thread management: Get existing threads and determine current thread
3032 threads , latest = get_threads (st .session_state .checkpoint )
3133 current = st .session_state .get ('thread_id' ) or latest or str (uuid .uuid4 ())
3234 st .session_state .thread_id = current
3335
36+ # Ensure current thread appears in the list
3437 if current not in threads :
3538 threads .insert (0 , current )
3639
40+ # Thread selection dropdown
3741 st .selectbox (
3842 "Select thread" ,
3943 threads ,
@@ -45,6 +49,7 @@ def main():
4549 st .button ("New chat" , on_click = lambda : setattr (st .session_state , 'thread_id' , str (uuid .uuid4 ())))
4650 st .button ("Delete current chat" , on_click = on_delete_thread , args = (st .session_state .thread_id ,))
4751
52+ # Streaming toggle
4853 use_streaming = st .checkbox (
4954 "Enable Streaming" ,
5055 value = True ,
@@ -55,7 +60,7 @@ def main():
5560 st .divider ()
5661 st .header ("⚙️ Agent Settings" )
5762
58- # Agent selection
63+ # Agent selection: Display available agents
5964 agent_names = [agent .get_name () for agent in AVAILABLE_AGENTS ]
6065 if not agent_names :
6166 st .warning ("No agents configured. Please add agents to AVAILABLE_AGENTS." )
@@ -73,10 +78,11 @@ def main():
7378 st .warning ("No agents configured. Please add agents to AVAILABLE_AGENTS." )
7479 st .stop ()
7580
81+ # Render agent-specific configuration UI
7682 st .subheader ("Agent Options" )
7783 options = selected_agent_config .render_options ()
7884
79- # Rebuild agent if needed
85+ # Rebuild agent if configuration changed
8086 prev_name = st .session_state .get ("current_agent_name" )
8187 needs_rebuild = (
8288 prev_name != selected_name or
@@ -90,65 +96,75 @@ def main():
9096 st .session_state .current_agent_name = selected_name
9197 st .session_state .agent_options = options
9298
99+ # === Main Area: Chat Interface ===
100+ # Chat input with multimodal support (text + images)
93101 submission = st .chat_input (
94102 "Ask me anything!" ,
95103 accept_file = True ,
96104 file_type = ["jpg" , "jpeg" , "png" ],
97105 )
98106
107+ # Display conversation history
99108 display_chat_history (st .session_state .checkpoint , st .session_state .thread_id )
100109
110+ # Handle new user input
101111 if submission :
102- # Parse submission
112+ # Parse submission (handles both dict and object formats)
103113 if isinstance (submission , dict ):
104114 user_text = submission .get ("text" , "" )
105115 user_files = submission .get ("files" , [])
106116 else :
107117 user_text = getattr (submission , "text" , submission if isinstance (submission , str ) else "" )
108118 user_files = getattr (submission , "files" , [])
109119
120+ # Convert to LangChain message format
110121 content = convert_input_to_content (user_text , user_files )
111122
112123 # Display user message
113124 with st .chat_message ("user" ):
114125 render_content (content )
115126
116- # Assistant response
127+ # Generate and display assistant response
117128 use_streaming = st .session_state .get ("use_streaming" , True )
118129
119130 with st .chat_message ("assistant" ):
120131 if use_streaming :
121- # Stream response with fixed order: thinking → tools → text
132+ # Streaming mode: Display thinking, tools, and text in separate containers
133+ # This ensures proper ordering even when messages arrive out of order
122134 thinking_container = st .container ()
123135 tools_container = st .container ()
124136 text_container = st .container ()
125137 text_buffer = []
126138
127139 def render_to_container (title , payload ):
140+ """Route thinking/tool messages to appropriate containers."""
128141 target = thinking_container if "Thinking" in title else tools_container
129142 with target :
130143 render_tool (title , payload )
131144
132145 with text_container :
133146 text_element = st .empty ()
134147
148+ # Stream agent response
135149 stream = st .session_state .agent .stream (
136150 {"messages" : [HumanMessage (content = content )]}, # type: ignore[arg-type]
137151 config = {"configurable" : {"thread_id" : st .session_state .thread_id }},
138152 stream_mode = "messages" ,
139153 )
140154
155+ # Process stream and display text chunks incrementally
141156 for text_chunk in extract_text_chunks (stream , tool_callback = render_to_container ):
142157 text_buffer .append (text_chunk )
143158 text_element .markdown ("" .join (text_buffer ))
144159 else :
145- # Invoke (non -streaming)
160+ # Non -streaming mode: Invoke agent and wait for complete response
146161 with st .spinner ("Processing..." ):
147162 st .session_state .agent .invoke (
148163 {"messages" : [HumanMessage (content = content )]}, # type: ignore[arg-type]
149164 config = {"configurable" : {"thread_id" : st .session_state .thread_id }},
150165 )
151166
167+ # Rerun to display the new message from history
152168 st .rerun ()
153169
154170
0 commit comments