Cause: The Streamlit app's expander or output sections may be appending older logs or improperly parsing data that is displayed. This could explain why the "UI logs" appear different or contain extra information not in the raw back-end logs.

Solution:
Ensure that the log pipeline from your back-end CrewManager and Agent layers is consistent. Check if there are additional formatting steps before rendering the logs to the UI.
Debug StreamToExpander or how logs are appended to agent_expander.


From the information you've provided and the screenshots shared, it seems like there are discrepancies between the raw logs from the agents' outputs and what is displayed in the user interface. This issue is likely due to how the logs are processed and presented in the front-end versus what is printed in the back-end console.

Here are possible causes and solutions for this behavior:

1. Mismatch Between Logs and UI Display
Cause: The Streamlit app's expander or output sections may be appending older logs or improperly parsing data that is displayed. This could explain why the "UI logs" appear different or contain extra information not in the raw back-end logs.
Solution:
Ensure that the log pipeline from your back-end CrewManager and Agent layers is consistent. Check if there are additional formatting steps before rendering the logs to the UI.
Debug StreamToExpander or how logs are appended to agent_expander.
2. JSON Serialization Errors
Cause: The tool is trying to serialize objects as dictionaries and failing. For instance:

python
Copy code
{"text": {"description": None, "type": "str"}}
The description field being None violates the expected schema. This could be due to:

Miscommunication between the Task input and the agent tools.
Validation logic issues when the agent interacts with TextToMoleculeTool.
Solution:

Validate the input to the tool and make sure description is populated before passing it to the tool.
Add logging in the back-end to catch invalid inputs earlier.
3. Streamlit State Management
Cause: Streamlit’s session state might be retaining and displaying older information due to improper clearing of state variables.
Solution: Explicitly reset st.session_state["generated"] and related variables after each task execution. For example:
python
Copy code
st.session_state["generated"] = []
st.session_state["results"] = []


# main.py

import os
import sys
import streamlit as st

from crewai import Task, Crew
from crewai.process import Process

# Update the import to fix deprecation warning
from langchain_community.chat_models import ChatOpenAI

from agents import create_agents
from stream_to_expander import StreamToExpander

# Set the OpenAI model name
os.environ["OPENAI_API_KEY"] = "sk-proj--A-L5FBmIV3asw5aj21LNq7F_LC3isEA"

OPENAI_MODEL_NAME = "gpt-3.5-turbo"

# Ensure the OpenAI API key is set
if "OPENAI_API_KEY" not in os.environ or os.environ["OPENAI_API_KEY"] == "your_openai_api_key_here":
    st.error("Please set your OpenAI API key as an environment variable.")
    st.stop()

# Setup Manager LLM
manager_llm = ChatOpenAI(model_name=OPENAI_MODEL_NAME, temperature=0)

# Streamlit App
st.set_page_config(page_title="Molecule Design Assistant", page_icon="🧪", layout="wide")

# Add GIF at the heading
st.markdown(
    """
    <div style='text-align: center;'>
        <img src='https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExaWNobDVjMjJpNTc1a2J6dm5oZW40eTdlbWMxcnN1NHZzOW43NWF1MiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/VcAt04a901woawqLv2/giphy.gif' alt='GIF Image' width='200'>
    </div>
    """,
    unsafe_allow_html=True,
)

st.markdown("<h1 style='text-align: center;'>🧪 Molecule Design Assistant</h1>", unsafe_allow_html=True)
st.markdown("<h3 style='text-align: center;'>Interact with AI agents to design and optimize molecules.</h3>", unsafe_allow_html=True)

# Initialize session state variables
if "generated" not in st.session_state:
    st.session_state["generated"] = []
if "past" not in st.session_state:
    st.session_state["past"] = []
if "input_text" not in st.session_state:
    st.session_state["input_text"] = ""
if "results" not in st.session_state:
    st.session_state["results"] = []
    
    
# Main Tabs
tab1, tab2 = st.tabs(["Main App", "Results Table"])

# Tab 1: Main Application
with tab1:
    # Create columns for layout
    col1, col2 = st.columns([3, 1])

    # User Input Section
    with col2:
        st.header("User Input")
        def get_text():
            input_text = st.text_area(
                label="Your Message",
                placeholder="Enter your request here...",
                value=st.session_state["input_text"],
                key="input",
                height=100,
            )
            return input_text

        user_input = get_text()
        submit_button = st.button(label="Submit", key="submit_btn")

        if submit_button:
            if user_input:
                st.session_state["past"].append(user_input)
                st.session_state["input_text"] = ""  # Clear input after submission

    # Agent Outputs Section
    with col1:
        st.header("Agent Outputs")
        agent_expander = st.expander("💬 Agent Conversations", expanded=False)

    # Conversation History Section
    with col2:
        if st.session_state["generated"]:
            st.subheader("Conversation History")
            for i in range(len(st.session_state["generated"])):
                with st.container():
                    st.markdown(f"**You:** {st.session_state['past'][i]}")
                    st.markdown(f"**Assistant:** {st.session_state['generated'][i]}")
                    st.markdown("---")

    # Function to Process User Request
    def process_user_request(input_text: str):
        try:
            sys.stdout = StreamToExpander(agent_expander)  # Redirect stdout to expander

            # Create agents with verbose output
            agents = create_agents(verbose=True)

            # Create Crew with Hierarchical Process
            crew = Crew(
                agents=agents,
                process=Process.hierarchical,
                manager_llm=manager_llm,
                memory=True,
                planning=True,
                verbose=True,
            )

            task = Task(
                description=input_text,
                expected_output="Provide the appropriate output based on the user's request.",
                agent=None,
            )
            crew.tasks = [task]
            result = crew.kickoff()

            sys.stdout = sys.__stdout__  # Reset stdout
            return result, agents
        except Exception as e:
            st.error(f"An error occurred during processing: {e}")
            sys.stdout = sys.__stdout__  # Reset stdout
            return None, None

    # Processing User Input
    if "past" in st.session_state and len(st.session_state["past"]) > len(st.session_state["generated"]):
        user_input = st.session_state["past"][-1]
        with col1:  # Place the spinner in the Agent Outputs section
            with st.spinner("🤖 **Agents at work...**"):
                output, agents = process_user_request(user_input)
        if output:
            st.session_state["generated"].append(output.raw if hasattr(output, "raw") else str(output))
            with col1:
                st.subheader("Final Answer")
                st.markdown(output.raw if hasattr(output, "raw") else str(output))
            st.session_state["results"].append({
                "Input": user_input,
                "Agents Used": ", ".join([agent.role for agent in agents]),
                "Output": output.raw if hasattr(output, "raw") else str(output),
            })


with tab2:
    st.header("Results Table")
    if st.session_state["results"]:
        import pandas as pd
        df = pd.DataFrame(st.session_state["results"])
        # Convert Output to string to avoid serialization issues
        df['Output'] = df['Output'].astype(str)
        st.table(df)
    else:
        st.write("No results yet.")

# Custom CSS for better UI
st.markdown(
    """
    <style>
    div.stButton > button:first-child {
        width: 100%;
        background-color: #2196F3 !important;  /* Changed to blue */
        color: white !important;
        border: none;
        padding: 10px 20px;
        text-align: center;
        font-size: 16px;
    }
    .stTextArea textarea {
        height: 100px !important;
    }
    </style>
    """,
    unsafe_allow_html=True,
)


# agents.py

from crewai import Agent
from tools.text_to_molecule_tool import TextToMoleculeTool
from tools.molecule_to_text_tool import MoleculeToTextTool
from tools.valid_molecule_tool import ValidMoleculeTool
from tools.molecule_optimizer_tool import MoleculeOptimizerTool
from tools.visualization_tool import VisualizationTool
from tools.rdkit_tools import CalculateLogPTool, CalculateMolWtTool, LipinskiRuleOfFiveTool, SimilarityMapTool

def create_agents(verbose=False):
    # Agent 1: Chemistry Expert with RDKit tools
    chemistry_expert = Agent(
        role="Chemistry Expert",
        goal="Provide detailed chemical analysis, calculate properties, and ensure molecule visualization.",
        backstory="""You are a senior chemist with expertise in molecule analysis, property calculation, and visualization. Your goal is to:
                    1. Validate the input molecule structure.
                    2. Calculate properties like LogP, molecular weight, and Lipinski's rule.
                    3. Generate a high-quality visualization of the molecule.
                    Ensure all outputs are in a consistent format for downstream use. If any step fails, provide a detailed error message for debugging.
        """,
        tools=[
            ValidMoleculeTool(),
            VisualizationTool(),
            CalculateLogPTool(),
            CalculateMolWtTool(),
            LipinskiRuleOfFiveTool(),
            SimilarityMapTool(),
        ],
        
        allow_delegation=True,
        verbose=verbose,
    )

    # Agent 2: Molecule Generator and Descriptor
    molecule_generator = Agent(
        role="Molecule Generator",
        goal="Generate valid molecular structures from text descriptions and convert molecules to textual descriptions",
        backstory="""You are a molecule design expert specializing in:
                    1. Converting textual descriptions into valid molecular structures.
                    2. Translating molecular structures (e.g., SMILES) into human-readable descriptions.

                    ### Instructions:
                    - For textual input:
                      - Generate a valid molecular structure that matches the description.
                      - Validate the generated molecule to ensure it is chemically sound.
                      - Provide the following outputs:
                        - **Molecule Name**: [Generated Name or 'N/A']
                        - **SMILES**: [SMILES String]
                        - **Description**: [Short textual description of the molecule]

                    - For SMILES input:
                      - Convert the given SMILES string into a human-readable textual description.
                      - Ensure the description is concise and accurate.

                    ### Error Handling:
                    - If the text description is unclear or cannot be translated into a valid molecule, provide an error message and suggest improvements or clarifications.
                    - If the SMILES string is invalid, notify the user and suggest corrections or alternatives.

                    ### Output Format:
                    Always present your outputs in the following structured format:
                    - **Input Type**: [Text Description or SMILES]
                    - **Input**: [User-provided input]
                    - **Generated Output**:
                      - **Molecule Name**: [Generated Name or 'N/A']
                      - **SMILES**: [SMILES String]
                      - **Description**: [Human-readable description of the molecule]
                    """,
        tools=[TextToMoleculeTool(), MoleculeToTextTool()],
        allow_delegation=True,
        verbose=verbose,
    )

    # Agent 3: Molecule Editor
    molecule_editor = Agent(
        role="Molecule Editor",
        goal="Refine and optimize molecular structures based on user-defined criteria",
        backstory="""You specialize in editing and optimizing molecular structures to achieve desired properties. 
                    - When given a molecule, suggest alternatives or optimizations that improve its target properties (e.g., molecular weight, solubility, stability).
                    - Always provide the rationale behind each suggestion.
                    Ensure outputs are in the following format:
                    - **Original Molecule**:
                      - **Name**: [Original Name or 'N/A']
                      - **SMILES**: [Original SMILES]
                    - **Optimized Molecule**:
                      - **Name**: [Optimized Name or 'N/A']
                      - **SMILES**: [Optimized SMILES]
                    - **Reason for Optimization**: [Explanation of changes and benefits]
                    """,
        tools=[MoleculeOptimizerTool()],
        allow_delegation=True,
        verbose=verbose,
    )

    # Additional agents (Agent 4 and Agent 5) can be added similarly when their tools are implemented

    return [chemistry_expert, molecule_generator, molecule_editor]


check these form the code and tell me the problems here 
ChatGPT said:
ChatGPT
Here are the potential issues in the provided code that may cause discrepancies between raw logs and the output displayed in the UI, and other runtime problems. I'll explain where the issues might arise and propose fixes:

1. Issue: Logs Mismatch Between Back-End and UI
Cause: StreamToExpander Implementation

The redirection of sys.stdout to StreamToExpander might not be resetting properly, causing older logs to append to the new ones. This would explain why logs in the UI seem to contain extra or unrelated information.

Solution:

Ensure that StreamToExpander has a clear initialization and reset mechanism for each session or log entry.
Add debug statements to confirm what is being redirected and appended.
Example Debug:

python
Copy code
sys.stdout = StreamToExpander(agent_expander)
print("Debug: Starting to process the request.")
Check StreamToExpander: Ensure the StreamToExpander properly clears buffers when switching tasks. If it holds on to previous outputs, this will cause old logs to persist.

2. Issue: JSON Serialization Errors
Cause: The TextToMoleculeTool expects a valid string, but the code is providing a nested dictionary. For instance:

json
Copy code
{"text": {"description": "some description", "type": "str"}}
However, it seems the tool schema expects a simple string:

json
Copy code
{"text": "some description"}
Solution: Update how the input is passed to the tool. Change the Tool Input format to match the expected schema.

Fix:

python
Copy code
tool_input = {"text": "2-methoxyphenol substituted by a hydroxymethyl group at position 4"}
Add a debug log before passing input to the tool to verify:

python
Copy code
print(f"Tool Input Debug: {tool_input}")
3. Issue: Streamlit State Management
Cause: Improper clearing of st.session_state variables can cause UI outputs to display older or mismatched results.

Solution:

Add explicit state resets for st.session_state variables after task completion.
Ensure all task-specific states are reset when moving to a new task.
Example:

python
Copy code
st.session_state["generated"] = []
st.session_state["results"] = []
st.session_state["past"] = []
st.session_state["input_text"] = ""
Add this reset logic after each task execution or during initialization.

4. Issue: Agent Workflow Logging
Cause: The process_user_request function relies on verbose agent logging, but errors or invalid input can break the flow.

Solution:

Add more granular logs at each step of the agent's workflow.
Capture errors explicitly and ensure they are logged cleanly to avoid breaking the flow.
Example:

python
Copy code
try:
    sys.stdout = StreamToExpander(agent_expander)
    agents = create_agents(verbose=True)
    print("Agents created successfully.")
except Exception as e:
    print(f"Error creating agents: {e}")
5. Issue: StreamToExpander Redirection
Cause: The redirection of sys.stdout may result in missed or incorrectly appended logs if the redirection is not properly restored.

Solution: Ensure sys.stdout is always reset, even during errors.

Example:

python
Copy code
try:
    sys.stdout = StreamToExpander(agent_expander)
    # Agent processing logic
except Exception as e:
    print(f"Error during processing: {e}")
finally:
    sys.stdout = sys.__stdout__