Merge pull request 'Added Agent Mode' (#7) from feature/backend_implementation into main
Reviewed-on: meulilivio/AISE1_Project#7
This commit is contained in:
commit
6bc71fec32
181
frontend/chat.py
181
frontend/chat.py
@ -2,10 +2,162 @@ import streamlit as st
|
||||
from backend.managers.chat_manager import ChatManager
|
||||
from backend.managers.system_prompter import SystemPrompter
|
||||
|
||||
def render_chat():
|
||||
st.subheader("Chat with AI Assistant")
|
||||
|
||||
chat_section = st.container()
|
||||
# ── Agent Mode helpers ────────────────────────────────────────────────────────
|
||||
|
||||
def _start_agent(task: str):
|
||||
"""Initialise a fresh CodingAgent, start the task, and propose the first action."""
|
||||
from backend.agent.coding_agent import CodingAgent
|
||||
agent = CodingAgent()
|
||||
agent.start_task(task)
|
||||
action = agent.propose_next_action()
|
||||
st.session_state.coding_agent = agent
|
||||
st.session_state.agent_pending_action = action
|
||||
st.session_state.agent_status = "waiting_approval"
|
||||
st.session_state.agent_log = []
|
||||
|
||||
|
||||
def _approve_action():
|
||||
"""Execute the pending action, append it to the log, then propose the next step."""
|
||||
agent = st.session_state.coding_agent
|
||||
pending = st.session_state.agent_pending_action
|
||||
|
||||
result = agent.approve()
|
||||
|
||||
st.session_state.agent_log.append({
|
||||
"thought": pending.get("thought", ""),
|
||||
"tool": result["tool"],
|
||||
"arguments": result.get("arguments", {}),
|
||||
"result": result["result"],
|
||||
})
|
||||
|
||||
if result["is_done"]:
|
||||
st.session_state.agent_status = "done"
|
||||
st.session_state.agent_pending_action = None
|
||||
else:
|
||||
next_action = agent.propose_next_action()
|
||||
st.session_state.agent_pending_action = next_action
|
||||
st.session_state.agent_status = "waiting_approval"
|
||||
|
||||
|
||||
def _reject_action(feedback: str):
|
||||
"""Reject the pending action with optional feedback, then replan."""
|
||||
agent = st.session_state.coding_agent
|
||||
agent.reject(feedback or "Please try a different approach.")
|
||||
next_action = agent.propose_next_action()
|
||||
st.session_state.agent_pending_action = next_action
|
||||
st.session_state.agent_status = "waiting_approval"
|
||||
|
||||
|
||||
def _reset_agent():
|
||||
"""Reset all agent state back to idle."""
|
||||
st.session_state.coding_agent = None
|
||||
st.session_state.agent_status = "idle"
|
||||
st.session_state.agent_log = []
|
||||
st.session_state.agent_pending_action = None
|
||||
|
||||
|
||||
# ── Agent Mode UI ─────────────────────────────────────────────────────────────
|
||||
|
||||
def render_agent_mode():
|
||||
# Toggle must always be rendered so Streamlit keeps agent_mode=True in session_state
|
||||
st.toggle("Agent Mode", key="agent_mode")
|
||||
|
||||
agent_status = st.session_state.get("agent_status", "idle")
|
||||
agent_log = st.session_state.get("agent_log", [])
|
||||
|
||||
# ── Agent Log ────────────────────────────────────────────────────────────
|
||||
if agent_log:
|
||||
with st.expander(f"Agent Log — {len(agent_log)} step(s) completed", expanded=False):
|
||||
for i, step in enumerate(agent_log):
|
||||
st.markdown(f"**Step {i + 1} — `{step['tool']}`**")
|
||||
st.caption(f"Thought: {step['thought']}")
|
||||
if step.get("arguments"):
|
||||
with st.container():
|
||||
st.json(step["arguments"])
|
||||
result_text = step.get("result", "")
|
||||
if result_text.startswith("ERROR") or result_text.startswith("SYNTAX ERROR"):
|
||||
st.error(result_text)
|
||||
elif result_text.startswith("OK") or result_text.startswith("DONE"):
|
||||
st.success(result_text)
|
||||
else:
|
||||
st.code(result_text, language=None)
|
||||
st.divider()
|
||||
|
||||
# ── Idle: task input ──────────────────────────────────────────────────────
|
||||
if agent_status == "idle":
|
||||
task = st.text_area(
|
||||
"Describe what the agent should do:",
|
||||
key="agent_task_input",
|
||||
height=120,
|
||||
placeholder="e.g. Write a function that sorts a list and saves it to sorted.py",
|
||||
)
|
||||
if st.button("Start Agent", type="primary", use_container_width=True):
|
||||
if task.strip():
|
||||
with st.spinner("Agent is thinking..."):
|
||||
_start_agent(task.strip())
|
||||
st.rerun()
|
||||
else:
|
||||
st.warning("Please describe a task first.")
|
||||
|
||||
# ── Waiting: show proposed action + Approve / Reject ─────────────────────
|
||||
elif agent_status == "waiting_approval":
|
||||
pending = st.session_state.get("agent_pending_action", {})
|
||||
|
||||
st.markdown("**The agent wants to execute the following step:**")
|
||||
|
||||
with st.container(border=True):
|
||||
st.markdown("**Thought**")
|
||||
st.markdown(pending.get("thought", "—"))
|
||||
|
||||
st.markdown(f"**Tool:** `{pending.get('tool', '—')}`")
|
||||
|
||||
args = pending.get("arguments", {})
|
||||
if args:
|
||||
st.markdown("**Arguments:**")
|
||||
if "content" in args:
|
||||
display_args = {k: v for k, v in args.items() if k != "content"}
|
||||
if display_args:
|
||||
st.json(display_args)
|
||||
st.code(args["content"], language="python")
|
||||
else:
|
||||
st.json(args)
|
||||
|
||||
feedback = st.text_input(
|
||||
"Rejection feedback (optional):",
|
||||
key="agent_reject_feedback",
|
||||
placeholder="e.g. Use a different approach...",
|
||||
)
|
||||
|
||||
col1, col2, col3 = st.columns([2, 2, 3])
|
||||
with col1:
|
||||
if st.button("Approve", type="primary", use_container_width=True):
|
||||
with st.spinner("Executing and planning next step..."):
|
||||
_approve_action()
|
||||
st.rerun()
|
||||
with col2:
|
||||
if st.button("Reject", use_container_width=True):
|
||||
with st.spinner("Agent is replanning..."):
|
||||
_reject_action(feedback)
|
||||
st.rerun()
|
||||
with col3:
|
||||
if st.button("Abort Task", use_container_width=True):
|
||||
_reset_agent()
|
||||
st.rerun()
|
||||
|
||||
# ── Done ─────────────────────────────────────────────────────────────────
|
||||
elif agent_status == "done":
|
||||
last_result = agent_log[-1]["result"] if agent_log else ""
|
||||
st.success(f"Task completed! {last_result}")
|
||||
if st.button("New Task", use_container_width=True):
|
||||
_reset_agent()
|
||||
st.rerun()
|
||||
|
||||
|
||||
# ── Normal Chat ───────────────────────────────────────────────────────────────
|
||||
|
||||
def render_normal_chat():
|
||||
chat_section = st.container()
|
||||
setup_section = st.container()
|
||||
|
||||
with chat_section:
|
||||
@ -13,6 +165,8 @@ def render_chat():
|
||||
for message in st.session_state.chat_history:
|
||||
st.markdown(f"**{message['role'].capitalize()}:** {message['content']}")
|
||||
|
||||
st.toggle("Agent Mode", key="agent_mode")
|
||||
|
||||
# Clear the input field before the widget is rendered (Streamlit requirement)
|
||||
if st.session_state.get("_clear_chat_input"):
|
||||
st.session_state.chat_input = ""
|
||||
@ -36,15 +190,24 @@ def render_chat():
|
||||
ai_response = f"Error: {e}"
|
||||
|
||||
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
||||
st.session_state._clear_chat_input = True # Clear input on next rerun
|
||||
st.session_state._clear_chat_input = True
|
||||
st.rerun()
|
||||
|
||||
with setup_section:
|
||||
st.info("This is where you can set up your AI assistant. For now, this section is just a placeholder.")
|
||||
st.toggle("Use debug system prompt", key="use_system_prompt", value=True)
|
||||
with setup_section:
|
||||
st.info("This is where you can set up your AI assistant. For now, this section is just a placeholder.")
|
||||
st.toggle("Use debug system prompt", key="use_system_prompt", value=True)
|
||||
|
||||
# Here you could add options to configure the AI assistant, such as selecting a model, setting parameters, etc.
|
||||
|
||||
# ── Entry point ───────────────────────────────────────────────────────────────
|
||||
|
||||
def render_chat():
|
||||
if st.session_state.get("agent_mode", False):
|
||||
st.subheader("Coding Agent")
|
||||
render_agent_mode()
|
||||
else:
|
||||
st.subheader("Chat with AI Assistant")
|
||||
render_normal_chat()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
render_chat()
|
||||
render_chat()
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import streamlit as st
|
||||
from backend.managers.chat_manager import ChatManager
|
||||
|
||||
|
||||
def init_state():
|
||||
# Sidebar state initialization
|
||||
if "last_selected" not in st.session_state:
|
||||
@ -35,8 +36,23 @@ def init_state():
|
||||
# Chat state initialization
|
||||
if "chat_history" not in st.session_state:
|
||||
st.session_state.chat_history = []
|
||||
|
||||
|
||||
|
||||
|
||||
# Agent Mode state
|
||||
if "agent_mode" not in st.session_state:
|
||||
st.session_state.agent_mode = False
|
||||
|
||||
if "coding_agent" not in st.session_state:
|
||||
st.session_state.coding_agent = None
|
||||
|
||||
if "agent_status" not in st.session_state:
|
||||
st.session_state.agent_status = "idle"
|
||||
|
||||
if "agent_log" not in st.session_state:
|
||||
st.session_state.agent_log = []
|
||||
|
||||
if "agent_pending_action" not in st.session_state:
|
||||
st.session_state.agent_pending_action = None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_state()
|
||||
init_state()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user