agent2: New thread from summary (#36578)
Release Notes: - N/A --------- Co-authored-by: Agus Zubiaga <agus@zed.dev> Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
c5040bd0a4
commit
85865fc950
6 changed files with 131 additions and 19 deletions
|
@ -111,6 +111,10 @@ impl HistoryStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn thread_from_session_id(&self, session_id: &acp::SessionId) -> Option<&DbThreadMetadata> {
|
||||
self.threads.iter().find(|thread| &thread.id == session_id)
|
||||
}
|
||||
|
||||
pub fn delete_thread(
|
||||
&mut self,
|
||||
id: acp::SessionId,
|
||||
|
|
|
@ -163,6 +163,36 @@ impl MessageEditor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert_thread_summary(
|
||||
&mut self,
|
||||
thread: agent2::DbThreadMetadata,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let start = self.editor.update(cx, |editor, cx| {
|
||||
editor.set_text(format!("{}\n", thread.title), window, cx);
|
||||
editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_before(Point::zero())
|
||||
.text_anchor
|
||||
});
|
||||
|
||||
self.confirm_completion(
|
||||
thread.title.clone(),
|
||||
start,
|
||||
thread.title.len(),
|
||||
MentionUri::Thread {
|
||||
id: thread.id.clone(),
|
||||
name: thread.title.to_string(),
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn editor(&self) -> &Entity<Editor> {
|
||||
&self.editor
|
||||
|
|
|
@ -155,6 +155,7 @@ impl AcpThreadView {
|
|||
pub fn new(
|
||||
agent: Rc<dyn AgentServer>,
|
||||
resume_thread: Option<DbThreadMetadata>,
|
||||
summarize_thread: Option<DbThreadMetadata>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
project: Entity<Project>,
|
||||
history_store: Entity<HistoryStore>,
|
||||
|
@ -164,7 +165,7 @@ impl AcpThreadView {
|
|||
) -> Self {
|
||||
let prevent_slash_commands = agent.clone().downcast::<ClaudeCode>().is_some();
|
||||
let message_editor = cx.new(|cx| {
|
||||
MessageEditor::new(
|
||||
let mut editor = MessageEditor::new(
|
||||
workspace.clone(),
|
||||
project.clone(),
|
||||
history_store.clone(),
|
||||
|
@ -177,7 +178,11 @@ impl AcpThreadView {
|
|||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
);
|
||||
if let Some(entry) = summarize_thread {
|
||||
editor.insert_thread_summary(entry, window, cx);
|
||||
}
|
||||
editor
|
||||
});
|
||||
|
||||
let list_state = ListState::new(0, gpui::ListAlignment::Bottom, px(2048.0));
|
||||
|
@ -3636,8 +3641,18 @@ impl AcpThreadView {
|
|||
.child(
|
||||
Button::new("start-new-thread", "Start New Thread")
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(cx.listener(|_this, _, _window, _cx| {
|
||||
// todo: Once thread summarization is implemented, start a new thread from a summary.
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
let Some(thread) = this.thread() else {
|
||||
return;
|
||||
};
|
||||
let session_id = thread.read(cx).session_id().clone();
|
||||
window.dispatch_action(
|
||||
crate::NewNativeAgentThreadFromSummary {
|
||||
from_session_id: session_id,
|
||||
}
|
||||
.boxed_clone(),
|
||||
cx,
|
||||
);
|
||||
})),
|
||||
)
|
||||
.when(burn_mode_available, |this| {
|
||||
|
@ -4320,6 +4335,7 @@ pub(crate) mod tests {
|
|||
AcpThreadView::new(
|
||||
Rc::new(agent),
|
||||
None,
|
||||
None,
|
||||
workspace.downgrade(),
|
||||
project,
|
||||
history_store,
|
||||
|
@ -4526,6 +4542,7 @@ pub(crate) mod tests {
|
|||
AcpThreadView::new(
|
||||
Rc::new(StubAgentServer::new(connection.as_ref().clone())),
|
||||
None,
|
||||
None,
|
||||
workspace.downgrade(),
|
||||
project.clone(),
|
||||
history_store.clone(),
|
||||
|
|
|
@ -30,7 +30,7 @@ use crate::{
|
|||
thread_history::{HistoryEntryElement, ThreadHistory},
|
||||
ui::{AgentOnboardingModal, EndTrialUpsell},
|
||||
};
|
||||
use crate::{ExternalAgent, NewExternalAgentThread};
|
||||
use crate::{ExternalAgent, NewExternalAgentThread, NewNativeAgentThreadFromSummary};
|
||||
use agent::{
|
||||
Thread, ThreadError, ThreadEvent, ThreadId, ThreadSummary, TokenUsageRatio,
|
||||
context_store::ContextStore,
|
||||
|
@ -98,6 +98,16 @@ pub fn init(cx: &mut App) {
|
|||
workspace.focus_panel::<AgentPanel>(window, cx);
|
||||
}
|
||||
})
|
||||
.register_action(
|
||||
|workspace, action: &NewNativeAgentThreadFromSummary, window, cx| {
|
||||
if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
|
||||
panel.update(cx, |panel, cx| {
|
||||
panel.new_native_agent_thread_from_summary(action, window, cx)
|
||||
});
|
||||
workspace.focus_panel::<AgentPanel>(window, cx);
|
||||
}
|
||||
},
|
||||
)
|
||||
.register_action(|workspace, _: &OpenHistory, window, cx| {
|
||||
if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
|
||||
workspace.focus_panel::<AgentPanel>(window, cx);
|
||||
|
@ -120,7 +130,7 @@ pub fn init(cx: &mut App) {
|
|||
if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
|
||||
workspace.focus_panel::<AgentPanel>(window, cx);
|
||||
panel.update(cx, |panel, cx| {
|
||||
panel.external_thread(action.agent, None, window, cx)
|
||||
panel.external_thread(action.agent, None, None, window, cx)
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -670,6 +680,7 @@ impl AgentPanel {
|
|||
this.external_thread(
|
||||
Some(crate::ExternalAgent::NativeAgent),
|
||||
Some(thread.clone()),
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
@ -974,6 +985,29 @@ impl AgentPanel {
|
|||
AgentDiff::set_active_thread(&self.workspace, thread.clone(), window, cx);
|
||||
}
|
||||
|
||||
fn new_native_agent_thread_from_summary(
|
||||
&mut self,
|
||||
action: &NewNativeAgentThreadFromSummary,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(thread) = self
|
||||
.acp_history_store
|
||||
.read(cx)
|
||||
.thread_from_session_id(&action.from_session_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.external_thread(
|
||||
Some(ExternalAgent::NativeAgent),
|
||||
None,
|
||||
Some(thread.clone()),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
fn new_prompt_editor(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let context = self
|
||||
.context_store
|
||||
|
@ -1015,6 +1049,7 @@ impl AgentPanel {
|
|||
&mut self,
|
||||
agent_choice: Option<crate::ExternalAgent>,
|
||||
resume_thread: Option<DbThreadMetadata>,
|
||||
summarize_thread: Option<DbThreadMetadata>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
|
@ -1083,6 +1118,7 @@ impl AgentPanel {
|
|||
crate::acp::AcpThreadView::new(
|
||||
server,
|
||||
resume_thread,
|
||||
summarize_thread,
|
||||
workspace.clone(),
|
||||
project,
|
||||
this.acp_history_store.clone(),
|
||||
|
@ -1754,6 +1790,7 @@ impl AgentPanel {
|
|||
agent2::HistoryEntry::AcpThread(entry) => this.external_thread(
|
||||
Some(ExternalAgent::NativeAgent),
|
||||
Some(entry.clone()),
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
|
@ -1823,15 +1860,23 @@ impl AgentPanel {
|
|||
AgentType::TextThread => {
|
||||
window.dispatch_action(NewTextThread.boxed_clone(), cx);
|
||||
}
|
||||
AgentType::NativeAgent => {
|
||||
self.external_thread(Some(crate::ExternalAgent::NativeAgent), None, window, cx)
|
||||
}
|
||||
AgentType::NativeAgent => self.external_thread(
|
||||
Some(crate::ExternalAgent::NativeAgent),
|
||||
None,
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
AgentType::Gemini => {
|
||||
self.external_thread(Some(crate::ExternalAgent::Gemini), None, window, cx)
|
||||
}
|
||||
AgentType::ClaudeCode => {
|
||||
self.external_thread(Some(crate::ExternalAgent::ClaudeCode), None, window, cx)
|
||||
self.external_thread(Some(crate::ExternalAgent::Gemini), None, None, window, cx)
|
||||
}
|
||||
AgentType::ClaudeCode => self.external_thread(
|
||||
Some(crate::ExternalAgent::ClaudeCode),
|
||||
None,
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1841,7 +1886,13 @@ impl AgentPanel {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.external_thread(Some(ExternalAgent::NativeAgent), Some(thread), window, cx);
|
||||
self.external_thread(
|
||||
Some(ExternalAgent::NativeAgent),
|
||||
Some(thread),
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2358,8 +2409,10 @@ impl AgentPanel {
|
|||
let focus_handle = self.focus_handle(cx);
|
||||
|
||||
let active_thread = match &self.active_view {
|
||||
ActiveView::Thread { thread, .. } => Some(thread.read(cx).thread().clone()),
|
||||
ActiveView::ExternalAgentThread { .. }
|
||||
ActiveView::ExternalAgentThread { thread_view } => {
|
||||
thread_view.read(cx).as_native_thread(cx)
|
||||
}
|
||||
ActiveView::Thread { .. }
|
||||
| ActiveView::TextThread { .. }
|
||||
| ActiveView::History
|
||||
| ActiveView::Configuration => None,
|
||||
|
@ -2396,15 +2449,15 @@ impl AgentPanel {
|
|||
let thread = active_thread.read(cx);
|
||||
|
||||
if !thread.is_empty() {
|
||||
let thread_id = thread.id().clone();
|
||||
let session_id = thread.id().clone();
|
||||
this.item(
|
||||
ContextMenuEntry::new("New From Summary")
|
||||
.icon(IconName::ThreadFromSummary)
|
||||
.icon_color(Color::Muted)
|
||||
.handler(move |window, cx| {
|
||||
window.dispatch_action(
|
||||
Box::new(NewThread {
|
||||
from_thread_id: Some(thread_id.clone()),
|
||||
Box::new(NewNativeAgentThreadFromSummary {
|
||||
from_session_id: session_id.clone(),
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
|
|
|
@ -146,6 +146,13 @@ pub struct NewExternalAgentThread {
|
|||
agent: Option<ExternalAgent>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Deserialize, JsonSchema, Action)]
|
||||
#[action(namespace = agent)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct NewNativeAgentThreadFromSummary {
|
||||
from_session_id: agent_client_protocol::SessionId,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum ExternalAgent {
|
||||
|
|
|
@ -4362,6 +4362,7 @@ mod tests {
|
|||
| "workspace::MoveItemToPaneInDirection"
|
||||
| "workspace::OpenTerminal"
|
||||
| "workspace::SendKeystrokes"
|
||||
| "agent::NewNativeAgentThreadFromSummary"
|
||||
| "zed::OpenBrowser"
|
||||
| "zed::OpenZedUrl" => {}
|
||||
_ => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue