Detailed changes
@@ -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",
@@ -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"
@@ -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
@@ -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::*;
@@ -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<Rc<dyn AgentSessionTruncate>> {
Some(Rc::new(StubAgentSessionEditor))
@@ -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};
@@ -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};
@@ -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
@@ -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<str>,
+ params: Option<serde_json::Value>,
+ },
+ Response {
+ id: RequestId,
+ result: Result<Option<serde_json::Value>, acp::Error>,
+ },
+ Notification {
+ method: Arc<str>,
+ params: Option<serde_json::Value>,
+ },
+}
+
+#[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<acp::ClientSideConnection>,
}
impl AcpConnectionRegistry {
@@ -63,16 +92,9 @@ impl AcpConnectionRegistry {
}
}
- pub fn set_active_connection(
- &self,
- agent_id: AgentId,
- connection: &Rc<acp::ClientSideConnection>,
- cx: &mut Context<Self>,
- ) {
- 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>) {
+ self.active_connection
+ .replace(Some(ActiveConnection { agent_id }));
cx.notify();
}
}
@@ -90,9 +112,10 @@ struct WatchedConnection {
agent_id: AgentId,
messages: Vec<WatchedConnectionMessage>,
list_state: ListState,
- connection: Weak<acp::ClientSideConnection>,
- incoming_request_methods: HashMap<acp::RequestId, Arc<str>>,
- outgoing_request_methods: HashMap<acp::RequestId, Arc<str>>,
+ #[allow(dead_code)]
+ incoming_request_methods: HashMap<RequestId, Arc<str>>,
+ #[allow(dead_code)]
+ outgoing_request_methods: HashMap<RequestId, Arc<str>>,
_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<Self>) {
+ #[allow(dead_code)]
+ fn push_stream_message(&mut self, stream_message: StreamMessage, cx: &mut Context<Self>) {
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<acp::RequestId>,
- direction: acp::StreamMessageDirection,
+ request_id: Option<RequestId>,
+ direction: StreamMessageDirection,
message_type: MessageType,
params: Result<Option<serde_json::Value>, acp::Error>,
collapsed_params_md: Option<Entity<Markdown>>,
@@ -427,6 +427,7 @@ impl WatchedConnectionMessage {
}
}
+#[allow(dead_code)]
fn collapsed_params_md(
params: &serde_json::Value,
language_registry: &Arc<LanguageRegistry>,
@@ -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,
@@ -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
@@ -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};
@@ -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};
@@ -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;
@@ -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
@@ -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()
}
@@ -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;
@@ -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};
@@ -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};
@@ -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};
@@ -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};
@@ -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};
@@ -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 _};
@@ -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 _};
@@ -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};
@@ -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};
@@ -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;
@@ -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};
@@ -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;
@@ -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;
@@ -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};
@@ -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 _;
@@ -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 _;
@@ -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;
@@ -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 _;
@@ -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 _;
@@ -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};
@@ -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;
@@ -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
@@ -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<RefCell<HashMap<acp::SessionId, AcpSession>>>,
+ session_list: Rc<RefCell<Option<Rc<AcpSessionList>>>>,
+}
+
+/// Work items sent from `Send` handler closures to the `!Send` foreground thread.
+type ForegroundWork = Box<dyn FnOnce(&mut AsyncApp, &ClientContext) + Send>;
+
pub struct AcpConnection {
id: AgentId,
telemetry_id: SharedString,
- connection: Rc<acp::ClientSideConnection>,
+ connection: ConnectionTo<agent_client_protocol_core::Agent>,
sessions: Rc<RefCell<HashMap<acp::SessionId, AcpSession>>>,
auth_methods: Vec<acp::AuthMethod>,
command: AgentServerCommand,
@@ -53,7 +63,8 @@ pub struct AcpConnection {
default_config_options: HashMap<String, String>,
child: Child,
session_list: Option<Rc<AcpSessionList>>,
- _io_task: Task<Result<(), acp::Error>>,
+ _io_task: Task<()>,
+ _dispatch_task: Task<()>,
_wait_task: Task<Result<()>>,
_stderr_task: Task<Result<()>>,
}
@@ -84,13 +95,13 @@ pub struct AcpSession {
}
pub struct AcpSessionList {
- connection: Rc<acp::ClientSideConnection>,
+ connection: ConnectionTo<agent_client_protocol_core::Agent>,
updates_tx: smol::channel::Sender<acp_thread::SessionListUpdate>,
updates_rx: smol::channel::Receiver<acp_thread::SessionListUpdate>,
}
impl AcpSessionList {
- fn new(connection: Rc<acp::ClientSideConnection>) -> Self {
+ fn new(connection: ConnectionTo<agent_client_protocol_core::Agent>) -> 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<RefCell<Option<Rc<AcpSessionList>>>> =
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::<ForegroundWork>();
+
+ // Build the transport from child stdio
+ let transport = ByteStreams::new(stdin, stdout);
+
+ // Use a oneshot channel to extract the ConnectionTo<Agent> 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<agent_client_protocol_core::Agent>| async move {
+ connection_tx.send(connection.clone()).ok();
+ // Keep the connection alive until the transport closes.
+ futures::future::pending::<Result<(), acp::Error>>().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<Agent> handle.
+ let connection: ConnectionTo<agent_client_protocol_core::Agent> = 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<Agent>
+ // 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<Result<()>> {
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<acp::ClientSideConnection>,
+ connection: ConnectionTo<agent_client_protocol_core::Agent>,
state: Rc<RefCell<acp::SessionModeState>>,
}
@@ -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<acp::ClientSideConnection>,
+ connection: ConnectionTo<agent_client_protocol_core::Agent>,
state: Rc<RefCell<acp::SessionModelState>>,
}
impl AcpModelSelector {
fn new(
session_id: acp::SessionId,
- connection: Rc<acp::ClientSideConnection>,
+ connection: ConnectionTo<agent_client_protocol_core::Agent>,
state: Rc<RefCell<acp::SessionModelState>>,
) -> 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<acp::ClientSideConnection>,
+ connection: ConnectionTo<agent_client_protocol_core::Agent>,
state: Rc<RefCell<Vec<acp::SessionConfigOption>>>,
watch_tx: Rc<RefCell<watch::Sender<()>>>,
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<RefCell<HashMap<acp::SessionId, AcpSession>>>,
- session_list: Rc<RefCell<Option<Rc<AcpSessionList>>>>,
- 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<WeakEntity<AcpThread>, 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<acp::RequestPermissionResponse, acp::Error> {
- 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<T: agent_client_protocol_core::JsonRpcResponse + Send + 'static>(
+ responder: agent_client_protocol_core::Responder<T>,
+ 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<acp::RequestPermissionResponse>,
+ 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<acp::WriteTextFileResponse, acp::Error> {
- 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<acp::ReadTextFileResponse, acp::Error> {
- 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<acp::WriteTextFileResponse>,
+ 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<acp::ReadTextFileResponse>,
+ 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<acp::CreateTerminalResponse, acp::Error> {
- 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<acp::CreateTerminalResponse>,
+ 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<acp::KillTerminalResponse, acp::Error> {
- 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<acp::ExtResponse, acp::Error> {
- 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<acp::ReleaseTerminalResponse, acp::Error> {
- 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<acp::KillTerminalResponse>,
+ 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<acp::TerminalOutputResponse, acp::Error> {
- 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<acp::ReleaseTerminalResponse>,
+ 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<acp::WaitForTerminalExitResponse, acp::Error> {
- 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<acp::TerminalOutputResponse>,
+ 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<WeakEntity<AcpThread>> {
- 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<acp::WaitForTerminalExitResponse>,
+ 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();
}
@@ -48,31 +48,34 @@ pub trait AgentServer: Send {
fn into_any(self: Rc<Self>) -> Rc<dyn Any>;
- fn default_mode(&self, _cx: &App) -> Option<agent_client_protocol::SessionModeId> {
+ fn default_mode(&self, _cx: &App) -> Option<agent_client_protocol_core::schema::SessionModeId> {
None
}
fn set_default_mode(
&self,
- _mode_id: Option<agent_client_protocol::SessionModeId>,
+ _mode_id: Option<agent_client_protocol_core::schema::SessionModeId>,
_fs: Arc<dyn Fs>,
_cx: &mut App,
) {
}
- fn default_model(&self, _cx: &App) -> Option<agent_client_protocol::ModelId> {
+ fn default_model(&self, _cx: &App) -> Option<agent_client_protocol_core::schema::ModelId> {
None
}
fn set_default_model(
&self,
- _model_id: Option<agent_client_protocol::ModelId>,
+ _model_id: Option<agent_client_protocol_core::schema::ModelId>,
_fs: Arc<dyn Fs>,
_cx: &mut App,
) {
}
- fn favorite_model_ids(&self, _cx: &mut App) -> HashSet<agent_client_protocol::ModelId> {
+ fn favorite_model_ids(
+ &self,
+ _cx: &mut App,
+ ) -> HashSet<agent_client_protocol_core::schema::ModelId> {
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<agent_client_protocol::SessionConfigValueId> {
+ ) -> HashSet<agent_client_protocol_core::schema::SessionConfigValueId> {
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<dyn Fs>,
_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<dyn Fs>,
_cx: &App,
@@ -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;
@@ -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;
@@ -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
@@ -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};
@@ -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
@@ -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};
@@ -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<SharedString>,
},
ContentBlock {
- blocks: Vec<agent_client_protocol::ContentBlock>,
+ blocks: Vec<agent_client_protocol_core::schema::ContentBlock>,
auto_submit: bool,
},
FromExternalSource(ExternalSourcePrompt),
@@ -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 _;
@@ -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;
@@ -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};
@@ -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<agent_client_protocol::ToolCallId>,
- pub expanded_tool_call_raw_inputs: HashSet<agent_client_protocol::ToolCallId>,
+ pub expanded_tool_calls: HashSet<agent_client_protocol_core::schema::ToolCallId>,
+ pub expanded_tool_call_raw_inputs: HashSet<agent_client_protocol_core::schema::ToolCallId>,
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<HashMap<agent_client_protocol::SessionId, ScrollHandle>>,
+ pub subagent_scroll_handles:
+ RefCell<HashMap<agent_client_protocol_core::schema::SessionId, ScrollHandle>>,
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<Subscription>,
pub last_synced_queue_length: usize,
pub turn_fields: TurnFields,
- pub discarded_partial_edits: HashSet<agent_client_protocol::ToolCallId>,
+ pub discarded_partial_edits: HashSet<agent_client_protocol_core::schema::ToolCallId>,
pub is_loading_contents: bool,
pub new_server_version_available: Option<SharedString>,
pub resumed_without_history: bool,
pub(crate) permission_selections:
- HashMap<agent_client_protocol::ToolCallId, PermissionSelection>,
+ HashMap<agent_client_protocol_core::schema::ToolCallId, PermissionSelection>,
pub resume_thread_metadata: Option<AgentSessionInfo>,
pub _cancel_task: Option<Task<()>>,
_save_task: Option<Task<()>>,
@@ -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;
@@ -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};
@@ -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,
@@ -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;
@@ -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::*;
@@ -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;
@@ -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::*;
@@ -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;
@@ -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;
@@ -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;
@@ -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,
@@ -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
@@ -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 _;
@@ -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
@@ -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::{
@@ -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,
@@ -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
@@ -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<AppState>, 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();
@@ -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,