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