acp: Remember following state (#36793)

A beta user reported that following was "lost" when asking for
confirmation, I
suspect they moved their cursor in the agent file while reviewing the
change.
Now we will resume following when the agent starts up again.

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2025-08-25 09:34:30 -06:00 committed by GitHub
parent 2fe3dbed31
commit 65fb17e2c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 17 deletions

View file

@ -774,7 +774,7 @@ pub enum AcpThreadEvent {
impl EventEmitter<AcpThreadEvent> for AcpThread {}
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Debug)]
pub enum ThreadStatus {
Idle,
WaitingForToolConfirmation,

View file

@ -274,6 +274,7 @@ pub struct AcpThreadView {
edits_expanded: bool,
plan_expanded: bool,
editor_expanded: bool,
should_be_following: bool,
editing_message: Option<usize>,
prompt_capabilities: Rc<Cell<PromptCapabilities>>,
is_loading_contents: bool,
@ -385,6 +386,7 @@ impl AcpThreadView {
edits_expanded: false,
plan_expanded: false,
editor_expanded: false,
should_be_following: false,
history_store,
hovered_recent_history_item: None,
prompt_capabilities,
@ -897,6 +899,13 @@ impl AcpThreadView {
let Some(thread) = self.thread().cloned() else {
return;
};
if self.should_be_following {
self.workspace
.update(cx, |workspace, cx| {
workspace.follow(CollaboratorId::Agent, window, cx);
})
.ok();
}
self.is_loading_contents = true;
let guard = cx.new(|_| ());
@ -938,6 +947,16 @@ impl AcpThreadView {
this.handle_thread_error(err, cx);
})
.ok();
} else {
this.update(cx, |this, cx| {
this.should_be_following = this
.workspace
.update(cx, |workspace, _| {
workspace.is_being_followed(CollaboratorId::Agent)
})
.unwrap_or_default();
})
.ok();
}
})
.detach();
@ -1254,6 +1273,7 @@ impl AcpThreadView {
tool_call_id: acp::ToolCallId,
option_id: acp::PermissionOptionId,
option_kind: acp::PermissionOptionKind,
window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(thread) = self.thread() else {
@ -1262,6 +1282,13 @@ impl AcpThreadView {
thread.update(cx, |thread, cx| {
thread.authorize_tool_call(tool_call_id, option_id, option_kind, cx);
});
if self.should_be_following {
self.workspace
.update(cx, |workspace, cx| {
workspace.follow(CollaboratorId::Agent, window, cx);
})
.ok();
}
cx.notify();
}
@ -2095,11 +2122,12 @@ impl AcpThreadView {
let tool_call_id = tool_call_id.clone();
let option_id = option.id.clone();
let option_kind = option.kind;
move |this, _, _, cx| {
move |this, _, window, cx| {
this.authorize_tool_call(
tool_call_id.clone(),
option_id.clone(),
option_kind,
window,
cx,
);
}
@ -3652,13 +3680,34 @@ impl AcpThreadView {
}
}
fn render_follow_toggle(&self, cx: &mut Context<Self>) -> impl IntoElement {
let following = self
.workspace
.read_with(cx, |workspace, _| {
workspace.is_being_followed(CollaboratorId::Agent)
fn is_following(&self, cx: &App) -> bool {
match self.thread().map(|thread| thread.read(cx).status()) {
Some(ThreadStatus::Generating) => self
.workspace
.read_with(cx, |workspace, _| {
workspace.is_being_followed(CollaboratorId::Agent)
})
.unwrap_or(false),
_ => self.should_be_following,
}
}
fn toggle_following(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let following = self.is_following(cx);
self.should_be_following = !following;
self.workspace
.update(cx, |workspace, cx| {
if following {
workspace.unfollow(CollaboratorId::Agent, window, cx);
} else {
workspace.follow(CollaboratorId::Agent, window, cx);
}
})
.unwrap_or(false);
.ok();
}
fn render_follow_toggle(&self, cx: &mut Context<Self>) -> impl IntoElement {
let following = self.is_following(cx);
IconButton::new("follow-agent", IconName::Crosshair)
.icon_size(IconSize::Small)
@ -3679,15 +3728,7 @@ impl AcpThreadView {
}
})
.on_click(cx.listener(move |this, _, window, cx| {
this.workspace
.update(cx, |workspace, cx| {
if following {
workspace.unfollow(CollaboratorId::Agent, window, cx);
} else {
workspace.follow(CollaboratorId::Agent, window, cx);
}
})
.ok();
this.toggle_following(window, cx);
}))
}