Display what the tool is doing (#27120)
<img width="639" alt="Screenshot 2025-03-19 at 4 56 47 PM" src="https://github.com/user-attachments/assets/b997f04d-4aff-4070-87b1-ffdb61019bd1" /> Release Notes: - N/A --------- Co-authored-by: Agus Zubiaga <hi@aguz.me>
This commit is contained in:
parent
aae81fd54c
commit
e3578fc44a
18 changed files with 349 additions and 132 deletions
|
@ -35,6 +35,7 @@ pub struct ActiveThread {
|
|||
list_state: ListState,
|
||||
rendered_messages_by_id: HashMap<MessageId, Entity<Markdown>>,
|
||||
rendered_scripting_tool_uses: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
|
||||
rendered_tool_use_labels: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
|
||||
editing_message: Option<(MessageId, EditMessageState)>,
|
||||
expanded_tool_uses: HashMap<LanguageModelToolUseId, bool>,
|
||||
last_error: Option<ThreadError>,
|
||||
|
@ -70,6 +71,7 @@ impl ActiveThread {
|
|||
messages: Vec::new(),
|
||||
rendered_messages_by_id: HashMap::default(),
|
||||
rendered_scripting_tool_uses: HashMap::default(),
|
||||
rendered_tool_use_labels: HashMap::default(),
|
||||
expanded_tool_uses: HashMap::default(),
|
||||
list_state: ListState::new(0, ListAlignment::Bottom, px(1024.), {
|
||||
let this = cx.entity().downgrade();
|
||||
|
@ -86,10 +88,29 @@ impl ActiveThread {
|
|||
for message in thread.read(cx).messages().cloned().collect::<Vec<_>>() {
|
||||
this.push_message(&message.id, message.text.clone(), window, cx);
|
||||
|
||||
for tool_use in thread.read(cx).scripting_tool_uses_for_message(message.id) {
|
||||
for tool_use in thread.read(cx).tool_uses_for_message(message.id, cx) {
|
||||
this.render_tool_use_label_markdown(
|
||||
tool_use.id.clone(),
|
||||
tool_use.ui_text.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
for tool_use in thread
|
||||
.read(cx)
|
||||
.scripting_tool_uses_for_message(message.id, cx)
|
||||
{
|
||||
this.render_tool_use_label_markdown(
|
||||
tool_use.id.clone(),
|
||||
tool_use.ui_text.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
this.render_scripting_tool_use_markdown(
|
||||
tool_use.id.clone(),
|
||||
tool_use.name.as_ref(),
|
||||
tool_use.ui_text.as_ref(),
|
||||
tool_use.input.clone(),
|
||||
window,
|
||||
cx,
|
||||
|
@ -287,6 +308,19 @@ impl ActiveThread {
|
|||
.insert(tool_use_id, lua_script);
|
||||
}
|
||||
|
||||
fn render_tool_use_label_markdown(
|
||||
&mut self,
|
||||
tool_use_id: LanguageModelToolUseId,
|
||||
tool_label: impl Into<SharedString>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.rendered_tool_use_labels.insert(
|
||||
tool_use_id,
|
||||
self.render_markdown(tool_label.into(), window, cx),
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_thread_event(
|
||||
&mut self,
|
||||
_thread: &Entity<Thread>,
|
||||
|
@ -341,9 +375,18 @@ impl ActiveThread {
|
|||
cx.notify();
|
||||
}
|
||||
ThreadEvent::UsePendingTools => {
|
||||
self.thread.update(cx, |thread, cx| {
|
||||
thread.use_pending_tools(cx);
|
||||
});
|
||||
let tool_uses = self
|
||||
.thread
|
||||
.update(cx, |thread, cx| thread.use_pending_tools(cx));
|
||||
|
||||
for tool_use in tool_uses {
|
||||
self.render_tool_use_label_markdown(
|
||||
tool_use.id,
|
||||
tool_use.ui_text.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
ThreadEvent::ToolFinished {
|
||||
pending_tool_use,
|
||||
|
@ -352,6 +395,13 @@ impl ActiveThread {
|
|||
} => {
|
||||
let canceled = *canceled;
|
||||
if let Some(tool_use) = pending_tool_use {
|
||||
self.render_tool_use_label_markdown(
|
||||
tool_use.id.clone(),
|
||||
SharedString::from(tool_use.ui_text.clone()),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
self.render_scripting_tool_use_markdown(
|
||||
tool_use.id.clone(),
|
||||
tool_use.name.as_ref(),
|
||||
|
@ -555,8 +605,8 @@ impl ActiveThread {
|
|||
// Get all the data we need from thread before we start using it in closures
|
||||
let checkpoint = thread.checkpoint_for_message(message_id);
|
||||
let context = thread.context_for_message(message_id);
|
||||
let tool_uses = thread.tool_uses_for_message(message_id);
|
||||
let scripting_tool_uses = thread.scripting_tool_uses_for_message(message_id);
|
||||
let tool_uses = thread.tool_uses_for_message(message_id, cx);
|
||||
let scripting_tool_uses = thread.scripting_tool_uses_for_message(message_id, cx);
|
||||
|
||||
// Don't render user messages that are just there for returning tool results.
|
||||
if message.role == Role::User
|
||||
|
@ -709,27 +759,25 @@ impl ActiveThread {
|
|||
)
|
||||
.child(div().p_2().child(message_content)),
|
||||
),
|
||||
Role::Assistant => {
|
||||
v_flex()
|
||||
.id(("message-container", ix))
|
||||
.child(div().py_3().px_4().child(message_content))
|
||||
.when(
|
||||
!tool_uses.is_empty() || !scripting_tool_uses.is_empty(),
|
||||
|parent| {
|
||||
parent.child(
|
||||
v_flex()
|
||||
.children(
|
||||
tool_uses
|
||||
.into_iter()
|
||||
.map(|tool_use| self.render_tool_use(tool_use, cx)),
|
||||
)
|
||||
.children(scripting_tool_uses.into_iter().map(|tool_use| {
|
||||
self.render_scripting_tool_use(tool_use, cx)
|
||||
})),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
Role::Assistant => v_flex()
|
||||
.id(("message-container", ix))
|
||||
.child(div().py_3().px_4().child(message_content))
|
||||
.when(
|
||||
!tool_uses.is_empty() || !scripting_tool_uses.is_empty(),
|
||||
|parent| {
|
||||
parent.child(
|
||||
v_flex()
|
||||
.children(
|
||||
tool_uses
|
||||
.into_iter()
|
||||
.map(|tool_use| self.render_tool_use(tool_use, cx)),
|
||||
)
|
||||
.children(scripting_tool_uses.into_iter().map(|tool_use| {
|
||||
self.render_scripting_tool_use(tool_use, window, cx)
|
||||
})),
|
||||
)
|
||||
},
|
||||
),
|
||||
Role::System => div().id(("message-container", ix)).py_1().px_2().child(
|
||||
v_flex()
|
||||
.bg(colors.editor_background)
|
||||
|
@ -805,11 +853,10 @@ impl ActiveThread {
|
|||
}
|
||||
}),
|
||||
))
|
||||
.child(
|
||||
Label::new(tool_use.name)
|
||||
.size(LabelSize::Small)
|
||||
.buffer_font(cx),
|
||||
),
|
||||
.child(div().text_ui_sm(cx).children(
|
||||
self.rendered_tool_use_labels.get(&tool_use.id).cloned(),
|
||||
))
|
||||
.truncate(),
|
||||
)
|
||||
.child({
|
||||
let (icon_name, color, animated) = match &tool_use.status {
|
||||
|
@ -937,6 +984,7 @@ impl ActiveThread {
|
|||
fn render_scripting_tool_use(
|
||||
&self,
|
||||
tool_use: ToolUse,
|
||||
window: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let is_open = self
|
||||
|
@ -982,7 +1030,12 @@ impl ActiveThread {
|
|||
}
|
||||
}),
|
||||
))
|
||||
.child(Label::new(tool_use.name)),
|
||||
.child(div().text_ui_sm(cx).child(self.render_markdown(
|
||||
tool_use.ui_text.clone(),
|
||||
window,
|
||||
cx,
|
||||
)))
|
||||
.truncate(),
|
||||
)
|
||||
.child(
|
||||
Label::new(match tool_use.status {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue