parent
0d4ca71e68
commit
2df06cd2e4
5 changed files with 219 additions and 166 deletions
3
assets/icons/light_bulb.svg
Normal file
3
assets/icons/light_bulb.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.1331 11.3776C10.2754 10.6665 10.1331 9.78593 11.1998 8.53327C11.82 7.80489 12.2664 6.96894 12.2664 6.04456C12.2664 4.91305 11.8169 3.82788 11.0168 3.02778C10.2167 2.22769 9.13152 1.7782 8.00001 1.7782C6.8685 1.7782 5.78334 2.22769 4.98324 3.02778C4.18314 3.82788 3.73364 4.91305 3.73364 6.04456C3.73364 6.75562 3.87586 7.6089 4.80024 8.53327C5.86683 9.80679 5.72462 10.6665 5.86683 11.3776M10.1331 11.3776V12.8821C10.1331 13.622 9.53341 14.2218 8.79353 14.2218H7.2065C6.46662 14.2218 5.86683 13.622 5.86683 12.8821V11.3776M10.1331 11.3776H5.86683" stroke="black" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 751 B |
|
@ -1756,7 +1756,7 @@ impl ActiveThread {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
div()
|
v_flex()
|
||||||
.text_ui(cx)
|
.text_ui(cx)
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.children(
|
.children(
|
||||||
|
@ -1841,177 +1841,225 @@ impl ActiveThread {
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let editor_bg = cx.theme().colors().editor_background;
|
let editor_bg = cx.theme().colors().panel_background;
|
||||||
|
|
||||||
div().pt_0p5().pb_2().child(
|
div().map(|this| {
|
||||||
v_flex()
|
if pending {
|
||||||
.rounded_lg()
|
this.v_flex()
|
||||||
.border_1()
|
.mt_neg_2()
|
||||||
.border_color(self.tool_card_border_color(cx))
|
.mb_1p5()
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.group("disclosure-header")
|
.group("disclosure-header")
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.py_1()
|
.child(
|
||||||
.px_2()
|
h_flex()
|
||||||
.bg(self.tool_card_header_bg(cx))
|
.gap_1p5()
|
||||||
.map(|this| {
|
.child(
|
||||||
if pending || is_open {
|
Icon::new(IconName::LightBulb)
|
||||||
this.rounded_t_md()
|
.size(IconSize::XSmall)
|
||||||
.border_b_1()
|
.color(Color::Muted),
|
||||||
.border_color(self.tool_card_border_color(cx))
|
)
|
||||||
} else {
|
.child({
|
||||||
this.rounded_md()
|
Label::new("Thinking")
|
||||||
}
|
.color(Color::Muted)
|
||||||
})
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.gap_1p5()
|
|
||||||
.child(
|
|
||||||
Icon::new(IconName::Brain)
|
|
||||||
.size(IconSize::XSmall)
|
|
||||||
.color(Color::Muted),
|
|
||||||
)
|
|
||||||
.child({
|
|
||||||
if pending {
|
|
||||||
Label::new("Thinking…")
|
|
||||||
.size(LabelSize::Small)
|
.size(LabelSize::Small)
|
||||||
.buffer_font(cx)
|
.with_animation(
|
||||||
|
"generating-label",
|
||||||
|
Animation::new(Duration::from_secs(1)).repeat(),
|
||||||
|
|mut label, delta| {
|
||||||
|
let text = match delta {
|
||||||
|
d if d < 0.25 => "Thinking",
|
||||||
|
d if d < 0.5 => "Thinking.",
|
||||||
|
d if d < 0.75 => "Thinking..",
|
||||||
|
_ => "Thinking...",
|
||||||
|
};
|
||||||
|
label.set_text(text);
|
||||||
|
label
|
||||||
|
},
|
||||||
|
)
|
||||||
.with_animation(
|
.with_animation(
|
||||||
"pulsating-label",
|
"pulsating-label",
|
||||||
Animation::new(Duration::from_secs(2))
|
Animation::new(Duration::from_secs(2))
|
||||||
.repeat()
|
.repeat()
|
||||||
.with_easing(pulsating_between(0.4, 0.8)),
|
.with_easing(pulsating_between(0.6, 1.)),
|
||||||
|label, delta| label.alpha(delta),
|
|label, delta| {
|
||||||
|
label.map_element(|label| label.alpha(delta))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.into_any_element()
|
}),
|
||||||
} else {
|
|
||||||
Label::new("Thought Process")
|
|
||||||
.size(LabelSize::Small)
|
|
||||||
.buffer_font(cx)
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.gap_1()
|
|
||||||
.child(
|
|
||||||
div().visible_on_hover("disclosure-header").child(
|
|
||||||
Disclosure::new("thinking-disclosure", is_open)
|
|
||||||
.opened_icon(IconName::ChevronUp)
|
|
||||||
.closed_icon(IconName::ChevronDown)
|
|
||||||
.on_click(cx.listener({
|
|
||||||
move |this, _event, _window, _cx| {
|
|
||||||
let is_open = this
|
|
||||||
.expanded_thinking_segments
|
|
||||||
.entry((message_id, ix))
|
|
||||||
.or_insert(false);
|
|
||||||
|
|
||||||
*is_open = !*is_open;
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child({
|
|
||||||
let (icon_name, color, animated) = if pending {
|
|
||||||
(IconName::ArrowCircle, Color::Accent, true)
|
|
||||||
} else {
|
|
||||||
(IconName::Check, Color::Success, false)
|
|
||||||
};
|
|
||||||
|
|
||||||
let icon =
|
|
||||||
Icon::new(icon_name).color(color).size(IconSize::Small);
|
|
||||||
|
|
||||||
if animated {
|
|
||||||
icon.with_animation(
|
|
||||||
"arrow-circle",
|
|
||||||
Animation::new(Duration::from_secs(2)).repeat(),
|
|
||||||
|icon, delta| {
|
|
||||||
icon.transform(Transformation::rotate(percentage(
|
|
||||||
delta,
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.into_any_element()
|
|
||||||
} else {
|
|
||||||
icon.into_any_element()
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.when(pending && !is_open, |this| {
|
|
||||||
let gradient_overlay = div()
|
|
||||||
.rounded_b_lg()
|
|
||||||
.h_20()
|
|
||||||
.absolute()
|
|
||||||
.w_full()
|
|
||||||
.bottom_0()
|
|
||||||
.left_0()
|
|
||||||
.bg(linear_gradient(
|
|
||||||
180.,
|
|
||||||
linear_color_stop(editor_bg, 1.),
|
|
||||||
linear_color_stop(editor_bg.opacity(0.2), 0.),
|
|
||||||
));
|
|
||||||
|
|
||||||
this.child(
|
|
||||||
div()
|
|
||||||
.relative()
|
|
||||||
.bg(editor_bg)
|
|
||||||
.rounded_b_lg()
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.id(("thinking-content", ix))
|
|
||||||
.p_2()
|
|
||||||
.h_20()
|
|
||||||
.track_scroll(scroll_handle)
|
|
||||||
.text_ui_sm(cx)
|
|
||||||
.child(
|
|
||||||
MarkdownElement::new(
|
|
||||||
markdown.clone(),
|
|
||||||
default_markdown_style(window, cx),
|
|
||||||
)
|
|
||||||
.on_url_click({
|
|
||||||
let workspace = self.workspace.clone();
|
|
||||||
move |text, window, cx| {
|
|
||||||
open_markdown_link(
|
|
||||||
text,
|
|
||||||
workspace.clone(),
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.overflow_hidden(),
|
|
||||||
)
|
)
|
||||||
.child(gradient_overlay),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.when(is_open, |this| {
|
|
||||||
this.child(
|
|
||||||
div()
|
|
||||||
.id(("thinking-content", ix))
|
|
||||||
.h_full()
|
|
||||||
.p_2()
|
|
||||||
.rounded_b_lg()
|
|
||||||
.bg(editor_bg)
|
|
||||||
.text_ui_sm(cx)
|
|
||||||
.child(
|
.child(
|
||||||
MarkdownElement::new(
|
h_flex()
|
||||||
markdown.clone(),
|
.gap_1()
|
||||||
default_markdown_style(window, cx),
|
.child(
|
||||||
)
|
div().visible_on_hover("disclosure-header").child(
|
||||||
.on_url_click({
|
Disclosure::new("thinking-disclosure", is_open)
|
||||||
let workspace = self.workspace.clone();
|
.opened_icon(IconName::ChevronUp)
|
||||||
move |text, window, cx| {
|
.closed_icon(IconName::ChevronDown)
|
||||||
open_markdown_link(text, workspace.clone(), window, cx);
|
.on_click(cx.listener({
|
||||||
}
|
move |this, _event, _window, _cx| {
|
||||||
}),
|
let is_open = this
|
||||||
|
.expanded_thinking_segments
|
||||||
|
.entry((message_id, ix))
|
||||||
|
.or_insert(false);
|
||||||
|
|
||||||
|
*is_open = !*is_open;
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child({
|
||||||
|
Icon::new(IconName::ArrowCircle)
|
||||||
|
.color(Color::Accent)
|
||||||
|
.size(IconSize::Small)
|
||||||
|
.with_animation(
|
||||||
|
"arrow-circle",
|
||||||
|
Animation::new(Duration::from_secs(2)).repeat(),
|
||||||
|
|icon, delta| {
|
||||||
|
icon.transform(Transformation::rotate(
|
||||||
|
percentage(delta),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}),
|
.when(!is_open, |this| {
|
||||||
)
|
let gradient_overlay = div()
|
||||||
|
.rounded_b_lg()
|
||||||
|
.h_full()
|
||||||
|
.absolute()
|
||||||
|
.w_full()
|
||||||
|
.bottom_0()
|
||||||
|
.left_0()
|
||||||
|
.bg(linear_gradient(
|
||||||
|
180.,
|
||||||
|
linear_color_stop(editor_bg, 1.),
|
||||||
|
linear_color_stop(editor_bg.opacity(0.2), 0.),
|
||||||
|
));
|
||||||
|
|
||||||
|
this.child(
|
||||||
|
div()
|
||||||
|
.relative()
|
||||||
|
.bg(editor_bg)
|
||||||
|
.rounded_b_lg()
|
||||||
|
.mt_2()
|
||||||
|
.pl_4()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id(("thinking-content", ix))
|
||||||
|
.max_h_20()
|
||||||
|
.track_scroll(scroll_handle)
|
||||||
|
.text_ui_sm(cx)
|
||||||
|
.overflow_hidden()
|
||||||
|
.child(
|
||||||
|
MarkdownElement::new(
|
||||||
|
markdown.clone(),
|
||||||
|
default_markdown_style(window, cx),
|
||||||
|
)
|
||||||
|
.on_url_click({
|
||||||
|
let workspace = self.workspace.clone();
|
||||||
|
move |text, window, cx| {
|
||||||
|
open_markdown_link(
|
||||||
|
text,
|
||||||
|
workspace.clone(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(gradient_overlay),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.when(is_open, |this| {
|
||||||
|
this.child(
|
||||||
|
div()
|
||||||
|
.id(("thinking-content", ix))
|
||||||
|
.h_full()
|
||||||
|
.bg(editor_bg)
|
||||||
|
.text_ui_sm(cx)
|
||||||
|
.child(
|
||||||
|
MarkdownElement::new(
|
||||||
|
markdown.clone(),
|
||||||
|
default_markdown_style(window, cx),
|
||||||
|
)
|
||||||
|
.on_url_click({
|
||||||
|
let workspace = self.workspace.clone();
|
||||||
|
move |text, window, cx| {
|
||||||
|
open_markdown_link(text, workspace.clone(), window, cx);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.v_flex()
|
||||||
|
.mt_neg_2()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.group("disclosure-header")
|
||||||
|
.pr_1()
|
||||||
|
.justify_between()
|
||||||
|
.opacity(0.8)
|
||||||
|
.hover(|style| style.opacity(1.))
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_1p5()
|
||||||
|
.child(
|
||||||
|
Icon::new(IconName::LightBulb)
|
||||||
|
.size(IconSize::XSmall)
|
||||||
|
.color(Color::Muted),
|
||||||
|
)
|
||||||
|
.child(Label::new("Thought Process").size(LabelSize::Small)),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div().visible_on_hover("disclosure-header").child(
|
||||||
|
Disclosure::new("thinking-disclosure", is_open)
|
||||||
|
.opened_icon(IconName::ChevronUp)
|
||||||
|
.closed_icon(IconName::ChevronDown)
|
||||||
|
.on_click(cx.listener({
|
||||||
|
move |this, _event, _window, _cx| {
|
||||||
|
let is_open = this
|
||||||
|
.expanded_thinking_segments
|
||||||
|
.entry((message_id, ix))
|
||||||
|
.or_insert(false);
|
||||||
|
|
||||||
|
*is_open = !*is_open;
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id(("thinking-content", ix))
|
||||||
|
.relative()
|
||||||
|
.mt_1p5()
|
||||||
|
.ml_1p5()
|
||||||
|
.pl_2p5()
|
||||||
|
.border_l_1()
|
||||||
|
.border_color(cx.theme().colors().border_variant)
|
||||||
|
.text_ui_sm(cx)
|
||||||
|
.when(is_open, |this| {
|
||||||
|
this.child(
|
||||||
|
MarkdownElement::new(
|
||||||
|
markdown.clone(),
|
||||||
|
default_markdown_style(window, cx),
|
||||||
|
)
|
||||||
|
.on_url_click({
|
||||||
|
let workspace = self.workspace.clone();
|
||||||
|
move |text, window, cx| {
|
||||||
|
open_markdown_link(text, workspace.clone(), window, cx);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_tool_use(
|
fn render_tool_use(
|
||||||
|
@ -2033,6 +2081,7 @@ impl ActiveThread {
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.map(|workspace| workspace.read(cx).app_state().fs.clone());
|
.map(|workspace| workspace.read(cx).app_state().fs.clone());
|
||||||
let needs_confirmation = matches!(&tool_use.status, ToolUseStatus::NeedsConfirmation);
|
let needs_confirmation = matches!(&tool_use.status, ToolUseStatus::NeedsConfirmation);
|
||||||
|
let edit_tools = tool_use.needs_confirmation;
|
||||||
|
|
||||||
let status_icons = div().child(match &tool_use.status {
|
let status_icons = div().child(match &tool_use.status {
|
||||||
ToolUseStatus::Pending | ToolUseStatus::NeedsConfirmation => {
|
ToolUseStatus::Pending | ToolUseStatus::NeedsConfirmation => {
|
||||||
|
@ -2209,10 +2258,10 @@ impl ActiveThread {
|
||||||
};
|
};
|
||||||
|
|
||||||
div().map(|element| {
|
div().map(|element| {
|
||||||
if !tool_use.needs_confirmation {
|
if !edit_tools {
|
||||||
element.child(
|
element.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.my_1p5()
|
.my_2()
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.group("disclosure-header")
|
.group("disclosure-header")
|
||||||
|
|
|
@ -2793,7 +2793,7 @@ fn render_thought_process_fold_icon_button(
|
||||||
let button = match status {
|
let button = match status {
|
||||||
ThoughtProcessStatus::Pending => button
|
ThoughtProcessStatus::Pending => button
|
||||||
.child(
|
.child(
|
||||||
Icon::new(IconName::Brain)
|
Icon::new(IconName::LightBulb)
|
||||||
.size(IconSize::Small)
|
.size(IconSize::Small)
|
||||||
.color(Color::Muted),
|
.color(Color::Muted),
|
||||||
)
|
)
|
||||||
|
@ -2808,7 +2808,7 @@ fn render_thought_process_fold_icon_button(
|
||||||
),
|
),
|
||||||
ThoughtProcessStatus::Completed => button
|
ThoughtProcessStatus::Completed => button
|
||||||
.style(ButtonStyle::Filled)
|
.style(ButtonStyle::Filled)
|
||||||
.child(Icon::new(IconName::Brain).size(IconSize::Small))
|
.child(Icon::new(IconName::LightBulb).size(IconSize::Small))
|
||||||
.child(Label::new("Thought Process").single_line()),
|
.child(Label::new("Thought Process").single_line()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl Tool for ThinkingTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn icon(&self) -> IconName {
|
fn icon(&self) -> IconName {
|
||||||
IconName::Brain
|
IconName::LightBulb
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_schema(&self, format: LanguageModelToolSchemaFormat) -> serde_json::Value {
|
fn input_schema(&self, format: LanguageModelToolSchemaFormat) -> serde_json::Value {
|
||||||
|
|
|
@ -141,6 +141,7 @@ pub enum IconName {
|
||||||
InlayHint,
|
InlayHint,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Library,
|
Library,
|
||||||
|
LightBulb,
|
||||||
LineHeight,
|
LineHeight,
|
||||||
Link,
|
Link,
|
||||||
ListTree,
|
ListTree,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue