Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import logging
import os
import queue
import re
import signal
import sqlite3
import subprocess
Expand Down Expand Up @@ -313,6 +314,14 @@ def estimate_tokens(text: str) -> int:
return max(1, len(text) // AVG_CHARS_PER_TOKEN)


def _strip_tool_blocks(text: str) -> str:
"""
LLM yanıtından <tool>...</tool> bloklarını sil.
Temiz metni konuşma geçmişine kaydetmek için kullanılır.
"""
return re.sub(r'<tool>.*?</tool>', '', text, flags=re.DOTALL).strip()


Comment on lines +322 to +324

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_strip_tool_blocks() only removes closed <tool>...</tool> blocks. In the unclosed-<tool> scenario handled later in _normal_stream, full_reply will still contain a partial <tool> block and this function will return it unchanged, so the polluted tool XML can still be persisted to SQLite and re-fed into future prompts. Consider stripping any trailing <tool> start tag with no closing tag (or truncating full_reply before saving) so malformed tool outputs can’t leak into history.

Suggested change
return re.sub(r'<tool>.*?</tool>', '', text, flags=re.DOTALL).strip()
# Önce kapalı <tool>...</tool> bloklarını kaldır.
cleaned = re.sub(r'<tool>.*?</tool>', '', text, flags=re.DOTALL)
# Ardından, kapanış etiketi olmayan sondaki bir <tool> bloğunu da temizle.
# Bu, akış sırasında kısmi tool çıktısının geçmişe sızmasını engeller.
last_open = cleaned.rfind("<tool")
if last_open != -1:
# Eğer bu noktadan sonra hiç </tool> yoksa, bu kısmi bir bloktur → kes.
if "</tool>" not in cleaned[last_open:]:
cleaned = cleaned[:last_open]
return cleaned.strip()

Copilot uses AI. Check for mistakes.
def fit_messages_to_budget(
messages: List[Dict[str, str]],
budget: int,
Expand Down Expand Up @@ -2907,7 +2916,7 @@ def webchat_stats_route():
return jsonify({"ok": False, "error": str(e)}), 500


@app.route('/api/webchat/users/<uid>', methods=['POST'])
@app.route('/api/webchat/users/<uid>', methods=['POST', 'PUT'])
def webchat_update_user_route(uid: str):
data = request.json or {}
# Remove non-updatable keys
Expand Down Expand Up @@ -2983,6 +2992,11 @@ def webchat_chat_route():
if not uid or not content:
return jsonify({"ok": False, "error": "uid ve content zorunlu"}), 400

# LLM çalışıyor mu? Erken kontrol — stream açmadan önce hata döndür
if not _llm_status.get("running"):
return jsonify({"ok": False,
"error": "LLM sunucusu çalışmıyor. Panelden başlatın."}), 503

# Rate check
rate = mm.webchat_check_rate(uid)
if not rate.get("allowed"):
Expand Down Expand Up @@ -3305,7 +3319,11 @@ def stream_conversation():
if content:
mm.save_message(chat_id, "user", content)
if full_reply:
mm.save_message(chat_id, "assistant", full_reply)
# <tool>...</tool> bloklarını geçmişe kaydetme — sadece temiz metin sakla
reply_to_save = _strip_tool_blocks(full_reply)
if reply_to_save:
mm.save_message(chat_id, "assistant", reply_to_save)
# LLM cevap üretti → rate sayacını artır (araç çağrısı olsa bile)
mm.webchat_log_message(uid)

def _normal_stream(msgs, max_tok):
Expand Down Expand Up @@ -3373,6 +3391,12 @@ def _normal_stream(msgs, max_tok):
except Exception:
pass

# Araç etiketi açıldı ama kapanmadı — sessiz tekrara izin verme
if in_tool and "</tool>" not in tool_buffer:
yield (f'data: {{"choices":[{{"delta":{{"content":'
f'" \\n[⚠ Araç etiketi kapatılmadı, yeniden deneyin]"}}}}]}}\n\n')
break # while döngüsünü bitir

if not in_tool or "</tool>" in tool_buffer:
if not in_tool:
break # Normal exit
Expand Down Expand Up @@ -3497,8 +3521,7 @@ def files_upload():

# Boyut kontrolü
try:
import base64
raw = base64.b64decode(data_b64)
raw = b64mod.b64decode(data_b64)
except Exception:
return jsonify({"ok": False, "error": "Geçersiz base64 verisi"}), 400

Expand Down
2 changes: 1 addition & 1 deletion chat_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1606,7 +1606,7 @@
const row = document.createElement('div');
row.className = 'sb-file';
row.innerHTML = `
<span class="sb-file-name">${escHtml(f.name)} <span style="color:var(--faint)">(${f.size})</span></span>
<span class="sb-file-name">${escHtml(f.name)} <span style="color:var(--faint)">(${fmtSize(f.size)})</span></span>
<div class="sb-actions">
<button class="sb-btn" onclick="window.open('/api/sandbox/download/${state.uid}/${encodeURIComponent(f.name)}')">İndir</button>
<button class="sb-btn del" onclick="deleteSandboxFile('${escHtml(f.name)}')">Sil</button>
Expand Down
Loading