agent: Render edit tool error as markdown (#30325)
Release Notes: - agent: Render edit tool error as markdown and allow selecting it
This commit is contained in:
parent
05a6c31ad8
commit
c512d43e8c
3 changed files with 98 additions and 68 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -676,6 +676,7 @@ dependencies = [
|
|||
"language_models",
|
||||
"linkme",
|
||||
"log",
|
||||
"markdown",
|
||||
"open",
|
||||
"paths",
|
||||
"portable-pty",
|
||||
|
|
|
@ -17,14 +17,14 @@ eval = []
|
|||
[dependencies]
|
||||
aho-corasick.workspace = true
|
||||
anyhow.workspace = true
|
||||
assistant_tool.workspace = true
|
||||
assistant_settings.workspace = true
|
||||
assistant_tool.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
chrono.workspace = true
|
||||
collections.workspace = true
|
||||
component.workspace = true
|
||||
editor.workspace = true
|
||||
derive_more.workspace = true
|
||||
editor.workspace = true
|
||||
feature_flags.workspace = true
|
||||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
|
@ -35,8 +35,9 @@ indoc.workspace = true
|
|||
itertools.workspace = true
|
||||
language.workspace = true
|
||||
language_model.workspace = true
|
||||
log.workspace = true
|
||||
linkme.workspace = true
|
||||
log.workspace = true
|
||||
markdown.workspace = true
|
||||
open.workspace = true
|
||||
paths.workspace = true
|
||||
portable-pty.workspace = true
|
||||
|
|
|
@ -20,6 +20,7 @@ use language::{
|
|||
language_settings::SoftWrap,
|
||||
};
|
||||
use language_model::{LanguageModel, LanguageModelRequest, LanguageModelToolSchemaFormat};
|
||||
use markdown::{Markdown, MarkdownElement, MarkdownStyle};
|
||||
use project::Project;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -335,7 +336,7 @@ pub struct EditFileToolCard {
|
|||
project: Entity<Project>,
|
||||
diff_task: Option<Task<Result<()>>>,
|
||||
preview_expanded: bool,
|
||||
error_expanded: bool,
|
||||
error_expanded: Option<Entity<Markdown>>,
|
||||
full_height_expanded: bool,
|
||||
total_lines: Option<u32>,
|
||||
editor_unique_id: EntityId,
|
||||
|
@ -378,7 +379,7 @@ impl EditFileToolCard {
|
|||
multibuffer,
|
||||
diff_task: None,
|
||||
preview_expanded: true,
|
||||
error_expanded: false,
|
||||
error_expanded: None,
|
||||
full_height_expanded: false,
|
||||
total_lines: None,
|
||||
}
|
||||
|
@ -435,9 +436,9 @@ impl ToolCard for EditFileToolCard {
|
|||
workspace: WeakEntity<Workspace>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let (failed, error_message) = match status {
|
||||
ToolUseStatus::Error(err) => (true, Some(err.to_string())),
|
||||
_ => (false, None),
|
||||
let error_message = match status {
|
||||
ToolUseStatus::Error(err) => Some(err),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let path_label_button = h_flex()
|
||||
|
@ -525,9 +526,11 @@ impl ToolCard for EditFileToolCard {
|
|||
.gap_1()
|
||||
.justify_between()
|
||||
.rounded_t_md()
|
||||
.when(!failed, |header| header.bg(codeblock_header_bg))
|
||||
.when(error_message.is_none(), |header| {
|
||||
header.bg(codeblock_header_bg)
|
||||
})
|
||||
.child(path_label_button)
|
||||
.when(failed, |header| {
|
||||
.when_some(error_message, |header, error_message| {
|
||||
header.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
|
@ -539,19 +542,28 @@ impl ToolCard for EditFileToolCard {
|
|||
.child(
|
||||
Disclosure::new(
|
||||
("edit-file-error-disclosure", self.editor_unique_id),
|
||||
self.error_expanded,
|
||||
self.error_expanded.is_some(),
|
||||
)
|
||||
.opened_icon(IconName::ChevronUp)
|
||||
.closed_icon(IconName::ChevronDown)
|
||||
.on_click(cx.listener(
|
||||
move |this, _event, _window, _cx| {
|
||||
this.error_expanded = !this.error_expanded;
|
||||
},
|
||||
)),
|
||||
.on_click(cx.listener({
|
||||
let error_message = error_message.clone();
|
||||
|
||||
move |this, _event, _window, cx| {
|
||||
if this.error_expanded.is_some() {
|
||||
this.error_expanded.take();
|
||||
} else {
|
||||
this.error_expanded = Some(cx.new(|cx| {
|
||||
Markdown::new(error_message.clone(), None, None, cx)
|
||||
}))
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
})),
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(!failed && self.has_diff(), |header| {
|
||||
.when(error_message.is_none() && self.has_diff(), |header| {
|
||||
header.child(
|
||||
Disclosure::new(
|
||||
("edit-file-disclosure", self.editor_unique_id),
|
||||
|
@ -658,12 +670,12 @@ impl ToolCard for EditFileToolCard {
|
|||
v_flex()
|
||||
.mb_2()
|
||||
.border_1()
|
||||
.when(failed, |card| card.border_dashed())
|
||||
.when(error_message.is_some(), |card| card.border_dashed())
|
||||
.border_color(border_color)
|
||||
.rounded_md()
|
||||
.overflow_hidden()
|
||||
.child(codeblock_header)
|
||||
.when(failed && self.error_expanded, |card| {
|
||||
.when_some(self.error_expanded.as_ref(), |card, error_markdown| {
|
||||
card.child(
|
||||
v_flex()
|
||||
.p_2()
|
||||
|
@ -683,65 +695,81 @@ impl ToolCard for EditFileToolCard {
|
|||
.rounded_md()
|
||||
.text_ui_sm(cx)
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.children(
|
||||
error_message
|
||||
.map(|error| div().child(error).into_any_element()),
|
||||
),
|
||||
.child(MarkdownElement::new(
|
||||
error_markdown.clone(),
|
||||
markdown_style(window, cx),
|
||||
)),
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(!self.has_diff() && !failed, |card| {
|
||||
.when(!self.has_diff() && error_message.is_none(), |card| {
|
||||
card.child(waiting_for_diff)
|
||||
})
|
||||
.when(
|
||||
!failed && self.preview_expanded && self.has_diff(),
|
||||
|card| {
|
||||
.when(self.preview_expanded && self.has_diff(), |card| {
|
||||
card.child(
|
||||
v_flex()
|
||||
.relative()
|
||||
.h_full()
|
||||
.when(!self.full_height_expanded, |editor_container| {
|
||||
editor_container
|
||||
.max_h(DEFAULT_COLLAPSED_LINES as f32 * editor_line_height)
|
||||
})
|
||||
.overflow_hidden()
|
||||
.border_t_1()
|
||||
.border_color(border_color)
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(editor)
|
||||
.when(
|
||||
!self.full_height_expanded && is_collapsible,
|
||||
|editor_container| editor_container.child(gradient_overlay),
|
||||
),
|
||||
)
|
||||
.when(is_collapsible, |card| {
|
||||
card.child(
|
||||
v_flex()
|
||||
.relative()
|
||||
.h_full()
|
||||
.when(!self.full_height_expanded, |editor_container| {
|
||||
editor_container
|
||||
.max_h(DEFAULT_COLLAPSED_LINES as f32 * editor_line_height)
|
||||
})
|
||||
.overflow_hidden()
|
||||
h_flex()
|
||||
.id(("expand-button", self.editor_unique_id))
|
||||
.flex_none()
|
||||
.cursor_pointer()
|
||||
.h_5()
|
||||
.justify_center()
|
||||
.border_t_1()
|
||||
.rounded_b_md()
|
||||
.border_color(border_color)
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(editor)
|
||||
.when(
|
||||
!self.full_height_expanded && is_collapsible,
|
||||
|editor_container| editor_container.child(gradient_overlay),
|
||||
),
|
||||
.hover(|style| style.bg(cx.theme().colors().element_hover.opacity(0.1)))
|
||||
.child(
|
||||
Icon::new(full_height_icon)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.tooltip(Tooltip::text(full_height_tooltip_label))
|
||||
.on_click(cx.listener(move |this, _event, _window, _cx| {
|
||||
this.full_height_expanded = !this.full_height_expanded;
|
||||
})),
|
||||
)
|
||||
.when(is_collapsible, |card| {
|
||||
card.child(
|
||||
h_flex()
|
||||
.id(("expand-button", self.editor_unique_id))
|
||||
.flex_none()
|
||||
.cursor_pointer()
|
||||
.h_5()
|
||||
.justify_center()
|
||||
.border_t_1()
|
||||
.rounded_b_md()
|
||||
.border_color(border_color)
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.hover(|style| {
|
||||
style.bg(cx.theme().colors().element_hover.opacity(0.1))
|
||||
})
|
||||
.child(
|
||||
Icon::new(full_height_icon)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.tooltip(Tooltip::text(full_height_tooltip_label))
|
||||
.on_click(cx.listener(move |this, _event, _window, _cx| {
|
||||
this.full_height_expanded = !this.full_height_expanded;
|
||||
})),
|
||||
)
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
|
||||
let theme_settings = ThemeSettings::get_global(cx);
|
||||
let ui_font_size = TextSize::Default.rems(cx);
|
||||
let mut text_style = window.text_style();
|
||||
|
||||
text_style.refine(&TextStyleRefinement {
|
||||
font_family: Some(theme_settings.ui_font.family.clone()),
|
||||
font_fallbacks: theme_settings.ui_font.fallbacks.clone(),
|
||||
font_features: Some(theme_settings.ui_font.features.clone()),
|
||||
font_size: Some(ui_font_size.into()),
|
||||
color: Some(cx.theme().colors().text),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
MarkdownStyle {
|
||||
base_text_style: text_style.clone(),
|
||||
selection_background_color: cx.theme().players().local().selection,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue