File size: 6,053 Bytes
edfa748
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# pages/2_Control_Panel.py (Modifications for Step 3)

import streamlit as st
import time
import json
# Use the updated API-backed functions
from .ui_utils import (
    list_all_agents,
    get_agent_status,
    get_agent_logs,
    start_agent,
    stop_agent,
    update_agent_config,
)

st.set_page_config(page_title="Agent Control Panel", layout="wide")

st.title("🕹️ Multi-Agent Control Panel")
st.caption("Manage and monitor Tensorus agents via API.")

# Fetch agent list from API
agent_list = list_all_agents()

if not agent_list:
    st.error("Could not fetch agent list from API. Please ensure the backend is running and reachable.")
    st.stop()

# Create a mapping from name to ID for easier selection
# Handle potential duplicate names if necessary, though IDs should be unique
agent_options = {agent['name']: agent['id'] for agent in agent_list}
# Add ID to name if names aren't unique (optional robustness)
# agent_options = {f"{agent['name']} ({agent['id']})": agent['id'] for agent in agent_list}


selected_agent_name = st.selectbox("Select Agent:", options=agent_options.keys())

if selected_agent_name:
    selected_agent_id = agent_options[selected_agent_name]
    st.divider()
    st.subheader(f"Control: {selected_agent_name} (`{selected_agent_id}`)")

    # Use session state to store fetched status and logs for the selected agent
    # This avoids refetching constantly unless a refresh is triggered
    agent_state_key = f"agent_status_{selected_agent_id}"
    agent_logs_key = f"agent_logs_{selected_agent_id}"

    # Button to force refresh status and logs
    if st.button(f"🔄 Refresh Status & Logs##{selected_agent_id}"): # Unique key per agent
        st.session_state[agent_state_key] = get_agent_status(selected_agent_id)
        st.session_state[agent_logs_key] = get_agent_logs(selected_agent_id)
        st.rerun() # Rerun to display refreshed data

    # Fetch status if not in session state or refresh button wasn't just clicked
    if agent_state_key not in st.session_state:
        st.session_state[agent_state_key] = get_agent_status(selected_agent_id)

    status_info = st.session_state[agent_state_key]

    if status_info:
        status = status_info.get('status', 'unknown')
        status_color = "green" if status in ["running", "starting"] else ("orange" if status in ["stopping"] else ("red" if status in ["error"] else "grey"))
        st.markdown(f"Current Status: :{status_color}[**{status.upper()}**]")
        last_log_ts = status_info.get('last_log_timestamp')
        if last_log_ts:
            st.caption(f"Last Log Entry (approx.): {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(last_log_ts))}")
    else:
        st.error(f"Could not retrieve status for agent '{selected_agent_name}'.")

    # Control Buttons (Now call API functions)
    col1, col2, col3 = st.columns([1, 1, 5])
    is_running = status_info and status_info.get('status') == 'running'
    is_stopped = status_info and status_info.get('status') == 'stopped'

    with col1:
        start_disabled = not is_stopped # Disable if not stopped
        if st.button("▶️ Start", key=f"start_{selected_agent_id}", disabled=start_disabled):
            if start_agent(selected_agent_id): # API call returns success/fail
                # Trigger refresh after short delay to allow backend state change (optimistic)
                time.sleep(1.0)
                # Clear state cache and rerun
                if agent_state_key in st.session_state: del st.session_state[agent_state_key]
                if agent_logs_key in st.session_state: del st.session_state[agent_logs_key]
                st.rerun()
    with col2:
        stop_disabled = not is_running # Disable if not running
        if st.button("⏹️ Stop", key=f"stop_{selected_agent_id}", disabled=stop_disabled):
            if stop_agent(selected_agent_id): # API call returns success/fail
                time.sleep(1.0)
                if agent_state_key in st.session_state: del st.session_state[agent_state_key]
                if agent_logs_key in st.session_state: del st.session_state[agent_logs_key]
                st.rerun()

    st.divider()

    # Configuration & Logs
    tab1, tab2 = st.tabs(["Configuration", "Logs"])

    with tab1:
        if status_info and 'config' in status_info:
            current_config = status_info['config']
            st.write("Current configuration:")
            st.json(current_config)

            with st.expander("Edit configuration"):
                form = st.form(key=f"cfg_form_{selected_agent_id}")
                config_text = form.text_area(
                    "Configuration JSON",
                    value=json.dumps(current_config, indent=2),
                    height=200,
                )
                submitted = form.form_submit_button("Update")
                if submitted:
                    try:
                        new_cfg = json.loads(config_text)
                        if update_agent_config(selected_agent_id, new_cfg):
                            if agent_state_key in st.session_state:
                                del st.session_state[agent_state_key]
                            time.sleep(0.5)
                            st.rerun()
                    except json.JSONDecodeError as e:
                        form.error(f"Invalid JSON: {e}")
        else:
            st.warning("Configuration not available.")

    with tab2:
        st.write("Recent logs (fetched from API):")
        # Fetch logs if not in session state
        if agent_logs_key not in st.session_state:
            st.session_state[agent_logs_key] = get_agent_logs(selected_agent_id)

        logs = st.session_state[agent_logs_key]
        if logs is not None:
            st.code("\n".join(logs), language="log")
        else:
            st.error("Could not retrieve logs.")

else:
    st.info("Select an agent from the dropdown above.")