Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(completion): replace CRLF with LF for code completion LLM requests #3303

Merged
merged 8 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/tabby/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ color-eyre = { version = "0.6.3" }
reqwest.workspace = true
async-openai.workspace = true
spinners = "4.1.1"
regex.workspace = true

[dependencies.openssl]
optional = true
Expand Down
37 changes: 27 additions & 10 deletions crates/tabby/src/services/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::sync::Arc;

use regex::Regex;
use serde::{Deserialize, Serialize};
use tabby_common::{
api::{
Expand Down Expand Up @@ -42,7 +43,7 @@
language: Option<String>,

/// When segments are set, the `prompt` is ignored during the inference.
segments: Option<Segments>,
pub segments: Option<Segments>,

/// A unique identifier representing your end-user, which can help Tabby to monitor & generating
/// reports.
Expand Down Expand Up @@ -105,10 +106,10 @@
#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
pub struct Segments {
/// Content that appears before the cursor in the editor window.
prefix: String,
pub prefix: String,

/// Content that appears after the cursor in the editor window.
suffix: Option<String>,
pub suffix: Option<String>,

/// The relative path of the file that is being edited.
/// - When [Segments::git_url] is set, this is the path of the file in the git repository.
Expand Down Expand Up @@ -191,7 +192,7 @@
#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
pub struct Choice {
index: u32,
text: String,
pub text: String,
}

impl Choice {
Expand All @@ -214,7 +215,7 @@
}))]
pub struct CompletionResponse {
id: String,
choices: Vec<Choice>,
pub choices: Vec<Choice>,

#[serde(skip_serializing_if = "Option::is_none")]
debug_data: Option<DebugData>,
Expand Down Expand Up @@ -321,35 +322,51 @@
self.config.max_decoding_tokens,
);

let mut use_crlf = false;
let (prompt, segments, snippets) = if let Some(prompt) = request.raw_prompt() {
(prompt, None, vec![])
} else if let Some(segments) = request.segments.as_ref() {
let mut new_segments = segments.clone();
if segments.prefix.contains("\r\n") {
use_crlf = true;
new_segments.prefix = segments.prefix.replace("\r\n", "\n");

Check warning on line 332 in crates/tabby/src/services/completion.rs

View check run for this annotation

Codecov / codecov/patch

crates/tabby/src/services/completion.rs#L331-L332

Added lines #L331 - L332 were not covered by tests
}
if let Some(suffix) = &segments.suffix {
if suffix.contains("\r\n") {
use_crlf = true;
new_segments.suffix = Some(suffix.replace("\r\n", "\n"));

Check warning on line 337 in crates/tabby/src/services/completion.rs

View check run for this annotation

Codecov / codecov/patch

crates/tabby/src/services/completion.rs#L336-L337

Added lines #L336 - L337 were not covered by tests
}
}

Check warning on line 339 in crates/tabby/src/services/completion.rs

View check run for this annotation

Codecov / codecov/patch

crates/tabby/src/services/completion.rs#L339

Added line #L339 was not covered by tests

let snippets = self
.build_snippets(
&language,
segments,
&new_segments,
allowed_code_repository,
request.disable_retrieval_augmented_code_completion(),
)
.await;
let prompt = self
.prompt_builder
.build(&language, segments.clone(), &snippets);
.build(&language, new_segments.clone(), &snippets);
(prompt, Some(segments), snippets)
} else {
return Err(CompletionError::EmptyPrompt);
};

let text = self.engine.generate(&prompt, options).await;
let segments = segments.cloned().map(|s| s.into());
let mut text = self.engine.generate(&prompt, options).await;
if use_crlf {
let re = Regex::new(r"([^\r])\n").unwrap(); // Match \n that is preceded by anything except \r
text = re.replace_all(&text, "$1\r\n").to_string() // Replace with captured character and \r\n

Check warning on line 360 in crates/tabby/src/services/completion.rs

View check run for this annotation

Codecov / codecov/patch

crates/tabby/src/services/completion.rs#L359-L360

Added lines #L359 - L360 were not covered by tests
}

self.logger.log(
request.user.clone(),
Event::Completion {
completion_id: completion_id.clone(),
language,
prompt: prompt.clone(),
segments,
segments: segments.cloned().map(|x| x.into()),
choices: vec![api::event::Choice {
index: 0,
text: text.clone(),
Expand Down
Loading