some implementetd stuff
This commit is contained in:
parent
1a5bd6633a
commit
241c6580f3
@ -21,6 +21,7 @@ class ChatManager:
|
|||||||
self.api_port = os.getenv("PORT")
|
self.api_port = os.getenv("PORT")
|
||||||
self.api_key = os.getenv("API_KEY")
|
self.api_key = os.getenv("API_KEY")
|
||||||
self.model = os.getenv("MODEL")
|
self.model = os.getenv("MODEL")
|
||||||
|
self.max_tokens = 2000
|
||||||
|
|
||||||
# API endpoint URL (OpenAI-compatible format)
|
# API endpoint URL (OpenAI-compatible format)
|
||||||
self.api_url = f"http://{self.api_host}:{self.api_port}/v1/chat/completions"
|
self.api_url = f"http://{self.api_host}:{self.api_port}/v1/chat/completions"
|
||||||
@ -64,7 +65,7 @@ class ChatManager:
|
|||||||
"model": self.model,
|
"model": self.model,
|
||||||
"messages": self.chat_history,
|
"messages": self.chat_history,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
"max_tokens": 2000,
|
"max_tokens": self.max_tokens,
|
||||||
"stream": False,
|
"stream": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
152
frontend/chat.py
152
frontend/chat.py
@ -1,11 +1,12 @@
|
|||||||
"""Chat view — renders both the normal chat interface and the Coding Agent mode."""
|
"""Chat view — renders both the normal chat interface and the Coding Agent mode."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
from backend.managers.chat_manager import ChatManager
|
from backend.managers.chat_manager import ChatManager
|
||||||
from backend.managers.system_prompter import SystemPrompter
|
from backend.managers.system_prompter import SystemPrompter
|
||||||
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
|
|
||||||
# ── Agent Mode helpers ────────────────────────────────────────────────────────
|
# ── Agent Mode helpers ────────────────────────────────────────────────────────
|
||||||
def _run_async(coro):
|
def _run_async(coro):
|
||||||
@ -210,39 +211,119 @@ def render_agent_mode():
|
|||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
|
|
||||||
|
# ── Normal Chat helpers ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _build_file_context() -> dict | None:
|
||||||
|
"""Return file context for the system prompt if a file is open and context is enabled.
|
||||||
|
|
||||||
|
Reads from files_content cache first; falls back to FileManager if the file
|
||||||
|
has not been loaded into the editor yet.
|
||||||
|
"""
|
||||||
|
if not st.session_state.get("include_file_context", True):
|
||||||
|
return None
|
||||||
|
active_file = st.session_state.get("active_file")
|
||||||
|
if not active_file:
|
||||||
|
return None
|
||||||
|
content = st.session_state.get("files_content", {}).get(active_file, "")
|
||||||
|
if not content:
|
||||||
|
try:
|
||||||
|
from backend.managers.file_manager import FileManager
|
||||||
|
fm = FileManager()
|
||||||
|
content = fm.read_file(Path(active_file)) or ""
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
return {"name": Path(active_file).name, "content": content}
|
||||||
|
|
||||||
|
|
||||||
|
@st.dialog("Clear Chat")
|
||||||
|
def _clear_chat_dialog():
|
||||||
|
"""Confirmation dialog before wiping the full conversation history."""
|
||||||
|
st.warning("All messages will be deleted. This cannot be undone.")
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
with col1:
|
||||||
|
if st.button("Clear", type="primary", use_container_width=True):
|
||||||
|
st.session_state.chat_manager.clear_history()
|
||||||
|
st.session_state.chat_history = []
|
||||||
|
st.rerun()
|
||||||
|
with col2:
|
||||||
|
if st.button("Cancel", use_container_width=True):
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
|
||||||
# ── Normal Chat ───────────────────────────────────────────────────────────────
|
# ── Normal Chat ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def render_normal_chat():
|
def render_normal_chat():
|
||||||
"""Render the standard multi-turn chat interface.
|
"""Render the standard multi-turn chat interface.
|
||||||
|
|
||||||
On the first message the system prompt is injected into the history.
|
Execution order on every rerun:
|
||||||
Each subsequent message appends to the same conversation so the AI retains
|
1. Apply model/token settings from the Settings panel (5e)
|
||||||
full context throughout the session.
|
2. Consume any pending debug message from the editor (5f)
|
||||||
|
3. Replay chat history
|
||||||
|
4. Handle chat input with updated system-prompt logic (5g)
|
||||||
|
5. Render Clear Chat button and Settings expander (5d, 5h)
|
||||||
"""
|
"""
|
||||||
|
chat_manager: ChatManager = st.session_state.chat_manager
|
||||||
|
|
||||||
|
# 5e — Apply model/token overrides from the Settings panel before any API call.
|
||||||
|
if st.session_state.get("selected_model"):
|
||||||
|
chat_manager.model = st.session_state.selected_model
|
||||||
|
if "chat_max_tokens" in st.session_state:
|
||||||
|
chat_manager.max_tokens = st.session_state.chat_max_tokens
|
||||||
|
|
||||||
|
# 5f — Consume a debug message forwarded from the editor's "Debug with AI" button.
|
||||||
|
pending_debug = st.session_state.pop("pending_debug_message", None)
|
||||||
|
if pending_debug:
|
||||||
|
if not chat_manager.get_history():
|
||||||
|
custom_prompt = st.session_state.get("custom_system_prompt", "").strip()
|
||||||
|
if custom_prompt:
|
||||||
|
chat_manager.add_message("system", custom_prompt)
|
||||||
|
else:
|
||||||
|
file_ctx = _build_file_context()
|
||||||
|
system_prompt = SystemPrompter.generate_prompt(file_ctx)
|
||||||
|
chat_manager.add_message("system", system_prompt)
|
||||||
|
|
||||||
|
with st.spinner("Sending debug info to AI..."):
|
||||||
|
try:
|
||||||
|
ai_response = chat_manager.send_message(pending_debug)
|
||||||
|
except Exception as e:
|
||||||
|
ai_response = f"Error: {e}"
|
||||||
|
|
||||||
|
st.session_state.chat_history.append({"role": "user", "content": pending_debug})
|
||||||
|
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
||||||
|
st.rerun()
|
||||||
|
return
|
||||||
|
|
||||||
# Replay the conversation history as chat bubbles (skip system messages).
|
# Replay the conversation history as chat bubbles (skip system messages).
|
||||||
for message in st.session_state.chat_history:
|
for message in st.session_state.chat_history:
|
||||||
role = message["role"]
|
if message["role"] == "system":
|
||||||
if role == "system":
|
|
||||||
continue
|
continue
|
||||||
with st.chat_message(role):
|
with st.chat_message(message["role"]):
|
||||||
st.markdown(message["content"])
|
st.markdown(message["content"])
|
||||||
|
|
||||||
# Chat input — Enter to send, no extra button needed
|
# Chat input — Enter to send, no extra button needed.
|
||||||
user_input = st.chat_input("Type your message here...")
|
user_input = st.chat_input("Type your message here...")
|
||||||
if user_input:
|
if user_input:
|
||||||
chat_manager = st.session_state.chat_manager
|
|
||||||
|
|
||||||
# On the very first user message, prepend the system prompt so the AI
|
# 5g — System-prompt logic: inject on first message, update on file change.
|
||||||
# knows it is a code assistant embedded in an editor.
|
|
||||||
if not chat_manager.get_history():
|
if not chat_manager.get_history():
|
||||||
system_prompt = SystemPrompter.generate_prompt()
|
custom_prompt = st.session_state.get("custom_system_prompt", "").strip()
|
||||||
chat_manager.add_message("system", system_prompt)
|
if custom_prompt:
|
||||||
|
chat_manager.add_message("system", custom_prompt)
|
||||||
|
else:
|
||||||
|
file_ctx = _build_file_context()
|
||||||
|
system_prompt = SystemPrompter.generate_prompt(file_ctx)
|
||||||
|
chat_manager.add_message("system", system_prompt)
|
||||||
|
elif st.session_state.get("active_file") and st.session_state.get("include_file_context", True):
|
||||||
|
# Follow-up messages: refresh the system prompt when the active file changes.
|
||||||
|
history = chat_manager.get_history()
|
||||||
|
if history and history[0]["role"] == "system":
|
||||||
|
file_ctx = _build_file_context()
|
||||||
|
if file_ctx:
|
||||||
|
history[0]["content"] = SystemPrompter.generate_prompt(file_ctx)
|
||||||
|
|
||||||
# Show user message immediately without waiting for response.
|
|
||||||
with st.chat_message("user"):
|
with st.chat_message("user"):
|
||||||
st.markdown(user_input)
|
st.markdown(user_input)
|
||||||
|
|
||||||
# Call the AI and show its response with a spinner while waiting.
|
|
||||||
with st.chat_message("assistant"):
|
with st.chat_message("assistant"):
|
||||||
with st.spinner("Thinking..."):
|
with st.spinner("Thinking..."):
|
||||||
try:
|
try:
|
||||||
@ -251,15 +332,44 @@ def render_normal_chat():
|
|||||||
ai_response = f"Error: {e}"
|
ai_response = f"Error: {e}"
|
||||||
st.markdown(ai_response)
|
st.markdown(ai_response)
|
||||||
|
|
||||||
st.session_state.chat_history.append({"role": "user", "content": user_input})
|
st.session_state.chat_history.append({"role": "user", "content": user_input})
|
||||||
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
# Rendered in the normal flow; JS above clones them to fixed positions
|
# 5d — Clear Chat opens a confirmation dialog instead of deleting immediately.
|
||||||
# and hides these originals.
|
if st.button("🗑️ Clear Chat"):
|
||||||
|
_clear_chat_dialog()
|
||||||
|
|
||||||
st.toggle("Agent Mode", key="agent_mode")
|
st.toggle("Agent Mode", key="agent_mode")
|
||||||
with st.expander("Settings", expanded=False):
|
|
||||||
st.toggle("Use debug system prompt", key="use_system_prompt", value=True)
|
# 5h — Settings expander: file context toggle, model, token limit, custom prompt.
|
||||||
|
with st.expander("⚙️ Settings", expanded=False):
|
||||||
|
st.toggle("Include current file as context", key="include_file_context", value=True)
|
||||||
|
|
||||||
|
st.divider()
|
||||||
|
|
||||||
|
default_model = chat_manager.model or ""
|
||||||
|
model_options = [default_model] if default_model else []
|
||||||
|
for m in ["claude-3-5-sonnet-20241022", "claude-3-haiku-20240307", "gpt-4o", "gpt-4o-mini"]:
|
||||||
|
if m not in model_options:
|
||||||
|
model_options.append(m)
|
||||||
|
st.selectbox("Model", model_options, key="selected_model")
|
||||||
|
|
||||||
|
st.slider(
|
||||||
|
"Max Response Tokens",
|
||||||
|
min_value=256, max_value=8000,
|
||||||
|
value=chat_manager.max_tokens,
|
||||||
|
step=256, key="chat_max_tokens",
|
||||||
|
)
|
||||||
|
|
||||||
|
st.divider()
|
||||||
|
|
||||||
|
st.text_area(
|
||||||
|
"Custom System Prompt (overrides default if set)",
|
||||||
|
key="custom_system_prompt",
|
||||||
|
height=120,
|
||||||
|
placeholder="Leave empty to use the default assistant prompt with optional file context.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ── Entry point ───────────────────────────────────────────────────────────────
|
# ── Entry point ───────────────────────────────────────────────────────────────
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
"""Code Editor view — renders the Ace editor, file tabs, and execution output."""
|
"""Code Editor view — renders the Ace editor, file tabs, and execution output."""
|
||||||
|
|
||||||
|
import ast
|
||||||
|
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
import streamlit_ace as st_ace
|
import streamlit_ace as st_ace
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -85,9 +87,13 @@ def _delete_dialog(abs_file_path: str):
|
|||||||
|
|
||||||
|
|
||||||
def run_active_file():
|
def run_active_file():
|
||||||
"""Execute the currently active file and store the result in session_state.
|
"""Execute the currently active file and store the result in exec_results[file_path].
|
||||||
Returns the execution result dict {stdout, stderr, return_code}, or None
|
|
||||||
if no active file is set.
|
Runs an ast.parse() check first — if the syntax is invalid the file is not
|
||||||
|
executed and ast_error=True is stored so the UI can show a targeted warning.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The result dict, or None if no active file is set.
|
||||||
"""
|
"""
|
||||||
active_file = st.session_state.active_file
|
active_file = st.session_state.active_file
|
||||||
|
|
||||||
@ -97,10 +103,20 @@ def run_active_file():
|
|||||||
|
|
||||||
execution_engine = ExecutionEngine()
|
execution_engine = ExecutionEngine()
|
||||||
debug_logger = DebugLogger()
|
debug_logger = DebugLogger()
|
||||||
|
|
||||||
debug_logger.clear()
|
debug_logger.clear()
|
||||||
debug_logger.log(f"Executing code from {active_file}...")
|
debug_logger.log(f"Executing code from {active_file}...")
|
||||||
|
|
||||||
|
# ast check — only for Python files
|
||||||
|
if Path(active_file).suffix == ".py":
|
||||||
|
source = st.session_state.get("files_content", {}).get(active_file, "")
|
||||||
|
try:
|
||||||
|
ast.parse(source)
|
||||||
|
except SyntaxError as e:
|
||||||
|
result = {"stdout": "", "stderr": str(e), "return_code": -1, "ast_error": True}
|
||||||
|
st.session_state.exec_results[active_file] = result
|
||||||
|
debug_logger.log_error(f"Syntax error: {e}")
|
||||||
|
return result
|
||||||
|
|
||||||
with st.spinner(f"Running {Path(active_file).name}..."):
|
with st.spinner(f"Running {Path(active_file).name}..."):
|
||||||
output = execution_engine.run_code(Path(active_file))
|
output = execution_engine.run_code(Path(active_file))
|
||||||
|
|
||||||
@ -109,12 +125,13 @@ def run_active_file():
|
|||||||
else:
|
else:
|
||||||
debug_logger.log_error(f"Execution failed with exit code {output['rc']}.")
|
debug_logger.log_error(f"Execution failed with exit code {output['rc']}.")
|
||||||
|
|
||||||
st.session_state.code_execution_output = {
|
result = {
|
||||||
"stdout": output["stdout"],
|
"stdout": output["stdout"],
|
||||||
"stderr": output["stderr"],
|
"stderr": output["stderr"],
|
||||||
"return_code": output["rc"]
|
"return_code": output["rc"],
|
||||||
|
"ast_error": False,
|
||||||
}
|
}
|
||||||
result = st.session_state.code_execution_output
|
st.session_state.exec_results[active_file] = result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def render_editor():
|
def render_editor():
|
||||||
@ -132,6 +149,24 @@ def render_editor():
|
|||||||
tab_names = [Path(f).name for f in st.session_state.open_files]
|
tab_names = [Path(f).name for f in st.session_state.open_files]
|
||||||
tabs = st.tabs(tab_names)
|
tabs = st.tabs(tab_names)
|
||||||
|
|
||||||
|
# Tab-Sprung via JavaScript — pop() verhindert Loop bei jedem Rerun.
|
||||||
|
# Wenn _jump_to_tab gesetzt ist, klickt das Script den richtigen Tab an.
|
||||||
|
jump_target = st.session_state.pop("_jump_to_tab", None)
|
||||||
|
if jump_target and jump_target in st.session_state.open_files:
|
||||||
|
idx = st.session_state.open_files.index(jump_target)
|
||||||
|
st.components.v1.html(
|
||||||
|
f"""<script>
|
||||||
|
(function() {{
|
||||||
|
setTimeout(function() {{
|
||||||
|
const tabs = window.parent.document
|
||||||
|
.querySelectorAll('button[data-baseweb="tab"]');
|
||||||
|
if (tabs[{idx}]) tabs[{idx}].click();
|
||||||
|
}}, 100);
|
||||||
|
}})();
|
||||||
|
</script>""",
|
||||||
|
height=0,
|
||||||
|
)
|
||||||
|
|
||||||
for idx, file_path in enumerate(st.session_state.open_files):
|
for idx, file_path in enumerate(st.session_state.open_files):
|
||||||
with tabs[idx]:
|
with tabs[idx]:
|
||||||
# Load file content from disk on first open; afterwards use the cached version.
|
# Load file content from disk on first open; afterwards use the cached version.
|
||||||
@ -179,36 +214,48 @@ def render_editor():
|
|||||||
if st.button("Delete File", key=f"delete_{file_path}"):
|
if st.button("Delete File", key=f"delete_{file_path}"):
|
||||||
_delete_dialog(file_path)
|
_delete_dialog(file_path)
|
||||||
|
|
||||||
if st.button("▶ Run Code", key="run_code"):
|
# ── Run + Output ──────────────────────────────────────────────────
|
||||||
result = run_active_file()
|
if st.button("▶ Run Code", key=f"run_code_{file_path}", type="primary"):
|
||||||
if not result:
|
run_active_file()
|
||||||
st.stop()
|
st.rerun()
|
||||||
|
|
||||||
st.subheader("Execution Output")
|
result = st.session_state.get("exec_results", {}).get(file_path)
|
||||||
|
if result:
|
||||||
|
st.subheader("Execution Output")
|
||||||
|
|
||||||
# Green on exit code 0 (success), red on anything else (error/crash).
|
if result.get("ast_error"):
|
||||||
if result["return_code"] == 0:
|
st.warning("⚠️ Syntax Error detected before execution — code was not run.")
|
||||||
st.success(f"Exit code: {result['return_code']}")
|
elif result["return_code"] == 0:
|
||||||
else:
|
st.success(f"✅ Exit code: 0")
|
||||||
st.error(f"Exit code: {result['return_code']}")
|
else:
|
||||||
|
st.error(f"❌ Exit code: {result['return_code']}")
|
||||||
|
|
||||||
if result["stdout"]:
|
# Debug with AI — only shown when there is an error or stderr output.
|
||||||
st.text_area(
|
if result["return_code"] != 0 or result.get("stderr"):
|
||||||
"Standard Output",
|
if st.button("🐛 Debug with AI", key=f"debug_with_ai_{file_path}", type="primary"):
|
||||||
value=result["stdout"],
|
file_name = Path(file_path).name
|
||||||
height=200,
|
error_text = result.get("stderr", "") or f"Exit code: {result['return_code']}"
|
||||||
disabled=True,
|
code_content = st.session_state.files_content.get(file_path, "")
|
||||||
key="run_stdout")
|
lang = LANG_MAP.get(Path(file_path).suffix, "python")
|
||||||
|
debug_message = (
|
||||||
|
f"I got an error while running **{file_name}**:\n\n"
|
||||||
|
f"**Error:** {error_text.strip()}\n"
|
||||||
|
f"**Exit Code:** {result['return_code']}\n\n"
|
||||||
|
f"**Here is the code:**\n```{lang}\n{code_content}\n```\n\n"
|
||||||
|
f"Can you help me fix this?"
|
||||||
|
)
|
||||||
|
st.session_state.pending_debug_message = debug_message
|
||||||
|
st.session_state["_navigate_to_chat"] = True
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
if result["stderr"]:
|
if result.get("stdout"):
|
||||||
st.text_area(
|
st.text_area("Standard Output", value=result["stdout"], height=200,
|
||||||
"Standard Error",
|
disabled=True, key=f"run_stdout_{file_path}")
|
||||||
value=result["stderr"],
|
if result.get("stderr"):
|
||||||
height=200,
|
st.text_area("Standard Error", value=result["stderr"], height=200,
|
||||||
disabled=True,
|
disabled=True, key=f"run_stderr_{file_path}")
|
||||||
key="run_stderr")
|
if not result.get("stdout") and not result.get("stderr"):
|
||||||
if not result["stdout"] and not result["stderr"]:
|
st.info("No output produced by the code execution.")
|
||||||
st.info("No output produced by the code execution.")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -173,9 +173,6 @@ def _delete_file_dialog(relative_file_path: str, file_name: str):
|
|||||||
if st.button("Delete", type="primary", use_container_width=True):
|
if st.button("Delete", type="primary", use_container_width=True):
|
||||||
if fm.delete_file(relative_file_path):
|
if fm.delete_file(relative_file_path):
|
||||||
abs_file_path = str(Path(fm.base_path) / relative_file_path)
|
abs_file_path = str(Path(fm.base_path) / relative_file_path)
|
||||||
print(f"Deleting file at absolute path: {abs_file_path}") # Debugging info
|
|
||||||
print(f"Current open files before deletion: {st.session_state.open_files}") # Debugging info
|
|
||||||
|
|
||||||
st.session_state.open_files.remove(abs_file_path)
|
st.session_state.open_files.remove(abs_file_path)
|
||||||
st.session_state.files_content.pop(abs_file_path, None)
|
st.session_state.files_content.pop(abs_file_path, None)
|
||||||
if st.session_state.active_file == abs_file_path:
|
if st.session_state.active_file == abs_file_path:
|
||||||
@ -257,7 +254,16 @@ def render_sidebar():
|
|||||||
Tree click handling:
|
Tree click handling:
|
||||||
- Clicking a file → appended to open_files, set as active_file
|
- Clicking a file → appended to open_files, set as active_file
|
||||||
- Clicking a folder → stored in selected_folder so the action bar appears
|
- Clicking a folder → stored in selected_folder so the action bar appears
|
||||||
|
|
||||||
|
Navigation flags (_navigate_to_editor, _navigate_to_chat) are consumed here
|
||||||
|
at the very top — before any widget is rendered — to avoid StreamlitAPIException.
|
||||||
"""
|
"""
|
||||||
|
# Consume navigation flags before any widget renders.
|
||||||
|
if st.session_state.pop("_navigate_to_editor", False):
|
||||||
|
st.session_state.radio_interface_options = "Code Editor"
|
||||||
|
if st.session_state.pop("_navigate_to_chat", False):
|
||||||
|
st.session_state.radio_interface_options = "Chat with AI Assistant"
|
||||||
|
|
||||||
st.sidebar.title("Navigation")
|
st.sidebar.title("Navigation")
|
||||||
|
|
||||||
navigation_section = st.sidebar.container()
|
navigation_section = st.sidebar.container()
|
||||||
@ -294,13 +300,16 @@ def render_sidebar():
|
|||||||
abs_path = fm.base_path / selected_path
|
abs_path = fm.base_path / selected_path
|
||||||
|
|
||||||
if abs_path.is_file():
|
if abs_path.is_file():
|
||||||
# Open the file in the editor.
|
# Open the file in the editor, jump to its tab,
|
||||||
|
# and switch the view to the Editor pane.
|
||||||
st.session_state.selected_folder = None
|
st.session_state.selected_folder = None
|
||||||
st.session_state.selected_folder_rel = None
|
st.session_state.selected_folder_rel = None
|
||||||
file_str = str(abs_path)
|
file_str = str(abs_path)
|
||||||
if file_str not in st.session_state.open_files:
|
if file_str not in st.session_state.open_files:
|
||||||
st.session_state.open_files.append(file_str)
|
st.session_state.open_files.append(file_str)
|
||||||
st.session_state.active_file = file_str
|
st.session_state.active_file = file_str
|
||||||
|
st.session_state._jump_to_tab = file_str
|
||||||
|
st.session_state._navigate_to_editor = True
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
elif abs_path.is_dir():
|
elif abs_path.is_dir():
|
||||||
|
|||||||
@ -88,6 +88,21 @@ def init_state():
|
|||||||
if "agent_pending_action" not in st.session_state:
|
if "agent_pending_action" not in st.session_state:
|
||||||
st.session_state.agent_pending_action = None
|
st.session_state.agent_pending_action = None
|
||||||
|
|
||||||
|
# Whether to inject the currently open file as context into the system prompt
|
||||||
|
if "include_file_context" not in st.session_state:
|
||||||
|
st.session_state.include_file_context = True
|
||||||
|
|
||||||
|
# Optional custom system prompt entered by the user in Settings (overrides default)
|
||||||
|
if "custom_system_prompt" not in st.session_state:
|
||||||
|
st.session_state.custom_system_prompt = ""
|
||||||
|
|
||||||
|
# Holds a pre-built debug message to be sent to the AI on the next chat render
|
||||||
|
if "pending_debug_message" not in st.session_state:
|
||||||
|
st.session_state.pending_debug_message = None
|
||||||
|
|
||||||
|
# Per-file execution results: {file_path: {stdout, stderr, return_code, ast_error}}
|
||||||
|
if "exec_results" not in st.session_state:
|
||||||
|
st.session_state.exec_results = {}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user