better agent

This commit is contained in:
2026-04-09 14:46:29 -03:00
parent ade92069c0
commit 64ecdca71e
11 changed files with 1424 additions and 434 deletions

View File

@@ -28,6 +28,8 @@ from cht.ui.session_dialog import SessionDialog
from cht.session import load_frame_index, load_segment_manifest, rebuild_manifest, global_time_to_segment
from cht.scrub.manager import ProxyManager
from cht.agent.runner import AgentRunner, check_claude_cli
from cht.agent.base import TextDelta, ToolCallStart, ToolCallEnd, ToolResult, ToolUse, Done, Error
from cht.agent.buffer import StreamingTextBuffer
from cht.telemetry import Telemetry
log = logging.getLogger(__name__)
@@ -245,6 +247,11 @@ class ChtWindow(Adw.ApplicationWindow):
self._update_scrub_bar_manifest()
self._populate_model_dropdown()
# Load persisted agent conversation
self._agent.load_from_session(mgr.session_dir)
if self._agent.thread.messages:
self._agent_output.load_thread(self._agent.thread)
def _reload_waveform(self, mgr):
"""Recompute waveform from existing segments in background."""
segments = mgr.recording_segments
@@ -289,6 +296,9 @@ class ChtWindow(Adw.ApplicationWindow):
self._load_existing_frames()
self._load_existing_transcript()
self._reload_waveform(mgr)
self._agent.load_from_session(mgr.session_dir)
if self._agent.thread.messages:
self._agent_output.load_thread(self._agent.thread)
self.set_title(f"{APP_NAME}{mgr.session_id}")
log.info("Waiting for sender...")
@@ -453,6 +463,11 @@ class ChtWindow(Adw.ApplicationWindow):
mgr = self._lifecycle.stream_mgr
last_session_id = mgr.session_id if mgr and not mgr.readonly else None
# Save agent thread before stopping
if mgr and self._agent.thread.messages:
from cht.agent.base import save_thread
save_thread(self._agent.thread, mgr.session_dir)
if self._telemetry:
self._telemetry.close()
self._telemetry = None
@@ -604,15 +619,53 @@ class ChtWindow(Adw.ApplicationWindow):
self._agent_output.append("No active session.\n")
return
self._agent_output.append(f"\n> {text}\n\n")
# Show user message in UI
from cht.agent.runner import _parse_mentions, _parse_transcript_mentions
from cht.agent.tools import load_frames, load_transcript
mgr = self._lifecycle.stream_mgr
frames = load_frames(mgr.frames_dir)
mentioned_frames = _parse_mentions(text, frames)
transcript = load_transcript(mgr.transcript_dir)
mentioned_transcripts = _parse_transcript_mentions(text, transcript)
self._agent_output.add_user_message(text, mentioned_frames, mentioned_transcripts)
# Prepare streaming
from cht.agent.base import _msg_id
msg_id = _msg_id()
self._agent_output.begin_assistant_message(msg_id)
full_text_parts = []
buffer = StreamingTextBuffer(
on_reveal=lambda chunk: self._agent_output.append_to_assistant(msg_id, chunk)
)
def on_event(event):
if isinstance(event, TextDelta):
full_text_parts.append(event.text)
GLib.idle_add(buffer.push, event.text)
elif isinstance(event, ToolCallStart):
tu = ToolUse(id=event.id, tool_name=event.name, input=event.input, status="running")
GLib.idle_add(self._agent_output.add_tool_call, tu)
elif isinstance(event, ToolResult):
GLib.idle_add(self._agent_output.update_tool_result, event.tool_use_id, event)
elif isinstance(event, Error):
GLib.idle_add(self._agent_output.append, f"[Error: {event.message}]\n")
def on_done(err):
def _finish():
buffer.flush()
if err:
self._agent_output.append(f"[Error: {err}]\n")
else:
self._agent_output.finish_assistant(msg_id, "".join(full_text_parts))
GLib.idle_add(_finish)
self._agent_output.begin_response()
self._agent.send(
message=text,
stream_mgr=self._lifecycle.stream_mgr,
stream_mgr=mgr,
tracker=self._lifecycle.tracker,
on_chunk=lambda chunk: GLib.idle_add(self._agent_output.replace_thinking, chunk),
on_done=lambda err: GLib.idle_add(self._agent_output.finish_response, err),
on_event=on_event,
on_done=on_done,
)
# -- Settings callbacks --