Skip to repository content146 lines · 4.7 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T02:33:24.540Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
apply_code_action_tool.rs
1use std::fmt::Write;
2use std::sync::Arc;
3
4use agent_client_protocol::schema::v1 as acp;
5use gpui::{App, Entity, SharedString, Task};
6use project::Project;
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10use super::symbol_locator::CodeActionStore;
11use crate::{AgentTool, ToolCallEventStream, ToolInput};
12
13/// Applies a code action previously retrieved by get_code_actions.
14///
15/// You must call get_code_actions first to get the list of available actions,
16/// then use the number from that list to choose which action to apply.
17///
18/// After applying a code action, the list is cleared. If you want to apply
19/// another action, call get_code_actions again.
20#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
21pub struct ApplyCodeActionToolInput {
22 /// The 1-based index of the code action to apply, from the list
23 /// returned by get_code_actions.
24 pub index: u32,
25}
26
27pub struct ApplyCodeActionTool {
28 project: Entity<Project>,
29 code_action_store: CodeActionStore,
30}
31
32impl ApplyCodeActionTool {
33 pub fn new(project: Entity<Project>, code_action_store: CodeActionStore) -> Self {
34 Self {
35 project,
36 code_action_store,
37 }
38 }
39}
40
41impl AgentTool for ApplyCodeActionTool {
42 type Input = ApplyCodeActionToolInput;
43 type Output = String;
44
45 const NAME: &'static str = "apply_code_action";
46
47 fn kind() -> acp::ToolKind {
48 acp::ToolKind::Other
49 }
50
51 fn initial_title(
52 &self,
53 input: Result<Self::Input, serde_json::Value>,
54 cx: &mut App,
55 ) -> SharedString {
56 if let Ok(input) = input {
57 let title = self
58 .code_action_store
59 .read(cx)
60 .as_ref()
61 .and_then(|pending| {
62 let index = input.index.checked_sub(1)? as usize;
63 Some(pending.actions.get(index)?.lsp_action.title().to_string())
64 });
65 if let Some(title) = title {
66 format!("Apply code action: {title}").into()
67 } else {
68 format!("Apply code action #{}", input.index).into()
69 }
70 } else {
71 "Apply code action".into()
72 }
73 }
74
75 fn run(
76 self: Arc<Self>,
77 input: ToolInput<Self::Input>,
78 _event_stream: ToolCallEventStream,
79 cx: &mut App,
80 ) -> Task<Result<String, String>> {
81 let project = self.project.clone();
82 let store = self.code_action_store.clone();
83 cx.spawn(async move |cx| {
84 let input = input
85 .recv()
86 .await
87 .map_err(|e| format!("Failed to receive tool input: {e}"))?;
88
89 let pending = store.update(cx, |store, _cx| store.take()).ok_or_else(|| {
90 "No code actions available. Call get_code_actions first.".to_string()
91 })?;
92
93 let zero_based_index = input
94 .index
95 .checked_sub(1)
96 .ok_or_else(|| "Index must be 1 or greater.".to_string())?;
97
98 let action = pending
99 .actions
100 .get(zero_based_index as usize)
101 .cloned()
102 .ok_or_else(|| {
103 format!(
104 "Index {} is out of range. There were {} code action(s) available.",
105 input.index,
106 pending.actions.len()
107 )
108 })?;
109
110 let title = action.lsp_action.title().to_string();
111 let buffer = pending.buffer.clone();
112
113 let apply_task = project.update(cx, |project, cx| {
114 project.apply_code_action(buffer, action, true, cx)
115 });
116
117 let transaction = apply_task
118 .await
119 .map_err(|e| format!("Failed to apply code action '{title}': {e}"))?;
120
121 if transaction.0.is_empty() {
122 return Ok(format!(
123 "Code action '{title}' was applied but made no changes.",
124 ));
125 }
126
127 let mut output = format!(
128 "Applied code action '{title}'. Modified {} file(s):\n",
129 transaction.0.len()
130 );
131
132 for (buffer, _) in &transaction.0 {
133 buffer.read_with(cx, |buffer, cx| {
134 let path = buffer
135 .file()
136 .map(|f| f.full_path(cx).display().to_string())
137 .unwrap_or_else(|| "<untitled>".to_string());
138 writeln!(output, "- {path}").ok();
139 });
140 }
141
142 Ok(output)
143 })
144 }
145}
146