feat: remove session hub and related commands from the application
This commit is contained in:
@@ -9,6 +9,8 @@ use crate::app::state::runtime::TurnEvent;
|
||||
use crate::app::state::types::{AgentMode, Origin, Overlay, Toast, ToastKind};
|
||||
use crate::dto::chat::message::{ChatMessage, Role};
|
||||
|
||||
const MAX_TOOL_ONLY_TURNS: usize = 6;
|
||||
|
||||
const MAX_AGENT_STEPS: usize = 40;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -58,9 +60,6 @@ pub enum Action {
|
||||
LessonReject {
|
||||
name: String,
|
||||
},
|
||||
SaveSession,
|
||||
ResumeSession,
|
||||
RefreshSessions,
|
||||
}
|
||||
|
||||
pub fn apply_action(state: &mut AppStateRest, action: Action) {
|
||||
@@ -82,11 +81,9 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
|
||||
| ModeKind::Workflow => Overlay::None,
|
||||
ModeKind::Help => Overlay::Help,
|
||||
ModeKind::Settings => Overlay::Settings,
|
||||
ModeKind::SessionHub => Overlay::SessionHub,
|
||||
ModeKind::QuitConfirm => Overlay::QuitConfirm,
|
||||
ModeKind::Onboard => Overlay::Onboard,
|
||||
ModeKind::OnboardProvider => Overlay::OnboardProvider,
|
||||
ModeKind::Picker => Overlay::Picker,
|
||||
ModeKind::KeyInput => Overlay::KeyInput,
|
||||
ModeKind::Editor => Overlay::Editor,
|
||||
ModeKind::Effort => Overlay::Effort,
|
||||
@@ -110,6 +107,7 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
|
||||
rt.push_message(ChatMessage::user(text));
|
||||
}
|
||||
spawn_turn(state);
|
||||
state.push_transcript(ChatMessageDisplay::new(Role::Assistant, "Thinking...".to_string()));
|
||||
state.dirty = true;
|
||||
}
|
||||
Action::InsertChar(c) => {
|
||||
@@ -273,53 +271,6 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
|
||||
}
|
||||
state.dirty = true;
|
||||
}
|
||||
Action::SaveSession => {
|
||||
save_current_session(state);
|
||||
state.push_toast(Toast::new(ToastKind::Success, "session saved".to_string()));
|
||||
state.dirty = true;
|
||||
}
|
||||
Action::ResumeSession => {
|
||||
let base = state.store_base_dir();
|
||||
let sessions = crate::model::session::Session::list(&base);
|
||||
let target = sessions.into_iter()
|
||||
.filter(|s| s.id != state.session_id)
|
||||
.max_by_key(|s| s.updated_at);
|
||||
if let Some(session) = target {
|
||||
let conv_path = session.conversation_path(&base);
|
||||
let loaded_msgs: Vec<crate::dto::chat::message::ChatMessage> =
|
||||
std::fs::read_to_string(&conv_path)
|
||||
.ok()
|
||||
.and_then(|data| serde_json::from_str(&data).ok())
|
||||
.unwrap_or_default();
|
||||
state.session_id = session.id.clone();
|
||||
state.session_dir = session.session_dir(&base);
|
||||
state.session_runtime = Some(crate::app::state::runtime::SessionRuntime::new(
|
||||
state.session_dir.clone(),
|
||||
));
|
||||
state.transcript_cache.messages.clear();
|
||||
if let Some(ref mut rt) = state.session_runtime {
|
||||
for msg in loaded_msgs {
|
||||
let display = ChatMessageDisplay::new(
|
||||
msg.role.clone(),
|
||||
msg.content.clone().unwrap_or_default(),
|
||||
);
|
||||
state.transcript_cache.messages.push(display);
|
||||
rt.push_message(msg);
|
||||
}
|
||||
}
|
||||
state.push_toast(Toast::new(ToastKind::Success,
|
||||
format!("resumed session: {}", session.title)));
|
||||
} else {
|
||||
state.push_toast(Toast::new(ToastKind::Info,
|
||||
"no other sessions to resume".to_string()));
|
||||
}
|
||||
state.dirty = true;
|
||||
}
|
||||
Action::RefreshSessions => {
|
||||
let base = state.store_base_dir();
|
||||
state.sessions = crate::model::session::Session::list(&base);
|
||||
state.dirty = true;
|
||||
}
|
||||
Action::Tick => {
|
||||
let now_ms = chrono::Utc::now().timestamp_millis();
|
||||
state.misc.drain_expired_toasts(now_ms);
|
||||
@@ -341,16 +292,39 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
|
||||
TurnEvent::AssistantMessage(msg) => {
|
||||
let display_content = msg.content.clone().unwrap_or_default();
|
||||
if !display_content.is_empty() {
|
||||
state.push_transcript(ChatMessageDisplay::new(Role::Assistant, display_content));
|
||||
let replaced = if let Some(last) = state.transcript_cache.messages.last_mut() {
|
||||
if last.role == Role::Assistant && last.content == "Thinking..." {
|
||||
last.content = display_content.clone();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !replaced {
|
||||
state.push_transcript(ChatMessageDisplay::new(Role::Assistant, display_content));
|
||||
}
|
||||
}
|
||||
if let Some(ref mut rt) = state.session_runtime {
|
||||
rt.push_message(msg);
|
||||
}
|
||||
}
|
||||
TurnEvent::ToolResult { tool_call_id, tool_name, output, is_error } => {
|
||||
TurnEvent::ToolResult { tool_call_id, tool_name, output, is_error, path } => {
|
||||
let display_path = path.unwrap_or_default();
|
||||
let display = if tool_name == "read" {
|
||||
let line_count = output.lines().count();
|
||||
if !display_path.is_empty() {
|
||||
format!("read: {} ({} lines)", display_path, line_count)
|
||||
} else {
|
||||
format!("read: {} line(s)", line_count)
|
||||
}
|
||||
} else {
|
||||
format!("{}: {}", tool_name, output)
|
||||
};
|
||||
state.push_transcript(ChatMessageDisplay::new(
|
||||
Role::Tool,
|
||||
format!("{}: {}", tool_name, output),
|
||||
display,
|
||||
));
|
||||
if let Some(ref mut rt) = state.session_runtime {
|
||||
rt.push_message(ChatMessage::tool_result(tool_call_id.clone(), output.clone()));
|
||||
@@ -520,6 +494,7 @@ fn run_agent_turn(
|
||||
) -> anyhow::Result<()> {
|
||||
let mut msgs = messages.to_vec();
|
||||
let mut edits_this_turn = 0u32;
|
||||
let mut tool_only_rounds = 0usize;
|
||||
|
||||
let system_text = format!(
|
||||
"{}\n\n{}",
|
||||
@@ -531,6 +506,13 @@ fn run_agent_turn(
|
||||
}
|
||||
|
||||
for _step in 0..MAX_AGENT_STEPS {
|
||||
if tool_only_rounds >= MAX_TOOL_ONLY_TURNS {
|
||||
msgs.push(ChatMessage::user(
|
||||
"Stop calling tools. Respond naturally now.".to_string(),
|
||||
));
|
||||
tool_only_rounds = 0;
|
||||
}
|
||||
|
||||
let response = tc
|
||||
.client
|
||||
.chat_with_tools(&msgs, Some(tc.tdefs.clone()))?;
|
||||
@@ -540,6 +522,7 @@ fn run_agent_turn(
|
||||
|
||||
let content = response.content.clone().unwrap_or_default();
|
||||
if has_tool_calls {
|
||||
tool_only_rounds += 1;
|
||||
let tool_calls = response.tool_calls.clone().unwrap_or_default();
|
||||
msgs.push(response);
|
||||
for tool_call in tool_calls {
|
||||
@@ -583,6 +566,8 @@ fn run_agent_turn(
|
||||
edits_this_turn += 1;
|
||||
}
|
||||
|
||||
let tool_path = args.get("path").and_then(|v| v.as_str()).map(|s| s.to_string());
|
||||
|
||||
{
|
||||
if let Ok(mut q) = events_q.lock() {
|
||||
q.push_back(TurnEvent::ToolResult {
|
||||
@@ -590,6 +575,7 @@ fn run_agent_turn(
|
||||
tool_name: tool_name.clone(),
|
||||
output: output.clone(),
|
||||
is_error,
|
||||
path: tool_path,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,6 @@ pub fn apply_command(command: Command) -> Vec<Action> {
|
||||
Command::Quit => {
|
||||
vec![Action::QuitConfirm]
|
||||
}
|
||||
Command::Resume => {
|
||||
vec![Action::SaveSession, Action::ResumeSession, Action::CloseOverlay]
|
||||
}
|
||||
Command::LessonCreate(text) => {
|
||||
vec![Action::SystemNote {
|
||||
kind: "lesson".to_string(),
|
||||
@@ -43,9 +40,6 @@ pub fn apply_command(command: Command) -> Vec<Action> {
|
||||
message: "transcript cleared".to_string(),
|
||||
}]
|
||||
}
|
||||
Command::Save => {
|
||||
vec![Action::SaveSession]
|
||||
}
|
||||
Command::Login { provider } => {
|
||||
vec![Action::SystemNote {
|
||||
kind: "oauth".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user