feat read files

This commit is contained in:
fsylvain committed 2026-09-22 16:35:13 +02:00
1 parent 78152d9974
commit f129aef5a5
3 files changed
+175 -11

No files matched your search

+50 -7
View File
@@ -439,7 +439,7 @@ class ModelLoaderThread(QThread):
class AskThread(QThread):
tool_call = pyqtSignal(str)
tool_call = pyqtSignal(str, str)
usage = pyqtSignal(dict)
token = pyqtSignal(str)
thinking_token = pyqtSignal(str)
@@ -479,6 +479,11 @@ class ChatWindow(QMainWindow):
self._sessions[0] if self._sessions else chatbot.new_session()
)
self._history: list[tuple[str, str]] = list(self._current_session.history)
# The loaded model has a single KV cache. Each chat keeps its own
# snapshot of that cache so switching chats restores that chat's
# context instead of continuing whichever chat ran last.
self._context_states: dict[str, object] = {}
self._context_owner: str | None = None
self._pending_question = ""
self._ask_thread: AskThread | None = None
# Position in chat_view's document where the in-progress streamed
@@ -718,6 +723,7 @@ class ChatWindow(QMainWindow):
return # already on an empty, unsaved chat
self._current_session = chatbot.new_session()
self._history = []
self._activate_session_context(self._current_session)
self.chat_view.clear()
self._append_system("Dev assist chatbot ready. Ask a development question.")
self.session_list.clearSelection()
@@ -734,6 +740,7 @@ class ChatWindow(QMainWindow):
return
self._current_session = session
self._history = list(session.history)
self._activate_session_context(session)
self._render_session_history(session)
self.statusBar().showMessage("Ready.")
@@ -759,6 +766,9 @@ class ChatWindow(QMainWindow):
if reply != QMessageBox.StandardButton.Yes:
return
chatbot.delete_session(session_id)
self._context_states.pop(session_id, None)
if self._context_owner == session_id:
self._context_owner = None
self._sessions = [s for s in self._sessions if s.id != session_id]
if self._current_session.id == session_id:
if self._sessions:
@@ -766,6 +776,7 @@ class ChatWindow(QMainWindow):
else:
self._current_session = chatbot.new_session()
self._history = list(self._current_session.history)
self._activate_session_context(self._current_session)
self.chat_view.clear()
if self._current_session.history:
self._render_session_history(self._current_session)
@@ -776,7 +787,7 @@ class ChatWindow(QMainWindow):
def _on_model_loaded(self, llm) -> None:
self._llm = llm
self._n_ctx = llm.n_ctx()
self.context_status_label.setText(f"Context: 0 / {self._n_ctx}")
self._activate_session_context(self._current_session)
self.statusBar().showMessage("Ready.")
self._append_system("Dev assist chatbot ready. Ask a development question.")
self._set_input_enabled(True)
@@ -799,6 +810,7 @@ class ChatWindow(QMainWindow):
self._answer_started = False
self._stream_thinking_id = None
self._activate_session_context(self._current_session)
messages = chatbot.build_messages(self._history, question)
self._pending_question = question
@@ -936,16 +948,47 @@ class ChatWindow(QMainWindow):
return
self._render_thinking(block_id, expanded=not block["expanded"])
def _on_tool_call(self, query: str) -> None:
def _on_tool_call(self, tool_name: str, target: str) -> None:
self._collapse_open_thinking()
self._discard_stream_card()
self.statusBar().showMessage(f"Searching: {query}")
self._append_system(f"Searching the web for: {query}")
if tool_name == "read_file":
self.statusBar().showMessage(f"Reading file: {target}")
self._append_system(f"Reading file: {target}")
else:
self.statusBar().showMessage(f"Searching: {target}")
self._append_system(f"Searching the web for: {target}")
def _show_context_usage(self, total: int | None) -> None:
if total is None or not self._n_ctx:
shown = "--" if total is None else total
limit = self._n_ctx or "--"
self.context_status_label.setText(f"Context: {shown} / {limit}")
return
pct = 100 * total / self._n_ctx
self.context_status_label.setText(f"Context: {total} / {self._n_ctx} ({pct:.0f}%)")
def _activate_session_context(self, session: "chatbot.ChatSession") -> None:
"""Make the loaded model's KV cache match this chat.
Leaving a chat stores its cache; entering one restores it, or clears
the cache when that chat has no snapshot yet (first visit this run).
"""
self._show_context_usage(session.context_tokens)
if self._llm is None or self._context_owner == session.id:
return
if self._context_owner is not None:
self._context_states[self._context_owner] = self._llm.save_state()
state = self._context_states.get(session.id)
if state is None:
self._llm.reset()
else:
self._llm.load_state(state)
self._context_owner = session.id
def _on_usage(self, usage: dict) -> None:
total = usage["total_tokens"]
pct = 100 * total / self._n_ctx if self._n_ctx else 0
self.context_status_label.setText(f"Context: {total} / {self._n_ctx} ({pct:.0f}%)")
self._current_session.context_tokens = total
self._show_context_usage(total)
def _on_answer(self, answer: str) -> None:
# Normally already collapsed by the first answer token (_on_token),