assistant: Overhaul provider infrastructure (#14929)
<img width="624" alt="image" src="https://github.com/user-attachments/assets/f492b0bd-14c3-49e2-b2ff-dc78e52b0815"> - [x] Correctly set custom model token count - [x] How to count tokens for Gemini models? - [x] Feature flag zed.dev provider - [x] Figure out how to configure custom models - [ ] Update docs Release Notes: - Added support for quickly switching between multiple language model providers in the assistant panel --------- Co-authored-by: Antonio <antonio@zed.dev>
This commit is contained in:
parent
17ef9a367f
commit
d0f52e90e6
55 changed files with 2757 additions and 2023 deletions
|
@ -21,7 +21,7 @@ pub use settings_store::{
|
|||
pub struct SettingsAssets;
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
let mut settings = SettingsStore::default();
|
||||
let mut settings = SettingsStore::new(cx);
|
||||
settings
|
||||
.set_default_settings(&default_settings(), cx)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::{settings_store::SettingsStore, Settings};
|
||||
use anyhow::{Context, Result};
|
||||
use fs::Fs;
|
||||
use futures::{channel::mpsc, StreamExt};
|
||||
use gpui::{AppContext, BackgroundExecutor, UpdateGlobal};
|
||||
use std::{io::ErrorKind, path::PathBuf, sync::Arc, time::Duration};
|
||||
use gpui::{AppContext, BackgroundExecutor, ReadGlobal, UpdateGlobal};
|
||||
use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||
use util::ResultExt;
|
||||
|
||||
pub const EMPTY_THEME_NAME: &str = "empty-theme";
|
||||
|
@ -91,46 +90,10 @@ pub fn handle_settings_file_changes(
|
|||
.detach();
|
||||
}
|
||||
|
||||
async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
|
||||
match fs.load(paths::settings_file()).await {
|
||||
result @ Ok(_) => result,
|
||||
Err(err) => {
|
||||
if let Some(e) = err.downcast_ref::<std::io::Error>() {
|
||||
if e.kind() == ErrorKind::NotFound {
|
||||
return Ok(crate::initial_user_settings_content().to_string());
|
||||
}
|
||||
}
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_settings_file<T: Settings>(
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &mut AppContext,
|
||||
update: impl 'static + Send + FnOnce(&mut T::FileContent),
|
||||
cx: &AppContext,
|
||||
update: impl 'static + Send + FnOnce(&mut T::FileContent, &AppContext),
|
||||
) {
|
||||
cx.spawn(|cx| async move {
|
||||
let old_text = load_settings(&fs).await?;
|
||||
let new_text = cx.read_global(|store: &SettingsStore, _cx| {
|
||||
store.new_text_for_update::<T>(old_text, update)
|
||||
})?;
|
||||
let initial_path = paths::settings_file().as_path();
|
||||
if fs.is_file(initial_path).await {
|
||||
let resolved_path = fs.canonicalize(initial_path).await.with_context(|| {
|
||||
format!("Failed to canonicalize settings path {:?}", initial_path)
|
||||
})?;
|
||||
|
||||
fs.atomic_write(resolved_path.clone(), new_text)
|
||||
.await
|
||||
.with_context(|| format!("Failed to write settings to file {:?}", resolved_path))?;
|
||||
} else {
|
||||
fs.atomic_write(initial_path.to_path_buf(), new_text)
|
||||
.await
|
||||
.with_context(|| format!("Failed to write settings to file {:?}", initial_path))?;
|
||||
}
|
||||
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
SettingsStore::global(cx).update_settings_file::<T>(fs, update);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use collections::{btree_map, hash_map, BTreeMap, HashMap};
|
||||
use gpui::{AppContext, AsyncAppContext, BorrowAppContext, Global, UpdateGlobal};
|
||||
use fs::Fs;
|
||||
use futures::{channel::mpsc, future::LocalBoxFuture, FutureExt, StreamExt};
|
||||
use gpui::{AppContext, AsyncAppContext, BorrowAppContext, Global, Task, UpdateGlobal};
|
||||
use lazy_static::lazy_static;
|
||||
use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema};
|
||||
use serde::{de::DeserializeOwned, Deserialize as _, Serialize};
|
||||
|
@ -161,23 +163,14 @@ pub struct SettingsStore {
|
|||
TypeId,
|
||||
Box<dyn Fn(&dyn Any) -> Option<usize> + Send + Sync + 'static>,
|
||||
)>,
|
||||
_setting_file_updates: Task<()>,
|
||||
setting_file_updates_tx: mpsc::UnboundedSender<
|
||||
Box<dyn FnOnce(AsyncAppContext) -> LocalBoxFuture<'static, Result<()>>>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl Global for SettingsStore {}
|
||||
|
||||
impl Default for SettingsStore {
|
||||
fn default() -> Self {
|
||||
SettingsStore {
|
||||
setting_values: Default::default(),
|
||||
raw_default_settings: serde_json::json!({}),
|
||||
raw_user_settings: serde_json::json!({}),
|
||||
raw_extension_settings: serde_json::json!({}),
|
||||
raw_local_settings: Default::default(),
|
||||
tab_size_callback: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SettingValue<T> {
|
||||
global_value: Option<T>,
|
||||
|
@ -207,6 +200,24 @@ trait AnySettingValue: 'static + Send + Sync {
|
|||
struct DeserializedSetting(Box<dyn Any>);
|
||||
|
||||
impl SettingsStore {
|
||||
pub fn new(cx: &AppContext) -> Self {
|
||||
let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
|
||||
Self {
|
||||
setting_values: Default::default(),
|
||||
raw_default_settings: serde_json::json!({}),
|
||||
raw_user_settings: serde_json::json!({}),
|
||||
raw_extension_settings: serde_json::json!({}),
|
||||
raw_local_settings: Default::default(),
|
||||
tab_size_callback: Default::default(),
|
||||
setting_file_updates_tx,
|
||||
_setting_file_updates: cx.spawn(|cx| async move {
|
||||
while let Some(setting_file_update) = setting_file_updates_rx.next().await {
|
||||
(setting_file_update)(cx.clone()).await.log_err();
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update<C, R>(cx: &mut C, f: impl FnOnce(&mut Self, &mut C) -> R) -> R
|
||||
where
|
||||
C: BorrowAppContext,
|
||||
|
@ -301,7 +312,7 @@ impl SettingsStore {
|
|||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test(cx: &mut AppContext) -> Self {
|
||||
let mut this = Self::default();
|
||||
let mut this = Self::new(cx);
|
||||
this.set_default_settings(&crate::test_settings(), cx)
|
||||
.unwrap();
|
||||
this.set_user_settings("{}", cx).unwrap();
|
||||
|
@ -323,6 +334,59 @@ impl SettingsStore {
|
|||
self.set_user_settings(&new_text, cx).unwrap();
|
||||
}
|
||||
|
||||
async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
|
||||
match fs.load(paths::settings_file()).await {
|
||||
result @ Ok(_) => result,
|
||||
Err(err) => {
|
||||
if let Some(e) = err.downcast_ref::<std::io::Error>() {
|
||||
if e.kind() == std::io::ErrorKind::NotFound {
|
||||
return Ok(crate::initial_user_settings_content().to_string());
|
||||
}
|
||||
}
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_settings_file<T: Settings>(
|
||||
&self,
|
||||
fs: Arc<dyn Fs>,
|
||||
update: impl 'static + Send + FnOnce(&mut T::FileContent, &AppContext),
|
||||
) {
|
||||
self.setting_file_updates_tx
|
||||
.unbounded_send(Box::new(move |cx: AsyncAppContext| {
|
||||
async move {
|
||||
let old_text = Self::load_settings(&fs).await?;
|
||||
let new_text = cx.read_global(|store: &SettingsStore, cx| {
|
||||
store.new_text_for_update::<T>(old_text, |content| update(content, cx))
|
||||
})?;
|
||||
let initial_path = paths::settings_file().as_path();
|
||||
if fs.is_file(initial_path).await {
|
||||
let resolved_path =
|
||||
fs.canonicalize(initial_path).await.with_context(|| {
|
||||
format!("Failed to canonicalize settings path {:?}", initial_path)
|
||||
})?;
|
||||
|
||||
fs.atomic_write(resolved_path.clone(), new_text)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!("Failed to write settings to file {:?}", resolved_path)
|
||||
})?;
|
||||
} else {
|
||||
fs.atomic_write(initial_path.to_path_buf(), new_text)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!("Failed to write settings to file {:?}", initial_path)
|
||||
})?;
|
||||
}
|
||||
|
||||
anyhow::Ok(())
|
||||
}
|
||||
.boxed_local()
|
||||
}))
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// Updates the value of a setting in a JSON file, returning the new text
|
||||
/// for that JSON file.
|
||||
pub fn new_text_for_update<T: Settings>(
|
||||
|
@ -1019,7 +1083,7 @@ mod tests {
|
|||
|
||||
#[gpui::test]
|
||||
fn test_settings_store_basic(cx: &mut AppContext) {
|
||||
let mut store = SettingsStore::default();
|
||||
let mut store = SettingsStore::new(cx);
|
||||
store.register_setting::<UserSettings>(cx);
|
||||
store.register_setting::<TurboSetting>(cx);
|
||||
store.register_setting::<MultiKeySettings>(cx);
|
||||
|
@ -1148,7 +1212,7 @@ mod tests {
|
|||
|
||||
#[gpui::test]
|
||||
fn test_setting_store_assign_json_before_register(cx: &mut AppContext) {
|
||||
let mut store = SettingsStore::default();
|
||||
let mut store = SettingsStore::new(cx);
|
||||
store
|
||||
.set_default_settings(
|
||||
r#"{
|
||||
|
@ -1191,7 +1255,7 @@ mod tests {
|
|||
|
||||
#[gpui::test]
|
||||
fn test_setting_store_update(cx: &mut AppContext) {
|
||||
let mut store = SettingsStore::default();
|
||||
let mut store = SettingsStore::new(cx);
|
||||
store.register_setting::<MultiKeySettings>(cx);
|
||||
store.register_setting::<UserSettings>(cx);
|
||||
store.register_setting::<LanguageSettings>(cx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue