
This PR restructures the way that tools and attachments add information about the current project to a conversation with the assistant. Rather than each tool call or attachment generating a new tool or system message containing information about the project, they can all collectively mutate a new type called a `ProjectContext`, which stores all of the project data that should be sent to the assistant. That data is then formatted in a single place, and passed to the assistant in one system message. This prevents multiple tools/attachments from including redundant context. Release Notes: - N/A --------- Co-authored-by: Kyle <kylek@zed.dev>
119 lines
3.4 KiB
Rust
119 lines
3.4 KiB
Rust
use anyhow::Result;
|
|
use assistant_tooling::{LanguageModelTool, ProjectContext, ToolOutput};
|
|
use editor::Editor;
|
|
use gpui::{prelude::*, Model, Task, View, WeakView};
|
|
use project::Project;
|
|
use schemars::JsonSchema;
|
|
use serde::Deserialize;
|
|
use ui::prelude::*;
|
|
use util::ResultExt;
|
|
use workspace::Workspace;
|
|
|
|
pub struct CreateBufferTool {
|
|
workspace: WeakView<Workspace>,
|
|
project: Model<Project>,
|
|
}
|
|
|
|
impl CreateBufferTool {
|
|
pub fn new(workspace: WeakView<Workspace>, project: Model<Project>) -> Self {
|
|
Self { workspace, project }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, JsonSchema)]
|
|
pub struct CreateBufferInput {
|
|
/// The contents of the buffer.
|
|
text: String,
|
|
|
|
/// The name of the language to use for the buffer.
|
|
///
|
|
/// This should be a human-readable name, like "Rust", "JavaScript", or "Python".
|
|
language: String,
|
|
}
|
|
|
|
impl LanguageModelTool for CreateBufferTool {
|
|
type Input = CreateBufferInput;
|
|
type Output = ();
|
|
type View = CreateBufferView;
|
|
|
|
fn name(&self) -> String {
|
|
"create_buffer".to_string()
|
|
}
|
|
|
|
fn description(&self) -> String {
|
|
"Create a new buffer in the current codebase".to_string()
|
|
}
|
|
|
|
fn execute(&self, input: &Self::Input, cx: &mut WindowContext) -> Task<Result<Self::Output>> {
|
|
cx.spawn({
|
|
let workspace = self.workspace.clone();
|
|
let project = self.project.clone();
|
|
let text = input.text.clone();
|
|
let language_name = input.language.clone();
|
|
|mut cx| async move {
|
|
let language = cx
|
|
.update(|cx| {
|
|
project
|
|
.read(cx)
|
|
.languages()
|
|
.language_for_name(&language_name)
|
|
})?
|
|
.await?;
|
|
|
|
let buffer = cx
|
|
.update(|cx| project.update(cx, |project, cx| project.create_buffer(cx)))?
|
|
.await?;
|
|
|
|
buffer.update(&mut cx, |buffer, cx| {
|
|
buffer.edit([(0..0, text)], None, cx);
|
|
buffer.set_language(Some(language), cx)
|
|
})?;
|
|
|
|
workspace
|
|
.update(&mut cx, |workspace, cx| {
|
|
workspace.add_item_to_active_pane(
|
|
Box::new(
|
|
cx.new_view(|cx| Editor::for_buffer(buffer, Some(project), cx)),
|
|
),
|
|
None,
|
|
cx,
|
|
);
|
|
})
|
|
.log_err();
|
|
|
|
Ok(())
|
|
}
|
|
})
|
|
}
|
|
|
|
fn output_view(
|
|
input: Self::Input,
|
|
output: Result<Self::Output>,
|
|
cx: &mut WindowContext,
|
|
) -> View<Self::View> {
|
|
cx.new_view(|_cx| CreateBufferView {
|
|
language: input.language,
|
|
output,
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct CreateBufferView {
|
|
language: String,
|
|
output: Result<()>,
|
|
}
|
|
|
|
impl Render for CreateBufferView {
|
|
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
|
div().child("Opening a buffer")
|
|
}
|
|
}
|
|
|
|
impl ToolOutput for CreateBufferView {
|
|
fn generate(&self, _: &mut ProjectContext, _: &mut WindowContext) -> String {
|
|
match &self.output {
|
|
Ok(_) => format!("Created a new {} buffer", self.language),
|
|
Err(err) => format!("Failed to create buffer: {err:?}"),
|
|
}
|
|
}
|
|
}
|