Add more context to the terminal assistant (#15492)

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-07-30 20:21:45 +03:00 committed by GitHub
parent 73e3dfc0c3
commit eedef487ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 33 additions and 8 deletions

View file

@ -55,6 +55,8 @@ actions!(
] ]
); );
const DEFAULT_CONTEXT_LINES: usize = 20;
#[derive(Clone, Default, Deserialize, PartialEq)] #[derive(Clone, Default, Deserialize, PartialEq)]
pub struct InlineAssist { pub struct InlineAssist {
prompt: Option<String>, prompt: Option<String>,

View file

@ -115,11 +115,19 @@ pub fn generate_terminal_assistant_prompt(
user_prompt: &str, user_prompt: &str,
shell: Option<&str>, shell: Option<&str>,
working_directory: Option<&str>, working_directory: Option<&str>,
latest_output: &[String],
) -> String { ) -> String {
let mut prompt = String::new(); let mut prompt = String::new();
writeln!(&mut prompt, "You are an expert terminal user.").unwrap(); writeln!(&mut prompt, "You are an expert terminal user.").unwrap();
writeln!(&mut prompt, "You will be given a description of a command and you need to respond with a command that matches the description.").unwrap(); writeln!(&mut prompt, "You will be given a description of a command and you need to respond with a command that matches the description.").unwrap();
writeln!(&mut prompt, "Do not include markdown blocks or any other text formatting in your response, always respond with a single command that can be executed in the given shell.").unwrap(); writeln!(&mut prompt, "Do not include markdown blocks or any other text formatting in your response, always respond with a single command that can be executed in the given shell.").unwrap();
writeln!(
&mut prompt,
"Current OS name is '{}', architecture is '{}'.",
std::env::consts::OS,
std::env::consts::ARCH,
)
.unwrap();
if let Some(shell) = shell { if let Some(shell) = shell {
writeln!(&mut prompt, "Current shell is '{shell}'.").unwrap(); writeln!(&mut prompt, "Current shell is '{shell}'.").unwrap();
} }
@ -130,6 +138,15 @@ pub fn generate_terminal_assistant_prompt(
) )
.unwrap(); .unwrap();
} }
if !latest_output.is_empty() {
writeln!(
&mut prompt,
"Latest non-empty {} lines of the terminal output: {:?}",
latest_output.len(),
latest_output
)
.unwrap();
}
writeln!(&mut prompt, "Here is the description of the command:").unwrap(); writeln!(&mut prompt, "Here is the description of the command:").unwrap();
prompt.push_str(user_prompt); prompt.push_str(user_prompt);
prompt prompt

View file

@ -11,6 +11,8 @@ use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
use ui::prelude::*; use ui::prelude::*;
use workspace::{dock::Panel, Workspace}; use workspace::{dock::Panel, Workspace};
use crate::DEFAULT_CONTEXT_LINES;
use super::create_label_for_command; use super::create_label_for_command;
pub(crate) struct TermSlashCommand; pub(crate) struct TermSlashCommand;
@ -73,7 +75,9 @@ impl SlashCommand for TermSlashCommand {
return Task::ready(Err(anyhow::anyhow!("no active terminal"))); return Task::ready(Err(anyhow::anyhow!("no active terminal")));
}; };
let line_count = argument.and_then(|a| parse_argument(a)).unwrap_or(20); let line_count = argument
.and_then(|a| parse_argument(a))
.unwrap_or(DEFAULT_CONTEXT_LINES);
let lines = active_terminal let lines = active_terminal
.read(cx) .read(cx)

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
humanize_token_count, prompts::generate_terminal_assistant_prompt, AssistantPanel, humanize_token_count, prompts::generate_terminal_assistant_prompt, AssistantPanel,
AssistantPanelEvent, ModelSelector, AssistantPanelEvent, ModelSelector, DEFAULT_CONTEXT_LINES,
}; };
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use client::telemetry::Telemetry; use client::telemetry::Telemetry;
@ -217,17 +217,18 @@ impl TerminalInlineAssistant {
let assist = self.assists.get(&assist_id).context("invalid assist")?; let assist = self.assists.get(&assist_id).context("invalid assist")?;
let shell = std::env::var("SHELL").ok(); let shell = std::env::var("SHELL").ok();
let working_directory = assist let (latest_output, working_directory) = assist
.terminal .terminal
.update(cx, |terminal, cx| { .update(cx, |terminal, cx| {
terminal let terminal = terminal.model().read(cx);
.model() let latest_output = terminal.last_n_non_empty_lines(DEFAULT_CONTEXT_LINES);
.read(cx) let working_directory = terminal
.working_directory() .working_directory()
.map(|path| path.to_string_lossy().to_string()) .map(|path| path.to_string_lossy().to_string());
(latest_output, working_directory)
}) })
.ok() .ok()
.flatten(); .unwrap_or_default();
let context_request = if assist.include_context { let context_request = if assist.include_context {
assist.workspace.as_ref().and_then(|workspace| { assist.workspace.as_ref().and_then(|workspace| {
@ -254,6 +255,7 @@ impl TerminalInlineAssistant {
.prompt(cx), .prompt(cx),
shell.as_deref(), shell.as_deref(),
working_directory.as_deref(), working_directory.as_deref(),
&latest_output,
); );
let mut messages = Vec::new(); let mut messages = Vec::new();