youngjin-langchain-tools 0.1.3__tar.gz → 0.1.4__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.
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/PKG-INFO +1 -1
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/pyproject.toml +1 -1
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/youngjin_langchain_tools/handlers/streamlit_langgraph_handler.py +79 -77
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/.gitignore +0 -0
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/LICENSE +0 -0
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/README.md +0 -0
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/youngjin_langchain_tools/__init__.py +0 -0
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/youngjin_langchain_tools/handlers/__init__.py +0 -0
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/youngjin_langchain_tools/utils/__init__.py +0 -0
- {youngjin_langchain_tools-0.1.3 → youngjin_langchain_tools-0.1.4}/youngjin_langchain_tools/utils/config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: youngjin-langchain-tools
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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
|
|
@@ -257,7 +257,7 @@ class StreamlitLanggraphHandler:
|
|
|
257
257
|
self._final_response: str = ""
|
|
258
258
|
self._status_container: Any = None
|
|
259
259
|
self._response_placeholder: Any = None
|
|
260
|
-
self.
|
|
260
|
+
self._thoughts_placeholder: Any = None # Placeholder for thoughts area
|
|
261
261
|
self._thought_history: List[Dict[str, Any]] = [] # History of old thoughts
|
|
262
262
|
self._current_thoughts: List[Dict[str, Any]] = [] # Current visible thoughts
|
|
263
263
|
|
|
@@ -356,8 +356,8 @@ class StreamlitLanggraphHandler:
|
|
|
356
356
|
|
|
357
357
|
# Create UI components
|
|
358
358
|
with self._container:
|
|
359
|
-
#
|
|
360
|
-
self.
|
|
359
|
+
# Thoughts area placeholder (manages history + current thoughts)
|
|
360
|
+
self._thoughts_placeholder = st.empty()
|
|
361
361
|
self._status_container = st.status(
|
|
362
362
|
self._config.thinking_label,
|
|
363
363
|
expanded=self._config.expand_new_thoughts
|
|
@@ -430,8 +430,6 @@ class StreamlitLanggraphHandler:
|
|
|
430
430
|
|
|
431
431
|
def _add_thought(self, thought_type: str, data: Dict[str, Any]) -> None:
|
|
432
432
|
"""Add a thought and manage history if max_thought_containers exceeded."""
|
|
433
|
-
import streamlit as st
|
|
434
|
-
|
|
435
433
|
thought = {"type": thought_type, "data": data}
|
|
436
434
|
self._current_thoughts.append(thought)
|
|
437
435
|
|
|
@@ -443,45 +441,62 @@ class StreamlitLanggraphHandler:
|
|
|
443
441
|
old_thought = self._current_thoughts.pop(0)
|
|
444
442
|
self._thought_history.append(old_thought)
|
|
445
443
|
|
|
446
|
-
|
|
447
|
-
|
|
444
|
+
# Re-render the entire thoughts area
|
|
445
|
+
self._render_thoughts()
|
|
448
446
|
|
|
449
|
-
def
|
|
450
|
-
"""
|
|
447
|
+
def _render_thought_item(self, thought: Dict[str, Any], in_history: bool = False) -> None:
|
|
448
|
+
"""Render a single thought item."""
|
|
451
449
|
import streamlit as st
|
|
452
450
|
|
|
453
|
-
if
|
|
454
|
-
|
|
451
|
+
if thought["type"] == "tool_call":
|
|
452
|
+
if self._config.show_tool_calls:
|
|
453
|
+
st.markdown(
|
|
454
|
+
f"{self._config.tool_call_emoji} "
|
|
455
|
+
f"**{thought['data']['name']}**: `{thought['data']['args']}`"
|
|
456
|
+
)
|
|
457
|
+
elif thought["type"] == "tool_result":
|
|
458
|
+
if self._config.show_tool_results:
|
|
459
|
+
tool_name = thought['data']['name']
|
|
460
|
+
content = thought['data']['content']
|
|
461
|
+
|
|
462
|
+
st.markdown(
|
|
463
|
+
f"{self._config.tool_complete_emoji} "
|
|
464
|
+
f"**{tool_name}** 완료"
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
if in_history:
|
|
468
|
+
# Shorter preview in history
|
|
469
|
+
max_len = 200
|
|
470
|
+
else:
|
|
471
|
+
max_len = self._config.max_tool_content_length
|
|
472
|
+
|
|
473
|
+
expanded = not self._config.collapse_completed_thoughts
|
|
474
|
+
with st.expander(f"📋 {tool_name} 결과 보기", expanded=expanded if not in_history else False):
|
|
475
|
+
if len(content) > max_len:
|
|
476
|
+
st.code(content[:max_len] + "\n... (truncated)", language="text")
|
|
477
|
+
else:
|
|
478
|
+
st.code(content, language="text")
|
|
479
|
+
|
|
480
|
+
def _render_thoughts(self) -> None:
|
|
481
|
+
"""Render all thoughts (history + current) in the placeholder."""
|
|
482
|
+
import streamlit as st
|
|
455
483
|
|
|
456
|
-
with self.
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
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")
|
|
484
|
+
with self._thoughts_placeholder.container():
|
|
485
|
+
# Render history expander if there are old thoughts
|
|
486
|
+
if self._thought_history:
|
|
487
|
+
with st.expander(f"📜 History ({len(self._thought_history)} items)", expanded=False):
|
|
488
|
+
for thought in self._thought_history:
|
|
489
|
+
self._render_thought_item(thought, in_history=True)
|
|
490
|
+
|
|
491
|
+
# Render current thoughts
|
|
492
|
+
for thought in self._current_thoughts:
|
|
493
|
+
self._render_thought_item(thought, in_history=False)
|
|
474
494
|
|
|
475
495
|
def _handle_updates(
|
|
476
496
|
self,
|
|
477
497
|
data: Dict[str, Any]
|
|
478
498
|
) -> Generator[Dict[str, Any], None, None]:
|
|
479
499
|
"""Handle 'updates' stream mode events."""
|
|
480
|
-
try:
|
|
481
|
-
import streamlit as st
|
|
482
|
-
except ImportError:
|
|
483
|
-
return
|
|
484
|
-
|
|
485
500
|
for source, update in data.items():
|
|
486
501
|
if not isinstance(update, dict):
|
|
487
502
|
continue
|
|
@@ -490,55 +505,42 @@ class StreamlitLanggraphHandler:
|
|
|
490
505
|
for msg in messages:
|
|
491
506
|
# Handle tool calls
|
|
492
507
|
if hasattr(msg, 'tool_calls') and msg.tool_calls:
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
tool_args = tc.get('args', {})
|
|
508
|
+
for tc in msg.tool_calls:
|
|
509
|
+
tool_name = tc.get('name', 'tool')
|
|
510
|
+
tool_args = tc.get('args', {})
|
|
497
511
|
|
|
498
|
-
|
|
499
|
-
|
|
512
|
+
# Add to thought tracking (this triggers re-render)
|
|
513
|
+
self._add_thought("tool_call", {"name": tool_name, "args": tool_args})
|
|
500
514
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
515
|
+
# Update status label to show current action
|
|
516
|
+
self._status_container.update(
|
|
517
|
+
label=f"{self._config.tool_call_emoji} {tool_name}...",
|
|
518
|
+
state="running"
|
|
519
|
+
)
|
|
506
520
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
521
|
+
yield {
|
|
522
|
+
"type": "tool_call",
|
|
523
|
+
"data": {"name": tool_name, "args": tool_args}
|
|
524
|
+
}
|
|
511
525
|
|
|
512
526
|
# Handle tool results
|
|
513
527
|
if source == "tools" and hasattr(msg, 'name'):
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
st.code(
|
|
531
|
-
tool_content[:self._config.max_tool_content_length]
|
|
532
|
-
+ "\n... (truncated)",
|
|
533
|
-
language="text"
|
|
534
|
-
)
|
|
535
|
-
else:
|
|
536
|
-
st.code(tool_content, language="text")
|
|
537
|
-
|
|
538
|
-
yield {
|
|
539
|
-
"type": "tool_result",
|
|
540
|
-
"data": {"name": tool_name, "content": tool_content}
|
|
541
|
-
}
|
|
528
|
+
tool_name = msg.name
|
|
529
|
+
tool_content = str(msg.content) if hasattr(msg, 'content') else ""
|
|
530
|
+
|
|
531
|
+
# Add to thought tracking (this triggers re-render)
|
|
532
|
+
self._add_thought("tool_result", {"name": tool_name, "content": tool_content})
|
|
533
|
+
|
|
534
|
+
# Update status to show thinking again
|
|
535
|
+
self._status_container.update(
|
|
536
|
+
label=self._config.thinking_label,
|
|
537
|
+
state="running"
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
yield {
|
|
541
|
+
"type": "tool_result",
|
|
542
|
+
"data": {"name": tool_name, "content": tool_content}
|
|
543
|
+
}
|
|
542
544
|
|
|
543
545
|
def _handle_messages(
|
|
544
546
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|