1use std::path::Path;
2use std::sync::Arc;
3
4use anyhow::{anyhow, Result};
5use assistant_tool::Tool;
6use gpui::{App, Entity, Task};
7use project::{Project, ProjectPath, WorktreeId};
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Serialize, Deserialize, JsonSchema)]
12pub struct ReadFileToolInput {
13 /// The ID of the worktree in which the file resides.
14 pub worktree_id: usize,
15 /// The path to the file to read.
16 ///
17 /// This path is relative to the worktree root, it must not be an absolute path.
18 pub path: Arc<Path>,
19}
20
21pub struct ReadFileTool;
22
23impl Tool for ReadFileTool {
24 fn name(&self) -> String {
25 "read-file".into()
26 }
27
28 fn description(&self) -> String {
29 "Reads the content of a file specified by a worktree ID and path. Use this tool when you need to access the contents of a file in the project.".into()
30 }
31
32 fn input_schema(&self) -> serde_json::Value {
33 let schema = schemars::schema_for!(ReadFileToolInput);
34 serde_json::to_value(&schema).unwrap()
35 }
36
37 fn run(
38 self: Arc<Self>,
39 input: serde_json::Value,
40 project: Entity<Project>,
41 cx: &mut App,
42 ) -> Task<Result<String>> {
43 let input = match serde_json::from_value::<ReadFileToolInput>(input) {
44 Ok(input) => input,
45 Err(err) => return Task::ready(Err(anyhow!(err))),
46 };
47
48 let project_path = ProjectPath {
49 worktree_id: WorktreeId::from_usize(input.worktree_id),
50 path: input.path,
51 };
52 cx.spawn(|cx| async move {
53 let buffer = cx
54 .update(|cx| {
55 project.update(cx, |project, cx| project.open_buffer(project_path, cx))
56 })?
57 .await?;
58
59 cx.update(|cx| buffer.read(cx).text())
60 })
61 }
62}