diff --git a/Cargo.lock b/Cargo.lock index 8b428dbcd537e33088f40fdde5e3251a6148672a..849129850d7df27c521bea00dcd3796c10369dea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,7 +7,7 @@ name = "acp_thread" version = "0.1.0" dependencies = [ "action_log", - "agent-client-protocol", + "agent-client-protocol-core", "anyhow", "base64 0.22.1", "buffer_diff", @@ -15,7 +15,7 @@ dependencies = [ "collections", "env_logger 0.11.8", "file_icons", - "futures 0.3.31", + "futures 0.3.32", "gpui", "image", "indoc", @@ -50,7 +50,7 @@ dependencies = [ name = "acp_tools" version = "0.1.0" dependencies = [ - "agent-client-protocol", + "agent-client-protocol-core", "collections", "gpui", "language", @@ -75,7 +75,7 @@ dependencies = [ "collections", "ctor", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "language", "log", @@ -100,7 +100,7 @@ dependencies = [ "editor", "extension_host", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "language", "project", @@ -144,7 +144,7 @@ version = "0.1.0" dependencies = [ "acp_thread", "action_log", - "agent-client-protocol", + "agent-client-protocol-core", "agent_servers", "agent_settings", "anyhow", @@ -163,7 +163,7 @@ dependencies = [ "eval_utils", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "git", "gpui", "gpui_tokio", @@ -217,27 +217,42 @@ dependencies = [ ] [[package]] -name = "agent-client-protocol" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c56a59cf6315e99f874d2c1f96c69d2da5ffe0087d211297fc4a41f849770a2" +name = "agent-client-protocol-core" +version = "0.1.0" dependencies = [ + "agent-client-protocol-derive", "agent-client-protocol-schema", "anyhow", - "async-broadcast", - "async-trait", - "derive_more", - "futures 0.3.31", - "log", + "boxfnonce", + "futures 0.3.32", + "futures-concurrency", + "jsonrpcmsg", + "rmcp", + "rustc-hash 2.1.1", + "schemars", "serde", "serde_json", + "thiserror 2.0.17", + "tokio", + "tokio-util", + "tracing", + "uuid", +] + +[[package]] +name = "agent-client-protocol-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "agent-client-protocol-schema" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0497b9a95a404e35799904835c57c6f8c69b9d08ccfd3cb5b7d746425cd6789" +checksum = "ca68e7e55681ce56546c0cecc6bc8f20493d24b44c6d93ec46174f310730bba2" dependencies = [ "anyhow", "derive_more", @@ -254,7 +269,7 @@ dependencies = [ "acp_thread", "acp_tools", "action_log", - "agent-client-protocol", + "agent-client-protocol-core", "anyhow", "async-trait", "chrono", @@ -264,7 +279,7 @@ dependencies = [ "env_logger 0.11.8", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "google_ai", "gpui", "gpui_tokio", @@ -295,7 +310,7 @@ dependencies = [ name = "agent_settings" version = "0.1.0" dependencies = [ - "agent-client-protocol", + "agent-client-protocol-core", "anyhow", "collections", "convert_case 0.8.0", @@ -321,7 +336,7 @@ dependencies = [ "acp_thread", "action_log", "agent", - "agent-client-protocol", + "agent-client-protocol-core", "agent_servers", "agent_settings", "ai_onboarding", @@ -344,7 +359,7 @@ dependencies = [ "feature_flags", "file_icons", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "git", "gpui", @@ -629,7 +644,7 @@ version = "0.1.0" dependencies = [ "anyhow", "chrono", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -750,7 +765,7 @@ name = "askpass" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "gpui", "log", "net", @@ -945,7 +960,7 @@ name = "async-pipe" version = "0.1.3" source = "git+https://github.com/zed-industries/async-pipe-rs?rev=82d00a04211cf4e1236029aa03e6b6ce2a74c553#82d00a04211cf4e1236029aa03e6b6ce2a74c553" dependencies = [ - "futures 0.3.31", + "futures 0.3.32", "log", ] @@ -1183,7 +1198,7 @@ dependencies = [ "clock", "ctor", "db", - "futures 0.3.31", + "futures 0.3.32", "futures-lite 1.13.0", "gpui", "http_client", @@ -1862,7 +1877,7 @@ dependencies = [ "anyhow", "aws-sdk-bedrockruntime", "aws-smithy-types", - "futures 0.3.31", + "futures 0.3.32", "schemars", "serde", "serde_json", @@ -2072,7 +2087,7 @@ version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "ident_case", "prettyplease", "proc-macro2", @@ -2110,6 +2125,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "boxfnonce" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426" + [[package]] name = "breadcrumbs" version = "0.1.0" @@ -2151,7 +2172,7 @@ version = "0.1.0" dependencies = [ "clock", "ctor", - "futures 0.3.31", + "futures 0.3.32", "git2", "gpui", "language", @@ -2348,7 +2369,7 @@ dependencies = [ "collections", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_tokio", "language", @@ -2669,7 +2690,7 @@ dependencies = [ "client", "clock", "collections", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "language", @@ -2863,7 +2884,7 @@ dependencies = [ "derive_more", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_tokio", "http_client", @@ -2917,7 +2938,7 @@ version = "0.1.0" dependencies = [ "anyhow", "cloud_api_types", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_tokio", "http_client", @@ -3049,7 +3070,7 @@ dependencies = [ "anyhow", "edit_prediction", "edit_prediction_types", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "icons", @@ -3095,7 +3116,7 @@ dependencies = [ "extension", "file_finder", "fs", - "futures 0.3.31", + "futures 0.3.32", "git", "git_hosting_providers", "git_ui", @@ -3172,7 +3193,7 @@ dependencies = [ "collections", "db", "editor", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "livekit_client", @@ -3433,7 +3454,7 @@ dependencies = [ "async-trait", "base64 0.22.1", "collections", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "log", @@ -3494,7 +3515,7 @@ dependencies = [ "edit_prediction_types", "editor", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "icons", "indoc", @@ -3528,7 +3549,7 @@ dependencies = [ "collections", "dirs 4.0.0", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "log", @@ -3978,7 +3999,7 @@ version = "0.1.0" dependencies = [ "cfg-if", "crash-handler", - "futures 0.3.31", + "futures 0.3.32", "log", "mach2 0.5.0", "minidumper", @@ -4035,7 +4056,7 @@ name = "credentials_provider" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "gpui", "paths", "release_channel", @@ -4318,7 +4339,7 @@ dependencies = [ "collections", "dap-types", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "language", @@ -4360,7 +4381,7 @@ dependencies = [ "dap", "dotenvy", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "json_dotpath", @@ -4396,6 +4417,16 @@ dependencies = [ "darling_macro 0.21.3", ] +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -4424,6 +4455,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + [[package]] name = "darling_macro" version = "0.20.11" @@ -4446,6 +4490,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", +] + [[package]] name = "dashmap" version = "6.1.0" @@ -4531,7 +4586,7 @@ dependencies = [ "anyhow", "dap", "editor", - "futures 0.3.31", + "futures 0.3.32", "gpui", "project", "serde_json", @@ -4558,7 +4613,7 @@ dependencies = [ "editor", "feature_flags", "file_icons", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "hex", @@ -4613,7 +4668,7 @@ name = "deepseek" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -4733,7 +4788,7 @@ dependencies = [ "async-trait", "env_logger 0.11.8", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http 1.3.1", "http_client", @@ -5121,7 +5176,7 @@ dependencies = [ "edit_prediction_types", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "heapless", "indoc", @@ -5181,7 +5236,7 @@ dependencies = [ "extension", "flate2", "fs", - "futures 0.3.31", + "futures 0.3.32", "gaoya", "gpui", "gpui_platform", @@ -5233,7 +5288,7 @@ dependencies = [ "clock", "collections", "env_logger 0.11.8", - "futures 0.3.31", + "futures 0.3.32", "gpui", "indoc", "language", @@ -5282,7 +5337,7 @@ dependencies = [ "editor", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "indoc", "language", @@ -5327,7 +5382,7 @@ dependencies = [ "feature_flags", "file_icons", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "git", "gpui", @@ -5722,7 +5777,7 @@ version = "0.1.0" dependencies = [ "acp_thread", "agent", - "agent-client-protocol", + "agent-client-protocol-core", "agent_ui", "anyhow", "clap", @@ -5734,7 +5789,7 @@ dependencies = [ "extension", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_platform", "gpui_tokio", @@ -5844,7 +5899,7 @@ dependencies = [ "collections", "dap", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "heck 0.5.0", "http_client", @@ -5912,7 +5967,7 @@ dependencies = [ "dap", "extension", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_tokio", "http_client", @@ -6120,7 +6175,7 @@ dependencies = [ "ctor", "editor", "file_icons", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "menu", @@ -6422,7 +6477,7 @@ dependencies = [ "collections", "dunce", "fs", - "futures 0.3.31", + "futures 0.3.32", "git", "gpui", "ignore", @@ -6520,9 +6575,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -6535,9 +6590,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -6558,15 +6613,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -6586,9 +6641,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -6620,9 +6675,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -6631,21 +6686,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures 0.1.31", "futures-channel", @@ -6654,9 +6709,9 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", + "libc", "memchr", "pin-project-lite", - "pin-utils", "slab", "tokio-io", ] @@ -7083,7 +7138,7 @@ dependencies = [ "async-trait", "collections", "derive_more", - "futures 0.3.31", + "futures 0.3.32", "git2", "gpui", "http_client", @@ -7160,7 +7215,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "futures 0.3.31", + "futures 0.3.32", "git", "gpui", "http_client", @@ -7192,7 +7247,7 @@ dependencies = [ "editor", "feature_flags", "file_icons", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "git", "gpui", @@ -7397,7 +7452,7 @@ name = "google_ai" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -7467,7 +7522,7 @@ dependencies = [ "env_logger 0.11.8", "etagere", "foreign-types 0.5.0", - "futures 0.3.31", + "futures 0.3.32", "futures-concurrency", "getrandom 0.3.4", "gpui_macros", @@ -7542,7 +7597,7 @@ dependencies = [ "calloop-wayland-source", "collections", "filedescriptor", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_wgpu", "http_client", @@ -7596,7 +7651,7 @@ dependencies = [ "dispatch2", "etagere", "foreign-types 0.5.0", - "futures 0.3.31", + "futures 0.3.32", "gpui", "image", "itertools 0.14.0", @@ -7665,7 +7720,7 @@ version = "0.1.0" dependencies = [ "anyhow", "console_error_panic_hook", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_wgpu", "http_client", @@ -7716,7 +7771,7 @@ dependencies = [ "anyhow", "collections", "etagere", - "futures 0.3.31", + "futures 0.3.32", "gpui", "image", "itertools 0.14.0", @@ -8200,7 +8255,7 @@ dependencies = [ "async-tar", "bytes 1.11.1", "derive_more", - "futures 0.3.31", + "futures 0.3.32", "http 1.3.1", "http-body 1.0.1", "log", @@ -9029,6 +9084,16 @@ dependencies = [ "util", ] +[[package]] +name = "jsonrpcmsg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d833a15225c779251e13929203518c2ff26e2fe0f322d584b213f4f4dad37bd" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "jsonschema" version = "0.37.4" @@ -9083,7 +9148,7 @@ dependencies = [ "async-trait", "bytes 1.11.1", "chrono", - "futures 0.3.31", + "futures 0.3.32", "serde", "serde_json", "thiserror 2.0.17", @@ -9099,7 +9164,7 @@ dependencies = [ "anyhow", "async-trait", "async-tungstenite", - "futures 0.3.31", + "futures 0.3.32", "jupyter-protocol", "serde", "serde_json", @@ -9217,7 +9282,7 @@ dependencies = [ "ec4rs", "encoding_rs", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "globset", "gpui", @@ -9297,7 +9362,7 @@ dependencies = [ "collections", "extension", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "language", "log", @@ -9323,7 +9388,7 @@ dependencies = [ "cloud_llm_client", "collections", "credentials_provider", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "icons", @@ -9367,7 +9432,7 @@ dependencies = [ "extension", "extension_host", "fs", - "futures 0.3.31", + "futures 0.3.32", "google_ai", "gpui", "gpui_tokio", @@ -9444,7 +9509,7 @@ dependencies = [ "command_palette_hooks", "edit_prediction", "editor", - "futures 0.3.31", + "futures 0.3.32", "gpui", "itertools 0.14.0", "language", @@ -9480,7 +9545,7 @@ dependencies = [ "chrono", "collections", "fs", - "futures 0.3.31", + "futures 0.3.32", "globset", "gpui", "grammars", @@ -9867,7 +9932,7 @@ dependencies = [ "core-video", "coreaudio-rs 0.12.1", "cpal", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_platform", "gpui_tokio", @@ -9911,7 +9976,7 @@ name = "lmstudio" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -9982,7 +10047,7 @@ dependencies = [ "async-pipe", "collections", "ctor", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_util", "log", @@ -10122,7 +10187,7 @@ dependencies = [ "collections", "env_logger 0.11.8", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_platform", "html5ever 0.27.0", @@ -10569,7 +10634,7 @@ name = "mistral" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -10758,7 +10823,7 @@ name = "nc" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "net", "smol", ] @@ -10854,7 +10919,7 @@ dependencies = [ "async-std", "async-tar", "async-trait", - "futures 0.3.31", + "futures 0.3.32", "http_client", "log", "paths", @@ -11178,7 +11243,7 @@ version = "0.9.2" source = "git+https://github.com/KillTheMule/nvim-rs?rev=764dd270c642f77f10f3e19d05cc178a6cbe69f3#764dd270c642f77f10f3e19d05cc178a6cbe69f3" dependencies = [ "async-trait", - "futures 0.3.31", + "futures 0.3.32", "log", "rmp", "rmpv", @@ -11378,7 +11443,7 @@ name = "ollama" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -11485,7 +11550,7 @@ name = "open_ai" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "log", "rand 0.9.2", @@ -11503,7 +11568,7 @@ version = "0.1.0" dependencies = [ "editor", "file_icons", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "picker", @@ -11524,7 +11589,7 @@ name = "open_router" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "http_client", "schemars", "serde", @@ -11539,7 +11604,7 @@ name = "opencode" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.32", "google_ai", "http_client", "schemars", @@ -11853,6 +11918,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" + [[package]] name = "pathdiff" version = "0.2.3" @@ -12853,7 +12924,7 @@ checksum = "af3fb618632874fb76937c2361a7f22afd393c982a2165595407edc75b06d3c1" dependencies = [ "atomic", "crossbeam-queue", - "futures 0.3.31", + "futures 0.3.32", "log", "parking_lot", "pin-project", @@ -13086,7 +13157,7 @@ dependencies = [ "extension", "fancy-regex 0.17.0", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "git", "git2", @@ -13152,7 +13223,7 @@ dependencies = [ "askpass", "clap", "client", - "futures 0.3.31", + "futures 0.3.32", "gpui", "gpui_platform", "http_client", @@ -13213,7 +13284,7 @@ version = "0.1.0" dependencies = [ "anyhow", "editor", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "language", @@ -13255,7 +13326,7 @@ dependencies = [ "chrono", "collections", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "handlebars 4.5.0", @@ -14010,7 +14081,7 @@ dependencies = [ "extension", "extension_host", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "http_client", @@ -14194,7 +14265,7 @@ dependencies = [ "base64 0.22.1", "collections", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "log", "parking_lot", @@ -14222,7 +14293,7 @@ dependencies = [ "anyhow", "askpass", "auto_update", - "futures 0.3.31", + "futures 0.3.32", "gpui", "log", "markdown", @@ -14260,7 +14331,7 @@ dependencies = [ "extension_host", "fork", "fs", - "futures 0.3.31", + "futures 0.3.32", "git", "git2", "git_hosting_providers", @@ -14342,7 +14413,7 @@ dependencies = [ "editor", "feature_flags", "file_icons", - "futures 0.3.31", + "futures 0.3.32", "gpui", "html_to_markdown", "http_client", @@ -14467,7 +14538,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes 1.11.1", - "futures 0.3.31", + "futures 0.3.32", "gpui_util", "http_client", "http_client_tls", @@ -14558,6 +14629,41 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rmcp" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2231b2c085b371c01bc90c0e6c1cab8834711b6394533375bdbf870b0166d419" +dependencies = [ + "async-trait", + "base64 0.22.1", + "chrono", + "futures 0.3.32", + "pastey", + "pin-project-lite", + "rmcp-macros", + "schemars", + "serde", + "serde_json", + "thiserror 2.0.17", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "rmcp-macros" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea0e100fadf81be85d7ff70f86cd805c7572601d4ab2946207f36540854b43" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.117", +] + [[package]] name = "rmp" version = "0.8.14" @@ -14639,7 +14745,7 @@ dependencies = [ "async-tungstenite", "base64 0.22.1", "collections", - "futures 0.3.31", + "futures 0.3.32", "gpui", "parking_lot", "proto", @@ -14732,7 +14838,7 @@ dependencies = [ "chrono", "data-encoding", "dirs 6.0.0", - "futures 0.3.31", + "futures 0.3.32", "glob", "jupyter-protocol", "serde", @@ -15106,7 +15212,7 @@ dependencies = [ "backtrace", "chrono", "flume", - "futures 0.3.31", + "futures 0.3.32", "parking_lot", "rand 0.9.2", "web-time", @@ -15133,6 +15239,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" dependencies = [ + "chrono", "dyn-clone", "indexmap", "ref-cast", @@ -15334,7 +15441,7 @@ dependencies = [ "collections", "editor", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "itertools 0.14.0", "language", @@ -15613,7 +15720,7 @@ dependencies = [ "collections", "ec4rs", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "indoc", "inventory", @@ -15717,7 +15824,7 @@ dependencies = [ "editor", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "heck 0.5.0", @@ -15858,7 +15965,7 @@ dependencies = [ "acp_thread", "action_log", "agent", - "agent-client-protocol", + "agent-client-protocol-core", "agent_settings", "agent_ui", "anyhow", @@ -16093,7 +16200,7 @@ dependencies = [ "collections", "extension", "fs", - "futures 0.3.31", + "futures 0.3.32", "gpui", "indoc", "parking_lot", @@ -16205,7 +16312,7 @@ version = "0.1.0" dependencies = [ "anyhow", "collections", - "futures 0.3.31", + "futures 0.3.32", "indoc", "libsqlite3-sys", "log", @@ -17251,7 +17358,7 @@ version = "0.1.0" dependencies = [ "anyhow", "collections", - "futures 0.3.31", + "futures 0.3.32", "gpui", "hex", "log", @@ -17298,7 +17405,7 @@ dependencies = [ name = "telemetry" version = "0.1.0" dependencies = [ - "futures 0.3.31", + "futures 0.3.32", "serde", "serde_json", "telemetry_events", @@ -17353,7 +17460,7 @@ dependencies = [ "alacritty_terminal", "anyhow", "collections", - "futures 0.3.31", + "futures 0.3.32", "gpui", "itertools 0.14.0", "libc", @@ -17399,7 +17506,7 @@ dependencies = [ "db", "dirs 4.0.0", "editor", - "futures 0.3.31", + "futures 0.3.32", "gpui", "itertools 0.14.0", "language", @@ -18035,7 +18142,7 @@ dependencies = [ "anyhow", "convert_case 0.8.0", "editor", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "gpui", "language", @@ -18911,7 +19018,7 @@ dependencies = [ "command-fds", "dirs 4.0.0", "dunce", - "futures 0.3.31", + "futures 0.3.32", "futures-lite 1.13.0", "git2", "globset", @@ -19068,7 +19175,7 @@ dependencies = [ "db", "editor", "env_logger 0.11.8", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "git_ui", "gpui", @@ -19432,7 +19539,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7516db7f32decdadb1c3b8deb1b7d78b9df7606c5cc2f6241737c2ab3a0258e" dependencies = [ - "futures 0.3.31", + "futures 0.3.32", "js-sys", "wasm-bindgen", "web-sys", @@ -19788,7 +19895,7 @@ dependencies = [ "cap-std", "cap-time-ext", "fs-set-times", - "futures 0.3.31", + "futures 0.3.32", "io-extras", "io-lifetimes", "rustix 1.1.2", @@ -19812,7 +19919,7 @@ dependencies = [ "anyhow", "async-trait", "bytes 1.11.1", - "futures 0.3.31", + "futures 0.3.32", "wasmtime", ] @@ -19830,7 +19937,7 @@ name = "watch" version = "0.1.0" dependencies = [ "ctor", - "futures 0.3.31", + "futures 0.3.32", "gpui", "parking_lot", "zlog", @@ -20000,7 +20107,7 @@ dependencies = [ "client", "cloud_api_types", "cloud_llm_client", - "futures 0.3.31", + "futures 0.3.32", "gpui", "http_client", "language_model", @@ -21194,7 +21301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" dependencies = [ "bitflags 2.10.0", - "futures 0.3.31", + "futures 0.3.32", "once_cell", ] @@ -21445,7 +21552,7 @@ dependencies = [ "db", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.32", "git", "gpui", "http_client", @@ -21493,7 +21600,7 @@ dependencies = [ "collections", "encoding_rs", "fs", - "futures 0.3.31", + "futures 0.3.32", "fuzzy", "git", "gpui", @@ -21745,7 +21852,7 @@ dependencies = [ "base64 0.22.1", "bytes 1.11.1", "flate2", - "futures 0.3.31", + "futures 0.3.32", "http-body-util", "hyper 1.7.0", "hyper-util", @@ -21900,7 +22007,7 @@ dependencies = [ "action_log", "activity_indicator", "agent", - "agent-client-protocol", + "agent-client-protocol-core", "agent_servers", "agent_settings", "agent_ui", @@ -21950,7 +22057,7 @@ dependencies = [ "feedback", "file_finder", "fs", - "futures 0.3.31", + "futures 0.3.32", "git", "git_graph", "git_hosting_providers", @@ -22326,7 +22433,7 @@ dependencies = [ "asynchronous-codec", "bytes 1.11.1", "crossbeam-queue", - "futures 0.3.31", + "futures 0.3.32", "log", "num-traits", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 3a393237ab9f5a5a8cd4b02517f6d22382ff51ff..1c5b124981f998cc548a44a1a0b0c0a7436f066b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -477,7 +477,7 @@ ztracing_macro = { path = "crates/ztracing_macro" } # External crates # -agent-client-protocol = { version = "=0.10.2", features = ["unstable"] } +agent-client-protocol-core = { path = "../acp-rust-sdk/src/agent-client-protocol-core", features = ["unstable"] } aho-corasick = "1.1" alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "9d9640d4" } any_vec = "0.14" diff --git a/crates/acp_thread/Cargo.toml b/crates/acp_thread/Cargo.toml index 7ef53bc522708680e64cfcc9ce2860990bfd7d13..9b1e0a9b64855c65e1108ec97d95530236e08f0e 100644 --- a/crates/acp_thread/Cargo.toml +++ b/crates/acp_thread/Cargo.toml @@ -17,7 +17,7 @@ test-support = ["gpui/test-support", "project/test-support", "dep:parking_lot", [dependencies] action_log.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true base64.workspace = true anyhow.workspace = true buffer_diff.workspace = true diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs index 0bcb8254c8b8123eef3faaa913bb360de8dcc76d..5746ca14bb962392dceab6666c6b2c22f263bf00 100644 --- a/crates/acp_thread/src/acp_thread.rs +++ b/crates/acp_thread/src/acp_thread.rs @@ -3,7 +3,7 @@ mod diff; mod mention; mod terminal; use action_log::{ActionLog, ActionLogTelemetry}; -use agent_client_protocol::{self as acp}; +use agent_client_protocol_core::schema as acp; use anyhow::{Context as _, Result, anyhow}; use collections::HashSet; pub use connection::*; diff --git a/crates/acp_thread/src/connection.rs b/crates/acp_thread/src/connection.rs index 58a8aa33830f12ffb713490c87c47133cc2ad96f..0835a05d6cb07ed40d6253b650b06379ce396c47 100644 --- a/crates/acp_thread/src/connection.rs +++ b/crates/acp_thread/src/connection.rs @@ -1,5 +1,5 @@ use crate::AcpThread; -use agent_client_protocol::{self as acp}; +use agent_client_protocol_core::schema as acp; use anyhow::Result; use chrono::{DateTime, Utc}; use collections::{HashMap, IndexMap}; @@ -939,7 +939,7 @@ mod test_support { fn truncate( &self, - _session_id: &agent_client_protocol::SessionId, + _session_id: &acp::SessionId, _cx: &App, ) -> Option> { Some(Rc::new(StubAgentSessionEditor)) diff --git a/crates/acp_thread/src/mention.rs b/crates/acp_thread/src/mention.rs index 753838d3b98ed60dc02c3d9383c28fe4f848a29e..b4928eb5edc102c1d7e50ed67e8ced3b5e1ef16e 100644 --- a/crates/acp_thread/src/mention.rs +++ b/crates/acp_thread/src/mention.rs @@ -1,4 +1,4 @@ -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Context as _, Result, bail}; use file_icons::FileIcons; use prompt_store::{PromptId, UserPromptId}; diff --git a/crates/acp_thread/src/terminal.rs b/crates/acp_thread/src/terminal.rs index fceb816f7f1471af1e5e2fb87f82bf66978c3df7..08fcf32e0d3da87551413153ade0802b7bc580fe 100644 --- a/crates/acp_thread/src/terminal.rs +++ b/crates/acp_thread/src/terminal.rs @@ -1,4 +1,4 @@ -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::Result; use futures::{FutureExt as _, future::Shared}; use gpui::{App, AppContext, AsyncApp, Context, Entity, Task}; diff --git a/crates/acp_tools/Cargo.toml b/crates/acp_tools/Cargo.toml index 8f14b1f93b32c6df521ea13ebf3f0f73e7ed755c..43963b4034411c0daee0d88bd5b15ff16a1c9018 100644 --- a/crates/acp_tools/Cargo.toml +++ b/crates/acp_tools/Cargo.toml @@ -14,7 +14,7 @@ path = "src/acp_tools.rs" doctest = false [dependencies] -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true collections.workspace = true gpui.workspace = true language.workspace= true diff --git a/crates/acp_tools/src/acp_tools.rs b/crates/acp_tools/src/acp_tools.rs index ae8a39c8df4f73ae8be6b748694dbde5d2a0c102..dfeaab42e14e8032721b4161472b974b9459b876 100644 --- a/crates/acp_tools/src/acp_tools.rs +++ b/crates/acp_tools/src/acp_tools.rs @@ -1,12 +1,6 @@ -use std::{ - cell::RefCell, - collections::HashSet, - fmt::Display, - rc::{Rc, Weak}, - sync::Arc, -}; +use std::{cell::RefCell, collections::HashSet, fmt::Display, sync::Arc}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use collections::HashMap; use gpui::{ App, Empty, Entity, EventEmitter, FocusHandle, Focusable, Global, ListAlignment, ListState, @@ -23,6 +17,42 @@ use workspace::{ Item, ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, }; +// Stub types for the old streaming API which is not available in agent-client-protocol-core. +// These allow the ACP debug panel code to compile but the streaming won't be active. +#[allow(dead_code)] +type RequestId = String; + +#[derive(Clone)] +#[allow(dead_code)] +enum StreamMessageDirection { + Incoming, + Outgoing, +} + +#[derive(Clone)] +#[allow(dead_code)] +enum StreamMessageContent { + Request { + id: RequestId, + method: Arc, + params: Option, + }, + Response { + id: RequestId, + result: Result, acp::Error>, + }, + Notification { + method: Arc, + params: Option, + }, +} + +#[allow(dead_code)] +struct StreamMessage { + direction: StreamMessageDirection, + message: StreamMessageContent, +} + actions!(dev, [OpenAcpLogs]); pub fn init(cx: &mut App) { @@ -49,7 +79,6 @@ pub struct AcpConnectionRegistry { struct ActiveConnection { agent_id: AgentId, - connection: Weak, } impl AcpConnectionRegistry { @@ -63,16 +92,9 @@ impl AcpConnectionRegistry { } } - pub fn set_active_connection( - &self, - agent_id: AgentId, - connection: &Rc, - cx: &mut Context, - ) { - self.active_connection.replace(Some(ActiveConnection { - agent_id, - connection: Rc::downgrade(connection), - })); + pub fn set_active_connection(&self, agent_id: AgentId, cx: &mut Context) { + self.active_connection + .replace(Some(ActiveConnection { agent_id })); cx.notify(); } } @@ -90,9 +112,10 @@ struct WatchedConnection { agent_id: AgentId, messages: Vec, list_state: ListState, - connection: Weak, - incoming_request_methods: HashMap>, - outgoing_request_methods: HashMap>, + #[allow(dead_code)] + incoming_request_methods: HashMap>, + #[allow(dead_code)] + outgoing_request_methods: HashMap>, _task: Task<()>, } @@ -124,38 +147,23 @@ impl AcpTools { }; if let Some(watched_connection) = self.watched_connection.as_ref() { - if Weak::ptr_eq( - &watched_connection.connection, - &active_connection.connection, - ) { + if watched_connection.agent_id == active_connection.agent_id { return; } } - if let Some(connection) = active_connection.connection.upgrade() { - let mut receiver = connection.subscribe(); - let task = cx.spawn(async move |this, cx| { - while let Ok(message) = receiver.recv().await { - this.update(cx, |this, cx| { - this.push_stream_message(message, cx); - }) - .ok(); - } - }); - - self.watched_connection = Some(WatchedConnection { - agent_id: active_connection.agent_id.clone(), - messages: vec![], - list_state: ListState::new(0, ListAlignment::Bottom, px(2048.)), - connection: active_connection.connection.clone(), - incoming_request_methods: HashMap::default(), - outgoing_request_methods: HashMap::default(), - _task: task, - }); - } + self.watched_connection = Some(WatchedConnection { + agent_id: active_connection.agent_id.clone(), + messages: vec![], + list_state: ListState::new(0, ListAlignment::Bottom, px(2048.)), + incoming_request_methods: HashMap::default(), + outgoing_request_methods: HashMap::default(), + _task: Task::ready(()), + }); } - fn push_stream_message(&mut self, stream_message: acp::StreamMessage, cx: &mut Context) { + #[allow(dead_code)] + fn push_stream_message(&mut self, stream_message: StreamMessage, cx: &mut Context) { let Some(connection) = self.watched_connection.as_mut() else { return; }; @@ -163,27 +171,19 @@ impl AcpTools { let index = connection.messages.len(); let (request_id, method, message_type, params) = match stream_message.message { - acp::StreamMessageContent::Request { id, method, params } => { + StreamMessageContent::Request { id, method, params } => { let method_map = match stream_message.direction { - acp::StreamMessageDirection::Incoming => { - &mut connection.incoming_request_methods - } - acp::StreamMessageDirection::Outgoing => { - &mut connection.outgoing_request_methods - } + StreamMessageDirection::Incoming => &mut connection.incoming_request_methods, + StreamMessageDirection::Outgoing => &mut connection.outgoing_request_methods, }; method_map.insert(id.clone(), method.clone()); (Some(id), method.into(), MessageType::Request, Ok(params)) } - acp::StreamMessageContent::Response { id, result } => { + StreamMessageContent::Response { id, result } => { let method_map = match stream_message.direction { - acp::StreamMessageDirection::Incoming => { - &mut connection.outgoing_request_methods - } - acp::StreamMessageDirection::Outgoing => { - &mut connection.incoming_request_methods - } + StreamMessageDirection::Incoming => &mut connection.outgoing_request_methods, + StreamMessageDirection::Outgoing => &mut connection.incoming_request_methods, }; if let Some(method) = method_map.remove(&id) { @@ -197,7 +197,7 @@ impl AcpTools { ) } } - acp::StreamMessageContent::Notification { method, params } => { + StreamMessageContent::Notification { method, params } => { (None, method.into(), MessageType::Notification, Ok(params)) } }; @@ -243,8 +243,8 @@ impl AcpTools { }; Some(serde_json::json!({ "_direction": match message.direction { - acp::StreamMessageDirection::Incoming => "incoming", - acp::StreamMessageDirection::Outgoing => "outgoing", + StreamMessageDirection::Incoming => "incoming", + StreamMessageDirection::Outgoing => "outgoing", }, "_type": message.message_type.to_string().to_lowercase(), "id": message.request_id, @@ -326,10 +326,10 @@ impl AcpTools { cx.notify() })) .child(match message.direction { - acp::StreamMessageDirection::Incoming => Icon::new(IconName::ArrowDown) + StreamMessageDirection::Incoming => Icon::new(IconName::ArrowDown) .color(Color::Error) .size(IconSize::Small), - acp::StreamMessageDirection::Outgoing => Icon::new(IconName::ArrowUp) + StreamMessageDirection::Outgoing => Icon::new(IconName::ArrowUp) .color(Color::Success) .size(IconSize::Small), }) @@ -402,8 +402,8 @@ impl AcpTools { struct WatchedConnectionMessage { name: SharedString, - request_id: Option, - direction: acp::StreamMessageDirection, + request_id: Option, + direction: StreamMessageDirection, message_type: MessageType, params: Result, acp::Error>, collapsed_params_md: Option>, @@ -427,6 +427,7 @@ impl WatchedConnectionMessage { } } +#[allow(dead_code)] fn collapsed_params_md( params: &serde_json::Value, language_registry: &Arc, @@ -459,6 +460,7 @@ fn expanded_params_md( cx.new(|cx| Markdown::new(params_md.into(), Some(language_registry.clone()), None, cx)) } +#[allow(dead_code)] enum MessageType { Request, Response, diff --git a/crates/agent/Cargo.toml b/crates/agent/Cargo.toml index a5a4c2742a444bf2e8b0a12b0bb233c6e51684f2..84e72c089628c3fa0ec3be1b4d2a824f58f8148b 100644 --- a/crates/agent/Cargo.toml +++ b/crates/agent/Cargo.toml @@ -19,7 +19,7 @@ workspace = true [dependencies] acp_thread.workspace = true action_log.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true agent_servers.workspace = true agent_settings.workspace = true anyhow.workspace = true diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index b7aa9d1e311016f572928993e049798c2b5e3bb2..5d87f88e8ab4bdc1167f66a7a5cbe89dc1550606 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -28,7 +28,7 @@ use acp_thread::{ AcpThread, AgentModelSelector, AgentSessionInfo, AgentSessionList, AgentSessionListRequest, AgentSessionListResponse, TokenUsageRatio, UserMessageId, }; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Context as _, Result, anyhow}; use chrono::{DateTime, Utc}; use collections::{HashMap, HashSet, IndexMap}; diff --git a/crates/agent/src/db.rs b/crates/agent/src/db.rs index bde07a040869bf11a1b95bf433bf6af1e2d0a932..e8b0383addf09f293d05b79d5e72f48a58546961 100644 --- a/crates/agent/src/db.rs +++ b/crates/agent/src/db.rs @@ -1,6 +1,6 @@ use crate::{AgentMessage, AgentMessageContent, UserMessage, UserMessageContent}; use acp_thread::UserMessageId; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentProfileId; use anyhow::{Result, anyhow}; use chrono::{DateTime, Utc}; diff --git a/crates/agent/src/native_agent_server.rs b/crates/agent/src/native_agent_server.rs index 7f19f9005e3ff54e361f57075b7af06508476564..a9b89fc518ddaa857713e24dfe6a59e732d3d2e3 100644 --- a/crates/agent/src/native_agent_server.rs +++ b/crates/agent/src/native_agent_server.rs @@ -1,6 +1,6 @@ use std::{any::Any, rc::Rc, sync::Arc}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_servers::{AgentServer, AgentServerDelegate}; use agent_settings::AgentSettings; use anyhow::Result; diff --git a/crates/agent/src/tests/mod.rs b/crates/agent/src/tests/mod.rs index 036a6f1030c43b16d51f864a1d0176891e90b772..54f3d5a5b0ae55fda9f0bdc0587d556c2c193710 100644 --- a/crates/agent/src/tests/mod.rs +++ b/crates/agent/src/tests/mod.rs @@ -3,7 +3,7 @@ use acp_thread::{ AgentConnection, AgentModelGroupName, AgentModelList, PermissionOptions, ThreadStatus, UserMessageId, }; -use agent_client_protocol::{self as acp}; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentProfileId; use anyhow::Result; use client::{Client, UserStore}; @@ -5228,7 +5228,7 @@ async fn test_max_subagent_depth_prevents_tool_registration(cx: &mut TestAppCont cx, ); thread.set_subagent_context(SubagentContext { - parent_thread_id: agent_client_protocol::SessionId::new("parent-id"), + parent_thread_id: acp::SessionId::new("parent-id"), depth: MAX_SUBAGENT_DEPTH - 1, }); thread diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index b61df1b8af84d312d7f186fb85e5a1d04ab59dfd..1d11372accc0902044a5dfea4c94db54fda3049c 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -12,7 +12,7 @@ use feature_flags::{ FeatureFlagAppExt as _, StreamingEditFileToolFeatureFlag, UpdatePlanToolFeatureFlag, }; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::{ AgentProfileId, AgentSettings, SUMMARIZE_THREAD_DETAILED_PROMPT, SUMMARIZE_THREAD_PROMPT, }; @@ -3341,7 +3341,7 @@ where T::description() } - fn kind(&self) -> agent_client_protocol::ToolKind { + fn kind(&self) -> agent_client_protocol_core::schema::ToolKind { T::kind() } diff --git a/crates/agent/src/thread_store.rs b/crates/agent/src/thread_store.rs index e62ff78871c65311627aab8f6a6e3c00481a0c2b..a4aac074c48ca1fb29c7dfaf86f119c68613534d 100644 --- a/crates/agent/src/thread_store.rs +++ b/crates/agent/src/thread_store.rs @@ -1,5 +1,5 @@ use crate::{DbThread, DbThreadMetadata, ThreadsDatabase}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Result, anyhow}; use gpui::{App, Context, Entity, Global, Task, prelude::*}; use util::path_list::PathList; diff --git a/crates/agent/src/tools/context_server_registry.rs b/crates/agent/src/tools/context_server_registry.rs index df4cc313036b55e8842a9c46567256afb92ed944..b4d65189c0a6c2f30e8d522e35ff807b14d5c1d4 100644 --- a/crates/agent/src/tools/context_server_registry.rs +++ b/crates/agent/src/tools/context_server_registry.rs @@ -1,5 +1,5 @@ use crate::{AgentToolOutput, AnyAgentTool, ToolCallEventStream, ToolInput}; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use anyhow::Result; use collections::{BTreeMap, HashMap}; use context_server::{ContextServerId, client::NotificationSubscription}; diff --git a/crates/agent/src/tools/copy_path_tool.rs b/crates/agent/src/tools/copy_path_tool.rs index 95688f27dcd8ca04aef72358ce52144f95138e17..5e9d72b43fcd1cf8a325a9f959eedf21adfd73a9 100644 --- a/crates/agent/src/tools/copy_path_tool.rs +++ b/crates/agent/src/tools/copy_path_tool.rs @@ -5,7 +5,7 @@ use super::tool_permissions::{ use crate::{ AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_for_paths, }; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use agent_settings::AgentSettings; use futures::FutureExt as _; use gpui::{App, Entity, Task}; @@ -198,7 +198,7 @@ impl AgentTool for CopyPathTool { #[cfg(test)] mod tests { use super::*; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use fs::Fs as _; use gpui::TestAppContext; use project::{FakeFs, Project}; diff --git a/crates/agent/src/tools/create_directory_tool.rs b/crates/agent/src/tools/create_directory_tool.rs index d6c59bcce30ab26991edba0fa7181ec45d10e1b0..eb918dabeb4bcbcd70afb7bd6c4ba666ddbcc0aa 100644 --- a/crates/agent/src/tools/create_directory_tool.rs +++ b/crates/agent/src/tools/create_directory_tool.rs @@ -2,7 +2,7 @@ use super::tool_permissions::{ SensitiveSettingsKind, authorize_symlink_access, canonicalize_worktree_roots, detect_symlink_escape, sensitive_settings_kind, }; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use agent_settings::AgentSettings; use futures::FutureExt as _; use gpui::{App, Entity, SharedString, Task}; @@ -169,7 +169,7 @@ impl AgentTool for CreateDirectoryTool { #[cfg(test)] mod tests { use super::*; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use fs::Fs as _; use gpui::TestAppContext; use project::{FakeFs, Project}; diff --git a/crates/agent/src/tools/delete_path_tool.rs b/crates/agent/src/tools/delete_path_tool.rs index 7433975c7b782a145dd3e5a80ee59cd92945a989..59a2c67cce716442299f9d5f3cb37befc6af9218 100644 --- a/crates/agent/src/tools/delete_path_tool.rs +++ b/crates/agent/src/tools/delete_path_tool.rs @@ -6,7 +6,7 @@ use crate::{ AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_for_path, }; use action_log::ActionLog; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use agent_settings::AgentSettings; use futures::{FutureExt as _, SinkExt, StreamExt, channel::mpsc}; use gpui::{App, AppContext, Entity, SharedString, Task}; @@ -228,7 +228,7 @@ impl AgentTool for DeletePathTool { #[cfg(test)] mod tests { use super::*; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use fs::Fs as _; use gpui::TestAppContext; use project::{FakeFs, Project}; diff --git a/crates/agent/src/tools/diagnostics_tool.rs b/crates/agent/src/tools/diagnostics_tool.rs index 5889f66c2edbe06055678b19474447e0f23e2b0f..7f995e3f2f18d9013ae2373a2689be460243d4b4 100644 --- a/crates/agent/src/tools/diagnostics_tool.rs +++ b/crates/agent/src/tools/diagnostics_tool.rs @@ -1,5 +1,5 @@ use crate::{AgentTool, ToolCallEventStream, ToolInput}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::Result; use futures::FutureExt as _; use gpui::{App, Entity, Task}; diff --git a/crates/agent/src/tools/edit_file_tool.rs b/crates/agent/src/tools/edit_file_tool.rs index 763efd6724a719b90af93843f203ef8c1c3976bb..f3b67cad2b993ce2518a1c285555beffebd80076 100644 --- a/crates/agent/src/tools/edit_file_tool.rs +++ b/crates/agent/src/tools/edit_file_tool.rs @@ -6,7 +6,7 @@ use crate::{ edit_agent::{EditAgent, EditAgentOutputEvent, EditFormat}, }; use acp_thread::Diff; -use agent_client_protocol::{self as acp, ToolCallLocation, ToolCallUpdateFields}; +use agent_client_protocol_core::schema::{self as acp, ToolCallLocation, ToolCallUpdateFields}; use anyhow::{Context as _, Result}; use collections::HashSet; use futures::{FutureExt as _, StreamExt as _}; diff --git a/crates/agent/src/tools/fetch_tool.rs b/crates/agent/src/tools/fetch_tool.rs index 75880801595ad0604c9f3a1fac58bd916809a8ba..9fbd538ebaa4e28f77a10c6182043089d71fc5bd 100644 --- a/crates/agent/src/tools/fetch_tool.rs +++ b/crates/agent/src/tools/fetch_tool.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use std::sync::Arc; use std::{borrow::Cow, cell::RefCell}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use anyhow::{Context as _, Result, bail}; use futures::{AsyncReadExt as _, FutureExt as _}; diff --git a/crates/agent/src/tools/find_path_tool.rs b/crates/agent/src/tools/find_path_tool.rs index 9c65461503225171bcda482d58871a94743481e3..8afc9dab09e9d40d6d801a7a19e5f3a444cb490c 100644 --- a/crates/agent/src/tools/find_path_tool.rs +++ b/crates/agent/src/tools/find_path_tool.rs @@ -1,5 +1,5 @@ use crate::{AgentTool, ToolCallEventStream, ToolInput}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Result, anyhow}; use futures::FutureExt as _; use gpui::{App, AppContext, Entity, SharedString, Task}; diff --git a/crates/agent/src/tools/grep_tool.rs b/crates/agent/src/tools/grep_tool.rs index fbfdc18585b822361effb6fd770e678b3e434a17..050e67e8241febf7caf6fb26081b60714f666c02 100644 --- a/crates/agent/src/tools/grep_tool.rs +++ b/crates/agent/src/tools/grep_tool.rs @@ -1,5 +1,5 @@ use crate::{AgentTool, ToolCallEventStream, ToolInput}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::Result; use futures::{FutureExt as _, StreamExt}; use gpui::{App, Entity, SharedString, Task}; diff --git a/crates/agent/src/tools/list_directory_tool.rs b/crates/agent/src/tools/list_directory_tool.rs index 7abbe1ed4c488210b9079e59765dddc8d5208bed..218412fe11115213fe6cb2052acd9d4c5e35b46d 100644 --- a/crates/agent/src/tools/list_directory_tool.rs +++ b/crates/agent/src/tools/list_directory_tool.rs @@ -3,7 +3,7 @@ use super::tool_permissions::{ resolve_project_path, }; use crate::{AgentTool, ToolCallEventStream, ToolInput}; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use anyhow::{Context as _, Result, anyhow}; use gpui::{App, Entity, SharedString, Task}; use project::{Project, ProjectPath, WorktreeSettings}; @@ -267,7 +267,7 @@ impl AgentTool for ListDirectoryTool { #[cfg(test)] mod tests { use super::*; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use fs::Fs as _; use gpui::{TestAppContext, UpdateGlobal}; use indoc::indoc; diff --git a/crates/agent/src/tools/move_path_tool.rs b/crates/agent/src/tools/move_path_tool.rs index 147947bb67ec646c38b51f37dd75779ed78ec85b..d88e529081e805cc9cfefde6c5d7cf879b2ab13c 100644 --- a/crates/agent/src/tools/move_path_tool.rs +++ b/crates/agent/src/tools/move_path_tool.rs @@ -5,7 +5,7 @@ use super::tool_permissions::{ use crate::{ AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_for_paths, }; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use agent_settings::AgentSettings; use futures::FutureExt as _; use gpui::{App, Entity, SharedString, Task}; @@ -205,7 +205,7 @@ impl AgentTool for MovePathTool { #[cfg(test)] mod tests { use super::*; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use fs::Fs as _; use gpui::TestAppContext; use project::{FakeFs, Project}; diff --git a/crates/agent/src/tools/now_tool.rs b/crates/agent/src/tools/now_tool.rs index fe1cafe5881d14c9700813f742e1f2df0aa1203e..1deeb6861802b8f96903eac5700a53a03d2b5dc4 100644 --- a/crates/agent/src/tools/now_tool.rs +++ b/crates/agent/src/tools/now_tool.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use chrono::{Local, Utc}; use gpui::{App, SharedString, Task}; use schemars::JsonSchema; diff --git a/crates/agent/src/tools/open_tool.rs b/crates/agent/src/tools/open_tool.rs index 344a513d10c2d62e4247dd3e47bcdf428586d6f0..bae306c75898ac927360af7b9c50b214a025cdc5 100644 --- a/crates/agent/src/tools/open_tool.rs +++ b/crates/agent/src/tools/open_tool.rs @@ -3,7 +3,7 @@ use super::tool_permissions::{ resolve_project_path, }; use crate::{AgentTool, ToolInput}; -use agent_client_protocol::ToolKind; +use agent_client_protocol_core::schema::ToolKind; use futures::FutureExt as _; use gpui::{App, AppContext as _, Entity, SharedString, Task}; use project::Project; diff --git a/crates/agent/src/tools/read_file_tool.rs b/crates/agent/src/tools/read_file_tool.rs index 093a8580892cfc4cec0a061bcc10717b28c608f2..96a44c443b63ebded8370b0ddeabb3257c8ab84c 100644 --- a/crates/agent/src/tools/read_file_tool.rs +++ b/crates/agent/src/tools/read_file_tool.rs @@ -1,5 +1,5 @@ use action_log::ActionLog; -use agent_client_protocol::{self as acp, ToolCallUpdateFields}; +use agent_client_protocol_core::schema::{self as acp, ToolCallUpdateFields}; use anyhow::{Context as _, Result, anyhow}; use futures::FutureExt as _; use gpui::{App, Entity, SharedString, Task}; @@ -347,7 +347,7 @@ impl AgentTool for ReadFileTool { #[cfg(test)] mod test { use super::*; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use fs::Fs as _; use gpui::{AppContext, TestAppContext, UpdateGlobal as _}; use project::{FakeFs, Project}; diff --git a/crates/agent/src/tools/restore_file_from_disk_tool.rs b/crates/agent/src/tools/restore_file_from_disk_tool.rs index 9273ea5b8bb041e0ea53f3ea72b94b46e5a7e294..1c9f398029eb5b8202fe2ad17a02a343f2324ca3 100644 --- a/crates/agent/src/tools/restore_file_from_disk_tool.rs +++ b/crates/agent/src/tools/restore_file_from_disk_tool.rs @@ -3,7 +3,7 @@ use super::tool_permissions::{ canonicalize_worktree_roots, path_has_symlink_escape, resolve_project_path, sensitive_settings_kind, }; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use collections::FxHashSet; use futures::FutureExt as _; diff --git a/crates/agent/src/tools/save_file_tool.rs b/crates/agent/src/tools/save_file_tool.rs index c6a1cd79db65127164fe66f966029b58a366da7f..833f74e02fd4486467094150583fe41379c0f79c 100644 --- a/crates/agent/src/tools/save_file_tool.rs +++ b/crates/agent/src/tools/save_file_tool.rs @@ -1,4 +1,4 @@ -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use collections::FxHashSet; use futures::FutureExt as _; diff --git a/crates/agent/src/tools/spawn_agent_tool.rs b/crates/agent/src/tools/spawn_agent_tool.rs index 27afbbdc3ea05ddbfea689d1bb1a18c53b42198b..0639e2fa11b4de1591e2c7e3813401a37008096e 100644 --- a/crates/agent/src/tools/spawn_agent_tool.rs +++ b/crates/agent/src/tools/spawn_agent_tool.rs @@ -1,5 +1,5 @@ use acp_thread::{SUBAGENT_SESSION_INFO_META_KEY, SubagentSessionInfo}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::Result; use gpui::{App, SharedString, Task}; use language_model::LanguageModelToolResultContent; diff --git a/crates/agent/src/tools/streaming_edit_file_tool.rs b/crates/agent/src/tools/streaming_edit_file_tool.rs index c0c29bfc43d9c58ac011b3170edf81210ba8ee66..c185295d713ddd1dd4a6fd32204c2a3f031ce8cb 100644 --- a/crates/agent/src/tools/streaming_edit_file_tool.rs +++ b/crates/agent/src/tools/streaming_edit_file_tool.rs @@ -11,7 +11,7 @@ use crate::{ }; use acp_thread::Diff; use action_log::ActionLog; -use agent_client_protocol::{self as acp, ToolCallLocation, ToolCallUpdateFields}; +use agent_client_protocol_core::schema::{self as acp, ToolCallLocation, ToolCallUpdateFields}; use anyhow::{Context as _, Result}; use collections::HashSet; use futures::FutureExt as _; diff --git a/crates/agent/src/tools/terminal_tool.rs b/crates/agent/src/tools/terminal_tool.rs index 82bf9a06480bb7d6db3611516281f42452ec5137..b19323da2b6990407fcb26280de2ab98979080e9 100644 --- a/crates/agent/src/tools/terminal_tool.rs +++ b/crates/agent/src/tools/terminal_tool.rs @@ -1,4 +1,4 @@ -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use anyhow::Result; use futures::FutureExt as _; diff --git a/crates/agent/src/tools/update_plan_tool.rs b/crates/agent/src/tools/update_plan_tool.rs index 8d45f8aad42a8cb10b3164212e1cde2b0104bdc2..af18f6409d0b1951eb72384c7baf00fabfd2d231 100644 --- a/crates/agent/src/tools/update_plan_tool.rs +++ b/crates/agent/src/tools/update_plan_tool.rs @@ -1,5 +1,5 @@ use crate::{AgentTool, ToolCallEventStream, ToolInput}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use gpui::{App, SharedString, Task}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/crates/agent/src/tools/web_search_tool.rs b/crates/agent/src/tools/web_search_tool.rs index c697a5b78f1fe8c84d6ed58db13f651a493ae8c3..7d0a50a8c9c2d78b8a0fd982402590d06d3f4aea 100644 --- a/crates/agent/src/tools/web_search_tool.rs +++ b/crates/agent/src/tools/web_search_tool.rs @@ -4,7 +4,7 @@ use crate::{ AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_from_settings, }; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use anyhow::Result; use cloud_llm_client::WebSearchResponse; diff --git a/crates/agent_servers/Cargo.toml b/crates/agent_servers/Cargo.toml index 1542466be35bbce80983a73a3fc2e0998799160c..4caf08c7c0bb9d64b61a96e912f5e8a5fb010eca 100644 --- a/crates/agent_servers/Cargo.toml +++ b/crates/agent_servers/Cargo.toml @@ -20,7 +20,7 @@ doctest = false acp_tools.workspace = true acp_thread.workspace = true action_log.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true anyhow.workspace = true async-trait.workspace = true chrono.workspace = true diff --git a/crates/agent_servers/src/acp.rs b/crates/agent_servers/src/acp.rs index 5f452bc9c0e2e9c2322042583295894a5866b053..2ef69c0fb0f3ab2262142aeb603e259c714f12a1 100644 --- a/crates/agent_servers/src/acp.rs +++ b/crates/agent_servers/src/acp.rs @@ -2,14 +2,15 @@ use acp_thread::{ AgentConnection, AgentSessionInfo, AgentSessionList, AgentSessionListRequest, AgentSessionListResponse, }; -use acp_tools::AcpConnectionRegistry; use action_log::ActionLog; -use agent_client_protocol::{self as acp, Agent as _, ErrorCode}; +use agent_client_protocol_core::schema::{self as acp, ErrorCode}; +use agent_client_protocol_core::{ByteStreams, ConnectionTo}; use anyhow::anyhow; use collections::HashMap; use feature_flags::{AcpBetaFeatureFlag, FeatureFlagAppExt as _}; -use futures::AsyncBufReadExt as _; +use futures::channel::mpsc; use futures::io::BufReader; +use futures::{AsyncBufReadExt as _, StreamExt as _}; use project::agent_server_store::AgentServerCommand; use project::{AgentId, Project}; use serde::Deserialize; @@ -40,10 +41,19 @@ pub const GEMINI_TERMINAL_AUTH_METHOD_ID: &str = "spawn-gemini-cli"; #[error("Unsupported version")] pub struct UnsupportedVersion; +/// Holds state needed by foreground work dispatched from background handler closures. +struct ClientContext { + sessions: Rc>>, + session_list: Rc>>>, +} + +/// Work items sent from `Send` handler closures to the `!Send` foreground thread. +type ForegroundWork = Box; + pub struct AcpConnection { id: AgentId, telemetry_id: SharedString, - connection: Rc, + connection: ConnectionTo, sessions: Rc>>, auth_methods: Vec, command: AgentServerCommand, @@ -53,7 +63,8 @@ pub struct AcpConnection { default_config_options: HashMap, child: Child, session_list: Option>, - _io_task: Task>, + _io_task: Task<()>, + _dispatch_task: Task<()>, _wait_task: Task>, _stderr_task: Task>, } @@ -84,13 +95,13 @@ pub struct AcpSession { } pub struct AcpSessionList { - connection: Rc, + connection: ConnectionTo, updates_tx: smol::channel::Sender, updates_rx: smol::channel::Receiver, } impl AcpSessionList { - fn new(connection: Rc) -> Self { + fn new(connection: ConnectionTo) -> Self { let (tx, rx) = smol::channel::unbounded(); Self { connection, @@ -123,7 +134,11 @@ impl AgentSessionList for AcpSessionList { let acp_request = acp::ListSessionsRequest::new() .cwd(request.cwd) .cursor(request.cursor); - let response = conn.list_sessions(acp_request).await?; + let response = conn + .send_request(acp_request) + .block_task() + .await + .map_err(map_acp_error)?; Ok(AgentSessionListResponse { sessions: response .sessions @@ -240,20 +255,225 @@ impl AcpConnection { let client_session_list: Rc>>> = Rc::new(RefCell::new(None)); - let client = ClientDelegate { + // Set up the foreground dispatch channel for bridging Send handler + // closures to the !Send foreground thread. + let (dispatch_tx, dispatch_rx) = mpsc::unbounded::(); + + // Build the transport from child stdio + let transport = ByteStreams::new(stdin, stdout); + + // Use a oneshot channel to extract the ConnectionTo from the + // connect_with closure. + let (connection_tx, connection_rx) = futures::channel::oneshot::channel(); + + // Build the connection with handler closures. + // All handlers forward work to the foreground dispatch channel. + let connection_future = { + let dispatch_tx = dispatch_tx.clone(); + agent_client_protocol_core::Client + .builder() + .name("zed") + // --- Request handlers (agent→client) --- + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::RequestPermissionRequest, + responder: agent_client_protocol_core::Responder< + acp::RequestPermissionResponse, + >, + _connection: ConnectionTo< + agent_client_protocol_core::Agent, + >| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_request_permission(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::WriteTextFileRequest, + responder: agent_client_protocol_core::Responder< + acp::WriteTextFileResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_write_text_file(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::ReadTextFileRequest, + responder: agent_client_protocol_core::Responder< + acp::ReadTextFileResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_read_text_file(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::CreateTerminalRequest, + responder: agent_client_protocol_core::Responder< + acp::CreateTerminalResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_create_terminal(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::KillTerminalRequest, + responder: agent_client_protocol_core::Responder< + acp::KillTerminalResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_kill_terminal(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::ReleaseTerminalRequest, + responder: agent_client_protocol_core::Responder< + acp::ReleaseTerminalResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_release_terminal(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::TerminalOutputRequest, + responder: agent_client_protocol_core::Responder< + acp::TerminalOutputResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_terminal_output(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + .on_receive_request( + { + let dispatch_tx = dispatch_tx.clone(); + async move |args: acp::WaitForTerminalExitRequest, + responder: agent_client_protocol_core::Responder< + acp::WaitForTerminalExitResponse, + >, + _connection| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_wait_for_terminal_exit(args, responder, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_request!(), + ) + // --- Notification handlers (agent→client) --- + .on_receive_notification( + { + let dispatch_tx = dispatch_tx.clone(); + async move |notification: acp::SessionNotification, + _connection: ConnectionTo< + agent_client_protocol_core::Agent, + >| { + dispatch_tx + .unbounded_send(Box::new(move |cx, ctx| { + handle_session_notification(notification, cx, ctx); + })) + .ok(); + Ok(()) + } + }, + agent_client_protocol_core::on_receive_notification!(), + ) + .connect_with( + transport, + move |connection: ConnectionTo| async move { + connection_tx.send(connection.clone()).ok(); + // Keep the connection alive until the transport closes. + futures::future::pending::>().await + }, + ) + }; + + // Spawn the connection loop on a background thread. + let io_task = cx.background_spawn(async move { + if let Err(err) = connection_future.await { + log::error!("ACP connection error: {err}"); + } + }); + + // Wait for the ConnectionTo handle. + let connection: ConnectionTo = connection_rx + .await + .context("Failed to receive ACP connection handle")?; + + // Set up the foreground dispatch loop to process work items from handlers. + let dispatch_context = ClientContext { sessions: sessions.clone(), session_list: client_session_list.clone(), - cx: cx.clone(), }; - let (connection, io_task) = acp::ClientSideConnection::new(client, stdin, stdout, { - let foreground_executor = cx.foreground_executor().clone(); - move |fut| { - foreground_executor.spawn(fut).detach(); + let dispatch_task = cx.spawn({ + let mut dispatch_rx = dispatch_rx; + async move |cx| { + while let Some(work) = dispatch_rx.next().await { + work(cx, &dispatch_context); + } } }); - let io_task = cx.background_spawn(io_task); - let stderr_task = cx.background_spawn(async move { let mut stderr = BufReader::new(stderr); let mut line = String::new(); @@ -285,16 +505,16 @@ impl AcpConnection { } }); - let connection = Rc::new(connection); - - cx.update(|cx| { - AcpConnectionRegistry::default_global(cx).update(cx, |registry, cx| { - registry.set_active_connection(agent_id.clone(), &connection, cx) - }); - }); + // TODO: Update AcpConnectionRegistry to support ConnectionTo + // The old streaming/subscribe API is not available in agent-client-protocol-core. + // cx.update(|cx| { + // AcpConnectionRegistry::default_global(cx).update(cx, |registry, cx| { + // registry.set_active_connection(agent_id.clone(), &connection, cx) + // }); + // }); let response = connection - .initialize( + .send_request( acp::InitializeRequest::new(acp::ProtocolVersion::V1) .client_capabilities( acp::ClientCapabilities::new() @@ -303,7 +523,6 @@ impl AcpConnection { .write_text_file(true)) .terminal(true) .auth(acp::AuthCapabilities::new().terminal(true)) - // Experimental: Allow for rendering terminal output from the agents .meta(acp::Meta::from_iter([ ("terminal_output".into(), true.into()), ("terminal-auth".into(), true.into()), @@ -314,6 +533,7 @@ impl AcpConnection { .title(release_channel.map(ToOwned::to_owned)), ), ) + .block_task() .await?; if response.protocol_version < MINIMUM_SUPPORTED_VERSION { @@ -322,9 +542,7 @@ impl AcpConnection { let telemetry_id = response .agent_info - // Use the one the agent provides if we have one .map(|info| info.name.into()) - // Otherwise, just use the name .unwrap_or_else(|| agent_id.0.to_string().into()); let session_list = if response @@ -372,6 +590,7 @@ impl AcpConnection { default_config_options, session_list, _io_task: io_task, + _dispatch_task: dispatch_task, _wait_task: wait_task, _stderr_task: stderr_task, child, @@ -447,11 +666,12 @@ impl AcpConnection { let conn = self.connection.clone(); async move |_| { let result = conn - .set_session_config_option(acp::SetSessionConfigOptionRequest::new( + .send_request(acp::SetSessionConfigOptionRequest::new( session_id, config_id_clone.clone(), default_value_id, )) + .block_task() .await .log_err(); @@ -566,17 +786,25 @@ impl AgentConnection for AcpConnection { let mcp_servers = mcp_servers_for_project(&project, cx); cx.spawn(async move |cx| { - let response = self.connection - .new_session(acp::NewSessionRequest::new(cwd.clone()).mcp_servers(mcp_servers)) + let response = self + .connection + .send_request( + acp::NewSessionRequest::new(cwd.clone()).mcp_servers(mcp_servers), + ) + .block_task() .await .map_err(map_acp_error)?; - let (modes, models, config_options) = config_state(response.modes, response.models, response.config_options); + let (modes, models, config_options) = + config_state(response.modes, response.models, response.config_options); if let Some(default_mode) = self.default_mode.clone() { if let Some(modes) = modes.as_ref() { let mut modes_ref = modes.borrow_mut(); - let has_mode = modes_ref.available_modes.iter().any(|mode| mode.id == default_mode); + let has_mode = modes_ref + .available_modes + .iter() + .any(|mode| mode.id == default_mode); if has_mode { let initial_mode_id = modes_ref.current_mode_id.clone(); @@ -587,14 +815,21 @@ impl AgentConnection for AcpConnection { let modes = modes.clone(); let conn = self.connection.clone(); async move |_| { - let result = conn.set_session_mode(acp::SetSessionModeRequest::new(session_id, default_mode)) - .await.log_err(); + let result = conn + .send_request(acp::SetSessionModeRequest::new( + session_id, + default_mode, + )) + .block_task() + .await + .log_err(); if result.is_none() { modes.borrow_mut().current_mode_id = initial_mode_id; } } - }).detach(); + }) + .detach(); modes_ref.current_mode_id = default_mode; } else { @@ -615,7 +850,10 @@ impl AgentConnection for AcpConnection { if let Some(default_model) = self.default_model.clone() { if let Some(models) = models.as_ref() { let mut models_ref = models.borrow_mut(); - let has_model = models_ref.available_models.iter().any(|model| model.model_id == default_model); + let has_model = models_ref + .available_models + .iter() + .any(|model| model.model_id == default_model); if has_model { let initial_model_id = models_ref.current_model_id.clone(); @@ -626,14 +864,21 @@ impl AgentConnection for AcpConnection { let models = models.clone(); let conn = self.connection.clone(); async move |_| { - let result = conn.set_session_model(acp::SetSessionModelRequest::new(session_id, default_model)) - .await.log_err(); + let result = conn + .send_request(acp::SetSessionModelRequest::new( + session_id, + default_model, + )) + .block_task() + .await + .log_err(); if result.is_none() { models.borrow_mut().current_model_id = initial_model_id; } } - }).detach(); + }) + .detach(); models_ref.current_model_id = default_model; } else { @@ -665,8 +910,9 @@ impl AgentConnection for AcpConnection { project, action_log, response.session_id.clone(), - // ACP doesn't currently support per-session prompt capabilities or changing capabilities dynamically. - watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()), + watch::Receiver::constant( + self.agent_capabilities.prompt_capabilities.clone(), + ), cx, ) }); @@ -745,9 +991,10 @@ impl AgentConnection for AcpConnection { cx.spawn(async move |cx| { let response = match self .connection - .load_session( + .send_request( acp::LoadSessionRequest::new(session_id.clone(), cwd).mcp_servers(mcp_servers), ) + .block_task() .await { Ok(response) => response, @@ -827,10 +1074,11 @@ impl AgentConnection for AcpConnection { cx.spawn(async move |cx| { let response = match self .connection - .resume_session( + .send_request( acp::ResumeSessionRequest::new(session_id.clone(), cwd) .mcp_servers(mcp_servers), ) + .block_task() .await { Ok(response) => response, @@ -875,7 +1123,8 @@ impl AgentConnection for AcpConnection { let conn = self.connection.clone(); let session_id = session_id.clone(); cx.foreground_executor().spawn(async move { - conn.close_session(acp::CloseSessionRequest::new(session_id.clone())) + conn.send_request(acp::CloseSessionRequest::new(session_id.clone())) + .block_task() .await?; self.sessions.borrow_mut().remove(&session_id); Ok(()) @@ -907,7 +1156,8 @@ impl AgentConnection for AcpConnection { fn authenticate(&self, method_id: acp::AuthMethodId, cx: &mut App) -> Task> { let conn = self.connection.clone(); cx.foreground_executor().spawn(async move { - conn.authenticate(acp::AuthenticateRequest::new(method_id)) + conn.send_request(acp::AuthenticateRequest::new(method_id)) + .block_task() .await?; Ok(()) }) @@ -923,7 +1173,7 @@ impl AgentConnection for AcpConnection { let sessions = self.sessions.clone(); let session_id = params.session_id.clone(); cx.foreground_executor().spawn(async move { - let result = conn.prompt(params).await; + let result = conn.send_request(params).block_task().await; let mut suppress_abort_err = false; @@ -974,15 +1224,12 @@ impl AgentConnection for AcpConnection { }) } - fn cancel(&self, session_id: &acp::SessionId, cx: &mut App) { + fn cancel(&self, session_id: &acp::SessionId, _cx: &mut App) { if let Some(session) = self.sessions.borrow_mut().get_mut(session_id) { session.suppress_abort_err = true; } - let conn = self.connection.clone(); let params = acp::CancelNotification::new(session_id.clone()); - cx.foreground_executor() - .spawn(async move { conn.cancel(params).await }) - .detach(); + self.connection.send_notification(params).log_err(); } fn session_modes( @@ -1280,7 +1527,7 @@ fn config_state( struct AcpSessionModes { session_id: acp::SessionId, - connection: Rc, + connection: ConnectionTo, state: Rc>, } @@ -1305,7 +1552,8 @@ impl acp_thread::AgentSessionModes for AcpSessionModes { let state = self.state.clone(); cx.foreground_executor().spawn(async move { let result = connection - .set_session_mode(acp::SetSessionModeRequest::new(session_id, mode_id)) + .send_request(acp::SetSessionModeRequest::new(session_id, mode_id)) + .block_task() .await; if result.is_err() { @@ -1321,14 +1569,14 @@ impl acp_thread::AgentSessionModes for AcpSessionModes { struct AcpModelSelector { session_id: acp::SessionId, - connection: Rc, + connection: ConnectionTo, state: Rc>, } impl AcpModelSelector { fn new( session_id: acp::SessionId, - connection: Rc, + connection: ConnectionTo, state: Rc>, ) -> Self { Self { @@ -1364,7 +1612,8 @@ impl acp_thread::AgentModelSelector for AcpModelSelector { let state = self.state.clone(); cx.foreground_executor().spawn(async move { let result = connection - .set_session_model(acp::SetSessionModelRequest::new(session_id, model_id)) + .send_request(acp::SetSessionModelRequest::new(session_id, model_id)) + .block_task() .await; if result.is_err() { @@ -1393,7 +1642,7 @@ impl acp_thread::AgentModelSelector for AcpModelSelector { struct AcpSessionConfigOptions { session_id: acp::SessionId, - connection: Rc, + connection: ConnectionTo, state: Rc>>, watch_tx: Rc>>, watch_rx: watch::Receiver<()>, @@ -1418,9 +1667,10 @@ impl acp_thread::AgentSessionConfigOptions for AcpSessionConfigOptions { cx.foreground_executor().spawn(async move { let response = connection - .set_session_config_option(acp::SetSessionConfigOptionRequest::new( + .send_request(acp::SetSessionConfigOptionRequest::new( session_id, config_id, value, )) + .block_task() .await?; *state.borrow_mut() = response.config_options.clone(); @@ -1434,312 +1684,457 @@ impl acp_thread::AgentSessionConfigOptions for AcpSessionConfigOptions { } } -struct ClientDelegate { - sessions: Rc>>, - session_list: Rc>>>, - cx: AsyncApp, +// --------------------------------------------------------------------------- +// Handler functions dispatched from background handler closures to the +// foreground thread via the ForegroundWork channel. +// --------------------------------------------------------------------------- + +fn session_thread( + ctx: &ClientContext, + session_id: &acp::SessionId, +) -> Result, acp::Error> { + let sessions = ctx.sessions.borrow(); + sessions + .get(session_id) + .map(|session| session.thread.clone()) + .ok_or_else(|| acp::Error::internal_error().data(format!("unknown session: {session_id}"))) } -#[async_trait::async_trait(?Send)] -impl acp::Client for ClientDelegate { - async fn request_permission( - &self, - arguments: acp::RequestPermissionRequest, - ) -> Result { - let thread; - { - let sessions_ref = self.sessions.borrow(); - let session = sessions_ref - .get(&arguments.session_id) - .context("Failed to get session")?; - thread = session.thread.clone(); - } - - let cx = &mut self.cx.clone(); - - let task = thread.update(cx, |thread, cx| { - thread.request_tool_call_authorization( - arguments.tool_call, - acp_thread::PermissionOptions::Flat(arguments.options), - cx, - ) - })??; - - let outcome = task.await; +fn respond_err( + responder: agent_client_protocol_core::Responder, + err: acp::Error, +) { + responder.respond_with_error(err).log_err(); +} - Ok(acp::RequestPermissionResponse::new(outcome.into())) - } +fn handle_request_permission( + args: acp::RequestPermissionRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + cx.spawn(async move |cx| { + let result: Result<_, acp::Error> = async { + let task = thread + .update(cx, |thread, cx| { + thread.request_tool_call_authorization( + args.tool_call, + acp_thread::PermissionOptions::Flat(args.options), + cx, + ) + }) + .map_err(acp::Error::from)? + .map_err(acp::Error::from)?; + Ok(task.await) + } + .await; - async fn write_text_file( - &self, - arguments: acp::WriteTextFileRequest, - ) -> Result { - let cx = &mut self.cx.clone(); - let task = self - .session_thread(&arguments.session_id)? - .update(cx, |thread, cx| { - thread.write_text_file(arguments.path, arguments.content, cx) - })?; - - task.await?; - - Ok(Default::default()) - } + match result { + Ok(outcome) => { + responder + .respond(acp::RequestPermissionResponse::new(outcome.into())) + .log_err(); + } + Err(e) => respond_err(responder, e), + } + }) + .detach(); +} - async fn read_text_file( - &self, - arguments: acp::ReadTextFileRequest, - ) -> Result { - let task = self.session_thread(&arguments.session_id)?.update( - &mut self.cx.clone(), - |thread, cx| { - thread.read_text_file(arguments.path, arguments.line, arguments.limit, false, cx) - }, - )?; +fn handle_write_text_file( + args: acp::WriteTextFileRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + cx.spawn(async move |cx| { + let result: Result<_, acp::Error> = async { + let task = thread + .update(cx, |thread, cx| { + thread.write_text_file(args.path, args.content, cx) + }) + .map_err(acp::Error::from)?; + task.await.map_err(acp::Error::from)?; + Ok(()) + } + .await; - let content = task.await?; + match result { + Ok(()) => { + responder + .respond(acp::WriteTextFileResponse::default()) + .log_err(); + } + Err(e) => respond_err(responder, e), + } + }) + .detach(); +} - Ok(acp::ReadTextFileResponse::new(content)) - } +fn handle_read_text_file( + args: acp::ReadTextFileRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + cx.spawn(async move |cx| { + let result: Result<_, acp::Error> = async { + thread + .update(cx, |thread, cx| { + thread.read_text_file(args.path, args.line, args.limit, false, cx) + }) + .map_err(acp::Error::from)? + .await + } + .await; - async fn session_notification( - &self, - notification: acp::SessionNotification, - ) -> Result<(), acp::Error> { - let sessions = self.sessions.borrow(); - let session = sessions - .get(¬ification.session_id) - .context("Failed to get session")?; - - if let acp::SessionUpdate::CurrentModeUpdate(acp::CurrentModeUpdate { - current_mode_id, - .. - }) = ¬ification.update - { - if let Some(session_modes) = &session.session_modes { - session_modes.borrow_mut().current_mode_id = current_mode_id.clone(); + match result { + Ok(content) => { + responder + .respond(acp::ReadTextFileResponse::new(content)) + .log_err(); } + Err(e) => respond_err(responder, e), } + }) + .detach(); +} - if let acp::SessionUpdate::ConfigOptionUpdate(acp::ConfigOptionUpdate { - config_options, - .. - }) = ¬ification.update - { - if let Some(opts) = &session.config_options { - *opts.config_options.borrow_mut() = config_options.clone(); - opts.tx.borrow_mut().send(()).ok(); - } +fn handle_session_notification( + notification: acp::SessionNotification, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let sessions = ctx.sessions.borrow(); + let Some(session) = sessions.get(¬ification.session_id) else { + log::warn!( + "Received session notification for unknown session: {:?}", + notification.session_id + ); + return; + }; + + if let acp::SessionUpdate::CurrentModeUpdate(acp::CurrentModeUpdate { + current_mode_id, .. + }) = ¬ification.update + { + if let Some(session_modes) = &session.session_modes { + session_modes.borrow_mut().current_mode_id = current_mode_id.clone(); } + } - if let acp::SessionUpdate::SessionInfoUpdate(info_update) = ¬ification.update - && let Some(session_list) = self.session_list.borrow().as_ref() - { - session_list.send_info_update(notification.session_id.clone(), info_update.clone()); + if let acp::SessionUpdate::ConfigOptionUpdate(acp::ConfigOptionUpdate { + config_options, .. + }) = ¬ification.update + { + if let Some(opts) = &session.config_options { + *opts.config_options.borrow_mut() = config_options.clone(); + opts.tx.borrow_mut().send(()).ok(); } + } - // Clone so we can inspect meta both before and after handing off to the thread - let update_clone = notification.update.clone(); + if let acp::SessionUpdate::SessionInfoUpdate(info_update) = ¬ification.update + && let Some(session_list) = ctx.session_list.borrow().as_ref() + { + session_list.send_info_update(notification.session_id.clone(), info_update.clone()); + } - // Pre-handle: if a ToolCall carries terminal_info, create/register a display-only terminal. - if let acp::SessionUpdate::ToolCall(tc) = &update_clone { - if let Some(meta) = &tc.meta { - if let Some(terminal_info) = meta.get("terminal_info") { - if let Some(id_str) = terminal_info.get("terminal_id").and_then(|v| v.as_str()) - { - let terminal_id = acp::TerminalId::new(id_str); - let cwd = terminal_info - .get("cwd") - .and_then(|v| v.as_str().map(PathBuf::from)); - - // Create a minimal display-only lower-level terminal and register it. - let _ = session.thread.update(&mut self.cx.clone(), |thread, cx| { - let builder = TerminalBuilder::new_display_only( - CursorShape::default(), - AlternateScroll::On, - None, - 0, - cx.background_executor(), - thread.project().read(cx).path_style(cx), - )?; - let lower = cx.new(|cx| builder.subscribe(cx)); - thread.on_terminal_provider_event( - TerminalProviderEvent::Created { - terminal_id, - label: tc.title.clone(), - cwd, - output_byte_limit: None, - terminal: lower, - }, - cx, - ); - anyhow::Ok(()) - }); - } + let update_clone = notification.update.clone(); + let thread = session.thread.clone(); + + // Pre-handle: if a ToolCall carries terminal_info, create/register a display-only terminal. + if let acp::SessionUpdate::ToolCall(tc) = &update_clone { + if let Some(meta) = &tc.meta { + if let Some(terminal_info) = meta.get("terminal_info") { + if let Some(id_str) = terminal_info.get("terminal_id").and_then(|v| v.as_str()) { + let terminal_id = acp::TerminalId::new(id_str); + let cwd = terminal_info + .get("cwd") + .and_then(|v| v.as_str().map(PathBuf::from)); + + let _ = thread.update(cx, |thread, cx| { + let builder = TerminalBuilder::new_display_only( + CursorShape::default(), + AlternateScroll::On, + None, + 0, + cx.background_executor(), + thread.project().read(cx).path_style(cx), + )?; + let lower = cx.new(|cx| builder.subscribe(cx)); + thread.on_terminal_provider_event( + TerminalProviderEvent::Created { + terminal_id, + label: tc.title.clone(), + cwd, + output_byte_limit: None, + terminal: lower, + }, + cx, + ); + anyhow::Ok(()) + }); } } } + } - // Forward the update to the acp_thread as usual. - session.thread.update(&mut self.cx.clone(), |thread, cx| { - thread.handle_session_update(notification.update.clone(), cx) - })??; - - // Post-handle: stream terminal output/exit if present on ToolCallUpdate meta. - if let acp::SessionUpdate::ToolCallUpdate(tcu) = &update_clone { - if let Some(meta) = &tcu.meta { - if let Some(term_out) = meta.get("terminal_output") { - if let Some(id_str) = term_out.get("terminal_id").and_then(|v| v.as_str()) { - let terminal_id = acp::TerminalId::new(id_str); - if let Some(s) = term_out.get("data").and_then(|v| v.as_str()) { - let data = s.as_bytes().to_vec(); - let _ = session.thread.update(&mut self.cx.clone(), |thread, cx| { - thread.on_terminal_provider_event( - TerminalProviderEvent::Output { terminal_id, data }, - cx, - ); - }); - } - } - } + // Drop sessions borrow before updating the thread, which may re-borrow. + drop(sessions); - // terminal_exit - if let Some(term_exit) = meta.get("terminal_exit") { - if let Some(id_str) = term_exit.get("terminal_id").and_then(|v| v.as_str()) { - let terminal_id = acp::TerminalId::new(id_str); - let status = acp::TerminalExitStatus::new() - .exit_code( - term_exit - .get("exit_code") - .and_then(|v| v.as_u64()) - .map(|i| i as u32), - ) - .signal( - term_exit - .get("signal") - .and_then(|v| v.as_str().map(|s| s.to_string())), - ); + // Forward the update to the acp_thread as usual. + if let Err(err) = thread + .update(cx, |thread, cx| { + thread.handle_session_update(notification.update.clone(), cx) + }) + .and_then(|inner| inner.map_err(anyhow::Error::from)) + { + log::error!( + "Failed to handle session update for {:?}: {err:?}", + notification.session_id + ); + } - let _ = session.thread.update(&mut self.cx.clone(), |thread, cx| { + // Post-handle: stream terminal output/exit if present on ToolCallUpdate meta. + if let acp::SessionUpdate::ToolCallUpdate(tcu) = &update_clone { + if let Some(meta) = &tcu.meta { + if let Some(term_out) = meta.get("terminal_output") { + if let Some(id_str) = term_out.get("terminal_id").and_then(|v| v.as_str()) { + let terminal_id = acp::TerminalId::new(id_str); + if let Some(s) = term_out.get("data").and_then(|v| v.as_str()) { + let data = s.as_bytes().to_vec(); + let _ = thread.update(cx, |thread, cx| { thread.on_terminal_provider_event( - TerminalProviderEvent::Exit { - terminal_id, - status, - }, + TerminalProviderEvent::Output { terminal_id, data }, cx, ); }); } } } - } - Ok(()) - } + if let Some(term_exit) = meta.get("terminal_exit") { + if let Some(id_str) = term_exit.get("terminal_id").and_then(|v| v.as_str()) { + let terminal_id = acp::TerminalId::new(id_str); + let status = acp::TerminalExitStatus::new() + .exit_code( + term_exit + .get("exit_code") + .and_then(|v| v.as_u64()) + .map(|i| i as u32), + ) + .signal( + term_exit + .get("signal") + .and_then(|v| v.as_str().map(|s| s.to_string())), + ); - async fn create_terminal( - &self, - args: acp::CreateTerminalRequest, - ) -> Result { - let thread = self.session_thread(&args.session_id)?; - let project = thread.read_with(&self.cx, |thread, _cx| thread.project().clone())?; - - let terminal_entity = acp_thread::create_terminal_entity( - args.command.clone(), - &args.args, - args.env - .into_iter() - .map(|env| (env.name, env.value)) - .collect(), - args.cwd.clone(), - &project, - &mut self.cx.clone(), - ) - .await?; + let _ = thread.update(cx, |thread, cx| { + thread.on_terminal_provider_event( + TerminalProviderEvent::Exit { + terminal_id, + status, + }, + cx, + ); + }); + } + } + } + } +} - // Register with renderer - let terminal_entity = thread.update(&mut self.cx.clone(), |thread, cx| { - thread.register_terminal_created( - acp::TerminalId::new(uuid::Uuid::new_v4().to_string()), - format!("{} {}", args.command, args.args.join(" ")), +fn handle_create_terminal( + args: acp::CreateTerminalRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + let project = match thread + .read_with(cx, |thread, _cx| thread.project().clone()) + .map_err(acp::Error::from) + { + Ok(p) => p, + Err(e) => return respond_err(responder, e), + }; + + cx.spawn(async move |cx| { + let result: Result<_, acp::Error> = async { + let terminal_entity = acp_thread::create_terminal_entity( + args.command.clone(), + &args.args, + args.env + .into_iter() + .map(|env| (env.name, env.value)) + .collect(), args.cwd.clone(), - args.output_byte_limit, - terminal_entity, + &project, cx, ) - })?; - let terminal_id = terminal_entity.read_with(&self.cx, |terminal, _| terminal.id().clone()); - Ok(acp::CreateTerminalResponse::new(terminal_id)) - } - - async fn kill_terminal( - &self, - args: acp::KillTerminalRequest, - ) -> Result { - self.session_thread(&args.session_id)? - .update(&mut self.cx.clone(), |thread, cx| { - thread.kill_terminal(args.terminal_id, cx) - })??; - - Ok(Default::default()) - } - - async fn ext_method(&self, _args: acp::ExtRequest) -> Result { - Err(acp::Error::method_not_found()) - } + .await + .map_err(acp::Error::from)?; + + let terminal_entity = thread + .update(cx, |thread, cx| { + thread.register_terminal_created( + acp::TerminalId::new(uuid::Uuid::new_v4().to_string()), + format!("{} {}", args.command, args.args.join(" ")), + args.cwd.clone(), + args.output_byte_limit, + terminal_entity, + cx, + ) + }) + .map_err(acp::Error::from)?; + let terminal_id = terminal_entity.read_with(cx, |terminal, _| terminal.id().clone()); + Ok(terminal_id) + } + .await; - async fn ext_notification(&self, _args: acp::ExtNotification) -> Result<(), acp::Error> { - Err(acp::Error::method_not_found()) - } + match result { + Ok(terminal_id) => { + responder + .respond(acp::CreateTerminalResponse::new(terminal_id)) + .log_err(); + } + Err(e) => respond_err(responder, e), + } + }) + .detach(); +} - async fn release_terminal( - &self, - args: acp::ReleaseTerminalRequest, - ) -> Result { - self.session_thread(&args.session_id)? - .update(&mut self.cx.clone(), |thread, cx| { - thread.release_terminal(args.terminal_id, cx) - })??; - - Ok(Default::default()) +fn handle_kill_terminal( + args: acp::KillTerminalRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + match thread + .update(cx, |thread, cx| thread.kill_terminal(args.terminal_id, cx)) + .map_err(acp::Error::from) + .and_then(|r| r.map_err(acp::Error::from)) + { + Ok(()) => { + responder + .respond(acp::KillTerminalResponse::default()) + .log_err(); + } + Err(e) => respond_err(responder, e), } +} - async fn terminal_output( - &self, - args: acp::TerminalOutputRequest, - ) -> Result { - self.session_thread(&args.session_id)? - .read_with(&mut self.cx.clone(), |thread, cx| { - let out = thread - .terminal(args.terminal_id)? - .read(cx) - .current_output(cx); - - Ok(out) - })? +fn handle_release_terminal( + args: acp::ReleaseTerminalRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + match thread + .update(cx, |thread, cx| { + thread.release_terminal(args.terminal_id, cx) + }) + .map_err(acp::Error::from) + .and_then(|r| r.map_err(acp::Error::from)) + { + Ok(()) => { + responder + .respond(acp::ReleaseTerminalResponse::default()) + .log_err(); + } + Err(e) => respond_err(responder, e), } +} - async fn wait_for_terminal_exit( - &self, - args: acp::WaitForTerminalExitRequest, - ) -> Result { - let exit_status = self - .session_thread(&args.session_id)? - .update(&mut self.cx.clone(), |thread, cx| { - anyhow::Ok(thread.terminal(args.terminal_id)?.read(cx).wait_for_exit()) - })?? - .await; - - Ok(acp::WaitForTerminalExitResponse::new(exit_status)) +fn handle_terminal_output( + args: acp::TerminalOutputRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + match thread + .read_with(cx, |thread, cx| -> Result<_, anyhow::Error> { + let out = thread + .terminal(args.terminal_id)? + .read(cx) + .current_output(cx); + Ok(out) + }) + .map_err(acp::Error::from) + .and_then(|r| r.map_err(acp::Error::from)) + { + Ok(output) => { + responder.respond(output).log_err(); + } + Err(e) => respond_err(responder, e), } } -impl ClientDelegate { - fn session_thread(&self, session_id: &acp::SessionId) -> Result> { - let sessions = self.sessions.borrow(); - sessions - .get(session_id) - .context("Failed to get session") - .map(|session| session.thread.clone()) - } +fn handle_wait_for_terminal_exit( + args: acp::WaitForTerminalExitRequest, + responder: agent_client_protocol_core::Responder, + cx: &mut AsyncApp, + ctx: &ClientContext, +) { + let thread = match session_thread(ctx, &args.session_id) { + Ok(t) => t, + Err(e) => return respond_err(responder, e), + }; + + cx.spawn(async move |cx| { + let result: Result<_, acp::Error> = async { + let exit_status = thread + .update(cx, |thread, cx| { + anyhow::Ok(thread.terminal(args.terminal_id)?.read(cx).wait_for_exit()) + }) + .map_err(acp::Error::from)? + .map_err(acp::Error::from)? + .await; + Ok(exit_status) + } + .await; + + match result { + Ok(exit_status) => { + responder + .respond(acp::WaitForTerminalExitResponse::new(exit_status)) + .log_err(); + } + Err(e) => respond_err(responder, e), + } + }) + .detach(); } diff --git a/crates/agent_servers/src/agent_servers.rs b/crates/agent_servers/src/agent_servers.rs index 2016e5aaaa27b62c956c5eee49c989172980de49..8ebc1c652d993f71f4d7e38046185dcf485b76a6 100644 --- a/crates/agent_servers/src/agent_servers.rs +++ b/crates/agent_servers/src/agent_servers.rs @@ -48,31 +48,34 @@ pub trait AgentServer: Send { fn into_any(self: Rc) -> Rc; - fn default_mode(&self, _cx: &App) -> Option { + fn default_mode(&self, _cx: &App) -> Option { None } fn set_default_mode( &self, - _mode_id: Option, + _mode_id: Option, _fs: Arc, _cx: &mut App, ) { } - fn default_model(&self, _cx: &App) -> Option { + fn default_model(&self, _cx: &App) -> Option { None } fn set_default_model( &self, - _model_id: Option, + _model_id: Option, _fs: Arc, _cx: &mut App, ) { } - fn favorite_model_ids(&self, _cx: &mut App) -> HashSet { + fn favorite_model_ids( + &self, + _cx: &mut App, + ) -> HashSet { HashSet::default() } @@ -91,16 +94,16 @@ pub trait AgentServer: Send { fn favorite_config_option_value_ids( &self, - _config_id: &agent_client_protocol::SessionConfigId, + _config_id: &agent_client_protocol_core::schema::SessionConfigId, _cx: &mut App, - ) -> HashSet { + ) -> HashSet { HashSet::default() } fn toggle_favorite_config_option_value( &self, - _config_id: agent_client_protocol::SessionConfigId, - _value_id: agent_client_protocol::SessionConfigValueId, + _config_id: agent_client_protocol_core::schema::SessionConfigId, + _value_id: agent_client_protocol_core::schema::SessionConfigValueId, _should_be_favorite: bool, _fs: Arc, _cx: &App, @@ -109,7 +112,7 @@ pub trait AgentServer: Send { fn toggle_favorite_model( &self, - _model_id: agent_client_protocol::ModelId, + _model_id: agent_client_protocol_core::schema::ModelId, _should_be_favorite: bool, _fs: Arc, _cx: &App, diff --git a/crates/agent_servers/src/custom.rs b/crates/agent_servers/src/custom.rs index 0dcd2240d6ecf6dc052cdd55953cff8ec1442eae..91f39b25b8cb7a477b78c291222b250094f2ab1a 100644 --- a/crates/agent_servers/src/custom.rs +++ b/crates/agent_servers/src/custom.rs @@ -1,6 +1,6 @@ use crate::{AgentServer, AgentServerDelegate, load_proxy_env}; use acp_thread::AgentConnection; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Context as _, Result}; use collections::HashSet; use credentials_provider::CredentialsProvider; diff --git a/crates/agent_servers/src/e2e_tests.rs b/crates/agent_servers/src/e2e_tests.rs index 956d106df2a260bd2eb31c14f4f1f1705bf74cd6..3f3c77f740eb4c1f249a772bc5f704fa53de2bc5 100644 --- a/crates/agent_servers/src/e2e_tests.rs +++ b/crates/agent_servers/src/e2e_tests.rs @@ -1,6 +1,6 @@ use crate::{AgentServer, AgentServerDelegate}; use acp_thread::{AcpThread, AgentThreadEntry, ToolCall, ToolCallStatus}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use futures::{FutureExt, StreamExt, channel::mpsc, select}; use gpui::AppContext; use gpui::{Entity, TestAppContext}; @@ -378,7 +378,7 @@ macro_rules! common_e2e_tests { async fn tool_call_with_permission(cx: &mut ::gpui::TestAppContext) { $crate::e2e_tests::test_tool_call_with_permission( $server, - ::agent_client_protocol::PermissionOptionId::new($allow_option_id), + ::agent_client_protocol_core::schema::PermissionOptionId::new($allow_option_id), cx, ) .await; diff --git a/crates/agent_settings/Cargo.toml b/crates/agent_settings/Cargo.toml index b2db5677dcfdc0994e7ce7a03c9c1dd850eb8514..942e54c37b97b493ddde90767465e68966b88e7b 100644 --- a/crates/agent_settings/Cargo.toml +++ b/crates/agent_settings/Cargo.toml @@ -12,7 +12,7 @@ workspace = true path = "src/agent_settings.rs" [dependencies] -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true anyhow.workspace = true collections.workspace = true convert_case.workspace = true diff --git a/crates/agent_settings/src/agent_settings.rs b/crates/agent_settings/src/agent_settings.rs index f0730d39eee17cbd544e5ba8574b30f03963c524..9b2a8673bb545467ed0099bc0aedf508db696f21 100644 --- a/crates/agent_settings/src/agent_settings.rs +++ b/crates/agent_settings/src/agent_settings.rs @@ -3,7 +3,7 @@ mod agent_profile; use std::path::{Component, Path}; use std::sync::{Arc, LazyLock}; -use agent_client_protocol::ModelId; +use agent_client_protocol_core::schema::ModelId; use collections::{HashSet, IndexMap}; use fs::Fs; use gpui::{App, Pixels, px}; diff --git a/crates/agent_ui/Cargo.toml b/crates/agent_ui/Cargo.toml index e505a124b6898953db9751ddfc8ab98cb7f496f0..ce03c3ddc67add55bfd0ca2ef1162ab33687050d 100644 --- a/crates/agent_ui/Cargo.toml +++ b/crates/agent_ui/Cargo.toml @@ -28,7 +28,7 @@ unit-eval = [] [dependencies] acp_thread.workspace = true action_log.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true agent.workspace = true agent_servers.workspace = true agent_settings.workspace = true diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 118f0dce6cb53c4e7851c79513cf936d6023a711..dd1594430c7ce512929a84344cc0fb89ef92289c 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -10,7 +10,7 @@ use std::{ use acp_thread::{AcpThread, MentionUri, ThreadStatus}; use agent::{ContextServerRegistry, SharedThread, ThreadStore}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_servers::AgentServer; use collections::HashSet; use db::kvp::{Dismissable, KeyValueStore}; diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index 185a54825d3af18f16f2eb30188ea866c099bf32..45620b4c26a17ac45419a8b4a07b029f9fd1966a 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -39,7 +39,7 @@ use std::rc::Rc; use std::sync::Arc; use ::ui::IconName; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::{AgentProfileId, AgentSettings}; use command_palette_hooks::CommandPaletteFilter; use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt as _}; @@ -232,7 +232,7 @@ pub struct NewExternalAgentThread { #[action(namespace = agent)] #[serde(deny_unknown_fields)] pub struct NewNativeAgentThreadFromSummary { - from_session_id: agent_client_protocol::SessionId, + from_session_id: agent_client_protocol_core::schema::SessionId, } #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] @@ -317,7 +317,7 @@ pub enum AgentInitialContent { title: Option, }, ContentBlock { - blocks: Vec, + blocks: Vec, auto_submit: bool, }, FromExternalSource(ExternalSourcePrompt), diff --git a/crates/agent_ui/src/completion_provider.rs b/crates/agent_ui/src/completion_provider.rs index a72b352375ef9b219729172f0d19854287e0e7fc..7ee3b60f95c1c08de98bd809a384e6608d110fa3 100644 --- a/crates/agent_ui/src/completion_provider.rs +++ b/crates/agent_ui/src/completion_provider.rs @@ -7,7 +7,7 @@ use std::sync::atomic::AtomicBool; use crate::DEFAULT_THREAD_TITLE; use crate::ThreadHistory; use acp_thread::MentionUri; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::Result; use editor::{CompletionProvider, Editor, code_context_menus::COMPLETION_MENU_MAX_WIDTH}; use futures::FutureExt as _; diff --git a/crates/agent_ui/src/config_options.rs b/crates/agent_ui/src/config_options.rs index 44c0baa232222c0ba7c1d54acdecaabacfa85f12..a1d1158e8e1c23ccfca93b50ee94f66ebcc20fbe 100644 --- a/crates/agent_ui/src/config_options.rs +++ b/crates/agent_ui/src/config_options.rs @@ -1,7 +1,7 @@ use std::{cmp::Reverse, rc::Rc, sync::Arc}; use acp_thread::AgentSessionConfigOptions; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_servers::AgentServer; use agent_settings::AgentSettings; use collections::HashSet; diff --git a/crates/agent_ui/src/conversation_view.rs b/crates/agent_ui/src/conversation_view.rs index 83a0c158a11c54be1ff54f553ce4b427da2cabc2..c3a17a06c958a879bdb672e4b60edc5a0ab3eee4 100644 --- a/crates/agent_ui/src/conversation_view.rs +++ b/crates/agent_ui/src/conversation_view.rs @@ -7,7 +7,7 @@ use acp_thread::{ use acp_thread::{AgentConnection, Plan}; use action_log::{ActionLog, ActionLogTelemetry, DiffStats}; use agent::{NativeAgentServer, NativeAgentSessionList, SharedThread, ThreadStore}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; #[cfg(test)] use agent_servers::AgentServerDelegate; use agent_servers::{AgentServer, GEMINI_TERMINAL_AUTH_METHOD_ID}; @@ -2750,7 +2750,7 @@ pub(crate) mod tests { }; use action_log::ActionLog; use agent::{AgentTool, EditFileTool, FetchTool, TerminalTool, ToolPermissionContext}; - use agent_client_protocol::SessionId; + use agent_client_protocol_core::schema::SessionId; use editor::MultiBufferOffset; use fs::FakeFs; use gpui::{EventEmitter, TestAppContext, VisualTestContext}; diff --git a/crates/agent_ui/src/conversation_view/thread_view.rs b/crates/agent_ui/src/conversation_view/thread_view.rs index c065c3de3d83c0eb5b68bf9a3610ff925762c952..4926a7337431c74c327f1d69e6047496c6b680e1 100644 --- a/crates/agent_ui/src/conversation_view/thread_view.rs +++ b/crates/agent_ui/src/conversation_view/thread_view.rs @@ -249,12 +249,13 @@ pub struct ThreadView { pub session_capabilities: SharedSessionCapabilities, /// Tracks which tool calls have their content/output expanded. /// Used for showing/hiding tool call results, terminal output, etc. - pub expanded_tool_calls: HashSet, - pub expanded_tool_call_raw_inputs: HashSet, + pub expanded_tool_calls: HashSet, + pub expanded_tool_call_raw_inputs: HashSet, pub expanded_thinking_blocks: HashSet<(usize, usize)>, auto_expanded_thinking_block: Option<(usize, usize)>, user_toggled_thinking_blocks: HashSet<(usize, usize)>, - pub subagent_scroll_handles: RefCell>, + pub subagent_scroll_handles: + RefCell>, pub edits_expanded: bool, pub plan_expanded: bool, pub queue_expanded: bool, @@ -266,12 +267,12 @@ pub struct ThreadView { pub queued_message_editor_subscriptions: Vec, pub last_synced_queue_length: usize, pub turn_fields: TurnFields, - pub discarded_partial_edits: HashSet, + pub discarded_partial_edits: HashSet, pub is_loading_contents: bool, pub new_server_version_available: Option, pub resumed_without_history: bool, pub(crate) permission_selections: - HashMap, + HashMap, pub resume_thread_metadata: Option, pub _cancel_task: Option>, _save_task: Option>, diff --git a/crates/agent_ui/src/entry_view_state.rs b/crates/agent_ui/src/entry_view_state.rs index eeaf8f6935a2294d8d9a1fe71b8d8acd62ee43a2..4cd34ceb38af52732af94550ac289895fc1a5a1a 100644 --- a/crates/agent_ui/src/entry_view_state.rs +++ b/crates/agent_ui/src/entry_view_state.rs @@ -3,7 +3,7 @@ use std::ops::Range; use super::thread_history::ThreadHistory; use acp_thread::{AcpThread, AgentThreadEntry}; use agent::ThreadStore; -use agent_client_protocol::ToolCallId; +use agent_client_protocol_core::schema::ToolCallId; use collections::HashMap; use editor::{Editor, EditorEvent, EditorMode, MinimapVisibility, SizingBehavior}; use gpui::{ @@ -465,7 +465,7 @@ mod tests { use std::sync::Arc; use acp_thread::{AgentConnection, StubAgentConnection}; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind}; use editor::RowInfo; use fs::FakeFs; diff --git a/crates/agent_ui/src/mention_set.rs b/crates/agent_ui/src/mention_set.rs index 4db856f9dd1e512a7b8b43eadcefccc22fe50188..2e150527e01a848a275917f9e4adcb2aa189c7c9 100644 --- a/crates/agent_ui/src/mention_set.rs +++ b/crates/agent_ui/src/mention_set.rs @@ -1,7 +1,7 @@ use crate::diagnostics::{DiagnosticsOptions, codeblock_fence_for_path, collect_diagnostics}; use acp_thread::{MentionUri, selection_name}; use agent::{ThreadStore, outline}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_servers::{AgentServer, AgentServerDelegate}; use anyhow::{Context as _, Result, anyhow}; use collections::{HashMap, HashSet}; diff --git a/crates/agent_ui/src/message_editor.rs b/crates/agent_ui/src/message_editor.rs index 8660e792cd23bc418b1d2c204bfafb2a81ba48df..a925553a2ef0c9a68ba3e9e2b36f36f1bda957e5 100644 --- a/crates/agent_ui/src/message_editor.rs +++ b/crates/agent_ui/src/message_editor.rs @@ -11,7 +11,7 @@ use crate::{ }; use acp_thread::MentionUri; use agent::ThreadStore; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Result, anyhow}; use editor::{ Addon, AnchorRangeExt, ContextMenuOptions, Editor, EditorElement, EditorEvent, EditorMode, @@ -1905,7 +1905,7 @@ mod tests { use acp_thread::MentionUri; use agent::{ThreadStore, outline}; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use base64::Engine as _; use editor::{ AnchorRangeExt as _, Editor, EditorMode, MultiBufferOffset, SelectionEffects, diff --git a/crates/agent_ui/src/mode_selector.rs b/crates/agent_ui/src/mode_selector.rs index 60c9b8787092388ad2b3e2d5817834018dc7ea25..c619940387b9fcb65dfa7f169120e2d1dd7b787f 100644 --- a/crates/agent_ui/src/mode_selector.rs +++ b/crates/agent_ui/src/mode_selector.rs @@ -1,5 +1,5 @@ use acp_thread::AgentSessionModes; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_servers::AgentServer; use agent_settings::AgentSettings; use fs::Fs; diff --git a/crates/agent_ui/src/model_selector.rs b/crates/agent_ui/src/model_selector.rs index 89ed3e490b33ca83cbdab25cfce77fee7cf9ccb6..805c1b7188d1c8e975cb960969631fa41f3e43ee 100644 --- a/crates/agent_ui/src/model_selector.rs +++ b/crates/agent_ui/src/model_selector.rs @@ -1,7 +1,7 @@ use std::{cmp::Reverse, rc::Rc, sync::Arc}; use acp_thread::{AgentModelIcon, AgentModelInfo, AgentModelList, AgentModelSelector}; -use agent_client_protocol::ModelId; +use agent_client_protocol_core::schema::ModelId; use agent_servers::AgentServer; use agent_settings::AgentSettings; use anyhow::Result; @@ -533,7 +533,7 @@ async fn fuzzy_search( #[cfg(test)] mod tests { - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use gpui::TestAppContext; use super::*; diff --git a/crates/agent_ui/src/test_support.rs b/crates/agent_ui/src/test_support.rs index 94502485b1f3a2bb6a6d88ccd897de56c5a566f5..2ffac1635836b253c7819d395580af777aba962e 100644 --- a/crates/agent_ui/src/test_support.rs +++ b/crates/agent_ui/src/test_support.rs @@ -1,5 +1,5 @@ use acp_thread::{AgentConnection, StubAgentConnection}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_servers::{AgentServer, AgentServerDelegate}; use gpui::{Entity, Task, TestAppContext, VisualTestContext}; use project::AgentId; diff --git a/crates/agent_ui/src/thread_history.rs b/crates/agent_ui/src/thread_history.rs index 7b7a3e60211896bf717fb3dfb2670d92b7409281..29e8cdd94c7da32d0bf49d851210fd7089f488ef 100644 --- a/crates/agent_ui/src/thread_history.rs +++ b/crates/agent_ui/src/thread_history.rs @@ -1,5 +1,5 @@ use acp_thread::{AgentSessionInfo, AgentSessionList, AgentSessionListRequest, SessionListUpdate}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use gpui::{App, Task}; use std::rc::Rc; use ui::prelude::*; diff --git a/crates/agent_ui/src/thread_import.rs b/crates/agent_ui/src/thread_import.rs index 5402b1c74353b73a522a068aa32dfd0a9dc85c60..4e5c4f7131ac41ebff0d9908677391b414bdbeb0 100644 --- a/crates/agent_ui/src/thread_import.rs +++ b/crates/agent_ui/src/thread_import.rs @@ -1,6 +1,6 @@ use acp_thread::AgentSessionListRequest; use agent::ThreadStore; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use chrono::Utc; use collections::HashSet; use db::kvp::Dismissable; diff --git a/crates/agent_ui/src/thread_metadata_store.rs b/crates/agent_ui/src/thread_metadata_store.rs index fcd9665c52451d62fe8185abca919148a1666126..9696e09d7d969e02841ee8aff9333d7f2a288918 100644 --- a/crates/agent_ui/src/thread_metadata_store.rs +++ b/crates/agent_ui/src/thread_metadata_store.rs @@ -2,7 +2,7 @@ use std::{path::Path, sync::Arc}; use acp_thread::AcpThreadEvent; use agent::{ThreadStore, ZED_AGENT_ID}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::Context as _; use chrono::{DateTime, Utc}; use collections::{HashMap, HashSet}; @@ -791,7 +791,7 @@ mod tests { use acp_thread::{AgentConnection, StubAgentConnection}; use action_log::ActionLog; use agent::DbThread; - use agent_client_protocol as acp; + use agent_client_protocol_core::schema as acp; use feature_flags::FeatureFlagAppExt; use gpui::TestAppContext; use project::FakeFs; diff --git a/crates/agent_ui/src/threads_archive_view.rs b/crates/agent_ui/src/threads_archive_view.rs index 9aca31e1edbe729fccecfc0dd8f0530d2aed2564..cd43d6627ce40197e2ebadd9238f9cc59e375a66 100644 --- a/crates/agent_ui/src/threads_archive_view.rs +++ b/crates/agent_ui/src/threads_archive_view.rs @@ -7,7 +7,7 @@ use crate::thread_metadata_store::{ThreadMetadata, ThreadMetadataStore}; use crate::{Agent, RemoveSelectedThread}; use agent::ThreadStore; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use chrono::{DateTime, Datelike as _, Local, NaiveDate, TimeDelta, Utc}; use editor::Editor; diff --git a/crates/agent_ui/src/ui/mention_crease.rs b/crates/agent_ui/src/ui/mention_crease.rs index 6e99647304d93fe91cd6b91dbd2bf3bfd82c7ab0..3b58b04f2d46f139ef1cfd529651f29d94cc786e 100644 --- a/crates/agent_ui/src/ui/mention_crease.rs +++ b/crates/agent_ui/src/ui/mention_crease.rs @@ -1,7 +1,7 @@ use std::{ops::RangeInclusive, path::PathBuf, time::Duration}; use acp_thread::MentionUri; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use editor::{Editor, SelectionEffects, scroll::Autoscroll}; use gpui::{ Animation, AnimationExt, AnyView, Context, IntoElement, WeakEntity, Window, pulsating_between, diff --git a/crates/eval_cli/Cargo.toml b/crates/eval_cli/Cargo.toml index cac5dc6aa28fa9dfa9b7d41caf0db125daf596dc..b68ebfdd0ffb8cff721abd93c24b2dc4769846ee 100644 --- a/crates/eval_cli/Cargo.toml +++ b/crates/eval_cli/Cargo.toml @@ -15,7 +15,7 @@ path = "src/main.rs" [dependencies] acp_thread.workspace = true agent.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true agent_ui.workspace = true anyhow.workspace = true clap.workspace = true diff --git a/crates/eval_cli/src/main.rs b/crates/eval_cli/src/main.rs index f9ab1835f94327c72462ba7014bf7517d12ac55d..1c2d4b7e86357811a28a9e38a8747e5e66b0612d 100644 --- a/crates/eval_cli/src/main.rs +++ b/crates/eval_cli/src/main.rs @@ -40,7 +40,7 @@ use std::time::{Duration, Instant}; use acp_thread::AgentConnection as _; use agent::{NativeAgent, NativeAgentConnection, Templates, ThreadStore}; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use anyhow::{Context, Result}; use clap::Parser; use feature_flags::FeatureFlagAppExt as _; diff --git a/crates/sidebar/Cargo.toml b/crates/sidebar/Cargo.toml index 04ed8808a14d4c6853b08669523d55a2ebba4482..c40ee1cf802e45b0b3fdb7076e4eaab6e50d6357 100644 --- a/crates/sidebar/Cargo.toml +++ b/crates/sidebar/Cargo.toml @@ -18,7 +18,7 @@ default = [] acp_thread.workspace = true action_log.workspace = true agent.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true agent_settings.workspace = true agent_ui = { workspace = true, features = ["audio"] } anyhow.workspace = true diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index a9664a048123253d617a08507cfe4288914d0e9e..78e305df4c55a46362df713fad99afaf5c928920 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -2,7 +2,7 @@ mod thread_switcher; use acp_thread::ThreadStatus; use action_log::DiffStats; -use agent_client_protocol::{self as acp}; +use agent_client_protocol_core::schema as acp; use agent_settings::AgentSettings; use agent_ui::thread_metadata_store::{ThreadMetadata, ThreadMetadataStore}; use agent_ui::threads_archive_view::{ diff --git a/crates/sidebar/src/thread_switcher.rs b/crates/sidebar/src/thread_switcher.rs index 86e2aeba38b9ee18a8f56597abc0d62f5741b714..2794d3417a10cb6924e6d50f0b7a6f7716af432e 100644 --- a/crates/sidebar/src/thread_switcher.rs +++ b/crates/sidebar/src/thread_switcher.rs @@ -1,5 +1,5 @@ use action_log::DiffStats; -use agent_client_protocol as acp; +use agent_client_protocol_core::schema as acp; use agent_ui::thread_metadata_store::ThreadMetadata; use gpui::{ Action as _, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Modifiers, diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 9feaa59c9762208e4e4e85748f21a7a3e0afc3db..49d7698b8d0bb3ebeaa36bf7596411d84acf6316 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -66,7 +66,7 @@ required-features = ["visual-tests"] acp_tools.workspace = true activity_indicator.workspace = true agent.workspace = true -agent-client-protocol.workspace = true +agent-client-protocol-core.workspace = true agent_settings.workspace = true agent_ui = { workspace = true, features = ["audio"] } anyhow.workspace = true diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 303f21b8ffa62f9d9f380d9c18beecd77775df20..5f809ade7fb5645e1b2cba9158cb523fcdc622b0 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -5,7 +5,6 @@ mod reliability; mod zed; use agent::{SharedThread, ThreadStore}; -use agent_client_protocol; use agent_ui::AgentPanel; use anyhow::{Context as _, Error, Result}; use clap::Parser; @@ -978,7 +977,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc, cx: &mut let shared_thread = SharedThread::from_bytes(&response.thread_data)?; let db_thread = shared_thread.to_db_thread(); - let session_id = agent_client_protocol::SessionId::new(session_id); + let session_id = agent_client_protocol_core::schema::SessionId::new(session_id); let save_session_id = session_id.clone(); diff --git a/crates/zed/src/visual_test_runner.rs b/crates/zed/src/visual_test_runner.rs index 7e081c15a564cb996f176345ee3330f00ee6b6f3..6d89da27c3945fc88005eb11913c63dd582bb818 100644 --- a/crates/zed/src/visual_test_runner.rs +++ b/crates/zed/src/visual_test_runner.rs @@ -95,7 +95,7 @@ fn main() { #[cfg(target_os = "macos")] use { acp_thread::{AgentConnection, StubAgentConnection}, - agent_client_protocol as acp, + agent_client_protocol_core::schema as acp, agent_servers::{AgentServer, AgentServerDelegate}, anyhow::{Context as _, Result}, assets::Assets,