Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:33:24.540Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

apply_code_action_tool.rs

146 lines · 4.7 KB · rust
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
Served at tenant.openagents/omega Member data and write actions are omitted.