small changes
This commit is contained in:
parent
8327c54bdb
commit
a8403eee92
19
README.md
19
README.md
@ -171,10 +171,12 @@ vorausgefüllten Debug-Nachricht.
|
||||
Zwei sich gegenseitig ausschliessende Ansichten, umgeschaltet via `st.toggle("Agent Mode")`:
|
||||
|
||||
**Normaler Chat** (`render_normal_chat()`):
|
||||
- Websuch-Panel oben — öffnet sich automatisch, wenn Suchergebnisse aktiv sind.
|
||||
- Kompakte 4-spaltige Toolbar direkt über dem Chat-Input:
|
||||
`[● Agent Mode]` `[🔍 Search]` `[🗑️ Clear]` `[⚙️ Settings]`
|
||||
— Web-Suche und Einstellungen jeweils als `st.popover`, Clear öffnet einen Bestätigungs-Dialog.
|
||||
- System-Prompt wird vor jeder ausgehenden Nachricht neu generiert (`_set_system_prompt()`).
|
||||
- Unterstützt Slash-Befehle `/search <Abfrage>` und `/search clear`.
|
||||
- Einstellungs-Expander: Dateikontext-Toggle, Modell-Auswahl, Max-Token-Slider,
|
||||
- Settings-Popover: Dateikontext-Toggle, Modell-Auswahl, Max-Token-Slider,
|
||||
benutzerdefinierter System-Prompt.
|
||||
- «Mit KI debuggen»-Nachrichten vom Editor werden über `pending_debug_message` im
|
||||
Session-State weitergeleitet.
|
||||
@ -228,7 +230,9 @@ Generiert kontextbewusste System-Prompts. Signatur:
|
||||
SystemPrompter.generate_prompt(
|
||||
user_message="",
|
||||
file_context=None, # {"name": str, "content": str}
|
||||
search_context=None, # reserviert, noch nicht verdrahtet
|
||||
search_context=None, # list[{"title", "url", "snippet"}] — in system_prompter.py implementiert,
|
||||
# aber in chat.py nicht verwendet: dort wird Search-Kontext direkt
|
||||
# als <search_context>-Block vor die Nachricht eingefügt
|
||||
task_type="default", # "debug" | "explain" | "optimize" | "default"
|
||||
)
|
||||
```
|
||||
@ -241,7 +245,7 @@ Funktion oder Klasse zurückzugeben, nach der der Benutzer fragt, anstatt die ge
|
||||
### `execution_engine.py`
|
||||
Führt Dateien in einem Subprocess mit `capture_output=True`, `text=True` und einem
|
||||
`RUN_TIMEOUT` von 30 Sekunden aus. Aktuell unterstützt:
|
||||
- `.py` — via `py`-Launcher (Windows) / `sys.executable`
|
||||
- `.py` — via `sys.executable` (plattformübergreifend; zeigt auf den aktuell aktiven Python-Interpreter)
|
||||
- `.tex` — via `pdflatex -interaction=nonstopmode` (erfordert pdflatex im PATH)
|
||||
|
||||
Rückgabe: `{"stdout": str, "stderr": str, "rc": int}`.
|
||||
@ -297,7 +301,7 @@ Wichtige Methoden:
|
||||
| `start_task(task)` | Setzt den gesamten Zustand zurück, befüllt History mit System + Aufgabe |
|
||||
| `propose_next_action()` | Ruft das LLM auf, parst JSON, speichert als `pending_action` |
|
||||
| `approve()` | Führt das ausstehende Tool via `dispatch_tool()` aus, loggt Ergebnis |
|
||||
| `reject(feedback)` | Injiziert Feedback + Replan-Tag; schlägt neue Aktion vor |
|
||||
| `reject(feedback)` | Injiziert Feedback + Replan-Tag in die History; `propose_next_action()` wird danach separat aufgerufen |
|
||||
| `follow_up(question)` | Fügt nach «done» eine Folgefrage ein, setzt Schleife fort |
|
||||
|
||||
Hilfsfunktionen (Modul-Ebene):
|
||||
@ -308,7 +312,7 @@ Hilfsfunktionen (Modul-Ebene):
|
||||
| `trim_messages(msgs)` | Entfernt alte Turns, wenn History `MAX_HISTORY_CHARS` (80 000 Zeichen) überschreitet; System-Nachricht + Original-Aufgabe bleiben immer erhalten |
|
||||
| `_strip_code_fences(text)` | Entfernt ` ```json `- / ` ``` `-Wrapper aus LLM-Antworten |
|
||||
| `dispatch_tool(name, arguments)` | Leitet weiter an `MCPToolAdapter.call_tool()` |
|
||||
| `get_tool_descriptions()` | Erstellt eine menschenlesbare Tool-Liste für den System-Prompt |
|
||||
| `build_all_tool_description()` | Erstellt eine menschenlesbare Tool-Liste für den System-Prompt |
|
||||
|
||||
### `mcp_server_adapter.py`
|
||||
Liest `mcp_server_config.json`, startet jeden Server als stdio-Subprocess (immer mit
|
||||
@ -335,12 +339,11 @@ Alle drei Server sind FastMCP-Applikationen, die über stdio kommunizieren.
|
||||
- Beide Tools nutzen SSRF-Schutz (gleiche URL-Validierung wie `search_manager.py`)
|
||||
|
||||
**`mcp_server_code_execution.py`** — Sandbox-Python-Analyse:
|
||||
- `check_code_safety(code)` — statische Analyse; blockiert gefährliche Imports/Builtins
|
||||
- `analyse_structure(code)` — AST-basierte Strukturzusammenfassung
|
||||
- `lint_code(code)` — pyflakes-Analyse
|
||||
- `python_code_validation(code)` — Sicherheits- + Syntaxprüfung ohne Ausführung
|
||||
- `run_python_sandboxed(code)` — Ausführung in einem Subprocess mit `PYTHONIOENCODING=utf-8`,
|
||||
10 s Timeout, Output begrenzt auf `MAX_OUTPUT_LENGTH`
|
||||
15 s Timeout, Output begrenzt auf `MAX_OUTPUT_LENGTH`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -167,6 +167,7 @@ Example:
|
||||
- After validation passes, run it with run_python to verify correctness.
|
||||
- If an error occurs, analyse it and try to fix it (up to 3 retries).
|
||||
- Stay within the workspace directory.
|
||||
- Never use emojis, umlauts (ä, ö, ü, Ä, Ö, Ü, ß), or any non-ASCII characters in string literals or print() calls — the execution environment uses cp1252 encoding which cannot handle them.
|
||||
- When the task is fully complete, call the "done" tool.
|
||||
- If you receive a <human_message>, acknowledge it and adjust your plan.
|
||||
- If you receive a <replan> tag, revise your plan before choosing the next tool.
|
||||
|
||||
@ -6,6 +6,7 @@ processes from blocking the UI indefinitely.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from backend.managers.debug_logger import get_logger
|
||||
@ -40,7 +41,7 @@ class ExecutionEngine:
|
||||
|
||||
# Build the shell command depending on file type
|
||||
if suffix == ".py":
|
||||
cmd = ["py", active_file.name]
|
||||
cmd = [sys.executable, active_file.name]
|
||||
elif suffix == ".tex":
|
||||
# pdflatex in non-interactive mode so it never waits for input
|
||||
cmd = [
|
||||
|
||||
@ -9,26 +9,38 @@ logger = get_logger(__name__)
|
||||
MAX_FILE_CHARS = 4000
|
||||
|
||||
# Per-task base prompts — selected via the task_type parameter.
|
||||
# Appended to every prompt — ensures generated code is safe to run on Windows
|
||||
# where the console encoding is cp1252 and cannot handle emojis or non-ASCII chars.
|
||||
_CODE_SAFETY_NOTE = (
|
||||
" When writing or suggesting code, never use emojis, umlauts (ä, ö, ü, Ä, Ö, Ü, ß), "
|
||||
"or any non-ASCII characters in string literals or print statements, "
|
||||
"as the execution environment uses cp1252 encoding which cannot handle them."
|
||||
)
|
||||
|
||||
_TASK_PROMPTS: dict[str, str] = {
|
||||
"debug": (
|
||||
"You are a debugging expert integrated into a lightweight code editor. "
|
||||
"Focus on identifying and fixing errors. "
|
||||
"Be concise and precise. Use markdown and fenced code blocks where appropriate."
|
||||
+ _CODE_SAFETY_NOTE
|
||||
),
|
||||
"explain": (
|
||||
"You are a code explainer integrated into a lightweight code editor. "
|
||||
"Use simple language and examples. "
|
||||
"Be concise and precise. Use markdown and fenced code blocks where appropriate."
|
||||
+ _CODE_SAFETY_NOTE
|
||||
),
|
||||
"optimize": (
|
||||
"You are a code optimization expert integrated into a lightweight code editor. "
|
||||
"Focus on performance and readability. "
|
||||
"Be concise and precise. Use markdown and fenced code blocks where appropriate."
|
||||
+ _CODE_SAFETY_NOTE
|
||||
),
|
||||
"default": (
|
||||
"You are an expert code assistant integrated into a lightweight code editor. "
|
||||
"Help the user with code suggestions, debugging, explanations, and improvements. "
|
||||
"Be concise and precise. Use markdown and fenced code blocks where appropriate."
|
||||
+ _CODE_SAFETY_NOTE
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@ -368,7 +368,7 @@ def _clear_chat_dialog():
|
||||
# ── Normal Chat ───────────────────────────────────────────────────────────────
|
||||
|
||||
def _render_search_panel():
|
||||
"""Render the collapsible web search panel above the chat history.
|
||||
"""Render the collapsible web search panel above the chat toolbar.
|
||||
|
||||
Stores results in session_state.search_results so they are automatically
|
||||
injected as context into the next message the user sends.
|
||||
@ -424,9 +424,6 @@ def render_normal_chat():
|
||||
logger.info("Chat mode")
|
||||
chat_manager: ChatManager = st.session_state.chat_manager
|
||||
|
||||
# Search panel always rendered at the top — expands automatically when results are active.
|
||||
_render_search_panel()
|
||||
|
||||
# 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
|
||||
@ -456,7 +453,58 @@ def render_normal_chat():
|
||||
with st.chat_message(message["role"]):
|
||||
st.markdown(message["content"])
|
||||
|
||||
# Chat input — Enter to send, no extra button needed.
|
||||
# ── Toolbar — directly above the sticky chat input ────────────────────────
|
||||
# In Streamlit, st.chat_input is a fixed footer. Elements placed BEFORE it
|
||||
# in code appear in the scrollable content area right above the input bar.
|
||||
_render_search_panel()
|
||||
|
||||
col_clear, col_agent, col_settings = st.columns([1, 1, 1])
|
||||
with col_clear:
|
||||
if st.button("🗑️ Clear Chat", use_container_width=True):
|
||||
_clear_chat_dialog()
|
||||
with col_agent:
|
||||
st.toggle("Agent Mode", key="agent_mode")
|
||||
with col_settings:
|
||||
with st.popover("⚙️ Settings", use_container_width=True):
|
||||
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.",
|
||||
)
|
||||
|
||||
# Chat input — sticky footer, always at the very bottom of the viewport.
|
||||
# Supports /search <query> and /search clear as special commands.
|
||||
user_input = st.chat_input("Type a message or /search <query>...")
|
||||
if user_input:
|
||||
@ -535,43 +583,6 @@ def render_normal_chat():
|
||||
st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
|
||||
st.rerun()
|
||||
|
||||
# 5d — Clear Chat opens a confirmation dialog instead of deleting immediately.
|
||||
if st.button("🗑️ Clear Chat"):
|
||||
_clear_chat_dialog()
|
||||
|
||||
# Toggle to switch to Agent Mode (render_normal_chat and render_agent_mode are
|
||||
# mutually exclusive, so the same key here causes no DuplicateWidgetID conflict).
|
||||
st.toggle("Agent Mode", key="agent_mode")
|
||||
|
||||
# 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 ───────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Core Framework
|
||||
streamlit>=1.28.0
|
||||
streamlit==1.57.0
|
||||
streamlit_arborist>=0.1.0
|
||||
|
||||
# AI/LLM Integration
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user