agent: Add UI for upsell scenarios (#29805)
Release Notes: - N/A --------- Co-authored-by: Marshall Bowers <git@maxdeviant.com>
This commit is contained in:
parent
a19687a815
commit
fe177f5d69
13 changed files with 659 additions and 135 deletions
|
@ -4,8 +4,12 @@ use std::sync::Arc;
|
|||
use crate::assistant_model_selector::{AssistantModelSelector, ModelType};
|
||||
use crate::context::{AgentContextKey, ContextCreasesAddon, ContextLoadResult, load_context};
|
||||
use crate::tool_compatibility::{IncompatibleToolsState, IncompatibleToolsTooltip};
|
||||
use crate::ui::{AgentPreview, AnimatedLabel, MaxModeTooltip};
|
||||
use crate::ui::{
|
||||
AnimatedLabel, MaxModeTooltip,
|
||||
preview::{AgentPreview, UsageCallout},
|
||||
};
|
||||
use buffer_diff::BufferDiff;
|
||||
use client::UserStore;
|
||||
use collections::{HashMap, HashSet};
|
||||
use editor::actions::{MoveUp, Paste};
|
||||
use editor::{
|
||||
|
@ -27,6 +31,7 @@ use language_model_selector::ToggleModelSelector;
|
|||
use multi_buffer;
|
||||
use project::Project;
|
||||
use prompt_store::PromptStore;
|
||||
use proto::Plan;
|
||||
use settings::Settings;
|
||||
use std::time::Duration;
|
||||
use theme::ThemeSettings;
|
||||
|
@ -53,6 +58,7 @@ pub struct MessageEditor {
|
|||
editor: Entity<Editor>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
project: Entity<Project>,
|
||||
user_store: Entity<UserStore>,
|
||||
context_store: Entity<ContextStore>,
|
||||
prompt_store: Option<Entity<PromptStore>>,
|
||||
context_strip: Entity<ContextStrip>,
|
||||
|
@ -126,6 +132,7 @@ impl MessageEditor {
|
|||
pub fn new(
|
||||
fs: Arc<dyn Fs>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
user_store: Entity<UserStore>,
|
||||
context_store: Entity<ContextStore>,
|
||||
prompt_store: Option<Entity<PromptStore>>,
|
||||
thread_store: WeakEntity<ThreadStore>,
|
||||
|
@ -188,6 +195,7 @@ impl MessageEditor {
|
|||
Self {
|
||||
editor: editor.clone(),
|
||||
project: thread.read(cx).project().clone(),
|
||||
user_store,
|
||||
thread,
|
||||
incompatible_tools_state: incompatible_tools.clone(),
|
||||
workspace,
|
||||
|
@ -1030,79 +1038,72 @@ impl MessageEditor {
|
|||
})
|
||||
}
|
||||
|
||||
fn render_usage_callout(&self, line_height: Pixels, cx: &mut Context<Self>) -> Option<Div> {
|
||||
if !cx.has_flag::<NewBillingFeatureFlag>() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let plan = self
|
||||
.user_store
|
||||
.read(cx)
|
||||
.current_plan()
|
||||
.map(|plan| match plan {
|
||||
Plan::Free => zed_llm_client::Plan::Free,
|
||||
Plan::ZedPro => zed_llm_client::Plan::ZedPro,
|
||||
Plan::ZedProTrial => zed_llm_client::Plan::ZedProTrial,
|
||||
})
|
||||
.unwrap_or(zed_llm_client::Plan::Free);
|
||||
let usage = self.thread.read(cx).last_usage()?;
|
||||
|
||||
Some(
|
||||
div()
|
||||
.child(UsageCallout::new(plan, usage))
|
||||
.line_height(line_height),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_token_limit_callout(
|
||||
&self,
|
||||
line_height: Pixels,
|
||||
token_usage_ratio: TokenUsageRatio,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Div {
|
||||
let heading = if token_usage_ratio == TokenUsageRatio::Exceeded {
|
||||
) -> Option<Div> {
|
||||
if !cx.has_flag::<NewBillingFeatureFlag>() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let title = if token_usage_ratio == TokenUsageRatio::Exceeded {
|
||||
"Thread reached the token limit"
|
||||
} else {
|
||||
"Thread reaching the token limit soon"
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.p_2()
|
||||
.gap_2()
|
||||
.flex_wrap()
|
||||
.justify_between()
|
||||
.bg(
|
||||
if token_usage_ratio == TokenUsageRatio::Exceeded {
|
||||
cx.theme().status().error_background.opacity(0.1)
|
||||
} else {
|
||||
cx.theme().status().warning_background.opacity(0.1)
|
||||
})
|
||||
.border_t_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.items_start()
|
||||
.child(
|
||||
h_flex()
|
||||
.h(line_height)
|
||||
.justify_center()
|
||||
.child(
|
||||
if token_usage_ratio == TokenUsageRatio::Exceeded {
|
||||
Icon::new(IconName::X)
|
||||
.color(Color::Error)
|
||||
.size(IconSize::XSmall)
|
||||
} else {
|
||||
Icon::new(IconName::Warning)
|
||||
.color(Color::Warning)
|
||||
.size(IconSize::XSmall)
|
||||
}
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.mr_auto()
|
||||
.child(Label::new(heading).size(LabelSize::Small))
|
||||
.child(
|
||||
Label::new(
|
||||
"Start a new thread from a summary to continue the conversation.",
|
||||
)
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new("new-thread", "Start New Thread")
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
let from_thread_id = Some(this.thread.read(cx).id().clone());
|
||||
let message = "Start a new thread from a summary to continue the conversation.";
|
||||
|
||||
window.dispatch_action(Box::new(NewThread {
|
||||
from_thread_id
|
||||
}), cx);
|
||||
}))
|
||||
.icon(IconName::Plus)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.label_size(LabelSize::Small),
|
||||
)
|
||||
let icon = if token_usage_ratio == TokenUsageRatio::Exceeded {
|
||||
Icon::new(IconName::X)
|
||||
.color(Color::Error)
|
||||
.size(IconSize::XSmall)
|
||||
} else {
|
||||
Icon::new(IconName::Warning)
|
||||
.color(Color::Warning)
|
||||
.size(IconSize::XSmall)
|
||||
};
|
||||
|
||||
Some(
|
||||
div()
|
||||
.child(ui::Callout::multi_line(
|
||||
title.into(),
|
||||
message.into(),
|
||||
icon,
|
||||
"Start New Thread".into(),
|
||||
Box::new(cx.listener(|this, _, window, cx| {
|
||||
let from_thread_id = Some(this.thread.read(cx).id().clone());
|
||||
window.dispatch_action(Box::new(NewThread { from_thread_id }), cx);
|
||||
})),
|
||||
))
|
||||
.line_height(line_height),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn last_estimated_token_count(&self) -> Option<usize> {
|
||||
|
@ -1307,8 +1308,16 @@ impl Render for MessageEditor {
|
|||
parent.child(self.render_changed_buffers(&changed_buffers, window, cx))
|
||||
})
|
||||
.child(self.render_editor(font_size, line_height, window, cx))
|
||||
.when(token_usage_ratio != TokenUsageRatio::Normal, |parent| {
|
||||
parent.child(self.render_token_limit_callout(line_height, token_usage_ratio, cx))
|
||||
.children({
|
||||
let usage_callout = self.render_usage_callout(line_height, cx);
|
||||
|
||||
if usage_callout.is_some() {
|
||||
usage_callout
|
||||
} else if token_usage_ratio != TokenUsageRatio::Normal {
|
||||
self.render_token_limit_callout(line_height, token_usage_ratio, cx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1354,6 +1363,12 @@ impl Component for MessageEditor {
|
|||
fn scope() -> ComponentScope {
|
||||
ComponentScope::Agent
|
||||
}
|
||||
|
||||
fn description() -> Option<&'static str> {
|
||||
Some(
|
||||
"The composer experience of the Agent Panel. This interface handles context, composing messages, switching profiles, models and more.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AgentPreview for MessageEditor {
|
||||
|
@ -1364,16 +1379,18 @@ impl AgentPreview for MessageEditor {
|
|||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Option<AnyElement> {
|
||||
if let Some(workspace_entity) = workspace.upgrade() {
|
||||
let fs = workspace_entity.read(cx).app_state().fs.clone();
|
||||
let weak_project = workspace_entity.read(cx).project().clone().downgrade();
|
||||
if let Some(workspace) = workspace.upgrade() {
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
let user_store = workspace.read(cx).app_state().user_store.clone();
|
||||
let weak_project = workspace.read(cx).project().clone().downgrade();
|
||||
let context_store = cx.new(|_cx| ContextStore::new(weak_project, None));
|
||||
let thread = active_thread.read(cx).thread().clone();
|
||||
|
||||
let example_message_editor = cx.new(|cx| {
|
||||
let default_message_editor = cx.new(|cx| {
|
||||
MessageEditor::new(
|
||||
fs,
|
||||
workspace,
|
||||
workspace.downgrade(),
|
||||
user_store,
|
||||
context_store,
|
||||
None,
|
||||
thread_store,
|
||||
|
@ -1387,8 +1404,15 @@ impl AgentPreview for MessageEditor {
|
|||
v_flex()
|
||||
.gap_4()
|
||||
.children(vec![single_example(
|
||||
"Default",
|
||||
example_message_editor.clone().into_any_element(),
|
||||
"Default Message Editor",
|
||||
div()
|
||||
.w(px(540.))
|
||||
.pt_12()
|
||||
.bg(cx.theme().colors().panel_background)
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(default_message_editor.clone())
|
||||
.into_any_element(),
|
||||
)])
|
||||
.into_any_element(),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue