дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix(agents): restore archived tasks for continued conversation (#349)
Archived agent tasks could be opened but never returned to the active list, so their message composer stayed disabled. Unarchive is now available in the task header, in the archived-task notice above the composer, and in the task context menu (including mixed bulk selections). Restoring a task moves it back to the active list, keeps its conversation and worktree, and reconnects the existing agent session on the next message; the backend persists and broadcasts the restored status and refuses restoration while a stopped turn is still settling.
Цей коміт міститься в:
1 джерело
2203938491
коміт
9a5b44bebb
11 files changed
+132
-3
No files matched your search
@@ -760,6 +760,26 @@ impl AgentManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns an archived task to the active list without starting the agent.
|
||||
pub fn unarchive(&self, id: &str) -> IdeResult<()> {
|
||||
let task = self.task(id)?;
|
||||
{
|
||||
let mut s = task.state.lock();
|
||||
if s.task.status != AgentStatus::Archived {
|
||||
return Ok(());
|
||||
}
|
||||
if s.busy {
|
||||
return Err(IdeError::invalid("the task is still stopping"));
|
||||
}
|
||||
s.task.status = AgentStatus::Ready;
|
||||
s.task.error = None;
|
||||
s.task.updated_ms = now_ms();
|
||||
}
|
||||
task.persist();
|
||||
task.emit_task();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Forgets the task; with `remove_worktree` also deletes its worktree (the branch stays).
|
||||
pub async fn delete(&self, id: &str, remove_worktree: bool) -> IdeResult<()> {
|
||||
let task = self.task(id)?;
|
||||
|
||||
@@ -817,3 +817,36 @@ async fn cursor_approval_choice_applies_before_first_prompt() {
|
||||
wait_for(&mgr, &task.id, AgentStatus::Ready).await;
|
||||
mgr.shutdown();
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn archived_tasks_can_be_restored_and_continue_their_session() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let agent = Arc::new(FakeAgent::default());
|
||||
let mgr = manager(tmp.path(), agent.clone());
|
||||
let task = mgr
|
||||
.create(NewAgentTask {
|
||||
prompt: text("again"),
|
||||
provider: "claude".into(),
|
||||
config: vec![],
|
||||
isolation: Isolation::Local,
|
||||
base: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for(&mgr, &task.id, AgentStatus::Ready).await;
|
||||
let entries = mgr.entries(&task.id, None).unwrap();
|
||||
mgr.archive(&task.id).unwrap();
|
||||
assert!(mgr.prompt(&task.id, text("again"), false).await.is_err());
|
||||
mgr.unarchive(&task.id).unwrap();
|
||||
assert_eq!(mgr.task(&task.id).unwrap().state.lock().task.status, AgentStatus::Ready);
|
||||
assert!(mgr.task(&task.id).unwrap().live.lock().is_none());
|
||||
assert_eq!(mgr.entries(&task.id, None).unwrap().len(), entries.len());
|
||||
drop(mgr);
|
||||
let mgr = manager(tmp.path(), agent.clone());
|
||||
assert_eq!(mgr.task(&task.id).unwrap().state.lock().task.status, AgentStatus::Ready);
|
||||
mgr.prompt(&task.id, text("again"), false).await.unwrap();
|
||||
wait_for(&mgr, &task.id, AgentStatus::Ready).await;
|
||||
assert!(agent.calls.lock().iter().any(|call| call == "session/load"));
|
||||
assert_eq!(mgr.entries(&task.id, None).unwrap().len(), entries.len() + 2);
|
||||
mgr.unarchive(&task.id).unwrap();
|
||||
}
|
||||
@@ -140,6 +140,10 @@ pub fn archive(host: &Host, window: &str, task: String) -> IdeResult<()> {
|
||||
host.project(window)?.agents.archive(&task)
|
||||
}
|
||||
|
||||
pub fn unarchive(host: &Host, window: &str, task: String) -> IdeResult<()> {
|
||||
host.project(window)?.agents.unarchive(&task)
|
||||
}
|
||||
|
||||
pub async fn delete(host: &Host, window: &str, task: String, remove_worktree: bool) -> IdeResult<()> {
|
||||
host.project(window)?.agents.delete(&task, remove_worktree).await
|
||||
}
|
||||
@@ -183,6 +187,7 @@ pub(crate) fn register(d: &mut Dispatcher) {
|
||||
d.add("agent_respond", |c| async move {
|
||||
respond(&c.host, &c.window, c.arg("task")?, c.arg("permission")?, c.arg("option")?)
|
||||
});
|
||||
d.add("agent_unarchive", |c| async move { unarchive(&c.host, &c.window, c.arg("task")?) });
|
||||
d.add("agent_archive", |c| async move { archive(&c.host, &c.window, c.arg("task")?) });
|
||||
d.add(
|
||||
"agent_delete",
|
||||
|
||||
Reference in new issue
Заблокувати користувача