From 7abe2c9c3188b8662ed03007a1f8c21c3c156075 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 18 Apr 2025 16:41:02 -0400 Subject: [PATCH] agent: Attach thread ID and prompt ID to telemetry events (#29069) This PR attaches the thread ID and the new prompt ID to telemetry events for completions in the Agent panel. Release Notes: - N/A --------- Co-authored-by: Mikayla Maki --- Cargo.lock | 13 +++++---- Cargo.toml | 2 +- crates/agent/src/active_thread.rs | 3 ++ crates/agent/src/buffer_codegen.rs | 2 ++ crates/agent/src/message_editor.rs | 3 ++ crates/agent/src/terminal_inline_assistant.rs | 2 ++ crates/agent/src/thread.rs | 29 +++++++++++++++++++ crates/assistant/src/inline_assistant.rs | 2 ++ .../src/terminal_inline_assistant.rs | 2 ++ .../assistant_context_editor/src/context.rs | 2 ++ crates/eval/src/example.rs | 2 ++ crates/git_ui/src/git_panel.rs | 2 ++ crates/language_model/src/request.rs | 2 ++ crates/language_models/src/provider/cloud.rs | 10 ++++++- crates/prompt_library/src/prompt_library.rs | 2 ++ crates/semantic_index/src/summary_index.rs | 2 ++ tooling/workspace-hack/Cargo.toml | 14 ++++++++- 17 files changed, 85 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d09eec222..9ce96bae46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1926,7 +1926,7 @@ dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.11.0", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -6781,7 +6781,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.57.0", + "windows-core 0.61.0", ] [[package]] @@ -11066,7 +11066,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes 1.10.1", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.12.1", "log", "multimap 0.10.0", "once_cell", @@ -11099,7 +11099,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.100", @@ -17747,6 +17747,7 @@ dependencies = [ "hyper-rustls 0.27.5", "indexmap", "inout", + "itertools 0.12.1", "itertools 0.13.0", "lazy_static", "libc", @@ -18369,9 +18370,9 @@ dependencies = [ [[package]] name = "zed_llm_client" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91b8b05f1028157205026e525869eb860fa89bec87ea60b445efc91d05df31f" +checksum = "ad17428120f5ca776dc5195e2411a282f5150a26d5536671f8943c622c31274f" dependencies = [ "anyhow", "serde", diff --git a/Cargo.toml b/Cargo.toml index 106f023231..bb2ffeba0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -604,7 +604,7 @@ wasmtime-wasi = "29" which = "6.0.0" wit-component = "0.221" workspace-hack = "0.1.0" -zed_llm_client = "0.6.0" +zed_llm_client = "0.6.1" zstd = "0.11" metal = "0.29" diff --git a/crates/agent/src/active_thread.rs b/crates/agent/src/active_thread.rs index 5dddbd23ad..6899e26fe5 100644 --- a/crates/agent/src/active_thread.rs +++ b/crates/agent/src/active_thread.rs @@ -1212,6 +1212,8 @@ impl ActiveThread { } let request = language_model::LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![LanguageModelRequestMessage { role: language_model::Role::User, content: vec![content.into()], @@ -1277,6 +1279,7 @@ impl ActiveThread { } self.thread.update(cx, |thread, cx| { + thread.advance_prompt_id(); thread.send_to_model(model.model, RequestKind::Chat, cx) }); cx.notify(); diff --git a/crates/agent/src/buffer_codegen.rs b/crates/agent/src/buffer_codegen.rs index 3cd9306fa7..bd8bf29758 100644 --- a/crates/agent/src/buffer_codegen.rs +++ b/crates/agent/src/buffer_codegen.rs @@ -425,6 +425,8 @@ impl CodegenAlternative { request_message.content.push(prompt.into()); Ok(LanguageModelRequest { + thread_id: None, + prompt_id: None, tools: Vec::new(), stop: Vec::new(), temperature: None, diff --git a/crates/agent/src/message_editor.rs b/crates/agent/src/message_editor.rs index 73ca95888d..d64c95b9b9 100644 --- a/crates/agent/src/message_editor.rs +++ b/crates/agent/src/message_editor.rs @@ -330,6 +330,7 @@ impl MessageEditor { // Send to model after summaries are done thread .update(cx, |thread, cx| { + thread.advance_prompt_id(); thread.send_to_model(model, request_kind, cx); }) .log_err(); @@ -1013,6 +1014,8 @@ impl MessageEditor { } let request = language_model::LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![LanguageModelRequestMessage { role: language_model::Role::User, content: vec![content.into()], diff --git a/crates/agent/src/terminal_inline_assistant.rs b/crates/agent/src/terminal_inline_assistant.rs index de3c96fc15..95099e542c 100644 --- a/crates/agent/src/terminal_inline_assistant.rs +++ b/crates/agent/src/terminal_inline_assistant.rs @@ -261,6 +261,8 @@ impl TerminalInlineAssistant { request_message.content.push(prompt.into()); Ok(LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![request_message], tools: Vec::new(), stop: Vec::new(), diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index ea9db9d9f5..a7044b0100 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -70,6 +70,24 @@ impl From<&str> for ThreadId { } } +/// The ID of the user prompt that initiated a request. +/// +/// This equates to the user physically submitting a message to the model (e.g., by pressing the Enter key). +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] +pub struct PromptId(Arc); + +impl PromptId { + pub fn new() -> Self { + Self(Uuid::new_v4().to_string().into()) + } +} + +impl std::fmt::Display for PromptId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)] pub struct MessageId(pub(crate) usize); @@ -274,6 +292,7 @@ pub struct Thread { detailed_summary_state: DetailedSummaryState, messages: Vec, next_message_id: MessageId, + last_prompt_id: PromptId, context: BTreeMap, context_by_message: HashMap>, project_context: SharedProjectContext, @@ -320,6 +339,7 @@ impl Thread { detailed_summary_state: DetailedSummaryState::NotGenerated, messages: Vec::new(), next_message_id: MessageId(0), + last_prompt_id: PromptId::new(), context: BTreeMap::default(), context_by_message: HashMap::default(), project_context: system_prompt, @@ -393,6 +413,7 @@ impl Thread { }) .collect(), next_message_id, + last_prompt_id: PromptId::new(), context: BTreeMap::default(), context_by_message: HashMap::default(), project_context, @@ -432,6 +453,10 @@ impl Thread { self.updated_at = Utc::now(); } + pub fn advance_prompt_id(&mut self) { + self.last_prompt_id = PromptId::new(); + } + pub fn summary(&self) -> Option { self.summary.clone() } @@ -942,6 +967,8 @@ impl Thread { cx: &mut Context, ) -> LanguageModelRequest { let mut request = LanguageModelRequest { + thread_id: Some(self.id.to_string()), + prompt_id: Some(self.last_prompt_id.to_string()), messages: vec![], tools: Vec::new(), stop: Vec::new(), @@ -1083,6 +1110,7 @@ impl Thread { cx: &mut Context, ) { let pending_completion_id = post_inc(&mut self.completion_count); + let prompt_id = self.last_prompt_id.clone(); let task = cx.spawn(async move |thread, cx| { let stream_completion_future = model.stream_completion_with_usage(request, &cx); let initial_token_usage = @@ -1273,6 +1301,7 @@ impl Thread { telemetry::event!( "Assistant Thread Completion", thread_id = thread.id().to_string(), + prompt_id = prompt_id, model = model.telemetry_id(), model_provider = model.provider_id().to_string(), input_tokens = usage.input_tokens, diff --git a/crates/assistant/src/inline_assistant.rs b/crates/assistant/src/inline_assistant.rs index d5914292de..b7ba199d83 100644 --- a/crates/assistant/src/inline_assistant.rs +++ b/crates/assistant/src/inline_assistant.rs @@ -2978,6 +2978,8 @@ impl CodegenAlternative { }); Ok(LanguageModelRequest { + thread_id: None, + prompt_id: None, messages, tools: Vec::new(), stop: Vec::new(), diff --git a/crates/assistant/src/terminal_inline_assistant.rs b/crates/assistant/src/terminal_inline_assistant.rs index 90e59cf376..db50193d2e 100644 --- a/crates/assistant/src/terminal_inline_assistant.rs +++ b/crates/assistant/src/terminal_inline_assistant.rs @@ -292,6 +292,8 @@ impl TerminalInlineAssistant { }); Ok(LanguageModelRequest { + thread_id: None, + prompt_id: None, messages, tools: Vec::new(), stop: Vec::new(), diff --git a/crates/assistant_context_editor/src/context.rs b/crates/assistant_context_editor/src/context.rs index b68b140d30..097cdb6ad5 100644 --- a/crates/assistant_context_editor/src/context.rs +++ b/crates/assistant_context_editor/src/context.rs @@ -2555,6 +2555,8 @@ impl AssistantContext { } let mut completion_request = LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: Vec::new(), tools: Vec::new(), stop: Vec::new(), diff --git a/crates/eval/src/example.rs b/crates/eval/src/example.rs index 7e48c11313..36f0fe7fdf 100644 --- a/crates/eval/src/example.rs +++ b/crates/eval/src/example.rs @@ -502,6 +502,8 @@ impl Example { )?; let request = LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![LanguageModelRequestMessage { role: Role::User, content: vec![MessageContent::Text(prompt)], diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index d180e1591a..a1369af11d 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -1744,6 +1744,8 @@ impl GitPanel { const PROMPT: &str = include_str!("commit_message_prompt.txt"); let request = LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![LanguageModelRequestMessage { role: Role::User, content: vec![content.into()], diff --git a/crates/language_model/src/request.rs b/crates/language_model/src/request.rs index 696e3644f6..754b1671bb 100644 --- a/crates/language_model/src/request.rs +++ b/crates/language_model/src/request.rs @@ -238,6 +238,8 @@ pub struct LanguageModelRequestTool { #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] pub struct LanguageModelRequest { + pub thread_id: Option, + pub prompt_id: Option, pub messages: Vec, pub tools: Vec, pub stop: Vec, diff --git a/crates/language_models/src/provider/cloud.rs b/crates/language_models/src/provider/cloud.rs index 25a048537b..525125354b 100644 --- a/crates/language_models/src/provider/cloud.rs +++ b/crates/language_models/src/provider/cloud.rs @@ -719,7 +719,7 @@ impl LanguageModel for CloudLanguageModel { fn stream_completion_with_usage( &self, - request: LanguageModelRequest, + mut request: LanguageModelRequest, _cx: &AsyncApp, ) -> BoxFuture< 'static, @@ -728,6 +728,8 @@ impl LanguageModel for CloudLanguageModel { Option, )>, > { + let thread_id = request.prompt_id.take(); + let prompt_id = request.prompt_id.take(); match &self.model { CloudModel::Anthropic(model) => { let request = into_anthropic( @@ -744,6 +746,8 @@ impl LanguageModel for CloudLanguageModel { client.clone(), llm_api_token, CompletionBody { + thread_id, + prompt_id, provider: zed_llm_client::LanguageModelProvider::Anthropic, model: request.model.clone(), provider_request: serde_json::to_value(&request)?, @@ -788,6 +792,8 @@ impl LanguageModel for CloudLanguageModel { client.clone(), llm_api_token, CompletionBody { + thread_id, + prompt_id, provider: zed_llm_client::LanguageModelProvider::OpenAi, model: request.model.clone(), provider_request: serde_json::to_value(&request)?, @@ -816,6 +822,8 @@ impl LanguageModel for CloudLanguageModel { client.clone(), llm_api_token, CompletionBody { + thread_id, + prompt_id, provider: zed_llm_client::LanguageModelProvider::Google, model: request.model.clone(), provider_request: serde_json::to_value(&request)?, diff --git a/crates/prompt_library/src/prompt_library.rs b/crates/prompt_library/src/prompt_library.rs index 5ed987f955..a0e9fbc9a3 100644 --- a/crates/prompt_library/src/prompt_library.rs +++ b/crates/prompt_library/src/prompt_library.rs @@ -924,6 +924,8 @@ impl PromptLibrary { .update(|_, cx| { model.count_tokens( LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![LanguageModelRequestMessage { role: Role::System, content: vec![body.to_string().into()], diff --git a/crates/semantic_index/src/summary_index.rs b/crates/semantic_index/src/summary_index.rs index 397b5f07d5..f1b829f9b5 100644 --- a/crates/semantic_index/src/summary_index.rs +++ b/crates/semantic_index/src/summary_index.rs @@ -557,6 +557,8 @@ impl SummaryIndex { ); let request = LanguageModelRequest { + thread_id: None, + prompt_id: None, messages: vec![LanguageModelRequestMessage { role: Role::User, content: vec![prompt.into()], diff --git a/tooling/workspace-hack/Cargo.toml b/tooling/workspace-hack/Cargo.toml index dc27f75552..c7a2529172 100644 --- a/tooling/workspace-hack/Cargo.toml +++ b/tooling/workspace-hack/Cargo.toml @@ -176,7 +176,7 @@ heck = { version = "0.4", features = ["unicode"] } hmac = { version = "0.12", default-features = false, features = ["reset"] } hyper = { version = "0.14", features = ["client", "http1", "http2", "runtime", "server", "stream"] } indexmap = { version = "2", features = ["serde"] } -itertools = { version = "0.13" } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } lazy_static = { version = "1", default-features = false, features = ["spin_no_std"] } libc = { version = "0.2", features = ["extra_traits"] } libsqlite3-sys = { version = "0.30", features = ["bundled", "unlock_notify"] } @@ -253,6 +253,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } naga = { version = "23", features = ["msl-out", "wgsl-in"] } nix = { version = "0.29", features = ["fs", "pthread", "signal"] } object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] } @@ -276,6 +277,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } naga = { version = "23", features = ["msl-out", "wgsl-in"] } nix = { version = "0.29", features = ["fs", "pthread", "signal"] } object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] } @@ -299,6 +301,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } naga = { version = "23", features = ["msl-out", "wgsl-in"] } nix = { version = "0.29", features = ["fs", "pthread", "signal"] } object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] } @@ -322,6 +325,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } naga = { version = "23", features = ["msl-out", "wgsl-in"] } nix = { version = "0.29", features = ["fs", "pthread", "signal"] } object = { version = "0.36", default-features = false, features = ["archive", "read_core", "unaligned", "write"] } @@ -351,6 +355,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } inout = { version = "0.1", default-features = false, features = ["block-padding"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] } mio = { version = "1", features = ["net", "os-ext"] } naga = { version = "23", features = ["spv-out", "wgsl-in"] } @@ -390,6 +395,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } inout = { version = "0.1", default-features = false, features = ["block-padding"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] } mio = { version = "1", features = ["net", "os-ext"] } naga = { version = "23", features = ["spv-out", "wgsl-in"] } @@ -427,6 +433,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } inout = { version = "0.1", default-features = false, features = ["block-padding"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] } mio = { version = "1", features = ["net", "os-ext"] } naga = { version = "23", features = ["spv-out", "wgsl-in"] } @@ -466,6 +473,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } inout = { version = "0.1", default-features = false, features = ["block-padding"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] } mio = { version = "1", features = ["net", "os-ext"] } naga = { version = "23", features = ["spv-out", "wgsl-in"] } @@ -495,6 +503,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } naga = { version = "23", features = ["spv-out", "wgsl-in"] } ring = { version = "0.17", features = ["std"] } rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", default-features = false, features = ["event"] } @@ -516,6 +525,7 @@ foldhash = { version = "0.1", default-features = false, features = ["std"] } getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } naga = { version = "23", features = ["spv-out", "wgsl-in"] } proc-macro2 = { version = "1", default-features = false, features = ["span-locations"] } ring = { version = "0.17", features = ["std"] } @@ -546,6 +556,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } inout = { version = "0.1", default-features = false, features = ["block-padding"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] } mio = { version = "1", features = ["net", "os-ext"] } naga = { version = "23", features = ["spv-out", "wgsl-in"] } @@ -585,6 +596,7 @@ getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-f gimli = { version = "0.31", default-features = false, features = ["read", "std", "write"] } hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] } inout = { version = "0.1", default-features = false, features = ["block-padding"] } +itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" } linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "system", "xdp"] } mio = { version = "1", features = ["net", "os-ext"] } naga = { version = "23", features = ["spv-out", "wgsl-in"] }