"""Centralised session-state initialisation for the Streamlit app. All keys used throughout the app are declared here with their default values. Calling init_state() at the top of app.py ensures every key exists before any page tries to read it, preventing KeyError on the first load. """ import streamlit as st from backend.managers.chat_manager import ChatManager def init_state(): # Sidebar state initialization # last_selected tracks the previously clicked tree node to detect new clicks if "last_selected" not in st.session_state: st.session_state.last_selected = None # Absolute path and workspace-relative path of the currently highlighted folder if "selected_folder" not in st.session_state: st.session_state.selected_folder = None if "selected_folder_rel" not in st.session_state: st.session_state.selected_folder_rel = None # Chat manager (persists across reruns) # ChatManager keeps the full conversation history in memory across reruns if "chat_manager" not in st.session_state: st.session_state.chat_manager = ChatManager() # Editor state initialization # List of absolute file paths that are currently open as tabs if "open_files" not in st.session_state: """A list of currently open file paths - absolute paths only. The order determines the tab order in the UI. Format: [ "path/to/file1.py", "path/to/file2.js", ... ] """ st.session_state.open_files = [] # Dict mapping file path → current editor content (may be unsaved) if "files_content" not in st.session_state: """A dictionary mapping file paths to their current content in the editor. Format: { "path/to/file.py": "file content as string", ... } """ st.session_state.files_content = {} # Absolute path of the file whose tab is currently active if "active_file" not in st.session_state: """The currently active file in the editor (absolute path in string e.g. "/workspace/path/to/file.py"). Should be one of the paths in open_files or None if no file is open.""" st.session_state.active_file = None # Index of the active tab (used by st.tabs) if "active_tab" not in st.session_state: st.session_state.active_tab = 0 if "is_editing" not in st.session_state: st.session_state.is_editing = False if "code_suggestions" not in st.session_state: st.session_state.code_suggestions = [] # Output dict from the last code run: {stdout, stderr, return_code} if "code_execution_output" not in st.session_state: st.session_state.code_execution_output = "" # Chat state initialization # Flat list of {"role": ..., "content": ...} dicts shown as chat bubbles if "chat_history" not in st.session_state: st.session_state.chat_history = [] # Agent Mode state # Whether the UI is currently in Agent Mode (vs normal chat) if "agent_mode" not in st.session_state: st.session_state.agent_mode = False # The live CodingAgent instance while a task is running if "coding_agent" not in st.session_state: st.session_state.coding_agent = None # Current status of the agent: "idle" | "waiting_approval" | "done" if "agent_status" not in st.session_state: st.session_state.agent_status = "idle" # List of completed steps shown in the collapsible Agent Log if "agent_log" not in st.session_state: st.session_state.agent_log = [] # The action the agent proposed but has not yet been approved or rejected if "agent_pending_action" not in st.session_state: st.session_state.agent_pending_action = None # Web search results to be injected as context into the next AI message. # List of {"title": str, "url": str, "snippet": str} dicts, or empty list. if "search_results" not in st.session_state: st.session_state.search_results = [] if __name__ == "__main__": init_state()