Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:35:45.349Z 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

system_specs.rs

299 lines · 9.5 KB · rust
1pub use gpui::GpuSpecs;
2use gpui::{App, AppContext as _, Task, Window, actions};
3use human_bytes::human_bytes;
4use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
5use semver::Version;
6use serde::Serialize;
7use std::{env, fmt::Display};
8use sysinfo::{MemoryRefreshKind, RefreshKind, System};
9
10actions!(
11    omega,
12    [
13        /// Copies system specifications to the clipboard for bug reports.
14        #[action(deprecated_aliases = ["zed::CopySystemSpecsIntoClipboard"])]
15        CopySystemSpecsIntoClipboard,
16    ]
17);
18
19#[derive(Clone, Debug, Serialize)]
20pub struct SystemSpecs {
21    app_version: String,
22    release_channel: &'static str,
23    os_name: String,
24    os_version: String,
25    memory: u64,
26    architecture: &'static str,
27    commit_sha: Option<String>,
28    bundle_type: Option<String>,
29    gpu_specs: Option<String>,
30}
31
32impl SystemSpecs {
33    pub fn new(
34        window: &mut Window,
35        cx: &mut App,
36        os_name: String,
37        os_version: String,
38    ) -> Task<Self> {
39        let app_version = AppVersion::global(cx).to_string();
40        let release_channel = ReleaseChannel::global(cx);
41        let system = System::new_with_specifics(
42            RefreshKind::nothing().with_memory(MemoryRefreshKind::everything()),
43        );
44        let memory = system.total_memory();
45        let architecture = env::consts::ARCH;
46        let commit_sha = match release_channel {
47            ReleaseChannel::Dev | ReleaseChannel::Nightly => {
48                AppCommitSha::try_global(cx).map(|sha| sha.full())
49            }
50            _ => None,
51        };
52        let bundle_type = bundle_type();
53
54        let gpu_specs = window.gpu_specs().map(|specs| {
55            format!(
56                "{} || {} || {}",
57                specs.device_name, specs.driver_name, specs.driver_info
58            )
59        });
60
61        cx.background_spawn(async move {
62            SystemSpecs {
63                app_version,
64                release_channel: release_channel.display_name(),
65                bundle_type,
66                os_name,
67                os_version,
68                memory,
69                architecture,
70                commit_sha,
71                gpu_specs,
72            }
73        })
74    }
75
76    pub fn new_stateless(
77        app_version: Version,
78        app_commit_sha: Option<AppCommitSha>,
79        release_channel: ReleaseChannel,
80        os_name: String,
81        os_version: String,
82    ) -> Self {
83        let system = System::new_with_specifics(
84            RefreshKind::nothing().with_memory(MemoryRefreshKind::everything()),
85        );
86        let memory = system.total_memory();
87        let architecture = env::consts::ARCH;
88        let commit_sha = match release_channel {
89            ReleaseChannel::Dev | ReleaseChannel::Nightly => app_commit_sha.map(|sha| sha.full()),
90            _ => None,
91        };
92        let bundle_type = bundle_type();
93
94        Self {
95            app_version: app_version.to_string(),
96            release_channel: release_channel.display_name(),
97            os_name,
98            os_version,
99            memory,
100            architecture,
101            commit_sha,
102            bundle_type,
103            gpu_specs: try_determine_available_gpus(),
104        }
105    }
106}
107
108impl Display for SystemSpecs {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        let os_information = format!("OS: {} {}", self.os_name, self.os_version);
111        let app_version_information = format!(
112            "Omega: v{} ({}) {}{}",
113            self.app_version,
114            match &self.commit_sha {
115                Some(commit_sha) => format!("{} {}", self.release_channel, commit_sha),
116                None => self.release_channel.to_string(),
117            },
118            if let Some(bundle_type) = &self.bundle_type {
119                format!("({bundle_type})")
120            } else {
121                "".to_string()
122            },
123            if cfg!(debug_assertions) {
124                "(Taylor's Version)"
125            } else {
126                ""
127            },
128        );
129        let system_specs = [
130            app_version_information,
131            os_information,
132            format!("Memory: {}", human_bytes(self.memory as f64)),
133            format!("Architecture: {}", self.architecture),
134        ]
135        .into_iter()
136        .chain(
137            self.gpu_specs
138                .as_ref()
139                .map(|specs| format!("GPU: {}", specs)),
140        )
141        .collect::<Vec<String>>()
142        .join("\n");
143
144        write!(f, "{system_specs}")
145    }
146}
147
148fn try_determine_available_gpus() -> Option<String> {
149    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
150    {
151        #[allow(
152            clippy::disallowed_methods,
153            reason = "we are not running in an executor"
154        )]
155        std::process::Command::new("vulkaninfo")
156            .args(&["--summary"])
157            .output()
158            .ok()
159            .map(|output| {
160                [
161                    "<details><summary>`vulkaninfo --summary` output</summary>",
162                    "",
163                    "```",
164                    String::from_utf8_lossy(&output.stdout).as_ref(),
165                    "```",
166                    "</details>",
167                ]
168                .join("\n")
169            })
170            .or(Some("Failed to run `vulkaninfo --summary`".to_string()))
171    }
172    #[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
173    {
174        None
175    }
176}
177
178#[derive(Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize, Clone)]
179pub struct GpuInfo {
180    pub device_name: Option<String>,
181    pub device_pci_id: u16,
182    pub vendor_name: Option<String>,
183    pub vendor_pci_id: u16,
184    pub driver_version: Option<String>,
185    pub driver_name: Option<String>,
186}
187
188#[cfg(any(target_os = "linux", target_os = "freebsd"))]
189pub fn read_gpu_info_from_sys_class_drm() -> anyhow::Result<Vec<GpuInfo>> {
190    use anyhow::Context as _;
191    use pciid_parser;
192    let dir_iter = std::fs::read_dir("/sys/class/drm").context("Failed to read /sys/class/drm")?;
193    let mut pci_addresses = vec![];
194    let mut gpus = Vec::<GpuInfo>::new();
195    let pci_db = pciid_parser::Database::read().ok();
196    for entry in dir_iter {
197        let Ok(entry) = entry else {
198            continue;
199        };
200
201        let device_path = entry.path().join("device");
202        let Some(pci_address) = device_path.read_link().ok().and_then(|pci_address| {
203            pci_address
204                .file_name()
205                .and_then(std::ffi::OsStr::to_str)
206                .map(str::trim)
207                .map(str::to_string)
208        }) else {
209            continue;
210        };
211        let Ok(device_pci_id) = read_pci_id_from_path(device_path.join("device")) else {
212            continue;
213        };
214        let Ok(vendor_pci_id) = read_pci_id_from_path(device_path.join("vendor")) else {
215            continue;
216        };
217        let driver_name = std::fs::read_link(device_path.join("driver"))
218            .ok()
219            .and_then(|driver_link| {
220                driver_link
221                    .file_name()
222                    .and_then(std::ffi::OsStr::to_str)
223                    .map(str::trim)
224                    .map(str::to_string)
225            });
226        let driver_version = driver_name
227            .as_ref()
228            .and_then(|driver_name| {
229                std::fs::read_to_string(format!("/sys/module/{driver_name}/version")).ok()
230            })
231            .as_deref()
232            .map(str::trim)
233            .map(str::to_string);
234
235        let already_found = gpus
236            .iter()
237            .zip(&pci_addresses)
238            .any(|(gpu, gpu_pci_address)| {
239                gpu_pci_address == &pci_address
240                    && gpu.driver_version == driver_version
241                    && gpu.driver_name == driver_name
242            });
243
244        if already_found {
245            continue;
246        }
247
248        let vendor = pci_db
249            .as_ref()
250            .and_then(|db| db.vendors.get(&vendor_pci_id));
251        let vendor_name = vendor.map(|vendor| vendor.name.clone());
252        let device_name = vendor
253            .and_then(|vendor| vendor.devices.get(&device_pci_id))
254            .map(|device| device.name.clone());
255
256        gpus.push(GpuInfo {
257            device_name,
258            device_pci_id,
259            vendor_name,
260            vendor_pci_id,
261            driver_version,
262            driver_name,
263        });
264        pci_addresses.push(pci_address);
265    }
266
267    Ok(gpus)
268}
269
270#[cfg(any(target_os = "linux", target_os = "freebsd"))]
271fn read_pci_id_from_path(path: impl AsRef<std::path::Path>) -> anyhow::Result<u16> {
272    use anyhow::Context as _;
273    let id = std::fs::read_to_string(path)?;
274    let id = id
275        .trim()
276        .strip_prefix("0x")
277        .context("Not a device ID")
278        .context(id.clone())?;
279    anyhow::ensure!(
280        id.len() == 4,
281        "Not a device id, expected 4 digits, found {}",
282        id.len()
283    );
284    u16::from_str_radix(id, 16).context("Failed to parse device ID")
285}
286
287/// Returns value of `ZED_BUNDLE_TYPE` set at compiletime or else at runtime.
288///
289/// The compiletime value is used by flatpak since it doesn't seem to have a way to provide a
290/// runtime environment variable.
291///
292/// The runtime value is used by snap since the Zed snaps use release binaries directly, and so
293/// cannot have this baked in.
294fn bundle_type() -> Option<String> {
295    option_env!("ZED_BUNDLE_TYPE")
296        .map(|bundle_type| bundle_type.to_string())
297        .or_else(|| env::var("ZED_BUNDLE_TYPE").ok())
298}
299
Served at tenant.openagents/omega Member data and write actions are omitted.