From d8bafb5c81790b69b431f74aaf1a3fa1df006975 Mon Sep 17 00:00:00 2001 From: Luc Georges Date: Thu, 8 Feb 2024 22:40:01 +0100 Subject: [PATCH] fix: helix editor build crash --- Cargo.lock | 12 +++ crates/custom-types/Cargo.toml | 14 ++++ crates/custom-types/src/lib.rs | 2 + crates/custom-types/src/llm_ls.rs | 118 ++++++++++++++++++++++++++ crates/custom-types/src/request.rs | 32 +++++++ crates/llm-ls/Cargo.toml | 1 + crates/llm-ls/src/backend.rs | 15 +--- crates/llm-ls/src/main.rs | 121 ++++----------------------- crates/lsp-client/Cargo.toml | 1 - crates/lsp-client/src/client.rs | 5 +- crates/lsp-client/src/error.rs | 10 +++ crates/testbed/Cargo.toml | 1 + crates/testbed/holes/helix-smol.json | 2 +- crates/testbed/holes/helix.json | 2 +- crates/testbed/repositories-ci.yaml | 11 +-- crates/testbed/repositories.yaml | 11 +-- crates/testbed/src/main.rs | 29 ++++--- crates/testbed/src/types.rs | 90 -------------------- 18 files changed, 240 insertions(+), 237 deletions(-) create mode 100644 crates/custom-types/Cargo.toml create mode 100644 crates/custom-types/src/lib.rs create mode 100644 crates/custom-types/src/llm_ls.rs create mode 100644 crates/custom-types/src/request.rs delete mode 100644 crates/testbed/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index bd3f737..5b4d6b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,6 +427,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "custom-types" +version = "0.1.0" +dependencies = [ + "lsp-types", + "serde", + "serde_json", + "uuid", +] + [[package]] name = "darling" version = "0.14.4" @@ -975,6 +985,7 @@ name = "llm-ls" version = "0.4.0" dependencies = [ "clap", + "custom-types", "home", "reqwest", "ropey", @@ -1968,6 +1979,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "custom-types", "futures", "futures-util", "home", diff --git a/crates/custom-types/Cargo.toml b/crates/custom-types/Cargo.toml new file mode 100644 index 0000000..c71324b --- /dev/null +++ b/crates/custom-types/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "custom-types" +version = "0.1.0" +edition.workspace = true +license.workspace = true +authors.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lsp-types = "0.94" +serde = "1" +serde_json = "1" +uuid = "1" diff --git a/crates/custom-types/src/lib.rs b/crates/custom-types/src/lib.rs new file mode 100644 index 0000000..63ea557 --- /dev/null +++ b/crates/custom-types/src/lib.rs @@ -0,0 +1,2 @@ +pub mod llm_ls; +pub mod request; diff --git a/crates/custom-types/src/llm_ls.rs b/crates/custom-types/src/llm_ls.rs new file mode 100644 index 0000000..10edc7c --- /dev/null +++ b/crates/custom-types/src/llm_ls.rs @@ -0,0 +1,118 @@ +use std::{fmt::Display, path::PathBuf}; + +use lsp_types::TextDocumentPositionParams; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_json::{Map, Value}; +use uuid::Uuid; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AcceptCompletionParams { + pub request_id: Uuid, + pub accepted_completion: u32, + pub shown_completions: Vec, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RejectCompletionParams { + pub request_id: Uuid, + pub shown_completions: Vec, +} + +#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Ide { + Neovim, + VSCode, + JetBrains, + Emacs, + Jupyter, + Sublime, + VisualStudio, + #[default] + Unknown, +} + +impl Display for Ide { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.serialize(f) + } +} + +fn parse_ide<'de, D>(d: D) -> std::result::Result +where + D: Deserializer<'de>, +{ + Deserialize::deserialize(d).map(|b: Option<_>| b.unwrap_or(Ide::Unknown)) +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Backend { + #[default] + HuggingFace, + Ollama, + OpenAi, + Tgi, +} + +impl Display for Backend { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.serialize(f) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct FimParams { + pub enabled: bool, + pub prefix: String, + pub middle: String, + pub suffix: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TokenizerConfig { + Local { + path: PathBuf, + }, + HuggingFace { + repository: String, + api_token: Option, + }, + Download { + url: String, + to: PathBuf, + }, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetCompletionsParams { + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + #[serde(default)] + #[serde(deserialize_with = "parse_ide")] + pub ide: Ide, + pub fim: FimParams, + pub api_token: Option, + pub model: String, + pub backend: Backend, + pub tokens_to_clear: Vec, + pub tokenizer_config: Option, + pub context_window: usize, + pub tls_skip_verify_insecure: bool, + pub request_body: Map, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Completion { + pub generated_text: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct GetCompletionsResult { + pub request_id: Uuid, + pub completions: Vec, +} diff --git a/crates/custom-types/src/request.rs b/crates/custom-types/src/request.rs new file mode 100644 index 0000000..d9c4fe6 --- /dev/null +++ b/crates/custom-types/src/request.rs @@ -0,0 +1,32 @@ +use lsp_types::request::Request; + +use crate::llm_ls::{ + AcceptCompletionParams, GetCompletionsParams, GetCompletionsResult, RejectCompletionParams, +}; + +#[derive(Debug)] +pub enum GetCompletions {} + +impl Request for GetCompletions { + type Params = GetCompletionsParams; + type Result = GetCompletionsResult; + const METHOD: &'static str = "llm-ls/getCompletions"; +} + +#[derive(Debug)] +pub enum AcceptCompletion {} + +impl Request for AcceptCompletion { + type Params = AcceptCompletionParams; + type Result = (); + const METHOD: &'static str = "llm-ls/acceptCompletion"; +} + +#[derive(Debug)] +pub enum RejectCompletion {} + +impl Request for RejectCompletion { + type Params = RejectCompletionParams; + type Result = (); + const METHOD: &'static str = "llm-ls/rejectCompletion"; +} diff --git a/crates/llm-ls/Cargo.toml b/crates/llm-ls/Cargo.toml index dbc3324..64cd202 100644 --- a/crates/llm-ls/Cargo.toml +++ b/crates/llm-ls/Cargo.toml @@ -8,6 +8,7 @@ name = "llm-ls" [dependencies] clap = { version = "4", features = ["derive"] } +custom-types = { path = "../custom-types" } home = "0.5" ropey = { version = "1.6", default-features = false, features = [ "simd", diff --git a/crates/llm-ls/src/backend.rs b/crates/llm-ls/src/backend.rs index c9f18cd..76a5d7c 100644 --- a/crates/llm-ls/src/backend.rs +++ b/crates/llm-ls/src/backend.rs @@ -1,4 +1,5 @@ -use super::{APIError, APIResponse, CompletionParams, Generation, Ide, NAME, VERSION}; +use super::{APIError, APIResponse, Generation, NAME, VERSION}; +use custom_types::llm_ls::{Backend, GetCompletionsParams, Ide}; use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, USER_AGENT}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; @@ -150,17 +151,7 @@ fn parse_openai_text(text: &str) -> Result> { } } -#[derive(Debug, Default, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -pub(crate) enum Backend { - #[default] - HuggingFace, - Ollama, - OpenAi, - Tgi, -} - -pub fn build_body(prompt: String, params: &CompletionParams) -> Map { +pub fn build_body(prompt: String, params: &GetCompletionsParams) -> Map { let mut body = params.request_body.clone(); match params.backend { Backend::HuggingFace | Backend::Tgi => { diff --git a/crates/llm-ls/src/main.rs b/crates/llm-ls/src/main.rs index cab0879..27441ad 100644 --- a/crates/llm-ls/src/main.rs +++ b/crates/llm-ls/src/main.rs @@ -1,7 +1,10 @@ use clap::Parser; +use custom_types::llm_ls::{ + AcceptCompletionParams, Backend, Completion, FimParams, GetCompletionsParams, + GetCompletionsResult, Ide, TokenizerConfig, +}; use ropey::Rope; -use serde::{Deserialize, Deserializer, Serialize}; -use serde_json::{Map, Value}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt::Display; use std::path::{Path, PathBuf}; @@ -19,7 +22,7 @@ use tracing_appender::rolling; use tracing_subscriber::EnvFilter; use uuid::Uuid; -use crate::backend::{build_body, build_headers, parse_generations, Backend}; +use crate::backend::{build_body, build_headers, parse_generations}; use crate::document::Document; use crate::error::{internal_error, Error, Result}; @@ -119,22 +122,6 @@ fn should_complete(document: &Document, position: Position) -> Result, - }, - Download { - url: String, - to: PathBuf, - }, -} - #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RequestParams { @@ -145,14 +132,6 @@ pub struct RequestParams { stop_tokens: Option>, } -#[derive(Debug, Deserialize, Serialize)] -struct FimParams { - enabled: bool, - prefix: String, - middle: String, - suffix: String, -} - #[derive(Debug, Serialize)] struct APIParams { max_new_tokens: u32, @@ -225,78 +204,6 @@ struct LlmService { unauthenticated_warn_at: Arc>, } -#[derive(Debug, Deserialize, Serialize)] -struct Completion { - generated_text: String, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -pub enum Ide { - Neovim, - VSCode, - JetBrains, - Emacs, - Jupyter, - Sublime, - VisualStudio, - #[default] - Unknown, -} - -impl Display for Ide { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.serialize(f) - } -} - -fn parse_ide<'de, D>(d: D) -> std::result::Result -where - D: Deserializer<'de>, -{ - Deserialize::deserialize(d).map(|b: Option<_>| b.unwrap_or(Ide::Unknown)) -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -struct AcceptedCompletion { - request_id: Uuid, - accepted_completion: u32, - shown_completions: Vec, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -struct RejectedCompletion { - request_id: Uuid, - shown_completions: Vec, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionParams { - #[serde(flatten)] - text_document_position: TextDocumentPositionParams, - #[serde(default)] - #[serde(deserialize_with = "parse_ide")] - ide: Ide, - fim: FimParams, - api_token: Option, - model: String, - backend: Backend, - tokens_to_clear: Vec, - tokenizer_config: Option, - context_window: usize, - tls_skip_verify_insecure: bool, - request_body: Map, -} - -#[derive(Debug, Deserialize, Serialize)] -struct CompletionResult { - request_id: Uuid, - completions: Vec, -} - fn build_prompt( pos: Position, text: &Rope, @@ -394,7 +301,7 @@ fn build_prompt( async fn request_completion( http_client: &reqwest::Client, prompt: String, - params: &CompletionParams, + params: &GetCompletionsParams, ) -> Result> { let t = Instant::now(); @@ -577,7 +484,10 @@ fn build_url(model: &str) -> String { } impl LlmService { - async fn get_completions(&self, params: CompletionParams) -> LspResult { + async fn get_completions( + &self, + params: GetCompletionsParams, + ) -> LspResult { let request_id = Uuid::new_v4(); let span = info_span!("completion_request", %request_id); async move { @@ -592,6 +502,7 @@ impl LlmService { cursor_character = ?params.text_document_position.position.character, language_id = %document.language_id, model = params.model, + backend = %params.backend, ide = %params.ide, request_body = serde_json::to_string(¶ms.request_body).map_err(internal_error)?, "received completion request for {}", @@ -611,7 +522,7 @@ impl LlmService { let completion_type = should_complete(document, params.text_document_position.position)?; info!(%completion_type, "completion type: {completion_type:?}"); if completion_type == CompletionType::Empty { - return Ok(CompletionResult { request_id, completions: vec![]}); + return Ok(GetCompletionsResult { request_id, completions: vec![]}); } let tokenizer = get_tokenizer( @@ -645,11 +556,11 @@ impl LlmService { .await?; let completions = format_generations(result, ¶ms.tokens_to_clear, completion_type); - Ok(CompletionResult { request_id, completions }) + Ok(GetCompletionsResult { request_id, completions }) }.instrument(span).await } - async fn accept_completion(&self, accepted: AcceptedCompletion) -> LspResult<()> { + async fn accept_completion(&self, accepted: AcceptCompletionParams) -> LspResult<()> { info!( request_id = %accepted.request_id, accepted_position = accepted.accepted_completion, @@ -659,7 +570,7 @@ impl LlmService { Ok(()) } - async fn reject_completion(&self, rejected: RejectedCompletion) -> LspResult<()> { + async fn reject_completion(&self, rejected: AcceptCompletionParams) -> LspResult<()> { info!( request_id = %rejected.request_id, shown_completions = serde_json::to_string(&rejected.shown_completions).map_err(internal_error)?, diff --git a/crates/lsp-client/Cargo.toml b/crates/lsp-client/Cargo.toml index 8dcd552..5cb1e60 100644 --- a/crates/lsp-client/Cargo.toml +++ b/crates/lsp-client/Cargo.toml @@ -13,4 +13,3 @@ serde = "1" serde_json = "1" tokio = { version = "1", features = ["io-util", "process"] } tracing = "0.1" - diff --git a/crates/lsp-client/src/client.rs b/crates/lsp-client/src/client.rs index 8fe3789..d6d6968 100644 --- a/crates/lsp-client/src/client.rs +++ b/crates/lsp-client/src/client.rs @@ -58,7 +58,7 @@ impl LspClient { pub async fn send_request( &self, params: R::Params, - ) -> Result { + ) -> Result { let (sender, receiver) = oneshot::channel::(); let request = self.res_queue @@ -68,7 +68,8 @@ impl LspClient { .register(R::METHOD.to_string(), params, sender); self.send(request.into()); - Ok(receiver.await?) + let (_, result) = receiver.await?.extract::()?; + Ok(result) } async fn complete_request( diff --git a/crates/lsp-client/src/error.rs b/crates/lsp-client/src/error.rs index 32f82fb..b176237 100644 --- a/crates/lsp-client/src/error.rs +++ b/crates/lsp-client/src/error.rs @@ -65,7 +65,9 @@ impl fmt::Display for ExtractError { pub enum Error { ChannelClosed(RecvError), Io(io::Error), + Extract(ExtractError), MissingBinaryPath, + Parse(String), } impl std::error::Error for Error {} @@ -76,6 +78,8 @@ impl fmt::Display for Error { Error::ChannelClosed(e) => write!(f, "Channel closed: {}", e), Error::Io(e) => write!(f, "IO error: {}", e), Error::MissingBinaryPath => write!(f, "Missing binary path"), + Error::Parse(e) => write!(f, "parse error: {}", e), + Error::Extract(e) => write!(f, "extract error: {}", e), } } } @@ -92,4 +96,10 @@ impl From for Error { } } +impl From for Error { + fn from(value: ExtractError) -> Self { + Self::Extract(value) + } +} + pub type Result = std::result::Result; diff --git a/crates/testbed/Cargo.toml b/crates/testbed/Cargo.toml index fdde7cc..05b7ea8 100644 --- a/crates/testbed/Cargo.toml +++ b/crates/testbed/Cargo.toml @@ -11,6 +11,7 @@ authors.workspace = true [dependencies] anyhow = "1" clap = { version = "4", features = ["derive"] } +custom-types = { path = "../custom-types" } futures = "0.3" futures-util = "0.3" home = "0.5" diff --git a/crates/testbed/holes/helix-smol.json b/crates/testbed/holes/helix-smol.json index 1a2b62b..261004c 100644 --- a/crates/testbed/holes/helix-smol.json +++ b/crates/testbed/holes/helix-smol.json @@ -1 +1 @@ -[{"cursor":{"line":73,"character":10},"file":"helix-core/src/chars.rs"},{"cursor":{"line":257,"character":11},"file":"helix-dap/src/types.rs"},{"cursor":{"line":39,"character":14},"file":"helix-view/src/info.rs"},{"cursor":{"line":116,"character":12},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":1,"character":14},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":2,"character":5},"file":"helix-core/src/config.rs"},{"cursor":{"line":151,"character":14},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":11,"character":10},"file":"helix-term/src/ui/lsp.rs"},{"cursor":{"line":18,"character":0},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":230,"character":3},"file":"helix-term/src/ui/markdown.rs"}] \ No newline at end of file +[{"cursor":{"line":9,"character":0},"file":"helix-core/src/increment/mod.rs"},{"cursor":{"line":47,"character":5},"file":"helix-stdx/src/env.rs"},{"cursor":{"line":444,"character":4},"file":"helix-term/src/ui/editor.rs"},{"cursor":{"line":939,"character":8},"file":"helix-tui/src/buffer.rs"},{"cursor":{"line":30,"character":6},"file":"helix-view/src/handlers.rs"},{"cursor":{"line":332,"character":0},"file":"helix-term/src/health.rs"},{"cursor":{"line":15,"character":2},"file":"helix-term/src/events.rs"},{"cursor":{"line":415,"character":2},"file":"helix-tui/src/widgets/reflow.rs"},{"cursor":{"line":316,"character":2},"file":"helix-core/src/shellwords.rs"},{"cursor":{"line":218,"character":2},"file":"helix-tui/src/backend/crossterm.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/helix.json b/crates/testbed/holes/helix.json index 3da8a85..2c144fa 100644 --- a/crates/testbed/holes/helix.json +++ b/crates/testbed/holes/helix.json @@ -1 +1 @@ -[{"cursor":{"line":330,"character":13},"file":"helix-core/src/position.rs"},{"cursor":{"line":21,"character":10},"file":"helix-term/src/lib.rs"},{"cursor":{"line":212,"character":13},"file":"helix-view/src/view.rs"},{"cursor":{"line":74,"character":8},"file":"helix-vcs/src/git.rs"},{"cursor":{"line":78,"character":7},"file":"helix-core/src/auto_pairs.rs"},{"cursor":{"line":61,"character":0},"file":"helix-term/src/ui/overlay.rs"},{"cursor":{"line":179,"character":5},"file":"helix-core/src/graphemes.rs"},{"cursor":{"line":82,"character":12},"file":"helix-tui/src/backend/test.rs"},{"cursor":{"line":486,"character":6},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":263,"character":8},"file":"helix-term/src/keymap/default.rs"},{"cursor":{"line":19,"character":4},"file":"helix-term/src/application.rs"},{"cursor":{"line":23,"character":5},"file":"helix-tui/src/backend/mod.rs"},{"cursor":{"line":54,"character":10},"file":"helix-term/src/ui/menu.rs"},{"cursor":{"line":9,"character":0},"file":"helix-core/src/fuzzy.rs"},{"cursor":{"line":22,"character":4},"file":"helix-view/src/info.rs"},{"cursor":{"line":58,"character":11},"file":"helix-vcs/src/lib.rs"},{"cursor":{"line":54,"character":7},"file":"helix-dap/src/client.rs"},{"cursor":{"line":177,"character":5},"file":"helix-view/src/register.rs"},{"cursor":{"line":54,"character":7},"file":"helix-core/src/increment/integer.rs"},{"cursor":{"line":53,"character":4},"file":"helix-core/src/increment/integer.rs"},{"cursor":{"line":2,"character":3},"file":"helix-core/src/lib.rs"},{"cursor":{"line":43,"character":1},"file":"helix-term/src/main.rs"},{"cursor":{"line":404,"character":13},"file":"helix-tui/src/widgets/block.rs"},{"cursor":{"line":405,"character":11},"file":"helix-dap/src/types.rs"},{"cursor":{"line":2,"character":0},"file":"helix-view/src/env.rs"},{"cursor":{"line":63,"character":3},"file":"helix-view/src/handlers/dap.rs"},{"cursor":{"line":77,"character":10},"file":"helix-tui/src/backend/crossterm.rs"},{"cursor":{"line":132,"character":13},"file":"helix-term/src/ui/markdown.rs"},{"cursor":{"line":190,"character":11},"file":"helix-tui/src/layout.rs"},{"cursor":{"line":62,"character":4},"file":"helix-core/src/auto_pairs.rs"},{"cursor":{"line":146,"character":14},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":280,"character":14},"file":"helix-core/src/shellwords.rs"},{"cursor":{"line":495,"character":14},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":274,"character":9},"file":"helix-lsp/src/transport.rs"},{"cursor":{"line":243,"character":10},"file":"helix-core/src/test.rs"},{"cursor":{"line":2,"character":10},"file":"helix-core/src/config.rs"},{"cursor":{"line":701,"character":1},"file":"helix-dap/src/types.rs"},{"cursor":{"line":67,"character":11},"file":"helix-view/src/lib.rs"},{"cursor":{"line":8,"character":4},"file":"helix-term/src/job.rs"},{"cursor":{"line":0,"character":4},"file":"helix-core/src/wrap.rs"},{"cursor":{"line":27,"character":12},"file":"helix-vcs/src/lib.rs"},{"cursor":{"line":1270,"character":0},"file":"helix-term/src/commands/lsp.rs"},{"cursor":{"line":109,"character":5},"file":"helix-tui/src/widgets/list.rs"},{"cursor":{"line":198,"character":3},"file":"helix-core/src/increment/integer.rs"},{"cursor":{"line":84,"character":10},"file":"helix-term/src/commands.rs"},{"cursor":{"line":102,"character":2},"file":"helix-view/src/base64.rs"},{"cursor":{"line":57,"character":6},"file":"helix-dap/src/types.rs"},{"cursor":{"line":7,"character":9},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":99,"character":10},"file":"helix-term/src/keymap.rs"},{"cursor":{"line":317,"character":1},"file":"helix-core/src/increment/date_time.rs"},{"cursor":{"line":303,"character":13},"file":"helix-term/src/health.rs"},{"cursor":{"line":69,"character":0},"file":"helix-core/src/doc_formatter/test.rs"},{"cursor":{"line":79,"character":4},"file":"helix-tui/src/symbols.rs"},{"cursor":{"line":156,"character":14},"file":"helix-core/src/increment/date_time.rs"},{"cursor":{"line":3760,"character":14},"file":"helix-term/src/commands.rs"},{"cursor":{"line":256,"character":5},"file":"helix-view/src/theme.rs"},{"cursor":{"line":231,"character":11},"file":"helix-tui/src/widgets/list.rs"},{"cursor":{"line":27,"character":4},"file":"helix-core/src/search.rs"},{"cursor":{"line":293,"character":11},"file":"helix-core/src/auto_pairs.rs"},{"cursor":{"line":52,"character":7},"file":"helix-core/src/line_ending.rs"},{"cursor":{"line":144,"character":8},"file":"helix-core/src/comment.rs"},{"cursor":{"line":20,"character":3},"file":"helix-view/src/info.rs"},{"cursor":{"line":131,"character":12},"file":"helix-view/src/base64.rs"},{"cursor":{"line":8,"character":8},"file":"helix-view/src/lib.rs"},{"cursor":{"line":489,"character":14},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":23,"character":7},"file":"helix-view/src/info.rs"},{"cursor":{"line":41,"character":4},"file":"helix-term/src/ui/overlay.rs"},{"cursor":{"line":48,"character":13},"file":"helix-core/src/diagnostic.rs"},{"cursor":{"line":6,"character":7},"file":"helix-core/src/lib.rs"},{"cursor":{"line":845,"character":5},"file":"helix-view/src/view.rs"},{"cursor":{"line":258,"character":2},"file":"helix-core/src/doc_formatter.rs"},{"cursor":{"line":5,"character":6},"file":"helix-tui/src/buffer.rs"},{"cursor":{"line":61,"character":4},"file":"helix-view/src/lib.rs"},{"cursor":{"line":157,"character":6},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":92,"character":3},"file":"helix-term/src/ui/lsp.rs"},{"cursor":{"line":128,"character":2},"file":"helix-term/src/ui/menu.rs"},{"cursor":{"line":1701,"character":11},"file":"helix-core/src/movement.rs"},{"cursor":{"line":1,"character":9},"file":"helix-view/src/env.rs"},{"cursor":{"line":330,"character":3},"file":"helix-view/src/keyboard.rs"},{"cursor":{"line":10,"character":0},"file":"helix-view/src/lib.rs"},{"cursor":{"line":625,"character":4},"file":"helix-dap/src/types.rs"},{"cursor":{"line":81,"character":11},"file":"helix-core/src/syntax.rs"},{"cursor":{"line":2268,"character":1},"file":"helix-term/src/commands/typed.rs"},{"cursor":{"line":21,"character":1},"file":"helix-core/src/fuzzy.rs"},{"cursor":{"line":57,"character":11},"file":"helix-term/src/ui/document.rs"},{"cursor":{"line":460,"character":7},"file":"helix-tui/src/text.rs"},{"cursor":{"line":7,"character":2},"file":"helix-term/src/lib.rs"},{"cursor":{"line":42,"character":12},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":39,"character":8},"file":"helix-term/src/ui/spinner.rs"},{"cursor":{"line":10,"character":2},"file":"helix-term/src/lib.rs"},{"cursor":{"line":57,"character":9},"file":"helix-vcs/src/git.rs"},{"cursor":{"line":15,"character":1},"file":"helix-tui/src/backend/test.rs"},{"cursor":{"line":109,"character":3},"file":"helix-dap/src/transport.rs"},{"cursor":{"line":119,"character":4},"file":"helix-core/src/history.rs"},{"cursor":{"line":18,"character":2},"file":"helix-core/src/path.rs"},{"cursor":{"line":13,"character":11},"file":"helix-lsp/src/snippet.rs"},{"cursor":{"line":0,"character":12},"file":"helix-loader/src/main.rs"},{"cursor":{"line":3,"character":6},"file":"helix-term/src/lib.rs"},{"cursor":{"line":49,"character":8},"file":"helix-term/src/job.rs"},{"cursor":{"line":176,"character":7},"file":"helix-parsec/src/lib.rs"}] \ No newline at end of file +[{"cursor":{"line":234,"character":14},"file":"helix-core/src/history.rs"},{"cursor":{"line":209,"character":1},"file":"helix-term/src/ui/menu.rs"},{"cursor":{"line":465,"character":0},"file":"helix-lsp/src/client.rs"},{"cursor":{"line":95,"character":2},"file":"helix-term/src/keymap/macros.rs"},{"cursor":{"line":14,"character":10},"file":"helix-term/src/ui/markdown.rs"},{"cursor":{"line":6,"character":5},"file":"helix-core/src/rope_reader.rs"},{"cursor":{"line":150,"character":7},"file":"helix-term/src/ui/document.rs"},{"cursor":{"line":48,"character":5},"file":"helix-view/src/macros.rs"},{"cursor":{"line":1582,"character":11},"file":"helix-term/src/commands.rs"},{"cursor":{"line":6,"character":8},"file":"helix-core/src/comment.rs"},{"cursor":{"line":5,"character":4},"file":"helix-core/src/rope_reader.rs"},{"cursor":{"line":88,"character":3},"file":"helix-tui/src/terminal.rs"},{"cursor":{"line":15,"character":14},"file":"helix-term/src/events.rs"},{"cursor":{"line":366,"character":3},"file":"helix-view/src/clipboard.rs"},{"cursor":{"line":7,"character":7},"file":"helix-view/src/events.rs"},{"cursor":{"line":152,"character":8},"file":"helix-dap/src/client.rs"},{"cursor":{"line":290,"character":3},"file":"helix-core/src/match_brackets.rs"},{"cursor":{"line":119,"character":6},"file":"helix-view/src/register.rs"},{"cursor":{"line":113,"character":2},"file":"helix-term/src/keymap/macros.rs"},{"cursor":{"line":34,"character":7},"file":"helix-core/src/rope_reader.rs"},{"cursor":{"line":37,"character":13},"file":"helix-core/src/object.rs"},{"cursor":{"line":209,"character":9},"file":"helix-term/src/keymap.rs"},{"cursor":{"line":4,"character":11},"file":"helix-term/build.rs"},{"cursor":{"line":31,"character":7},"file":"helix-core/src/rope_reader.rs"},{"cursor":{"line":1,"character":7},"file":"helix-stdx/src/lib.rs"},{"cursor":{"line":324,"character":0},"file":"helix-loader/src/lib.rs"},{"cursor":{"line":231,"character":13},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":134,"character":7},"file":"helix-tui/src/terminal.rs"},{"cursor":{"line":121,"character":0},"file":"helix-tui/src/widgets/paragraph.rs"},{"cursor":{"line":276,"character":10},"file":"helix-core/src/match_brackets.rs"},{"cursor":{"line":565,"character":0},"file":"helix-core/src/selection.rs"},{"cursor":{"line":579,"character":8},"file":"helix-view/src/input.rs"},{"cursor":{"line":63,"character":5},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":6,"character":8},"file":"helix-term/src/ui/info.rs"},{"cursor":{"line":214,"character":9},"file":"helix-tui/src/widgets/block.rs"},{"cursor":{"line":270,"character":3},"file":"helix-term/src/ui/menu.rs"},{"cursor":{"line":130,"character":7},"file":"helix-term/src/ui/editor.rs"},{"cursor":{"line":8,"character":12},"file":"helix-core/src/search.rs"},{"cursor":{"line":404,"character":10},"file":"helix-tui/src/widgets/reflow.rs"},{"cursor":{"line":6,"character":2},"file":"helix-core/src/object.rs"},{"cursor":{"line":91,"character":14},"file":"helix-term/src/args.rs"},{"cursor":{"line":195,"character":14},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":118,"character":12},"file":"helix-vcs/src/git.rs"},{"cursor":{"line":906,"character":13},"file":"helix-lsp/src/client.rs"},{"cursor":{"line":7,"character":5},"file":"helix-view/src/events.rs"},{"cursor":{"line":239,"character":6},"file":"helix-core/src/shellwords.rs"},{"cursor":{"line":52,"character":0},"file":"helix-event/src/redraw.rs"},{"cursor":{"line":29,"character":12},"file":"helix-loader/src/grammar.rs"},{"cursor":{"line":603,"character":2},"file":"helix-core/src/selection.rs"},{"cursor":{"line":252,"character":10},"file":"helix-tui/src/layout.rs"},{"cursor":{"line":27,"character":13},"file":"helix-view/src/info.rs"},{"cursor":{"line":733,"character":11},"file":"helix-term/src/ui/picker.rs"},{"cursor":{"line":29,"character":0},"file":"helix-term/src/handlers.rs"},{"cursor":{"line":56,"character":3},"file":"helix-loader/src/grammar.rs"},{"cursor":{"line":249,"character":0},"file":"helix-term/src/ui/markdown.rs"},{"cursor":{"line":267,"character":4},"file":"helix-view/src/register.rs"},{"cursor":{"line":3143,"character":2},"file":"helix-term/src/commands/typed.rs"},{"cursor":{"line":73,"character":2},"file":"helix-core/src/increment/date_time.rs"},{"cursor":{"line":181,"character":0},"file":"helix-dap/src/types.rs"},{"cursor":{"line":28,"character":6},"file":"helix-term/src/ui/popup.rs"},{"cursor":{"line":15,"character":7},"file":"helix-event/src/cancel.rs"},{"cursor":{"line":40,"character":7},"file":"helix-event/src/lib.rs"},{"cursor":{"line":132,"character":2},"file":"helix-tui/src/widgets/table.rs"},{"cursor":{"line":25,"character":0},"file":"helix-view/src/info.rs"},{"cursor":{"line":141,"character":7},"file":"helix-tui/src/backend/crossterm.rs"},{"cursor":{"line":251,"character":1},"file":"helix-dap/src/client.rs"},{"cursor":{"line":327,"character":8},"file":"helix-term/src/handlers/completion.rs"},{"cursor":{"line":230,"character":7},"file":"helix-view/src/input.rs"},{"cursor":{"line":68,"character":0},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":23,"character":11},"file":"helix-stdx/src/rope.rs"},{"cursor":{"line":639,"character":10},"file":"helix-view/src/tree.rs"},{"cursor":{"line":104,"character":3},"file":"helix-lsp/src/transport.rs"},{"cursor":{"line":117,"character":14},"file":"helix-core/src/doc_formatter/test.rs"},{"cursor":{"line":129,"character":4},"file":"helix-core/src/doc_formatter/test.rs"},{"cursor":{"line":22,"character":1},"file":"helix-tui/src/backend/mod.rs"},{"cursor":{"line":297,"character":4},"file":"helix-loader/src/lib.rs"},{"cursor":{"line":1884,"character":13},"file":"helix-view/src/document.rs"},{"cursor":{"line":62,"character":11},"file":"helix-vcs/src/diff/worker.rs"},{"cursor":{"line":42,"character":4},"file":"helix-event/src/debounce.rs"},{"cursor":{"line":371,"character":4},"file":"helix-core/src/position.rs"},{"cursor":{"line":248,"character":2},"file":"helix-core/src/line_ending.rs"},{"cursor":{"line":1,"character":10},"file":"helix-core/src/diagnostic.rs"},{"cursor":{"line":10,"character":5},"file":"helix-term/src/events.rs"},{"cursor":{"line":885,"character":13},"file":"helix-term/src/commands.rs"},{"cursor":{"line":297,"character":8},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":152,"character":12},"file":"helix-core/src/diff.rs"},{"cursor":{"line":228,"character":4},"file":"helix-tui/src/widgets/table.rs"},{"cursor":{"line":25,"character":4},"file":"helix-view/src/lib.rs"},{"cursor":{"line":8,"character":0},"file":"helix-loader/src/main.rs"},{"cursor":{"line":80,"character":1},"file":"helix-event/src/hook.rs"},{"cursor":{"line":284,"character":13},"file":"helix-term/src/handlers/signature_help.rs"},{"cursor":{"line":7,"character":8},"file":"helix-view/src/graphics.rs"},{"cursor":{"line":214,"character":1},"file":"helix-core/src/increment/integer.rs"},{"cursor":{"line":19,"character":3},"file":"helix-loader/src/config.rs"},{"cursor":{"line":57,"character":0},"file":"helix-lsp/src/file_operations.rs"},{"cursor":{"line":16,"character":7},"file":"helix-loader/src/config.rs"},{"cursor":{"line":0,"character":6},"file":"helix-core/src/increment/mod.rs"},{"cursor":{"line":41,"character":2},"file":"helix-tui/src/widgets/mod.rs"},{"cursor":{"line":50,"character":12},"file":"helix-term/src/ui/overlay.rs"},{"cursor":{"line":173,"character":14},"file":"helix-tui/src/widgets/list.rs"}] \ No newline at end of file diff --git a/crates/testbed/repositories-ci.yaml b/crates/testbed/repositories-ci.yaml index 0c1bd21..3d49f1a 100644 --- a/crates/testbed/repositories-ci.yaml +++ b/crates/testbed/repositories-ci.yaml @@ -6,11 +6,12 @@ fim: middle: suffix: model: bigcode/starcoder -request_params: - maxNewTokens: 150 +backend: huggingface +request_body: + max_new_tokens: 150 temperature: 0.2 - doSample: true - topP: 0.95 + do_sample: true + top_p: 0.95 tls_skip_verify_insecure: false tokenizer_config: repository: bigcode/starcoder @@ -202,7 +203,7 @@ repositories: type: github owner: helix-editor name: helix - revision: ae6a0a9cfd377fbfa494760282498cf2ca322782 + revision: a1272bdb17a63361342a318982e46129d558743c exclude_paths: - .cargo - .github diff --git a/crates/testbed/repositories.yaml b/crates/testbed/repositories.yaml index 4418993..1ec7dfb 100644 --- a/crates/testbed/repositories.yaml +++ b/crates/testbed/repositories.yaml @@ -6,11 +6,12 @@ fim: middle: suffix: model: bigcode/starcoder -request_params: - maxNewTokens: 150 +backend: huggingface +request_body: + max_new_tokens: 150 temperature: 0.2 - doSample: true - topP: 0.95 + do_sample: true + top_p: 0.95 tls_skip_verify_insecure: false tokenizer_config: repository: bigcode/starcoder @@ -202,7 +203,7 @@ repositories: type: github owner: helix-editor name: helix - revision: ae6a0a9cfd377fbfa494760282498cf2ca322782 + revision: a1272bdb17a63361342a318982e46129d558743c exclude_paths: - .cargo - .github diff --git a/crates/testbed/src/main.rs b/crates/testbed/src/main.rs index 2169b80..fa7a543 100644 --- a/crates/testbed/src/main.rs +++ b/crates/testbed/src/main.rs @@ -10,9 +10,13 @@ use std::{ use anyhow::anyhow; use clap::Parser; +use custom_types::{ + llm_ls::{Backend, FimParams, GetCompletionsParams, Ide, TokenizerConfig}, + request::GetCompletions, +}; use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt}; use lang::Language; -use lsp_client::{client::LspClient, error::ExtractError, msg::RequestId, server::Server}; +use lsp_client::{client::LspClient, error::ExtractError, server::Server}; use lsp_types::{ DidOpenTextDocumentParams, InitializeParams, TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, @@ -20,6 +24,7 @@ use lsp_types::{ use ropey::Rope; use runner::Runner; use serde::{Deserialize, Serialize}; +use serde_json::{Map, Value}; use tempfile::TempDir; use tokio::{ fs::{self, read_to_string, File, OpenOptions}, @@ -32,19 +37,11 @@ use tracing::{debug, error, info, info_span, warn, Instrument}; use tracing_subscriber::EnvFilter; use url::Url; -use crate::{ - holes_generator::generate_holes, - runner::run_test, - types::{ - FimParams, GetCompletions, GetCompletionsParams, GetCompletionsResult, Ide, RequestParams, - TokenizerConfig, - }, -}; +use crate::{holes_generator::generate_holes, runner::run_test}; mod holes_generator; mod lang; mod runner; -mod types; /// Testbed runs llm-ls' code completion to measure its performance #[derive(Parser, Debug)] @@ -201,11 +198,12 @@ struct RepositoriesConfig { context_window: usize, fim: FimParams, model: String, - request_params: RequestParams, + backend: Backend, repositories: Vec, tls_skip_verify_insecure: bool, tokenizer_config: Option, tokens_to_clear: Vec, + request_body: Map, } struct HoleCompletionResult { @@ -463,10 +461,11 @@ async fn complete_holes( context_window, fim, model, - request_params, + backend, tls_skip_verify_insecure, tokenizer_config, tokens_to_clear, + request_body, .. } = repos_config; async move { @@ -516,14 +515,14 @@ async fn complete_holes( }, }, ); - let response = client + let result = client .send_request::(GetCompletionsParams { api_token: api_token.clone(), context_window, fim: fim.clone(), ide: Ide::default(), model: model.clone(), - request_params: request_params.clone(), + backend, text_document_position: TextDocumentPositionParams { position: hole.cursor, text_document: TextDocumentIdentifier { uri }, @@ -531,9 +530,9 @@ async fn complete_holes( tls_skip_verify_insecure, tokens_to_clear: tokens_to_clear.clone(), tokenizer_config: tokenizer_config.clone(), + request_body: request_body.clone(), }) .await?; - let (_, result): (RequestId, GetCompletionsResult) = response.extract()?; file_content.insert(hole_start, &result.completions[0].generated_text); let mut file = OpenOptions::new() diff --git a/crates/testbed/src/types.rs b/crates/testbed/src/types.rs deleted file mode 100644 index c75da6d..0000000 --- a/crates/testbed/src/types.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::path::PathBuf; - -use lsp_types::{request::Request, TextDocumentPositionParams}; -use serde::{Deserialize, Deserializer, Serialize}; -use uuid::Uuid; - -#[derive(Debug)] -pub(crate) enum GetCompletions {} - -impl Request for GetCompletions { - type Params = GetCompletionsParams; - type Result = GetCompletionsResult; - const METHOD: &'static str = "llm-ls/getCompletions"; -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct RequestParams { - pub(crate) max_new_tokens: u32, - pub(crate) temperature: f32, - pub(crate) do_sample: bool, - pub(crate) top_p: f32, - pub(crate) stop_tokens: Option>, -} - -#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -pub(crate) enum Ide { - Neovim, - VSCode, - JetBrains, - Emacs, - Jupyter, - Sublime, - VisualStudio, - #[default] - Unknown, -} - -fn parse_ide<'de, D>(d: D) -> std::result::Result -where - D: Deserializer<'de>, -{ - Deserialize::deserialize(d).map(|b: Option<_>| b.unwrap_or(Ide::Unknown)) -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub(crate) struct FimParams { - pub(crate) enabled: bool, - pub(crate) prefix: String, - pub(crate) middle: String, - pub(crate) suffix: String, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(untagged)] -pub(crate) enum TokenizerConfig { - Local { path: PathBuf }, - HuggingFace { repository: String }, - Download { url: String, to: PathBuf }, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct GetCompletionsParams { - #[serde(flatten)] - pub(crate) text_document_position: TextDocumentPositionParams, - pub(crate) request_params: RequestParams, - #[serde(default)] - #[serde(deserialize_with = "parse_ide")] - pub(crate) ide: Ide, - pub(crate) fim: FimParams, - pub(crate) api_token: Option, - pub(crate) model: String, - pub(crate) tokens_to_clear: Vec, - pub(crate) tokenizer_config: Option, - pub(crate) context_window: usize, - pub(crate) tls_skip_verify_insecure: bool, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub(crate) struct Completion { - pub(crate) generated_text: String, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub(crate) struct GetCompletionsResult { - request_id: Uuid, - pub(crate) completions: Vec, -}