First pass at swapping out the crates

Ben Brandt created

Change summary

Cargo.lock                                            |  297 ++-
Cargo.toml                                            |    2 
crates/acp_thread/Cargo.toml                          |    2 
crates/acp_thread/src/acp_thread.rs                   |    2 
crates/acp_thread/src/connection.rs                   |    4 
crates/acp_thread/src/mention.rs                      |    2 
crates/acp_thread/src/terminal.rs                     |    2 
crates/acp_tools/Cargo.toml                           |    2 
crates/acp_tools/src/acp_tools.rs                     |  140 
crates/agent/Cargo.toml                               |    2 
crates/agent/src/agent.rs                             |    2 
crates/agent/src/db.rs                                |    2 
crates/agent/src/native_agent_server.rs               |    2 
crates/agent/src/tests/mod.rs                         |    4 
crates/agent/src/thread.rs                            |    4 
crates/agent/src/thread_store.rs                      |    2 
crates/agent/src/tools/context_server_registry.rs     |    2 
crates/agent/src/tools/copy_path_tool.rs              |    4 
crates/agent/src/tools/create_directory_tool.rs       |    4 
crates/agent/src/tools/delete_path_tool.rs            |    4 
crates/agent/src/tools/diagnostics_tool.rs            |    2 
crates/agent/src/tools/edit_file_tool.rs              |    2 
crates/agent/src/tools/fetch_tool.rs                  |    2 
crates/agent/src/tools/find_path_tool.rs              |    2 
crates/agent/src/tools/grep_tool.rs                   |    2 
crates/agent/src/tools/list_directory_tool.rs         |    4 
crates/agent/src/tools/move_path_tool.rs              |    4 
crates/agent/src/tools/now_tool.rs                    |    2 
crates/agent/src/tools/open_tool.rs                   |    2 
crates/agent/src/tools/read_file_tool.rs              |    4 
crates/agent/src/tools/restore_file_from_disk_tool.rs |    2 
crates/agent/src/tools/save_file_tool.rs              |    2 
crates/agent/src/tools/spawn_agent_tool.rs            |    2 
crates/agent/src/tools/streaming_edit_file_tool.rs    |    2 
crates/agent/src/tools/terminal_tool.rs               |    2 
crates/agent/src/tools/update_plan_tool.rs            |    2 
crates/agent/src/tools/web_search_tool.rs             |    2 
crates/agent_servers/Cargo.toml                       |    2 
crates/agent_servers/src/acp.rs                       | 1039 ++++++++----
crates/agent_servers/src/agent_servers.rs             |   23 
crates/agent_servers/src/custom.rs                    |    2 
crates/agent_servers/src/e2e_tests.rs                 |    4 
crates/agent_settings/Cargo.toml                      |    2 
crates/agent_settings/src/agent_settings.rs           |    2 
crates/agent_ui/Cargo.toml                            |    2 
crates/agent_ui/src/agent_panel.rs                    |    2 
crates/agent_ui/src/agent_ui.rs                       |    6 
crates/agent_ui/src/completion_provider.rs            |    2 
crates/agent_ui/src/config_options.rs                 |    2 
crates/agent_ui/src/conversation_view.rs              |    4 
crates/agent_ui/src/conversation_view/thread_view.rs  |   11 
crates/agent_ui/src/entry_view_state.rs               |    4 
crates/agent_ui/src/mention_set.rs                    |    2 
crates/agent_ui/src/message_editor.rs                 |    4 
crates/agent_ui/src/mode_selector.rs                  |    2 
crates/agent_ui/src/model_selector.rs                 |    4 
crates/agent_ui/src/test_support.rs                   |    2 
crates/agent_ui/src/thread_history.rs                 |    2 
crates/agent_ui/src/thread_import.rs                  |    2 
crates/agent_ui/src/thread_metadata_store.rs          |    4 
crates/agent_ui/src/threads_archive_view.rs           |    2 
crates/agent_ui/src/ui/mention_crease.rs              |    2 
crates/eval_cli/Cargo.toml                            |    2 
crates/eval_cli/src/main.rs                           |    2 
crates/sidebar/Cargo.toml                             |    2 
crates/sidebar/src/sidebar.rs                         |    2 
crates/sidebar/src/thread_switcher.rs                 |    2 
crates/zed/Cargo.toml                                 |    2 
crates/zed/src/main.rs                                |    3 
crates/zed/src/visual_test_runner.rs                  |    2 
70 files changed, 1,073 insertions(+), 602 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -7,7 +7,7 @@ name = "acp_thread"
 version = "0.1.0"
 dependencies = [
  "action_log",
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "anyhow",
  "base64 0.22.1",
  "buffer_diff",
@@ -15,7 +15,7 @@ dependencies = [
  "collections",
  "env_logger 0.11.8",
  "file_icons",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "image",
  "indoc",
@@ -50,7 +50,7 @@ dependencies = [
 name = "acp_tools"
 version = "0.1.0"
 dependencies = [
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "collections",
  "gpui",
  "language",
@@ -75,7 +75,7 @@ dependencies = [
  "collections",
  "ctor",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "language",
  "log",
@@ -100,7 +100,7 @@ dependencies = [
  "editor",
  "extension_host",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "language",
  "project",
@@ -144,7 +144,7 @@ version = "0.1.0"
 dependencies = [
  "acp_thread",
  "action_log",
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "agent_servers",
  "agent_settings",
  "anyhow",
@@ -163,7 +163,7 @@ dependencies = [
  "eval_utils",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "git",
  "gpui",
  "gpui_tokio",
@@ -217,27 +217,42 @@ dependencies = [
 ]
 
 [[package]]
-name = "agent-client-protocol"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c56a59cf6315e99f874d2c1f96c69d2da5ffe0087d211297fc4a41f849770a2"
+name = "agent-client-protocol-core"
+version = "0.1.0"
 dependencies = [
+ "agent-client-protocol-derive",
  "agent-client-protocol-schema",
  "anyhow",
- "async-broadcast",
- "async-trait",
- "derive_more",
- "futures 0.3.31",
- "log",
+ "boxfnonce",
+ "futures 0.3.32",
+ "futures-concurrency",
+ "jsonrpcmsg",
+ "rmcp",
+ "rustc-hash 2.1.1",
+ "schemars",
  "serde",
  "serde_json",
+ "thiserror 2.0.17",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "uuid",
+]
+
+[[package]]
+name = "agent-client-protocol-derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
 ]
 
 [[package]]
 name = "agent-client-protocol-schema"
-version = "0.11.2"
+version = "0.11.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0497b9a95a404e35799904835c57c6f8c69b9d08ccfd3cb5b7d746425cd6789"
+checksum = "ca68e7e55681ce56546c0cecc6bc8f20493d24b44c6d93ec46174f310730bba2"
 dependencies = [
  "anyhow",
  "derive_more",
@@ -254,7 +269,7 @@ dependencies = [
  "acp_thread",
  "acp_tools",
  "action_log",
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "anyhow",
  "async-trait",
  "chrono",
@@ -264,7 +279,7 @@ dependencies = [
  "env_logger 0.11.8",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "google_ai",
  "gpui",
  "gpui_tokio",
@@ -295,7 +310,7 @@ dependencies = [
 name = "agent_settings"
 version = "0.1.0"
 dependencies = [
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "anyhow",
  "collections",
  "convert_case 0.8.0",
@@ -321,7 +336,7 @@ dependencies = [
  "acp_thread",
  "action_log",
  "agent",
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "agent_servers",
  "agent_settings",
  "ai_onboarding",
@@ -344,7 +359,7 @@ dependencies = [
  "feature_flags",
  "file_icons",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "git",
  "gpui",
@@ -629,7 +644,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "chrono",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -750,7 +765,7 @@ name = "askpass"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "log",
  "net",
@@ -945,7 +960,7 @@ name = "async-pipe"
 version = "0.1.3"
 source = "git+https://github.com/zed-industries/async-pipe-rs?rev=82d00a04211cf4e1236029aa03e6b6ce2a74c553#82d00a04211cf4e1236029aa03e6b6ce2a74c553"
 dependencies = [
- "futures 0.3.31",
+ "futures 0.3.32",
  "log",
 ]
 
@@ -1183,7 +1198,7 @@ dependencies = [
  "clock",
  "ctor",
  "db",
- "futures 0.3.31",
+ "futures 0.3.32",
  "futures-lite 1.13.0",
  "gpui",
  "http_client",
@@ -1862,7 +1877,7 @@ dependencies = [
  "anyhow",
  "aws-sdk-bedrockruntime",
  "aws-smithy-types",
- "futures 0.3.31",
+ "futures 0.3.32",
  "schemars",
  "serde",
  "serde_json",
@@ -2072,7 +2087,7 @@ version = "3.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365"
 dependencies = [
- "darling 0.21.3",
+ "darling 0.23.0",
  "ident_case",
  "prettyplease",
  "proc-macro2",
@@ -2110,6 +2125,12 @@ dependencies = [
  "syn 2.0.117",
 ]
 
+[[package]]
+name = "boxfnonce"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426"
+
 [[package]]
 name = "breadcrumbs"
 version = "0.1.0"
@@ -2151,7 +2172,7 @@ version = "0.1.0"
 dependencies = [
  "clock",
  "ctor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "git2",
  "gpui",
  "language",
@@ -2348,7 +2369,7 @@ dependencies = [
  "collections",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_tokio",
  "language",
@@ -2669,7 +2690,7 @@ dependencies = [
  "client",
  "clock",
  "collections",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "language",
@@ -2863,7 +2884,7 @@ dependencies = [
  "derive_more",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_tokio",
  "http_client",
@@ -2917,7 +2938,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "cloud_api_types",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_tokio",
  "http_client",
@@ -3049,7 +3070,7 @@ dependencies = [
  "anyhow",
  "edit_prediction",
  "edit_prediction_types",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "icons",
@@ -3095,7 +3116,7 @@ dependencies = [
  "extension",
  "file_finder",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "git",
  "git_hosting_providers",
  "git_ui",
@@ -3172,7 +3193,7 @@ dependencies = [
  "collections",
  "db",
  "editor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "gpui",
  "livekit_client",
@@ -3433,7 +3454,7 @@ dependencies = [
  "async-trait",
  "base64 0.22.1",
  "collections",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "log",
@@ -3494,7 +3515,7 @@ dependencies = [
  "edit_prediction_types",
  "editor",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "icons",
  "indoc",
@@ -3528,7 +3549,7 @@ dependencies = [
  "collections",
  "dirs 4.0.0",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "log",
@@ -3978,7 +3999,7 @@ version = "0.1.0"
 dependencies = [
  "cfg-if",
  "crash-handler",
- "futures 0.3.31",
+ "futures 0.3.32",
  "log",
  "mach2 0.5.0",
  "minidumper",
@@ -4035,7 +4056,7 @@ name = "credentials_provider"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "paths",
  "release_channel",
@@ -4318,7 +4339,7 @@ dependencies = [
  "collections",
  "dap-types",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "language",
@@ -4360,7 +4381,7 @@ dependencies = [
  "dap",
  "dotenvy",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "json_dotpath",
@@ -4396,6 +4417,16 @@ dependencies = [
  "darling_macro 0.21.3",
 ]
 
+[[package]]
+name = "darling"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
+dependencies = [
+ "darling_core 0.23.0",
+ "darling_macro 0.23.0",
+]
+
 [[package]]
 name = "darling_core"
 version = "0.20.11"
@@ -4424,6 +4455,19 @@ dependencies = [
  "syn 2.0.117",
 ]
 
+[[package]]
+name = "darling_core"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
+dependencies = [
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.117",
+]
+
 [[package]]
 name = "darling_macro"
 version = "0.20.11"
@@ -4446,6 +4490,17 @@ dependencies = [
  "syn 2.0.117",
 ]
 
+[[package]]
+name = "darling_macro"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
+dependencies = [
+ "darling_core 0.23.0",
+ "quote",
+ "syn 2.0.117",
+]
+
 [[package]]
 name = "dashmap"
 version = "6.1.0"
@@ -4531,7 +4586,7 @@ dependencies = [
  "anyhow",
  "dap",
  "editor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "project",
  "serde_json",
@@ -4558,7 +4613,7 @@ dependencies = [
  "editor",
  "feature_flags",
  "file_icons",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "gpui",
  "hex",
@@ -4613,7 +4668,7 @@ name = "deepseek"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -4733,7 +4788,7 @@ dependencies = [
  "async-trait",
  "env_logger 0.11.8",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http 1.3.1",
  "http_client",
@@ -5121,7 +5176,7 @@ dependencies = [
  "edit_prediction_types",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "heapless",
  "indoc",
@@ -5181,7 +5236,7 @@ dependencies = [
  "extension",
  "flate2",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gaoya",
  "gpui",
  "gpui_platform",
@@ -5233,7 +5288,7 @@ dependencies = [
  "clock",
  "collections",
  "env_logger 0.11.8",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "indoc",
  "language",
@@ -5282,7 +5337,7 @@ dependencies = [
  "editor",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "indoc",
  "language",
@@ -5327,7 +5382,7 @@ dependencies = [
  "feature_flags",
  "file_icons",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "git",
  "gpui",
@@ -5722,7 +5777,7 @@ version = "0.1.0"
 dependencies = [
  "acp_thread",
  "agent",
- "agent-client-protocol",
+ "agent-client-protocol-core",
  "agent_ui",
  "anyhow",
  "clap",
@@ -5734,7 +5789,7 @@ dependencies = [
  "extension",
  "feature_flags",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_platform",
  "gpui_tokio",
@@ -5844,7 +5899,7 @@ dependencies = [
  "collections",
  "dap",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "heck 0.5.0",
  "http_client",
@@ -5912,7 +5967,7 @@ dependencies = [
  "dap",
  "extension",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_tokio",
  "http_client",
@@ -6120,7 +6175,7 @@ dependencies = [
  "ctor",
  "editor",
  "file_icons",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "gpui",
  "menu",
@@ -6422,7 +6477,7 @@ dependencies = [
  "collections",
  "dunce",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "git",
  "gpui",
  "ignore",
@@ -6520,9 +6575,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
 
 [[package]]
 name = "futures"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -6535,9 +6590,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -6558,15 +6613,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -6586,9 +6641,9 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
 
 [[package]]
 name = "futures-lite"
@@ -6620,9 +6675,9 @@ dependencies = [
 
 [[package]]
 name = "futures-macro"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6631,21 +6686,21 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
 
 [[package]]
 name = "futures-task"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
 
 [[package]]
 name = "futures-util"
-version = "0.3.31"
+version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
 dependencies = [
  "futures 0.1.31",
  "futures-channel",
@@ -6654,9 +6709,9 @@ dependencies = [
  "futures-macro",
  "futures-sink",
  "futures-task",
+ "libc",
  "memchr",
  "pin-project-lite",
- "pin-utils",
  "slab",
  "tokio-io",
 ]
@@ -7083,7 +7138,7 @@ dependencies = [
  "async-trait",
  "collections",
  "derive_more",
- "futures 0.3.31",
+ "futures 0.3.32",
  "git2",
  "gpui",
  "http_client",
@@ -7160,7 +7215,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "async-trait",
- "futures 0.3.31",
+ "futures 0.3.32",
  "git",
  "gpui",
  "http_client",
@@ -7192,7 +7247,7 @@ dependencies = [
  "editor",
  "feature_flags",
  "file_icons",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "git",
  "gpui",
@@ -7397,7 +7452,7 @@ name = "google_ai"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -7467,7 +7522,7 @@ dependencies = [
  "env_logger 0.11.8",
  "etagere",
  "foreign-types 0.5.0",
- "futures 0.3.31",
+ "futures 0.3.32",
  "futures-concurrency",
  "getrandom 0.3.4",
  "gpui_macros",
@@ -7542,7 +7597,7 @@ dependencies = [
  "calloop-wayland-source",
  "collections",
  "filedescriptor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_wgpu",
  "http_client",
@@ -7596,7 +7651,7 @@ dependencies = [
  "dispatch2",
  "etagere",
  "foreign-types 0.5.0",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "image",
  "itertools 0.14.0",
@@ -7665,7 +7720,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "console_error_panic_hook",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_wgpu",
  "http_client",
@@ -7716,7 +7771,7 @@ dependencies = [
  "anyhow",
  "collections",
  "etagere",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "image",
  "itertools 0.14.0",
@@ -8200,7 +8255,7 @@ dependencies = [
  "async-tar",
  "bytes 1.11.1",
  "derive_more",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http 1.3.1",
  "http-body 1.0.1",
  "log",
@@ -9029,6 +9084,16 @@ dependencies = [
  "util",
 ]
 
+[[package]]
+name = "jsonrpcmsg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d833a15225c779251e13929203518c2ff26e2fe0f322d584b213f4f4dad37bd"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "jsonschema"
 version = "0.37.4"
@@ -9083,7 +9148,7 @@ dependencies = [
  "async-trait",
  "bytes 1.11.1",
  "chrono",
- "futures 0.3.31",
+ "futures 0.3.32",
  "serde",
  "serde_json",
  "thiserror 2.0.17",
@@ -9099,7 +9164,7 @@ dependencies = [
  "anyhow",
  "async-trait",
  "async-tungstenite",
- "futures 0.3.31",
+ "futures 0.3.32",
  "jupyter-protocol",
  "serde",
  "serde_json",
@@ -9217,7 +9282,7 @@ dependencies = [
  "ec4rs",
  "encoding_rs",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "globset",
  "gpui",
@@ -9297,7 +9362,7 @@ dependencies = [
  "collections",
  "extension",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "language",
  "log",
@@ -9323,7 +9388,7 @@ dependencies = [
  "cloud_llm_client",
  "collections",
  "credentials_provider",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "http_client",
  "icons",
@@ -9367,7 +9432,7 @@ dependencies = [
  "extension",
  "extension_host",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "google_ai",
  "gpui",
  "gpui_tokio",
@@ -9444,7 +9509,7 @@ dependencies = [
  "command_palette_hooks",
  "edit_prediction",
  "editor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "itertools 0.14.0",
  "language",
@@ -9480,7 +9545,7 @@ dependencies = [
  "chrono",
  "collections",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "globset",
  "gpui",
  "grammars",
@@ -9867,7 +9932,7 @@ dependencies = [
  "core-video",
  "coreaudio-rs 0.12.1",
  "cpal",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_platform",
  "gpui_tokio",
@@ -9911,7 +9976,7 @@ name = "lmstudio"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -9982,7 +10047,7 @@ dependencies = [
  "async-pipe",
  "collections",
  "ctor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_util",
  "log",
@@ -10122,7 +10187,7 @@ dependencies = [
  "collections",
  "env_logger 0.11.8",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_platform",
  "html5ever 0.27.0",
@@ -10569,7 +10634,7 @@ name = "mistral"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -10758,7 +10823,7 @@ name = "nc"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "net",
  "smol",
 ]
@@ -10854,7 +10919,7 @@ dependencies = [
  "async-std",
  "async-tar",
  "async-trait",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "log",
  "paths",
@@ -11178,7 +11243,7 @@ version = "0.9.2"
 source = "git+https://github.com/KillTheMule/nvim-rs?rev=764dd270c642f77f10f3e19d05cc178a6cbe69f3#764dd270c642f77f10f3e19d05cc178a6cbe69f3"
 dependencies = [
  "async-trait",
- "futures 0.3.31",
+ "futures 0.3.32",
  "log",
  "rmp",
  "rmpv",
@@ -11378,7 +11443,7 @@ name = "ollama"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -11485,7 +11550,7 @@ name = "open_ai"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "log",
  "rand 0.9.2",
@@ -11503,7 +11568,7 @@ version = "0.1.0"
 dependencies = [
  "editor",
  "file_icons",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "gpui",
  "picker",
@@ -11524,7 +11589,7 @@ name = "open_router"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "http_client",
  "schemars",
  "serde",
@@ -11539,7 +11604,7 @@ name = "opencode"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "futures 0.3.31",
+ "futures 0.3.32",
  "google_ai",
  "http_client",
  "schemars",
@@ -11853,6 +11918,12 @@ version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
+[[package]]
+name = "pastey"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec"
+
 [[package]]
 name = "pathdiff"
 version = "0.2.3"
@@ -12853,7 +12924,7 @@ checksum = "af3fb618632874fb76937c2361a7f22afd393c982a2165595407edc75b06d3c1"
 dependencies = [
  "atomic",
  "crossbeam-queue",
- "futures 0.3.31",
+ "futures 0.3.32",
  "log",
  "parking_lot",
  "pin-project",
@@ -13086,7 +13157,7 @@ dependencies = [
  "extension",
  "fancy-regex 0.17.0",
  "fs",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "git",
  "git2",
@@ -13152,7 +13223,7 @@ dependencies = [
  "askpass",
  "clap",
  "client",
- "futures 0.3.31",
+ "futures 0.3.32",
  "gpui",
  "gpui_platform",
  "http_client",
@@ -13213,7 +13284,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "editor",
- "futures 0.3.31",
+ "futures 0.3.32",
  "fuzzy",
  "gpui",
  "language",

Cargo.toml 🔗

@@ -477,7 +477,7 @@ ztracing_macro = { path = "crates/ztracing_macro" }
 # External crates
 #
 
-agent-client-protocol = { version = "=0.10.2", features = ["unstable"] }
+agent-client-protocol-core = { path = "../acp-rust-sdk/src/agent-client-protocol-core", features = ["unstable"] }
 aho-corasick = "1.1"
 alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "9d9640d4" }
 any_vec = "0.14"

crates/acp_thread/Cargo.toml 🔗

@@ -17,7 +17,7 @@ test-support = ["gpui/test-support", "project/test-support", "dep:parking_lot",
 
 [dependencies]
 action_log.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 base64.workspace = true
 anyhow.workspace = true
 buffer_diff.workspace = true

crates/acp_thread/src/acp_thread.rs 🔗

@@ -3,7 +3,7 @@ mod diff;
 mod mention;
 mod terminal;
 use action_log::{ActionLog, ActionLogTelemetry};
-use agent_client_protocol::{self as acp};
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Context as _, Result, anyhow};
 use collections::HashSet;
 pub use connection::*;

crates/acp_thread/src/connection.rs 🔗

@@ -1,5 +1,5 @@
 use crate::AcpThread;
-use agent_client_protocol::{self as acp};
+use agent_client_protocol_core::schema as acp;
 use anyhow::Result;
 use chrono::{DateTime, Utc};
 use collections::{HashMap, IndexMap};
@@ -939,7 +939,7 @@ mod test_support {
 
         fn truncate(
             &self,
-            _session_id: &agent_client_protocol::SessionId,
+            _session_id: &acp::SessionId,
             _cx: &App,
         ) -> Option<Rc<dyn AgentSessionTruncate>> {
             Some(Rc::new(StubAgentSessionEditor))

crates/acp_thread/src/mention.rs 🔗

@@ -1,4 +1,4 @@
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Context as _, Result, bail};
 use file_icons::FileIcons;
 use prompt_store::{PromptId, UserPromptId};

crates/acp_thread/src/terminal.rs 🔗

@@ -1,4 +1,4 @@
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::Result;
 use futures::{FutureExt as _, future::Shared};
 use gpui::{App, AppContext, AsyncApp, Context, Entity, Task};

crates/acp_tools/Cargo.toml 🔗

@@ -14,7 +14,7 @@ path = "src/acp_tools.rs"
 doctest = false
 
 [dependencies]
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 collections.workspace = true
 gpui.workspace = true
 language.workspace= true

crates/acp_tools/src/acp_tools.rs 🔗

@@ -1,12 +1,6 @@
-use std::{
-    cell::RefCell,
-    collections::HashSet,
-    fmt::Display,
-    rc::{Rc, Weak},
-    sync::Arc,
-};
+use std::{cell::RefCell, collections::HashSet, fmt::Display, sync::Arc};
 
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use collections::HashMap;
 use gpui::{
     App, Empty, Entity, EventEmitter, FocusHandle, Focusable, Global, ListAlignment, ListState,
@@ -23,6 +17,42 @@ use workspace::{
     Item, ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
 };
 
+// Stub types for the old streaming API which is not available in agent-client-protocol-core.
+// These allow the ACP debug panel code to compile but the streaming won't be active.
+#[allow(dead_code)]
+type RequestId = String;
+
+#[derive(Clone)]
+#[allow(dead_code)]
+enum StreamMessageDirection {
+    Incoming,
+    Outgoing,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+enum StreamMessageContent {
+    Request {
+        id: RequestId,
+        method: Arc<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,

crates/agent/Cargo.toml 🔗

@@ -19,7 +19,7 @@ workspace = true
 [dependencies]
 acp_thread.workspace = true
 action_log.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 agent_servers.workspace = true
 agent_settings.workspace = true
 anyhow.workspace = true

crates/agent/src/agent.rs 🔗

@@ -28,7 +28,7 @@ use acp_thread::{
     AcpThread, AgentModelSelector, AgentSessionInfo, AgentSessionList, AgentSessionListRequest,
     AgentSessionListResponse, TokenUsageRatio, UserMessageId,
 };
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Context as _, Result, anyhow};
 use chrono::{DateTime, Utc};
 use collections::{HashMap, HashSet, IndexMap};

crates/agent/src/db.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{AgentMessage, AgentMessageContent, UserMessage, UserMessageContent};
 use acp_thread::UserMessageId;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentProfileId;
 use anyhow::{Result, anyhow};
 use chrono::{DateTime, Utc};

crates/agent/src/native_agent_server.rs 🔗

@@ -1,6 +1,6 @@
 use std::{any::Any, rc::Rc, sync::Arc};
 
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_servers::{AgentServer, AgentServerDelegate};
 use agent_settings::AgentSettings;
 use anyhow::Result;

crates/agent/src/tests/mod.rs 🔗

@@ -3,7 +3,7 @@ use acp_thread::{
     AgentConnection, AgentModelGroupName, AgentModelList, PermissionOptions, ThreadStatus,
     UserMessageId,
 };
-use agent_client_protocol::{self as acp};
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentProfileId;
 use anyhow::Result;
 use client::{Client, UserStore};
@@ -5228,7 +5228,7 @@ async fn test_max_subagent_depth_prevents_tool_registration(cx: &mut TestAppCont
             cx,
         );
         thread.set_subagent_context(SubagentContext {
-            parent_thread_id: agent_client_protocol::SessionId::new("parent-id"),
+            parent_thread_id: acp::SessionId::new("parent-id"),
             depth: MAX_SUBAGENT_DEPTH - 1,
         });
         thread

crates/agent/src/thread.rs 🔗

@@ -12,7 +12,7 @@ use feature_flags::{
     FeatureFlagAppExt as _, StreamingEditFileToolFeatureFlag, UpdatePlanToolFeatureFlag,
 };
 
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::{
     AgentProfileId, AgentSettings, SUMMARIZE_THREAD_DETAILED_PROMPT, SUMMARIZE_THREAD_PROMPT,
 };
@@ -3341,7 +3341,7 @@ where
         T::description()
     }
 
-    fn kind(&self) -> agent_client_protocol::ToolKind {
+    fn kind(&self) -> agent_client_protocol_core::schema::ToolKind {
         T::kind()
     }
 

crates/agent/src/thread_store.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{DbThread, DbThreadMetadata, ThreadsDatabase};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Result, anyhow};
 use gpui::{App, Context, Entity, Global, Task, prelude::*};
 use util::path_list::PathList;

crates/agent/src/tools/context_server_registry.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{AgentToolOutput, AnyAgentTool, ToolCallEventStream, ToolInput};
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use anyhow::Result;
 use collections::{BTreeMap, HashMap};
 use context_server::{ContextServerId, client::NotificationSubscription};

crates/agent/src/tools/copy_path_tool.rs 🔗

@@ -5,7 +5,7 @@ use super::tool_permissions::{
 use crate::{
     AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_for_paths,
 };
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use agent_settings::AgentSettings;
 use futures::FutureExt as _;
 use gpui::{App, Entity, Task};
@@ -198,7 +198,7 @@ impl AgentTool for CopyPathTool {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use fs::Fs as _;
     use gpui::TestAppContext;
     use project::{FakeFs, Project};

crates/agent/src/tools/create_directory_tool.rs 🔗

@@ -2,7 +2,7 @@ use super::tool_permissions::{
     SensitiveSettingsKind, authorize_symlink_access, canonicalize_worktree_roots,
     detect_symlink_escape, sensitive_settings_kind,
 };
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use agent_settings::AgentSettings;
 use futures::FutureExt as _;
 use gpui::{App, Entity, SharedString, Task};
@@ -169,7 +169,7 @@ impl AgentTool for CreateDirectoryTool {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use fs::Fs as _;
     use gpui::TestAppContext;
     use project::{FakeFs, Project};

crates/agent/src/tools/delete_path_tool.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
     AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_for_path,
 };
 use action_log::ActionLog;
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use agent_settings::AgentSettings;
 use futures::{FutureExt as _, SinkExt, StreamExt, channel::mpsc};
 use gpui::{App, AppContext, Entity, SharedString, Task};
@@ -228,7 +228,7 @@ impl AgentTool for DeletePathTool {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use fs::Fs as _;
     use gpui::TestAppContext;
     use project::{FakeFs, Project};

crates/agent/src/tools/diagnostics_tool.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{AgentTool, ToolCallEventStream, ToolInput};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::Result;
 use futures::FutureExt as _;
 use gpui::{App, Entity, Task};

crates/agent/src/tools/edit_file_tool.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
     edit_agent::{EditAgent, EditAgentOutputEvent, EditFormat},
 };
 use acp_thread::Diff;
-use agent_client_protocol::{self as acp, ToolCallLocation, ToolCallUpdateFields};
+use agent_client_protocol_core::schema::{self as acp, ToolCallLocation, ToolCallUpdateFields};
 use anyhow::{Context as _, Result};
 use collections::HashSet;
 use futures::{FutureExt as _, StreamExt as _};

crates/agent/src/tools/fetch_tool.rs 🔗

@@ -2,7 +2,7 @@ use std::rc::Rc;
 use std::sync::Arc;
 use std::{borrow::Cow, cell::RefCell};
 
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use anyhow::{Context as _, Result, bail};
 use futures::{AsyncReadExt as _, FutureExt as _};

crates/agent/src/tools/find_path_tool.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{AgentTool, ToolCallEventStream, ToolInput};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Result, anyhow};
 use futures::FutureExt as _;
 use gpui::{App, AppContext, Entity, SharedString, Task};

crates/agent/src/tools/grep_tool.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{AgentTool, ToolCallEventStream, ToolInput};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::Result;
 use futures::{FutureExt as _, StreamExt};
 use gpui::{App, Entity, SharedString, Task};

crates/agent/src/tools/list_directory_tool.rs 🔗

@@ -3,7 +3,7 @@ use super::tool_permissions::{
     resolve_project_path,
 };
 use crate::{AgentTool, ToolCallEventStream, ToolInput};
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use anyhow::{Context as _, Result, anyhow};
 use gpui::{App, Entity, SharedString, Task};
 use project::{Project, ProjectPath, WorktreeSettings};
@@ -267,7 +267,7 @@ impl AgentTool for ListDirectoryTool {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use fs::Fs as _;
     use gpui::{TestAppContext, UpdateGlobal};
     use indoc::indoc;

crates/agent/src/tools/move_path_tool.rs 🔗

@@ -5,7 +5,7 @@ use super::tool_permissions::{
 use crate::{
     AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision, decide_permission_for_paths,
 };
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use agent_settings::AgentSettings;
 use futures::FutureExt as _;
 use gpui::{App, Entity, SharedString, Task};
@@ -205,7 +205,7 @@ impl AgentTool for MovePathTool {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use fs::Fs as _;
     use gpui::TestAppContext;
     use project::{FakeFs, Project};

crates/agent/src/tools/now_tool.rs 🔗

@@ -1,6 +1,6 @@
 use std::sync::Arc;
 
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use chrono::{Local, Utc};
 use gpui::{App, SharedString, Task};
 use schemars::JsonSchema;

crates/agent/src/tools/open_tool.rs 🔗

@@ -3,7 +3,7 @@ use super::tool_permissions::{
     resolve_project_path,
 };
 use crate::{AgentTool, ToolInput};
-use agent_client_protocol::ToolKind;
+use agent_client_protocol_core::schema::ToolKind;
 use futures::FutureExt as _;
 use gpui::{App, AppContext as _, Entity, SharedString, Task};
 use project::Project;

crates/agent/src/tools/read_file_tool.rs 🔗

@@ -1,5 +1,5 @@
 use action_log::ActionLog;
-use agent_client_protocol::{self as acp, ToolCallUpdateFields};
+use agent_client_protocol_core::schema::{self as acp, ToolCallUpdateFields};
 use anyhow::{Context as _, Result, anyhow};
 use futures::FutureExt as _;
 use gpui::{App, Entity, SharedString, Task};
@@ -347,7 +347,7 @@ impl AgentTool for ReadFileTool {
 #[cfg(test)]
 mod test {
     use super::*;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use fs::Fs as _;
     use gpui::{AppContext, TestAppContext, UpdateGlobal as _};
     use project::{FakeFs, Project};

crates/agent/src/tools/restore_file_from_disk_tool.rs 🔗

@@ -3,7 +3,7 @@ use super::tool_permissions::{
     canonicalize_worktree_roots, path_has_symlink_escape, resolve_project_path,
     sensitive_settings_kind,
 };
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use collections::FxHashSet;
 use futures::FutureExt as _;

crates/agent/src/tools/save_file_tool.rs 🔗

@@ -1,4 +1,4 @@
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use collections::FxHashSet;
 use futures::FutureExt as _;

crates/agent/src/tools/spawn_agent_tool.rs 🔗

@@ -1,5 +1,5 @@
 use acp_thread::{SUBAGENT_SESSION_INFO_META_KEY, SubagentSessionInfo};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::Result;
 use gpui::{App, SharedString, Task};
 use language_model::LanguageModelToolResultContent;

crates/agent/src/tools/streaming_edit_file_tool.rs 🔗

@@ -11,7 +11,7 @@ use crate::{
 };
 use acp_thread::Diff;
 use action_log::ActionLog;
-use agent_client_protocol::{self as acp, ToolCallLocation, ToolCallUpdateFields};
+use agent_client_protocol_core::schema::{self as acp, ToolCallLocation, ToolCallUpdateFields};
 use anyhow::{Context as _, Result};
 use collections::HashSet;
 use futures::FutureExt as _;

crates/agent/src/tools/terminal_tool.rs 🔗

@@ -1,4 +1,4 @@
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use anyhow::Result;
 use futures::FutureExt as _;

crates/agent/src/tools/update_plan_tool.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{AgentTool, ToolCallEventStream, ToolInput};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use gpui::{App, SharedString, Task};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};

crates/agent/src/tools/web_search_tool.rs 🔗

@@ -4,7 +4,7 @@ use crate::{
     AgentTool, ToolCallEventStream, ToolInput, ToolPermissionDecision,
     decide_permission_from_settings,
 };
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use anyhow::Result;
 use cloud_llm_client::WebSearchResponse;

crates/agent_servers/Cargo.toml 🔗

@@ -20,7 +20,7 @@ doctest = false
 acp_tools.workspace = true
 acp_thread.workspace = true
 action_log.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 anyhow.workspace = true
 async-trait.workspace = true
 chrono.workspace = true

crates/agent_servers/src/acp.rs 🔗

@@ -2,14 +2,15 @@ use acp_thread::{
     AgentConnection, AgentSessionInfo, AgentSessionList, AgentSessionListRequest,
     AgentSessionListResponse,
 };
-use acp_tools::AcpConnectionRegistry;
 use action_log::ActionLog;
-use agent_client_protocol::{self as acp, Agent as _, ErrorCode};
+use agent_client_protocol_core::schema::{self as acp, ErrorCode};
+use agent_client_protocol_core::{ByteStreams, ConnectionTo};
 use anyhow::anyhow;
 use collections::HashMap;
 use feature_flags::{AcpBetaFeatureFlag, FeatureFlagAppExt as _};
-use futures::AsyncBufReadExt as _;
+use futures::channel::mpsc;
 use futures::io::BufReader;
+use futures::{AsyncBufReadExt as _, StreamExt as _};
 use project::agent_server_store::AgentServerCommand;
 use project::{AgentId, Project};
 use serde::Deserialize;
@@ -40,10 +41,19 @@ pub const GEMINI_TERMINAL_AUTH_METHOD_ID: &str = "spawn-gemini-cli";
 #[error("Unsupported version")]
 pub struct UnsupportedVersion;
 
+/// Holds state needed by foreground work dispatched from background handler closures.
+struct ClientContext {
+    sessions: Rc<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(&notification.session_id)
-            .context("Failed to get session")?;
-
-        if let acp::SessionUpdate::CurrentModeUpdate(acp::CurrentModeUpdate {
-            current_mode_id,
-            ..
-        }) = &notification.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,
-            ..
-        }) = &notification.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(&notification.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, ..
+    }) = &notification.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) = &notification.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, ..
+    }) = &notification.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) = &notification.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();
 }

crates/agent_servers/src/agent_servers.rs 🔗

@@ -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,

crates/agent_servers/src/custom.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{AgentServer, AgentServerDelegate, load_proxy_env};
 use acp_thread::AgentConnection;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Context as _, Result};
 use collections::HashSet;
 use credentials_provider::CredentialsProvider;

crates/agent_servers/src/e2e_tests.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{AgentServer, AgentServerDelegate};
 use acp_thread::{AcpThread, AgentThreadEntry, ToolCall, ToolCallStatus};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use futures::{FutureExt, StreamExt, channel::mpsc, select};
 use gpui::AppContext;
 use gpui::{Entity, TestAppContext};
@@ -378,7 +378,7 @@ macro_rules! common_e2e_tests {
             async fn tool_call_with_permission(cx: &mut ::gpui::TestAppContext) {
                 $crate::e2e_tests::test_tool_call_with_permission(
                     $server,
-                    ::agent_client_protocol::PermissionOptionId::new($allow_option_id),
+                    ::agent_client_protocol_core::schema::PermissionOptionId::new($allow_option_id),
                     cx,
                 )
                 .await;

crates/agent_settings/Cargo.toml 🔗

@@ -12,7 +12,7 @@ workspace = true
 path = "src/agent_settings.rs"
 
 [dependencies]
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 anyhow.workspace = true
 collections.workspace = true
 convert_case.workspace = true

crates/agent_settings/src/agent_settings.rs 🔗

@@ -3,7 +3,7 @@ mod agent_profile;
 use std::path::{Component, Path};
 use std::sync::{Arc, LazyLock};
 
-use agent_client_protocol::ModelId;
+use agent_client_protocol_core::schema::ModelId;
 use collections::{HashSet, IndexMap};
 use fs::Fs;
 use gpui::{App, Pixels, px};

crates/agent_ui/Cargo.toml 🔗

@@ -28,7 +28,7 @@ unit-eval = []
 [dependencies]
 acp_thread.workspace = true
 action_log.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 agent.workspace = true
 agent_servers.workspace = true
 agent_settings.workspace = true

crates/agent_ui/src/agent_panel.rs 🔗

@@ -10,7 +10,7 @@ use std::{
 
 use acp_thread::{AcpThread, MentionUri, ThreadStatus};
 use agent::{ContextServerRegistry, SharedThread, ThreadStore};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_servers::AgentServer;
 use collections::HashSet;
 use db::kvp::{Dismissable, KeyValueStore};

crates/agent_ui/src/agent_ui.rs 🔗

@@ -39,7 +39,7 @@ use std::rc::Rc;
 use std::sync::Arc;
 
 use ::ui::IconName;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::{AgentProfileId, AgentSettings};
 use command_palette_hooks::CommandPaletteFilter;
 use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt as _};
@@ -232,7 +232,7 @@ pub struct NewExternalAgentThread {
 #[action(namespace = agent)]
 #[serde(deny_unknown_fields)]
 pub struct NewNativeAgentThreadFromSummary {
-    from_session_id: agent_client_protocol::SessionId,
+    from_session_id: agent_client_protocol_core::schema::SessionId,
 }
 
 #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
@@ -317,7 +317,7 @@ pub enum AgentInitialContent {
         title: Option<SharedString>,
     },
     ContentBlock {
-        blocks: Vec<agent_client_protocol::ContentBlock>,
+        blocks: Vec<agent_client_protocol_core::schema::ContentBlock>,
         auto_submit: bool,
     },
     FromExternalSource(ExternalSourcePrompt),

crates/agent_ui/src/completion_provider.rs 🔗

@@ -7,7 +7,7 @@ use std::sync::atomic::AtomicBool;
 use crate::DEFAULT_THREAD_TITLE;
 use crate::ThreadHistory;
 use acp_thread::MentionUri;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::Result;
 use editor::{CompletionProvider, Editor, code_context_menus::COMPLETION_MENU_MAX_WIDTH};
 use futures::FutureExt as _;

crates/agent_ui/src/config_options.rs 🔗

@@ -1,7 +1,7 @@
 use std::{cmp::Reverse, rc::Rc, sync::Arc};
 
 use acp_thread::AgentSessionConfigOptions;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_servers::AgentServer;
 use agent_settings::AgentSettings;
 use collections::HashSet;

crates/agent_ui/src/conversation_view.rs 🔗

@@ -7,7 +7,7 @@ use acp_thread::{
 use acp_thread::{AgentConnection, Plan};
 use action_log::{ActionLog, ActionLogTelemetry, DiffStats};
 use agent::{NativeAgentServer, NativeAgentSessionList, SharedThread, ThreadStore};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 #[cfg(test)]
 use agent_servers::AgentServerDelegate;
 use agent_servers::{AgentServer, GEMINI_TERMINAL_AUTH_METHOD_ID};
@@ -2750,7 +2750,7 @@ pub(crate) mod tests {
     };
     use action_log::ActionLog;
     use agent::{AgentTool, EditFileTool, FetchTool, TerminalTool, ToolPermissionContext};
-    use agent_client_protocol::SessionId;
+    use agent_client_protocol_core::schema::SessionId;
     use editor::MultiBufferOffset;
     use fs::FakeFs;
     use gpui::{EventEmitter, TestAppContext, VisualTestContext};

crates/agent_ui/src/conversation_view/thread_view.rs 🔗

@@ -249,12 +249,13 @@ pub struct ThreadView {
     pub session_capabilities: SharedSessionCapabilities,
     /// Tracks which tool calls have their content/output expanded.
     /// Used for showing/hiding tool call results, terminal output, etc.
-    pub expanded_tool_calls: HashSet<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<()>>,

crates/agent_ui/src/entry_view_state.rs 🔗

@@ -3,7 +3,7 @@ use std::ops::Range;
 use super::thread_history::ThreadHistory;
 use acp_thread::{AcpThread, AgentThreadEntry};
 use agent::ThreadStore;
-use agent_client_protocol::ToolCallId;
+use agent_client_protocol_core::schema::ToolCallId;
 use collections::HashMap;
 use editor::{Editor, EditorEvent, EditorMode, MinimapVisibility, SizingBehavior};
 use gpui::{
@@ -465,7 +465,7 @@ mod tests {
     use std::sync::Arc;
 
     use acp_thread::{AgentConnection, StubAgentConnection};
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
     use editor::RowInfo;
     use fs::FakeFs;

crates/agent_ui/src/mention_set.rs 🔗

@@ -1,7 +1,7 @@
 use crate::diagnostics::{DiagnosticsOptions, codeblock_fence_for_path, collect_diagnostics};
 use acp_thread::{MentionUri, selection_name};
 use agent::{ThreadStore, outline};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_servers::{AgentServer, AgentServerDelegate};
 use anyhow::{Context as _, Result, anyhow};
 use collections::{HashMap, HashSet};

crates/agent_ui/src/message_editor.rs 🔗

@@ -11,7 +11,7 @@ use crate::{
 };
 use acp_thread::MentionUri;
 use agent::ThreadStore;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Result, anyhow};
 use editor::{
     Addon, AnchorRangeExt, ContextMenuOptions, Editor, EditorElement, EditorEvent, EditorMode,
@@ -1905,7 +1905,7 @@ mod tests {
 
     use acp_thread::MentionUri;
     use agent::{ThreadStore, outline};
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use base64::Engine as _;
     use editor::{
         AnchorRangeExt as _, Editor, EditorMode, MultiBufferOffset, SelectionEffects,

crates/agent_ui/src/mode_selector.rs 🔗

@@ -1,5 +1,5 @@
 use acp_thread::AgentSessionModes;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_servers::AgentServer;
 use agent_settings::AgentSettings;
 use fs::Fs;

crates/agent_ui/src/model_selector.rs 🔗

@@ -1,7 +1,7 @@
 use std::{cmp::Reverse, rc::Rc, sync::Arc};
 
 use acp_thread::{AgentModelIcon, AgentModelInfo, AgentModelList, AgentModelSelector};
-use agent_client_protocol::ModelId;
+use agent_client_protocol_core::schema::ModelId;
 use agent_servers::AgentServer;
 use agent_settings::AgentSettings;
 use anyhow::Result;
@@ -533,7 +533,7 @@ async fn fuzzy_search(
 
 #[cfg(test)]
 mod tests {
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use gpui::TestAppContext;
 
     use super::*;

crates/agent_ui/src/test_support.rs 🔗

@@ -1,5 +1,5 @@
 use acp_thread::{AgentConnection, StubAgentConnection};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_servers::{AgentServer, AgentServerDelegate};
 use gpui::{Entity, Task, TestAppContext, VisualTestContext};
 use project::AgentId;

crates/agent_ui/src/thread_history.rs 🔗

@@ -1,5 +1,5 @@
 use acp_thread::{AgentSessionInfo, AgentSessionList, AgentSessionListRequest, SessionListUpdate};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use gpui::{App, Task};
 use std::rc::Rc;
 use ui::prelude::*;

crates/agent_ui/src/thread_import.rs 🔗

@@ -1,6 +1,6 @@
 use acp_thread::AgentSessionListRequest;
 use agent::ThreadStore;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use chrono::Utc;
 use collections::HashSet;
 use db::kvp::Dismissable;

crates/agent_ui/src/thread_metadata_store.rs 🔗

@@ -2,7 +2,7 @@ use std::{path::Path, sync::Arc};
 
 use acp_thread::AcpThreadEvent;
 use agent::{ThreadStore, ZED_AGENT_ID};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::Context as _;
 use chrono::{DateTime, Utc};
 use collections::{HashMap, HashSet};
@@ -791,7 +791,7 @@ mod tests {
     use acp_thread::{AgentConnection, StubAgentConnection};
     use action_log::ActionLog;
     use agent::DbThread;
-    use agent_client_protocol as acp;
+    use agent_client_protocol_core::schema as acp;
     use feature_flags::FeatureFlagAppExt;
     use gpui::TestAppContext;
     use project::FakeFs;

crates/agent_ui/src/threads_archive_view.rs 🔗

@@ -7,7 +7,7 @@ use crate::thread_metadata_store::{ThreadMetadata, ThreadMetadataStore};
 use crate::{Agent, RemoveSelectedThread};
 
 use agent::ThreadStore;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use chrono::{DateTime, Datelike as _, Local, NaiveDate, TimeDelta, Utc};
 use editor::Editor;

crates/agent_ui/src/ui/mention_crease.rs 🔗

@@ -1,7 +1,7 @@
 use std::{ops::RangeInclusive, path::PathBuf, time::Duration};
 
 use acp_thread::MentionUri;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use editor::{Editor, SelectionEffects, scroll::Autoscroll};
 use gpui::{
     Animation, AnimationExt, AnyView, Context, IntoElement, WeakEntity, Window, pulsating_between,

crates/eval_cli/Cargo.toml 🔗

@@ -15,7 +15,7 @@ path = "src/main.rs"
 [dependencies]
 acp_thread.workspace = true
 agent.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 agent_ui.workspace = true
 anyhow.workspace = true
 clap.workspace = true

crates/eval_cli/src/main.rs 🔗

@@ -40,7 +40,7 @@ use std::time::{Duration, Instant};
 
 use acp_thread::AgentConnection as _;
 use agent::{NativeAgent, NativeAgentConnection, Templates, ThreadStore};
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use anyhow::{Context, Result};
 use clap::Parser;
 use feature_flags::FeatureFlagAppExt as _;

crates/sidebar/Cargo.toml 🔗

@@ -18,7 +18,7 @@ default = []
 acp_thread.workspace = true
 action_log.workspace = true
 agent.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 agent_settings.workspace = true
 agent_ui = { workspace = true, features = ["audio"] }
 anyhow.workspace = true

crates/sidebar/src/sidebar.rs 🔗

@@ -2,7 +2,7 @@ mod thread_switcher;
 
 use acp_thread::ThreadStatus;
 use action_log::DiffStats;
-use agent_client_protocol::{self as acp};
+use agent_client_protocol_core::schema as acp;
 use agent_settings::AgentSettings;
 use agent_ui::thread_metadata_store::{ThreadMetadata, ThreadMetadataStore};
 use agent_ui::threads_archive_view::{

crates/sidebar/src/thread_switcher.rs 🔗

@@ -1,5 +1,5 @@
 use action_log::DiffStats;
-use agent_client_protocol as acp;
+use agent_client_protocol_core::schema as acp;
 use agent_ui::thread_metadata_store::ThreadMetadata;
 use gpui::{
     Action as _, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Modifiers,

crates/zed/Cargo.toml 🔗

@@ -66,7 +66,7 @@ required-features = ["visual-tests"]
 acp_tools.workspace = true
 activity_indicator.workspace = true
 agent.workspace = true
-agent-client-protocol.workspace = true
+agent-client-protocol-core.workspace = true
 agent_settings.workspace = true
 agent_ui = { workspace = true, features = ["audio"] }
 anyhow.workspace = true

crates/zed/src/main.rs 🔗

@@ -5,7 +5,6 @@ mod reliability;
 mod zed;
 
 use agent::{SharedThread, ThreadStore};
-use agent_client_protocol;
 use agent_ui::AgentPanel;
 use anyhow::{Context as _, Error, Result};
 use clap::Parser;
@@ -978,7 +977,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<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();
 

crates/zed/src/visual_test_runner.rs 🔗

@@ -95,7 +95,7 @@ fn main() {
 #[cfg(target_os = "macos")]
 use {
     acp_thread::{AgentConnection, StubAgentConnection},
-    agent_client_protocol as acp,
+    agent_client_protocol_core::schema as acp,
     agent_servers::{AgentServer, AgentServerDelegate},
     anyhow::{Context as _, Result},
     assets::Assets,