youngjin-langchain-tools 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: youngjin-langchain-tools
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: LangGraph utilities for Streamlit - StreamlitLanggraphHandler and more
5
5
  Project-URL: Homepage, https://github.com/yourusername/youngjin-langchain-tools
6
6
  Project-URL: Documentation, https://github.com/yourusername/youngjin-langchain-tools#readme
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "youngjin-langchain-tools"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "LangGraph utilities for Streamlit - StreamlitLanggraphHandler and more"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -8,8 +8,8 @@ LangGraph agent responses in Streamlit applications.
8
8
  Replaces the deprecated StreamlitCallbackHandler for LangGraph-based agents.
9
9
  """
10
10
 
11
- from typing import Any, Dict, List, Optional, Union, Generator
12
- from dataclasses import dataclass, field
11
+ from typing import Any, Dict, List, Optional, Generator
12
+ from dataclasses import dataclass
13
13
  import logging
14
14
  import re
15
15
 
@@ -129,6 +129,13 @@ class StreamlitLanggraphHandlerConfig:
129
129
  expand_new_thoughts: bool = True
130
130
  """Whether to expand the status container to show tool calls."""
131
131
 
132
+ collapse_completed_thoughts: bool = True
133
+ """Whether to automatically collapse completed thought containers."""
134
+
135
+ max_thought_containers: int = 4
136
+ """Maximum number of thought containers to show at once.
137
+ When exceeded, oldest thoughts are moved to a 'History' expander."""
138
+
132
139
  max_tool_content_length: int = 2000
133
140
  """Maximum length of tool output to display before truncating."""
134
141
 
@@ -202,6 +209,8 @@ class StreamlitLanggraphHandler:
202
209
  container: Any,
203
210
  *,
204
211
  expand_new_thoughts: bool = True,
212
+ collapse_completed_thoughts: bool = True,
213
+ max_thought_containers: int = 4,
205
214
  max_tool_content_length: int = 2000,
206
215
  show_tool_calls: bool = True,
207
216
  show_tool_results: bool = True,
@@ -217,6 +226,11 @@ class StreamlitLanggraphHandler:
217
226
  Usually st.container() or similar.
218
227
  expand_new_thoughts: Whether to expand status container
219
228
  to show tool calls. Defaults to True.
229
+ collapse_completed_thoughts: Whether to collapse completed
230
+ thought containers. Defaults to True.
231
+ max_thought_containers: Maximum number of thought containers
232
+ to show at once. Oldest are moved to
233
+ 'History' expander. Defaults to 4.
220
234
  max_tool_content_length: Maximum characters of tool output
221
235
  to display. Defaults to 2000.
222
236
  show_tool_calls: Whether to show tool call info. Defaults to True.
@@ -230,6 +244,8 @@ class StreamlitLanggraphHandler:
230
244
  else:
231
245
  self._config = StreamlitLanggraphHandlerConfig(
232
246
  expand_new_thoughts=expand_new_thoughts,
247
+ collapse_completed_thoughts=collapse_completed_thoughts,
248
+ max_thought_containers=max_thought_containers,
233
249
  max_tool_content_length=max_tool_content_length,
234
250
  show_tool_calls=show_tool_calls,
235
251
  show_tool_results=show_tool_results,
@@ -241,6 +257,9 @@ class StreamlitLanggraphHandler:
241
257
  self._final_response: str = ""
242
258
  self._status_container: Any = None
243
259
  self._response_placeholder: Any = None
260
+ self._history_placeholder: Any = None # Placeholder for history expander
261
+ self._thought_history: List[Dict[str, Any]] = [] # History of old thoughts
262
+ self._current_thoughts: List[Dict[str, Any]] = [] # Current visible thoughts
244
263
 
245
264
  @property
246
265
  def config(self) -> StreamlitLanggraphHandlerConfig:
@@ -332,9 +351,13 @@ class StreamlitLanggraphHandler:
332
351
 
333
352
  # Reset state
334
353
  self._final_response = ""
354
+ self._thought_history = []
355
+ self._current_thoughts = []
335
356
 
336
357
  # Create UI components
337
358
  with self._container:
359
+ # History expander placeholder (will be shown when needed)
360
+ self._history_placeholder = st.empty()
338
361
  self._status_container = st.status(
339
362
  self._config.thinking_label,
340
363
  expanded=self._config.expand_new_thoughts
@@ -405,6 +428,50 @@ class StreamlitLanggraphHandler:
405
428
 
406
429
  yield {"type": "complete", "data": {"response": self._final_response}}
407
430
 
431
+ def _add_thought(self, thought_type: str, data: Dict[str, Any]) -> None:
432
+ """Add a thought and manage history if max_thought_containers exceeded."""
433
+ import streamlit as st
434
+
435
+ thought = {"type": thought_type, "data": data}
436
+ self._current_thoughts.append(thought)
437
+
438
+ # Check if we need to move old thoughts to history
439
+ max_containers = self._config.max_thought_containers
440
+ if len(self._current_thoughts) > max_containers:
441
+ # Move oldest thoughts to history
442
+ while len(self._current_thoughts) > max_containers:
443
+ old_thought = self._current_thoughts.pop(0)
444
+ self._thought_history.append(old_thought)
445
+
446
+ # Update history expander
447
+ self._update_history_expander()
448
+
449
+ def _update_history_expander(self) -> None:
450
+ """Update the history expander with old thoughts."""
451
+ import streamlit as st
452
+
453
+ if not self._thought_history:
454
+ return
455
+
456
+ with self._history_placeholder.container():
457
+ with st.expander(f"📜 History ({len(self._thought_history)} items)", expanded=False):
458
+ for thought in self._thought_history:
459
+ if thought["type"] == "tool_call":
460
+ st.markdown(
461
+ f"{self._config.tool_call_emoji} "
462
+ f"**{thought['data']['name']}**: `{thought['data']['args']}`"
463
+ )
464
+ elif thought["type"] == "tool_result":
465
+ st.markdown(
466
+ f"{self._config.tool_complete_emoji} "
467
+ f"**{thought['data']['name']}** 완료"
468
+ )
469
+ content = thought['data']['content']
470
+ if len(content) > 200: # Shorter preview in history
471
+ st.code(content[:200] + "\n... (truncated)", language="text")
472
+ else:
473
+ st.code(content, language="text")
474
+
408
475
  def _handle_updates(
409
476
  self,
410
477
  data: Dict[str, Any]
@@ -428,6 +495,9 @@ class StreamlitLanggraphHandler:
428
495
  tool_name = tc.get('name', 'tool')
429
496
  tool_args = tc.get('args', {})
430
497
 
498
+ # Add to thought tracking
499
+ self._add_thought("tool_call", {"name": tool_name, "args": tool_args})
500
+
431
501
  with self._status_container:
432
502
  st.write(
433
503
  f"{self._config.tool_call_emoji} "
@@ -445,12 +515,17 @@ class StreamlitLanggraphHandler:
445
515
  tool_name = msg.name
446
516
  tool_content = str(msg.content) if hasattr(msg, 'content') else ""
447
517
 
518
+ # Add to thought tracking
519
+ self._add_thought("tool_result", {"name": tool_name, "content": tool_content})
520
+
448
521
  with self._status_container:
449
522
  st.write(
450
523
  f"{self._config.tool_complete_emoji} "
451
524
  f"**{tool_name}** 완료"
452
525
  )
453
- with st.expander(f"📋 {tool_name} 결과 보기", expanded=False):
526
+ # Collapse based on config
527
+ expanded = not self._config.collapse_completed_thoughts
528
+ with st.expander(f"📋 {tool_name} 결과 보기", expanded=expanded):
454
529
  if len(tool_content) > self._config.max_tool_content_length:
455
530
  st.code(
456
531
  tool_content[:self._config.max_tool_content_length]