Compare commits

...

5 Commits

Author SHA1 Message Date
Nathan Sobo
500b581a46 language-model 2024-06-27 21:24:03 -06:00
Nathan Sobo
ccc6e13f99 Revert "Added the 'semantic_mining' crate to the Cargo.toml file."
This reverts commit 8f6ea25a95.
2024-06-24 14:35:09 -06:00
Nathan Sobo
aceb5581b3 Try aider 2024-06-24 14:30:14 -06:00
Nathan Sobo (aider)
24c8bad8de Added a new crate 'miner' to the Cargo.toml file. 2024-06-24 14:26:47 -06:00
Nathan Sobo (aider)
8f6ea25a95 Added the 'semantic_mining' crate to the Cargo.toml file. 2024-06-24 14:25:10 -06:00
13 changed files with 417 additions and 2 deletions

1
.gitignore vendored
View File

@@ -28,3 +28,4 @@ DerivedData/
.vscode
.wrangler
.flatpak-builder
.aider*

26
Cargo.lock generated
View File

@@ -5832,6 +5832,20 @@ dependencies = [
"util",
]
[[package]]
name = "language_model"
version = "0.1.0"
dependencies = [
"anyhow",
"client",
"collections",
"futures 0.3.28",
"gpui",
"proto",
"schemars",
"util",
]
[[package]]
name = "language_selector"
version = "0.1.0"
@@ -6427,6 +6441,18 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "miner"
version = "0.1.0"
dependencies = [
"anyhow",
"futures 0.3.28",
"gpui",
"project",
"schemars",
"worktree",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"

View File

@@ -53,11 +53,13 @@ members = [
"crates/languages",
"crates/live_kit_client",
"crates/live_kit_server",
"crates/language_model",
"crates/lsp",
"crates/markdown",
"crates/markdown_preview",
"crates/media",
"crates/menu",
"crates/miner",
"crates/multi_buffer",
"crates/node_runtime",
"crates/notifications",
@@ -200,6 +202,7 @@ image_viewer = { path = "crates/image_viewer" }
inline_completion_button = { path = "crates/inline_completion_button" }
journal = { path = "crates/journal" }
language = { path = "crates/language" }
language_model = { path = "crates/language_model" }
language_selector = { path = "crates/language_selector" }
language_tools = { path = "crates/language_tools" }
languages = { path = "crates/languages" }

View File

@@ -1,4 +1,4 @@
use crate::{AppContext, BorrowAppContext};
use crate::{AppContext, BorrowAppContext, Model};
/// A marker trait for types that can be stored in GPUI's global state.
///
@@ -72,3 +72,5 @@ impl<T: Global> UpdateGlobal for T {
cx.set_global(global)
}
}
impl<T: Global> Global for Model<T> {}

View File

@@ -0,0 +1,20 @@
[package]
name = "language_model"
version = "0.1.0"
edition = "2021"
[lib]
path = "src/language_model.rs"
[dependencies]
anyhow.workspace = true
client.workspace = true
collections.workspace = true
futures.workspace = true
gpui.workspace = true
proto.workspace = true
schemars.workspace = true
util.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,94 @@
mod registry;
mod zed_cloud;
pub use registry::*;
pub use zed_cloud::*;
use anyhow::Result;
use futures::{future::BoxFuture, stream::BoxStream};
use gpui::{AnyView, AppContext, SharedString, Task, WindowContext};
use schemars::schema::RootSchema;
pub trait LanguageModel {
fn is_authenticated(&self, cx: &mut AppContext) -> bool;
fn authenticate(&self, cx: &mut AppContext) -> Task<Result<()>>;
fn authentication_prompt(&self, cx: &mut WindowContext) -> AnyView;
fn reset_credentials(&self, cx: &mut AppContext) -> Task<Result<()>>;
fn count_tokens(
&self,
request: LanguageModelRequest,
cx: &mut AppContext,
) -> BoxFuture<'static, Result<usize>>;
fn complete(
&self,
request: LanguageModelRequest,
cx: &mut AppContext,
) -> BoxFuture<'static, Result<BoxStream<'static, Result<LanguageModelOutput>>>>;
}
pub enum LanguageModelOutput {
Text(String),
ToolCall(ToolCall),
}
pub struct ToolCall {
pub id: String,
pub name: String,
pub arguments: String,
}
pub struct LanguageModelRequest {
pub tools: Vec<LanguageModelTool>,
pub messages: Vec<LanguageModelRequestMessage>,
pub stop: Vec<String>,
pub temperature: f32,
}
pub struct LanguageModelTool {
pub name: String,
pub description: String,
pub parameters: RootSchema,
}
pub struct LanguageModelRequestMessage {
role: Role,
content: String,
}
pub enum Role {
User,
Assistant,
System,
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct LanguageModelId(pub SharedString);
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct LanguageModelName(pub SharedString);
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct LanguageModelProviderName(SharedString);
impl From<String> for LanguageModelId {
fn from(value: String) -> Self {
Self(SharedString::from(value))
}
}
impl From<String> for LanguageModelName {
fn from(value: String) -> Self {
Self(SharedString::from(value))
}
}
impl From<String> for LanguageModelProviderName {
fn from(value: String) -> Self {
Self(SharedString::from(value))
}
}

View File

@@ -0,0 +1,102 @@
use crate::{LanguageModel, LanguageModelId, LanguageModelName, LanguageModelProviderName};
use anyhow::Result;
use collections::HashMap;
use gpui::{AppContext, Global, Model, ModelContext};
use std::sync::Arc;
#[derive(Clone)]
pub struct ProvidedLanguageModel {
pub id: LanguageModelId,
pub name: LanguageModelName,
}
#[derive(Clone)]
struct AvailableLanguageModel {
pub provider: LanguageModelProviderName,
pub model: ProvidedLanguageModel,
}
pub trait LanguageModelProvider: 'static {
fn name(&self, cx: &AppContext) -> LanguageModelProviderName;
fn provided_models(&self, cx: &AppContext) -> Vec<ProvidedLanguageModel>;
fn model(&self, id: LanguageModelId, cx: &AppContext) -> Result<Arc<dyn LanguageModel>>;
}
impl<T: LanguageModelProvider> LanguageModelProvider for Model<T> {
fn name(&self, cx: &AppContext) -> LanguageModelProviderName {
self.read(cx).name(cx)
}
fn provided_models(&self, cx: &AppContext) -> Vec<ProvidedLanguageModel> {
self.read(cx).provided_models(cx)
}
fn model(&self, id: LanguageModelId, cx: &AppContext) -> Result<Arc<dyn LanguageModel>> {
self.read(cx).model(id, cx)
}
}
pub struct LanguageModelRegistry {
providers: HashMap<LanguageModelProviderName, Box<dyn LanguageModelProvider>>,
}
impl Global for LanguageModelRegistry {}
impl LanguageModelRegistry {
pub fn new() -> Self {
Self {
providers: HashMap::default(),
}
}
pub fn register<T>(&mut self, provider: Model<T>, cx: &mut ModelContext<Self>)
where
T: LanguageModelProvider,
{
cx.observe(&provider, |_, _, cx| {
cx.notify();
})
.detach();
if self
.providers
.insert(provider.name(cx), Box::new(provider.clone()))
.is_some()
{
panic!(
"A provider with the name {} already exists",
provider.name(cx).0
);
}
}
pub fn available_models(&self, cx: &AppContext) -> Vec<AvailableLanguageModel> {
self.providers
.values()
.flat_map(|provider| {
provider
.provided_models(cx)
.into_iter()
.map(|model| AvailableLanguageModel {
provider: provider.name(cx),
model,
})
})
.collect()
}
pub fn model(
&mut self,
info: &AvailableLanguageModel,
cx: &mut AppContext,
) -> Result<Arc<dyn LanguageModel>> {
let provider = self
.providers
.get(&info.provider)
.ok_or_else(|| anyhow::anyhow!("No provider found for name: {:?}", info.provider))?;
provider.model(info.model.id.clone(), cx)
}
}

View File

@@ -0,0 +1,108 @@
use client::Client;
use gpui::ModelContext;
use std::sync::Arc;
use crate::{
LanguageModel, LanguageModelId, LanguageModelProvider, LanguageModelProviderName,
ProvidedLanguageModel,
};
pub struct ZedCloudModelProvider {
client: Arc<Client>,
available_models: Vec<ProvidedLanguageModel>,
}
impl ZedCloudModelProvider {
pub fn new(client: Arc<Client>, cx: &mut ModelContext<Self>) -> Self {
let authenticated = client.user_id().is_some();
if authenticated {
client.request(client::proto::GetAvail {});
let models = cx.spawn(|this, mut cx| async move {
let response = this.update(&mut cx, |this, _| {})?;
response.await
});
match models.await {
Ok(models) => {
self.available_models = models
.models
.into_iter()
.map(|model| ProvidedLanguageModel {
id: LanguageModelId(model.id),
name: model.name,
})
.collect();
}
Err(err) => {
log::error!("Failed to fetch language models: {}", err);
}
}
}
Self {
client,
available_models: Vec::new(),
}
}
}
impl LanguageModelProvider for ZedCloudModelProvider {
fn name(&self, _cx: &gpui::AppContext) -> crate::LanguageModelProviderName {
LanguageModelProviderName("Zed Cloud".into())
}
fn provided_models(&self, _cx: &gpui::AppContext) -> Vec<ProvidedLanguageModel> {
self.available_models.clone()
}
fn model(
&self,
id: LanguageModelId,
_cx: &gpui::AppContext,
) -> gpui::Result<Arc<dyn LanguageModel>> {
todo!()
}
}
struct ZedCloudModel {
id: LanguageModelId,
client: Arc<Client>,
}
impl LanguageModel for ZedCloudModel {
fn is_authenticated(&self, cx: &mut gpui::AppContext) -> bool {
todo!()
}
fn authenticate(&self, cx: &mut gpui::AppContext) -> gpui::Task<gpui::Result<()>> {
todo!()
}
fn authentication_prompt(&self, cx: &mut gpui::WindowContext) -> gpui::AnyView {
todo!()
}
fn reset_credentials(&self, cx: &mut gpui::AppContext) -> gpui::Task<gpui::Result<()>> {
todo!()
}
fn count_tokens(
&self,
request: crate::LanguageModelRequest,
cx: &mut gpui::AppContext,
) -> futures::future::BoxFuture<'static, gpui::Result<usize>> {
todo!()
}
fn complete(
&self,
request: crate::LanguageModelRequest,
cx: &mut gpui::AppContext,
) -> futures::future::BoxFuture<
'static,
gpui::Result<futures::stream::BoxStream<'static, gpui::Result<crate::LanguageModelOutput>>>,
> {
todo!()
}
}

18
crates/miner/Cargo.toml Normal file
View File

@@ -0,0 +1,18 @@
[package]
name = "miner"
version = "0.1.0"
edition = "2021"
publish = false
license = "GPL-3.0-or-later"
[lib]
path = "src/miner.rs"
doctest = false
[dependencies]
anyhow.workspace = true
futures.workspace = true
gpui.workspace = true
project.workspace = true
schemars.workspace = true
worktree.workspace = true

View File

@@ -0,0 +1 @@

24
crates/miner/src/miner.rs Normal file
View File

@@ -0,0 +1,24 @@
mod language_model;
use futures::Stream;
use gpui::Model;
use project::Project;
use std::sync::Arc;
pub struct Miner {
project: Model<Project>,
language_model: Arc<dyn LanguageModel>,
}
impl Miner {
pub fn new(project: Model<Project>, language_model: Arc<dyn LanguageModel>) -> Self {
Self {
project,
language_model,
}
}
}
pub trait LanguageModel: Send + Sync {
fn generate(&self) -> Box<dyn Stream<Item = String> + Send + Unpin>;
}

View File

@@ -201,6 +201,8 @@ message Envelope {
JoinHostedProject join_hosted_project = 164;
GetAvailableLanguageModels get_available_language_models = 211;
GetAvailableLanguageModelsResponse get_available_language_models_response = 212; // current max
CompleteWithLanguageModel complete_with_language_model = 166;
LanguageModelResponse language_model_response = 167;
CountTokensWithLanguageModel count_tokens_with_language_model = 168;
@@ -255,7 +257,7 @@ message Envelope {
TaskTemplates task_templates = 206;
LinkedEditingRange linked_editing_range = 209;
LinkedEditingRangeResponse linked_editing_range_response = 210; // current max
LinkedEditingRangeResponse linked_editing_range_response = 210;
}
reserved 158 to 161;
@@ -1959,6 +1961,19 @@ message SetRoomParticipantRole {
ChannelRole role = 3;
}
message GetAvailableLanguageModels {}
message GetAvailableLanguageModelsResponse {
repeated LanguageModelInfo models = 1;
}
message LanguageModelInfo {
string id = 1; // Unique identifier for the model
string name = 2; // Human-readable name of the model
string description = 3; // Brief description of the model's capabilities
uint32 max_tokens = 4; // Maximum number of tokens the model can process
}
message CompleteWithLanguageModel {
string model = 1;
repeated LanguageModelRequestMessage messages = 2;

View File

@@ -179,6 +179,7 @@ messages!(
(FormatBuffers, Foreground),
(FormatBuffersResponse, Foreground),
(FuzzySearchUsers, Foreground),
(GetAvailableLanguageModels, Background),
(GetCachedEmbeddings, Background),
(GetCachedEmbeddingsResponse, Background),
(GetChannelMembers, Foreground),