diff --git a/MANIFEST.in b/MANIFEST.in index f37bbc38..0d345542 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,8 +1,8 @@ # Include all Python files in agentpress directory -recursive-include agentpress *.py +recursive-include core *.py # Include example files -recursive-include agentpress/examples * +recursive-include core/examples * # Include any other necessary files include LICENSE diff --git a/README.md b/README.md index 1aae12b7..46ef72b4 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,12 @@ When you run `agentpress init` and select the example agent – you will get cod You can find the complete implementation in our [example-agent](agentpress/examples/example-agent/agent.py) directory. +5. Thread Viewer + +Run the thread viewer to view messages of threads in a stylisedweb UI: +```bash +streamlit run agentpress/ui.py +``` ## Development diff --git a/agentpress/cli.py b/core/cli.py similarity index 99% rename from agentpress/cli.py rename to core/cli.py index 0cd69203..54ae8637 100644 --- a/agentpress/cli.py +++ b/core/cli.py @@ -13,7 +13,7 @@ MODULES = { }, "thread_manager": { "required": True, - "files": ["thread_manager.py"], + "files": ["thread_manager.py", "ui.py"], "description": "Message thread management module - Manages conversation history and message flows" }, "tool_system": { diff --git a/agentpress/examples/example-agent/agent.py b/core/examples/example-agent/agent.py similarity index 100% rename from agentpress/examples/example-agent/agent.py rename to core/examples/example-agent/agent.py diff --git a/agentpress/examples/example-agent/tools/files_tool.py b/core/examples/example-agent/tools/files_tool.py similarity index 100% rename from agentpress/examples/example-agent/tools/files_tool.py rename to core/examples/example-agent/tools/files_tool.py diff --git a/agentpress/examples/example-agent/tools/terminal_tool.py b/core/examples/example-agent/tools/terminal_tool.py similarity index 100% rename from agentpress/examples/example-agent/tools/terminal_tool.py rename to core/examples/example-agent/tools/terminal_tool.py diff --git a/agentpress/llm.py b/core/llm.py similarity index 100% rename from agentpress/llm.py rename to core/llm.py diff --git a/agentpress/state_manager.py b/core/state_manager.py similarity index 100% rename from agentpress/state_manager.py rename to core/state_manager.py diff --git a/agentpress/thread_manager.py b/core/thread_manager.py similarity index 100% rename from agentpress/thread_manager.py rename to core/thread_manager.py diff --git a/agentpress/tool.py b/core/tool.py similarity index 100% rename from agentpress/tool.py rename to core/tool.py diff --git a/agentpress/tool_registry.py b/core/tool_registry.py similarity index 100% rename from agentpress/tool_registry.py rename to core/tool_registry.py diff --git a/core/ui.py b/core/ui.py new file mode 100644 index 00000000..b14f12c3 --- /dev/null +++ b/core/ui.py @@ -0,0 +1,119 @@ +import streamlit as st +import json +import os +from datetime import datetime + +def load_thread_files(threads_dir: str): + """Load all thread files from the threads directory.""" + thread_files = [] + if os.path.exists(threads_dir): + for file in os.listdir(threads_dir): + if file.endswith('.json'): + thread_files.append(file) + return thread_files + +def load_thread_content(thread_file: str, threads_dir: str): + """Load the content of a specific thread file.""" + with open(os.path.join(threads_dir, thread_file), 'r') as f: + return json.load(f) + +def format_message_content(content): + """Format message content handling both string and list formats.""" + if isinstance(content, str): + return content + elif isinstance(content, list): + formatted_content = [] + for item in content: + if item.get('type') == 'text': + formatted_content.append(item['text']) + elif item.get('type') == 'image_url': + formatted_content.append("[Image]") + return "\n".join(formatted_content) + return str(content) + +def main(): + st.title("Thread Viewer") + + # Directory selection in sidebar + st.sidebar.title("Configuration") + + # Initialize session state with default directory + if 'threads_dir' not in st.session_state: + default_dir = "./threads" + if os.path.exists(default_dir): + st.session_state.threads_dir = default_dir + + # Use Streamlit's file uploader for directory selection + uploaded_dir = st.sidebar.text_input( + "Enter threads directory path", + value="./threads" if not st.session_state.threads_dir else st.session_state.threads_dir, + placeholder="/path/to/threads", + help="Enter the full path to your threads directory" + ) + + # Automatically load directory if it exists + if os.path.exists(uploaded_dir): + st.session_state.threads_dir = uploaded_dir + else: + st.sidebar.error("Directory not found!") + + if st.session_state.threads_dir: + st.sidebar.success(f"Selected directory: {st.session_state.threads_dir}") + threads_dir = st.session_state.threads_dir + + # Thread selection + st.sidebar.title("Select Thread") + thread_files = load_thread_files(threads_dir) + + if not thread_files: + st.warning(f"No thread files found in '{threads_dir}'") + return + + selected_thread = st.sidebar.selectbox( + "Choose a thread file", + thread_files, + format_func=lambda x: f"Thread: {x.replace('.json', '')}" + ) + + if selected_thread: + thread_data = load_thread_content(selected_thread, threads_dir) + messages = thread_data.get("messages", []) + + # Display thread ID in sidebar + st.sidebar.text(f"Thread ID: {selected_thread.replace('.json', '')}") + + # Display messages in chat-like interface + for message in messages: + role = message.get("role", "unknown") + content = message.get("content", "") + + # Determine avatar based on role + if role == "assistant": + avatar = "🤖" + elif role == "user": + avatar = "👤" + elif role == "system": + avatar = "⚙️" + elif role == "tool": + avatar = "🔧" + else: + avatar = "❓" + + # Format the message container + with st.chat_message(role, avatar=avatar): + formatted_content = format_message_content(content) + st.markdown(formatted_content) + + if "tool_calls" in message: + st.markdown("**Tool Calls:**") + for tool_call in message["tool_calls"]: + st.code( + f"Function: {tool_call['function']['name']}\n" + f"Arguments: {tool_call['function']['arguments']}", + language="json" + ) + else: + st.sidebar.warning("Please enter and load a threads directory") + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 854974ff..383a6fb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,10 @@ click = "^8.1.7" questionary = "^2.0.1" [tool.poetry.scripts] -agentpress = "agentpress.cli:main" +agentpress = "core.cli:main" + +[[tool.poetry.packages]] +include = "core" [build-system] requires = ["poetry-core"]