Add assistant events (#2978)

Add assistant events

Release Notes:

- N/A
This commit is contained in:
Joseph T. Lyons 2023-09-15 15:25:35 -04:00 committed by GitHub
parent b9c1f3d558
commit 5df9a57a8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 4 deletions

2
Cargo.lock generated
View file

@ -101,6 +101,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
"client",
"collections", "collections",
"ctor", "ctor",
"editor", "editor",
@ -127,6 +128,7 @@ dependencies = [
"theme", "theme",
"tiktoken-rs 0.4.5", "tiktoken-rs 0.4.5",
"util", "util",
"uuid 1.4.1",
"workspace", "workspace",
] ]

View file

@ -9,6 +9,7 @@ path = "src/ai.rs"
doctest = false doctest = false
[dependencies] [dependencies]
client = { path = "../client" }
collections = { path = "../collections"} collections = { path = "../collections"}
editor = { path = "../editor" } editor = { path = "../editor" }
fs = { path = "../fs" } fs = { path = "../fs" }
@ -19,6 +20,7 @@ search = { path = "../search" }
settings = { path = "../settings" } settings = { path = "../settings" }
theme = { path = "../theme" } theme = { path = "../theme" }
util = { path = "../util" } util = { path = "../util" }
uuid = { version = "1.1.2", features = ["v4"] }
workspace = { path = "../workspace" } workspace = { path = "../workspace" }
anyhow.workspace = true anyhow.workspace = true

View file

@ -61,6 +61,7 @@ struct SavedMessage {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct SavedConversation { struct SavedConversation {
id: Option<String>,
zed: String, zed: String,
version: String, version: String,
text: String, text: String,

View file

@ -6,6 +6,7 @@ use crate::{
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use chrono::{DateTime, Local}; use chrono::{DateTime, Local};
use client::{telemetry::AssistantKind, ClickhouseEvent, TelemetrySettings};
use collections::{hash_map, HashMap, HashSet, VecDeque}; use collections::{hash_map, HashMap, HashSet, VecDeque};
use editor::{ use editor::{
display_map::{ display_map::{
@ -48,6 +49,7 @@ use theme::{
AssistantStyle, AssistantStyle,
}; };
use util::{paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt}; use util::{paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt};
use uuid::Uuid;
use workspace::{ use workspace::{
dock::{DockPosition, Panel}, dock::{DockPosition, Panel},
searchable::Direction, searchable::Direction,
@ -296,6 +298,7 @@ impl AssistantPanel {
self.include_conversation_in_next_inline_assist, self.include_conversation_in_next_inline_assist,
self.inline_prompt_history.clone(), self.inline_prompt_history.clone(),
codegen.clone(), codegen.clone(),
self.workspace.clone(),
cx, cx,
); );
cx.focus_self(); cx.focus_self();
@ -724,6 +727,7 @@ impl AssistantPanel {
self.api_key.clone(), self.api_key.clone(),
self.languages.clone(), self.languages.clone(),
self.fs.clone(), self.fs.clone(),
self.workspace.clone(),
cx, cx,
) )
}); });
@ -1059,6 +1063,7 @@ impl AssistantPanel {
} }
let fs = self.fs.clone(); let fs = self.fs.clone();
let workspace = self.workspace.clone();
let api_key = self.api_key.clone(); let api_key = self.api_key.clone();
let languages = self.languages.clone(); let languages = self.languages.clone();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
@ -1073,8 +1078,9 @@ impl AssistantPanel {
if let Some(ix) = this.editor_index_for_path(&path, cx) { if let Some(ix) = this.editor_index_for_path(&path, cx) {
this.set_active_editor_index(Some(ix), cx); this.set_active_editor_index(Some(ix), cx);
} else { } else {
let editor = cx let editor = cx.add_view(|cx| {
.add_view(|cx| ConversationEditor::for_conversation(conversation, fs, cx)); ConversationEditor::for_conversation(conversation, fs, workspace, cx)
});
this.add_conversation(editor, cx); this.add_conversation(editor, cx);
} }
})?; })?;
@ -1348,6 +1354,7 @@ struct Summary {
} }
struct Conversation { struct Conversation {
id: Option<String>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
message_anchors: Vec<MessageAnchor>, message_anchors: Vec<MessageAnchor>,
messages_metadata: HashMap<MessageId, MessageMetadata>, messages_metadata: HashMap<MessageId, MessageMetadata>,
@ -1398,6 +1405,7 @@ impl Conversation {
let model = settings.default_open_ai_model.clone(); let model = settings.default_open_ai_model.clone();
let mut this = Self { let mut this = Self {
id: Some(Uuid::new_v4().to_string()),
message_anchors: Default::default(), message_anchors: Default::default(),
messages_metadata: Default::default(), messages_metadata: Default::default(),
next_message_id: Default::default(), next_message_id: Default::default(),
@ -1435,6 +1443,7 @@ impl Conversation {
fn serialize(&self, cx: &AppContext) -> SavedConversation { fn serialize(&self, cx: &AppContext) -> SavedConversation {
SavedConversation { SavedConversation {
id: self.id.clone(),
zed: "conversation".into(), zed: "conversation".into(),
version: SavedConversation::VERSION.into(), version: SavedConversation::VERSION.into(),
text: self.buffer.read(cx).text(), text: self.buffer.read(cx).text(),
@ -1462,6 +1471,10 @@ impl Conversation {
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Self { ) -> Self {
let id = match saved_conversation.id {
Some(id) => Some(id),
None => Some(Uuid::new_v4().to_string()),
};
let model = saved_conversation.model; let model = saved_conversation.model;
let markdown = language_registry.language_for_name("Markdown"); let markdown = language_registry.language_for_name("Markdown");
let mut message_anchors = Vec::new(); let mut message_anchors = Vec::new();
@ -1491,6 +1504,7 @@ impl Conversation {
}); });
let mut this = Self { let mut this = Self {
id,
message_anchors, message_anchors,
messages_metadata: saved_conversation.message_metadata, messages_metadata: saved_conversation.message_metadata,
next_message_id, next_message_id,
@ -2108,6 +2122,7 @@ struct ScrollPosition {
struct ConversationEditor { struct ConversationEditor {
conversation: ModelHandle<Conversation>, conversation: ModelHandle<Conversation>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
workspace: WeakViewHandle<Workspace>,
editor: ViewHandle<Editor>, editor: ViewHandle<Editor>,
blocks: HashSet<BlockId>, blocks: HashSet<BlockId>,
scroll_position: Option<ScrollPosition>, scroll_position: Option<ScrollPosition>,
@ -2119,15 +2134,17 @@ impl ConversationEditor {
api_key: Rc<RefCell<Option<String>>>, api_key: Rc<RefCell<Option<String>>>,
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
workspace: WeakViewHandle<Workspace>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let conversation = cx.add_model(|cx| Conversation::new(api_key, language_registry, cx)); let conversation = cx.add_model(|cx| Conversation::new(api_key, language_registry, cx));
Self::for_conversation(conversation, fs, cx) Self::for_conversation(conversation, fs, workspace, cx)
} }
fn for_conversation( fn for_conversation(
conversation: ModelHandle<Conversation>, conversation: ModelHandle<Conversation>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
workspace: WeakViewHandle<Workspace>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let editor = cx.add_view(|cx| { let editor = cx.add_view(|cx| {
@ -2150,6 +2167,7 @@ impl ConversationEditor {
blocks: Default::default(), blocks: Default::default(),
scroll_position: None, scroll_position: None,
fs, fs,
workspace,
_subscriptions, _subscriptions,
}; };
this.update_message_headers(cx); this.update_message_headers(cx);
@ -2157,6 +2175,13 @@ impl ConversationEditor {
} }
fn assist(&mut self, _: &Assist, cx: &mut ViewContext<Self>) { fn assist(&mut self, _: &Assist, cx: &mut ViewContext<Self>) {
report_assistant_event(
self.workspace.clone(),
self.conversation.read(cx).id.clone(),
AssistantKind::Panel,
cx,
);
let cursors = self.cursors(cx); let cursors = self.cursors(cx);
let user_messages = self.conversation.update(cx, |conversation, cx| { let user_messages = self.conversation.update(cx, |conversation, cx| {
@ -2665,6 +2690,7 @@ enum InlineAssistantEvent {
struct InlineAssistant { struct InlineAssistant {
id: usize, id: usize,
prompt_editor: ViewHandle<Editor>, prompt_editor: ViewHandle<Editor>,
workspace: WeakViewHandle<Workspace>,
confirmed: bool, confirmed: bool,
has_focus: bool, has_focus: bool,
include_conversation: bool, include_conversation: bool,
@ -2780,6 +2806,7 @@ impl InlineAssistant {
include_conversation: bool, include_conversation: bool,
prompt_history: VecDeque<String>, prompt_history: VecDeque<String>,
codegen: ModelHandle<Codegen>, codegen: ModelHandle<Codegen>,
workspace: WeakViewHandle<Workspace>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let prompt_editor = cx.add_view(|cx| { let prompt_editor = cx.add_view(|cx| {
@ -2801,6 +2828,7 @@ impl InlineAssistant {
Self { Self {
id, id,
prompt_editor, prompt_editor,
workspace,
confirmed: false, confirmed: false,
has_focus: false, has_focus: false,
include_conversation, include_conversation,
@ -2859,6 +2887,8 @@ impl InlineAssistant {
if self.confirmed { if self.confirmed {
cx.emit(InlineAssistantEvent::Dismissed); cx.emit(InlineAssistantEvent::Dismissed);
} else { } else {
report_assistant_event(self.workspace.clone(), None, AssistantKind::Inline, cx);
let prompt = self.prompt_editor.read(cx).text(cx); let prompt = self.prompt_editor.read(cx).text(cx);
self.prompt_editor.update(cx, |editor, cx| { self.prompt_editor.update(cx, |editor, cx| {
editor.set_read_only(true); editor.set_read_only(true);
@ -3347,3 +3377,30 @@ mod tests {
.collect() .collect()
} }
} }
fn report_assistant_event(
workspace: WeakViewHandle<Workspace>,
conversation_id: Option<String>,
assistant_kind: AssistantKind,
cx: &AppContext,
) {
let Some(workspace) = workspace.upgrade(cx) else {
return;
};
let client = workspace.read(cx).project().read(cx).client();
let telemetry = client.telemetry();
let model = settings::get::<AssistantSettings>(cx)
.default_open_ai_model
.clone();
let event = ClickhouseEvent::Assistant {
conversation_id,
kind: assistant_kind,
model: model.full_name(),
};
let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
telemetry.report_clickhouse_event(event, telemetry_settings)
}

View file

@ -56,6 +56,13 @@ struct ClickhouseEventWrapper {
event: ClickhouseEvent, event: ClickhouseEvent,
} }
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum AssistantKind {
Panel,
Inline,
}
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum ClickhouseEvent { pub enum ClickhouseEvent {
@ -76,6 +83,11 @@ pub enum ClickhouseEvent {
room_id: Option<u64>, room_id: Option<u64>,
channel_id: Option<u64>, channel_id: Option<u64>,
}, },
Assistant {
conversation_id: Option<String>,
kind: AssistantKind,
model: &'static str,
},
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View file

@ -26,7 +26,6 @@ impl<C: SafeStylable> ComponentExt<C> for C {
} }
pub mod disclosure { pub mod disclosure {
use gpui::{ use gpui::{
elements::{Component, ContainerStyle, Empty, Flex, ParentElement, SafeStylable}, elements::{Component, ContainerStyle, Empty, Flex, ParentElement, SafeStylable},
Action, Element, Action, Element,