1use agent_settings::AgentProfileId;
2use anyhow::Result;
3use async_trait::async_trait;
4use util::rel_path::RelPath;
5
6use crate::example::{Example, ExampleContext, ExampleMetadata, JudgeAssertion, LanguageServer};
7
8pub struct AddArgToTraitMethod;
9
10#[async_trait(?Send)]
11impl Example for AddArgToTraitMethod {
12 fn meta(&self) -> ExampleMetadata {
13 ExampleMetadata {
14 name: "add_arg_to_trait_method".to_string(),
15 url: "https://github.com/zed-industries/zed.git".to_string(),
16 revision: "f69aeb6311dde3c0b8979c293d019d66498d54f2".to_string(),
17 language_server: Some(LanguageServer {
18 file_extension: "rs".to_string(),
19 allow_preexisting_diagnostics: false,
20 }),
21 max_assertions: None,
22 profile_id: AgentProfileId::default(),
23 existing_thread_json: None,
24 max_turns: None,
25 }
26 }
27
28 async fn conversation(&self, cx: &mut ExampleContext) -> Result<()> {
29 const FILENAME: &str = "assistant_tool.rs";
30 let _ = cx.prompt(format!(
31 r#"
32 Add a `window: Option<gpui::AnyWindowHandle>` argument to the `Tool::run` trait method in {FILENAME},
33 and update all the implementations of the trait and call sites accordingly.
34 "#
35 )).await?;
36
37 // Adds ignored argument to all but `batch_tool`
38
39 let add_ignored_window_paths = &[
40 "code_action_tool",
41 "code_symbols_tool",
42 "contents_tool",
43 "copy_path_tool",
44 "create_directory_tool",
45 "create_file_tool",
46 "delete_path_tool",
47 "diagnostics_tool",
48 "edit_file_tool",
49 "fetch_tool",
50 "grep_tool",
51 "list_directory_tool",
52 "move_path_tool",
53 "now_tool",
54 "open_tool",
55 "path_search_tool",
56 "read_file_tool",
57 "rename_tool",
58 "symbol_info_tool",
59 "terminal_tool",
60 "thinking_tool",
61 "web_search_tool",
62 ];
63
64 let edits = cx.edits();
65
66 for tool_name in add_ignored_window_paths {
67 let path_str = format!("crates/assistant_tools/src/{}.rs", tool_name);
68 let edits = edits.get(RelPath::unix(&path_str).unwrap());
69
70 let ignored = edits.is_some_and(|edits| {
71 edits.has_added_line(" _window: Option<gpui::AnyWindowHandle>,\n")
72 });
73 let uningored = edits.is_some_and(|edits| {
74 edits.has_added_line(" window: Option<gpui::AnyWindowHandle>,\n")
75 });
76
77 cx.assert(ignored || uningored, format!("Argument: {}", tool_name))
78 .ok();
79
80 cx.assert(ignored, format!("`_` prefix: {}", tool_name))
81 .ok();
82 }
83
84 // Adds unignored argument to `batch_tool`
85
86 let batch_tool_edits =
87 edits.get(RelPath::unix("crates/assistant_tools/src/batch_tool.rs").unwrap());
88
89 cx.assert(
90 batch_tool_edits.is_some_and(|edits| {
91 edits.has_added_line(" window: Option<gpui::AnyWindowHandle>,\n")
92 }),
93 "Argument: batch_tool",
94 )
95 .ok();
96
97 Ok(())
98 }
99
100 fn diff_assertions(&self) -> Vec<JudgeAssertion> {
101 vec![
102 JudgeAssertion {
103 id: "batch tool passes window to each".to_string(),
104 description:
105 "batch_tool is modified to pass a clone of the window to each tool it calls."
106 .to_string(),
107 },
108 JudgeAssertion {
109 id: "tool tests updated".to_string(),
110 description:
111 "tool tests are updated to pass the new `window` argument (`None` is ok)."
112 .to_string(),
113 },
114 ]
115 }
116}