Compare commits

...

2 Commits

Author SHA1 Message Date
Richard Feldman
c7e926b7d9 wip 2024-10-17 16:52:08 -04:00
Richard Feldman
3bac98a056 WIP add Chat and Edit buttons
Co-authored-by: Antonio <antonio@zed.dev>
Co-authored-by: Marshall <marshall@zed.dev>
2024-10-17 16:20:01 -04:00
3 changed files with 151 additions and 21 deletions

View File

@@ -58,7 +58,9 @@ use crate::slash_command_settings::SlashCommandSettings;
actions!(
assistant,
[
Assist,
AssistLegacy,
AssistChat,
AssistEdit,
Split,
CopyCode,
CycleMessageRole,

View File

@@ -11,12 +11,13 @@ use crate::{
},
slash_command_picker,
terminal_inline_assistant::TerminalInlineAssistant,
Assist, AssistantPatch, AssistantPatchStatus, CacheStatus, ConfirmCommand, Content, Context,
ContextEvent, ContextId, ContextStore, ContextStoreEvent, CopyCode, CycleMessageRole,
DeployHistory, DeployPromptLibrary, InlineAssistant, InsertDraggedFiles, InsertIntoEditor,
Message, MessageId, MessageMetadata, MessageStatus, ModelPickerDelegate, ModelSelector,
NewContext, PendingSlashCommand, PendingSlashCommandStatus, QuoteSelection,
RemoteContextMetadata, SavedContextMetadata, Split, ToggleFocus, ToggleModelSelector,
AssistChat, AssistEdit, AssistLegacy, AssistantPatch, AssistantPatchStatus, CacheStatus,
ConfirmCommand, Content, Context, ContextEvent, ContextId, ContextStore, ContextStoreEvent,
CopyCode, CycleMessageRole, DeployHistory, DeployPromptLibrary, InlineAssistant,
InsertDraggedFiles, InsertIntoEditor, Message, MessageId, MessageKind, MessageMetadata,
MessageStatus, ModelPickerDelegate, ModelSelector, NewContext, PendingSlashCommand,
PendingSlashCommandStatus, QuoteSelection, RemoteContextMetadata, SavedContextMetadata, Split,
ToggleFocus, ToggleModelSelector,
};
use anyhow::Result;
use assistant_slash_command::{SlashCommand, SlashCommandOutputSection};
@@ -1585,7 +1586,19 @@ impl ContextEditor {
);
}
fn assist(&mut self, _: &Assist, cx: &mut ViewContext<Self>) {
fn assist_legacy(&mut self, _: &AssistLegacy, cx: &mut ViewContext<Self>) {
self.assist(MessageKind::Legacy, cx)
}
fn assist_chat(&mut self, _: &AssistChat, cx: &mut ViewContext<Self>) {
self.assist(MessageKind::Chat, cx)
}
fn assist_edit(&mut self, _: &AssistEdit, cx: &mut ViewContext<Self>) {
self.assist(MessageKind::Edit, cx)
}
fn assist(&mut self, message_kind: MessageKind, cx: &mut ViewContext<Self>) {
let provider = LanguageModelRegistry::read_global(cx).active_provider();
if provider
.as_ref()
@@ -1601,7 +1614,7 @@ impl ContextEditor {
}
self.last_error = None;
self.send_to_model(cx);
self.send_to_model(message_kind, cx);
cx.notify();
}
@@ -1620,8 +1633,11 @@ impl ContextEditor {
false
}
fn send_to_model(&mut self, cx: &mut ViewContext<Self>) {
if let Some(user_message) = self.context.update(cx, |context, cx| context.assist(cx)) {
fn send_to_model(&mut self, message_kind: MessageKind, cx: &mut ViewContext<Self>) {
if let Some(user_message) = self
.context
.update(cx, |context, cx| context.assist(message_kind, cx))
{
let new_selection = {
let cursor = user_message
.start
@@ -3596,6 +3612,80 @@ impl ContextEditor {
}
}
fn render_chat_or_edit(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
todo!()
// let focus_handle = self.focus_handle(cx).clone();
// let (style, tooltip) = match token_state(&self.context, cx) {
// Some(TokenState::NoTokensLeft { .. }) => (
// ButtonStyle::Tinted(TintColor::Negative),
// Some(Tooltip::text("Token limit reached", cx)),
// ),
// Some(TokenState::HasMoreTokens {
// over_warn_threshold,
// ..
// }) => {
// let (style, tooltip) = if over_warn_threshold {
// (
// ButtonStyle::Tinted(TintColor::Warning),
// Some(Tooltip::text("Token limit is close to exhaustion", cx)),
// )
// } else {
// (ButtonStyle::Filled, None)
// };
// (style, tooltip)
// }
// None => (ButtonStyle::Filled, None),
// };
// let provider = LanguageModelRegistry::read_global(cx).active_provider();
// let has_configuration_error = configuration_error(cx).is_some();
// let needs_to_accept_terms = self.show_accept_terms
// && provider
// .as_ref()
// .map_or(false, |provider| provider.must_accept_terms(cx));
// let disabled = has_configuration_error || needs_to_accept_terms;
// h_flex()
// .w_full()
// .justify_between()
// .child(
// ButtonLike::new("edit_button")
// .disabled(disabled)
// .style(style)
// .when_some(tooltip, |button, tooltip| {
// button.tooltip(move |_| tooltip.clone())
// })
// .layer(ElevationIndex::ModalSurface)
// .child(Label::new("Edit"))
// .children(
// KeyBinding::for_action_in(&AssistLegacy, &focus_handle, cx)
// .map(|binding| binding.into_any_element()),
// )
// .on_click(move |_event, cx| {
// focus_handle.dispatch_action(&AssistLegacy, cx);
// }),
// )
// .child(
// ButtonLike::new("chat_button")
// .disabled(disabled)
// .style(style)
// .when_some(tooltip, |button, tooltip| {
// button.tooltip(move |_| tooltip.clone())
// })
// .layer(ElevationIndex::ModalSurface)
// .child(Label::new("Chat"))
// .children(
// KeyBinding::for_action_in(&AssistLegacy, &focus_handle, cx)
// .map(|binding| binding.into_any_element()),
// )
// .on_click(move |_event, cx| {
// focus_handle.dispatch_action(&AssistLegacy, cx);
// }),
// )
}
fn render_send_button(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let focus_handle = self.focus_handle(cx).clone();
@@ -3639,11 +3729,11 @@ impl ContextEditor {
.layer(ElevationIndex::ModalSurface)
.child(Label::new("Send"))
.children(
KeyBinding::for_action_in(&Assist, &focus_handle, cx)
KeyBinding::for_action_in(&AssistLegacy, &focus_handle, cx)
.map(|binding| binding.into_any_element()),
)
.on_click(move |_event, cx| {
focus_handle.dispatch_action(&Assist, cx);
focus_handle.dispatch_action(&AssistLegacy, cx);
})
}
@@ -3881,6 +3971,8 @@ impl EventEmitter<SearchEvent> for ContextEditor {}
impl Render for ContextEditor {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let settings = AssistantSettings::get_global(cx);
let render_live_diffs = settings.are_live_diffs_enabled(cx);
let provider = LanguageModelRegistry::read_global(cx).active_provider();
let accept_terms = if self.show_accept_terms {
provider
@@ -3905,7 +3997,9 @@ impl Render for ContextEditor {
.capture_action(cx.listener(ContextEditor::paste))
.capture_action(cx.listener(ContextEditor::cycle_message_role))
.capture_action(cx.listener(ContextEditor::confirm_command))
.on_action(cx.listener(ContextEditor::assist))
.on_action(cx.listener(ContextEditor::assist_legacy))
.on_action(cx.listener(ContextEditor::assist_chat))
.on_action(cx.listener(ContextEditor::assist_edit))
.on_action(cx.listener(ContextEditor::split))
.size_full()
.children(self.render_notice(cx))
@@ -3965,12 +4059,13 @@ impl Render for ContextEditor {
}),
),
)
.child(
h_flex()
.w_full()
.justify_end()
.child(div().child(self.render_send_button(cx))),
),
.child(h_flex().w_full().justify_end().child(div().child(
if render_live_diffs {
self.render_chat_or_edit(cx)
} else {
self.render_send_button(cx)
},
))),
),
)
}

View File

@@ -113,6 +113,10 @@ impl ContextOperation {
message.status.context("invalid status")?,
),
timestamp: id.0,
// kind: {
// let todo = (); // TODO: Should these go in the protocol?
// MessageKind::Legacy
// },
cache: None,
},
version: language::proto::deserialize_version(&insert.version),
@@ -128,6 +132,10 @@ impl ContextOperation {
timestamp: language::proto::deserialize_timestamp(
update.timestamp.context("invalid timestamp")?,
),
// kind: {
// let todo = (); // TODO: Should these go in the protocol?
// MessageKind::Legacy
// },
cache: None,
},
version: language::proto::deserialize_version(&update.version),
@@ -351,16 +359,28 @@ pub struct MessageMetadata {
pub role: Role,
pub status: MessageStatus,
pub(crate) timestamp: clock::Lamport,
// pub kind: MessageKind,
#[serde(skip)]
pub cache: Option<MessageCacheMetadata>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum MessageKind {
/// No preamble
Legacy,
/// Preamble along the lines of "This is a chat message:"
Chat,
/// Preamble along the lines of "This is an edit message:"
Edit,
}
impl From<&Message> for MessageMetadata {
fn from(message: &Message) -> Self {
Self {
role: message.role,
status: message.status.clone(),
timestamp: message.id.0,
// kind: message.kind,
cache: message.cache.clone(),
}
}
@@ -390,6 +410,7 @@ pub struct Message {
pub id: MessageId,
pub role: Role,
pub status: MessageStatus,
pub kind: MessageKind,
pub cache: Option<MessageCacheMetadata>,
}
@@ -1865,7 +1886,11 @@ impl Context {
})
}
pub fn assist(&mut self, cx: &mut ModelContext<Self>) -> Option<MessageAnchor> {
pub fn assist(
&mut self,
message_kind: MessageKind,
cx: &mut ModelContext<Self>,
) -> Option<MessageAnchor> {
let model_registry = LanguageModelRegistry::read_global(cx);
let provider = model_registry.active_provider()?;
let model = model_registry.active_model()?;
@@ -1875,6 +1900,14 @@ impl Context {
log::info!("completion provider has no credentials");
return None;
}
let last_message = self
.messages(cx)
.find(|message| message.id == last_message_id);
// Mutate this so that future completion requests include past preambles too.
last_message.kind = message_kind;
// Compute which messages to cache, including the last one.
self.mark_cache_anchors(&model.cache_configuration(), false, cx);