added initial working status in inline assistant prompt

This commit is contained in:
KCaverly 2023-10-05 13:01:11 +03:00
parent 933c21f3d3
commit ec1b4e6f85
4 changed files with 129 additions and 77 deletions

View File

@ -290,7 +290,7 @@ impl EmbeddingProvider for OpenAIEmbeddings {
let mut request_number = 0;
let mut rate_limiting = false;
let mut request_timeout: u64 = 15;
let mut request_timeout: u64 = 30;
let mut response: Response<AsyncBody>;
while request_number < MAX_RETRIES {
response = self

View File

@ -24,10 +24,10 @@ use futures::StreamExt;
use gpui::{
actions,
elements::{
ChildView, Component, Empty, Flex, Label, MouseEventHandler, ParentElement, SafeStylable,
Stack, Svg, Text, UniformList, UniformListState,
ChildView, Component, Empty, Flex, Label, LabelStyle, MouseEventHandler, ParentElement,
SafeStylable, Stack, Svg, Text, UniformList, UniformListState,
},
fonts::HighlightStyle,
fonts::{HighlightStyle, TextStyle},
geometry::vector::{vec2f, Vector2F},
platform::{CursorStyle, MouseButton, PromptLevel},
Action, AnyElement, AppContext, AsyncAppContext, ClipboardItem, Element, Entity, ModelContext,
@ -37,7 +37,7 @@ use gpui::{
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _};
use project::Project;
use search::BufferSearchBar;
use semantic_index::SemanticIndex;
use semantic_index::{SemanticIndex, SemanticIndexStatus};
use settings::SettingsStore;
use std::{
cell::{Cell, RefCell},
@ -2756,6 +2756,7 @@ struct InlineAssistant {
semantic_index: Option<ModelHandle<SemanticIndex>>,
semantic_permissioned: Option<bool>,
project: ModelHandle<Project>,
maintain_rate_limit: Option<Task<()>>,
}
impl Entity for InlineAssistant {
@ -2772,67 +2773,65 @@ impl View for InlineAssistant {
let theme = theme::current(cx);
Flex::row()
.with_child(
Flex::row()
.with_child(
Button::action(ToggleIncludeConversation)
.with_tooltip("Include Conversation", theme.tooltip.clone())
.with_children([Flex::row()
.with_child(
Button::action(ToggleIncludeConversation)
.with_tooltip("Include Conversation", theme.tooltip.clone())
.with_id(self.id)
.with_contents(theme::components::svg::Svg::new("icons/ai.svg"))
.toggleable(self.include_conversation)
.with_style(theme.assistant.inline.include_conversation.clone())
.element()
.aligned(),
)
.with_children(if SemanticIndex::enabled(cx) {
Some(
Button::action(ToggleRetrieveContext)
.with_tooltip("Retrieve Context", theme.tooltip.clone())
.with_id(self.id)
.with_contents(theme::components::svg::Svg::new("icons/ai.svg"))
.toggleable(self.include_conversation)
.with_style(theme.assistant.inline.include_conversation.clone())
.with_contents(theme::components::svg::Svg::new(
"icons/magnifying_glass.svg",
))
.toggleable(self.retrieve_context)
.with_style(theme.assistant.inline.retrieve_context.clone())
.element()
.aligned(),
)
.with_children(if SemanticIndex::enabled(cx) {
Some(
Button::action(ToggleRetrieveContext)
.with_tooltip("Retrieve Context", theme.tooltip.clone())
.with_id(self.id)
.with_contents(theme::components::svg::Svg::new(
"icons/magnifying_glass.svg",
))
.toggleable(self.retrieve_context)
.with_style(theme.assistant.inline.retrieve_context.clone())
.element()
.aligned(),
)
} else {
None
})
.with_children(if let Some(error) = self.codegen.read(cx).error() {
Some(
Svg::new("icons/error.svg")
.with_color(theme.assistant.error_icon.color)
.constrained()
.with_width(theme.assistant.error_icon.width)
.contained()
.with_style(theme.assistant.error_icon.container)
.with_tooltip::<ErrorIcon>(
self.id,
error.to_string(),
None,
theme.tooltip.clone(),
cx,
)
.aligned(),
)
} else {
None
})
.aligned()
.constrained()
.dynamically({
let measurements = self.measurements.clone();
move |constraint, _, _| {
let measurements = measurements.get();
SizeConstraint {
min: vec2f(measurements.gutter_width, constraint.min.y()),
max: vec2f(measurements.gutter_width, constraint.max.y()),
}
} else {
None
})
.with_children(if let Some(error) = self.codegen.read(cx).error() {
Some(
Svg::new("icons/error.svg")
.with_color(theme.assistant.error_icon.color)
.constrained()
.with_width(theme.assistant.error_icon.width)
.contained()
.with_style(theme.assistant.error_icon.container)
.with_tooltip::<ErrorIcon>(
self.id,
error.to_string(),
None,
theme.tooltip.clone(),
cx,
)
.aligned(),
)
} else {
None
})
.aligned()
.constrained()
.dynamically({
let measurements = self.measurements.clone();
move |constraint, _, _| {
let measurements = measurements.get();
SizeConstraint {
min: vec2f(measurements.gutter_width, constraint.min.y()),
max: vec2f(measurements.gutter_width, constraint.max.y()),
}
}),
)
}
})])
.with_child(Empty::new().constrained().dynamically({
let measurements = self.measurements.clone();
move |constraint, _, _| {
@ -2855,6 +2854,19 @@ impl View for InlineAssistant {
.left()
.flex(1., true),
)
.with_children(if self.retrieve_context {
Some(
Flex::row()
.with_child(Label::new(
self.retrieve_context_status(cx),
theme.assistant.inline.context_status.text.clone(),
))
.flex(1., true)
.aligned(),
)
} else {
None
})
.contained()
.with_style(theme.assistant.inline.container)
.into_any()
@ -2896,11 +2908,15 @@ impl InlineAssistant {
editor.set_placeholder_text(placeholder, cx);
editor
});
let subscriptions = vec![
let mut subscriptions = vec![
cx.observe(&codegen, Self::handle_codegen_changed),
cx.subscribe(&prompt_editor, Self::handle_prompt_editor_events),
];
if let Some(semantic_index) = semantic_index.clone() {
subscriptions.push(cx.observe(&semantic_index, Self::semantic_index_changed));
}
Self {
id,
prompt_editor,
@ -2918,6 +2934,7 @@ impl InlineAssistant {
semantic_permissioned: None,
semantic_index,
project,
maintain_rate_limit: None,
}
}
@ -2947,6 +2964,34 @@ impl InlineAssistant {
}
}
fn semantic_index_changed(
&mut self,
semantic_index: ModelHandle<SemanticIndex>,
cx: &mut ViewContext<Self>,
) {
let project = self.project.clone();
let status = semantic_index.read(cx).status(&project);
match status {
SemanticIndexStatus::Indexing {
rate_limit_expiry: Some(_),
..
} => {
if self.maintain_rate_limit.is_none() {
self.maintain_rate_limit = Some(cx.spawn(|this, mut cx| async move {
loop {
cx.background().timer(Duration::from_secs(1)).await;
this.update(&mut cx, |_, cx| cx.notify()).log_err();
}
}));
}
return;
}
_ => {
self.maintain_rate_limit = None;
}
}
}
fn handle_codegen_changed(&mut self, _: ModelHandle<Codegen>, cx: &mut ViewContext<Self>) {
let is_read_only = !self.codegen.read(cx).idle();
self.prompt_editor.update(cx, |editor, cx| {
@ -3044,16 +3089,7 @@ impl InlineAssistant {
cx.emit(InlineAssistantEvent::RetrieveContextToggled {
retrieve_context: this.retrieve_context,
});
if this.retrieve_context {
let context_status = this.retrieve_context_status(cx);
if let Some(workspace) = this.workspace.upgrade(cx) {
workspace.update(cx, |workspace, cx| {
workspace.show_toast(Toast::new(0, context_status), cx)
});
}
}
this.index_project(project, cx).log_err();
cx.notify();
})?;
@ -3062,6 +3098,18 @@ impl InlineAssistant {
.detach_and_log_err(cx);
}
fn index_project(
&self,
project: ModelHandle<Project>,
cx: &mut ViewContext<Self>,
) -> anyhow::Result<()> {
if let Some(semantic_index) = self.semantic_index.clone() {
let _ = semantic_index.update(cx, |index, cx| index.index_project(project, cx));
}
anyhow::Ok(())
}
fn retrieve_context_status(&self, cx: &mut ViewContext<Self>) -> String {
let project = self.project.clone();
if let Some(semantic_index) = self.semantic_index.clone() {
@ -3072,23 +3120,23 @@ impl InlineAssistant {
"Not Authenticated!\nPlease ensure you have an `OPENAI_API_KEY` in your environment variables.".to_string()
}
semantic_index::SemanticIndexStatus::Indexed => {
"Indexing for Context Retrieval Complete!".to_string()
"Indexing Complete!".to_string()
}
semantic_index::SemanticIndexStatus::Indexing { remaining_files, rate_limit_expiry } => {
let mut status = format!("Indexing for Context Retrieval...\nRemaining files to index: {remaining_files}");
let mut status = format!("Remaining files to index for Context Retrieval: {remaining_files}");
if let Some(rate_limit_expiry) = rate_limit_expiry {
let remaining_seconds =
rate_limit_expiry.duration_since(Instant::now());
if remaining_seconds > Duration::from_secs(0) {
writeln!(status, "Rate limit resets in {}s", remaining_seconds.as_secs()).unwrap();
write!(status, " (rate limit resets in {}s)", remaining_seconds.as_secs()).unwrap();
}
}
status
}
_ => {
"Indexing for Context Retrieval...\nRemaining files to index: 48".to_string()
semantic_index::SemanticIndexStatus::NotIndexed => {
"Not Indexed for Context Retrieval".to_string()
}
};
}

View File

@ -1191,6 +1191,7 @@ pub struct InlineAssistantStyle {
pub pending_edit_background: Color,
pub include_conversation: ToggleIconButtonStyle,
pub retrieve_context: ToggleIconButtonStyle,
pub context_status: ContainedText,
}
#[derive(Clone, Deserialize, Default, JsonSchema)]

View File

@ -79,6 +79,9 @@ export default function assistant(): any {
},
},
pending_edit_background: background(theme.highest, "positive"),
context_status: {
...text(theme.highest, "mono", "disabled", { size: "sm" }),
},
retrieve_context: toggleable({
base: interactive({
base: {