diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs index 2760b29446..f420a0d989 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs @@ -14,7 +14,7 @@ use sha2::{Digest, Sha256}; use crate::acpx_provider_session::{ AcpxPermissionMode, AcpxProviderRuntimePolicy, AcpxProviderSession, AcpxProviderSessionConfig, - AcpxProviderSessionIdentity, AcpxTurnControlCapabilities, + AcpxProviderSessionIdentity, AcpxTurnControlCapabilities, CursorMode, }; use crate::acpx_sidecar_transport::AcpxSidecarTransportConfig; #[cfg(test)] @@ -135,6 +135,8 @@ struct AcpxProviderDescriptor { #[serde(default)] instructions: String, permission_mode: AcpxPermissionMode, + #[serde(default, skip_serializing_if = "Option::is_none")] + cursor_mode: Option, permission_mode_pinned: bool, #[serde(default)] provider_policy: Option, @@ -213,7 +215,7 @@ impl AcpxProviderDescriptor { "2026.09.26-dd393fe", None, None, - "sha256:b1440d559ebc4eef5c7a582f1c81fc153270cfbafa1731a8ee76d83713bdf61b", + "sha256:aa8c0b2b84786982bcd06b7634bf95be6f2bc42bb8def48a8751dc50cf739b6b", ), "copilot" => ( self.model.as_str(), @@ -246,6 +248,7 @@ impl AcpxProviderDescriptor { || self.model.trim().is_empty() || self.model.len() > 240 || self.model.contains('\0') + || ((self.agent == "cursor") != self.cursor_mode.is_some()) || (matches!(self.agent.as_str(), "pi" | "cursor" | "copilot") && self.provider_policy.is_none()) || self.agent_server_package != expected.1 @@ -341,6 +344,7 @@ impl AcpxProviderDescriptor { normalized_session_id: self.normalized_session_id.clone(), working_directory: PathBuf::from(&self.cwd), permission_mode: self.permission_mode, + cursor_mode: self.cursor_mode, permission_mode_pinned: self.permission_mode_pinned, provider_policy: self.provider_policy.clone(), system_instructions: self.instructions.clone(), @@ -424,7 +428,7 @@ impl AcpxProviderDescriptor { } fn public_descriptor(&self, identity: Option<&AcpxProviderSessionIdentity>) -> Value { - json!({ + let mut descriptor = json!({ "provider": "acpx", "driver": "acpx_runtime", "providerVersion": self.provider_version, @@ -440,7 +444,11 @@ impl AcpxProviderDescriptor { "providerSessionId": identity.map(|value| value.agent_session_id.as_str()), "acpxRecordId": identity.map(|value| value.acpx_record_id.as_str()), "permissionMode": self.permission_mode, - }) + }); + if let Some(mode) = self.cursor_mode { + descriptor["cursorMode"] = json!(mode); + } + descriptor } } @@ -570,9 +578,11 @@ impl AcpxDurableState { identity .validate() .map_err(|error| DurableRunnerError::invalid(error.to_string()))?; - if identity.profile_digest != self.descriptor.command_digest { + if identity.profile_digest != self.descriptor.command_digest + || identity.cursor_mode != self.descriptor.cursor_mode + { return Err(DurableRunnerError::invalid( - "ACPX durable identity no longer matches its qualified profile digest", + "ACPX durable identity no longer matches its qualified profile or Cursor mode", )); } } @@ -2510,6 +2520,7 @@ mod tests { requested_model: descriptor.model.clone(), effective_model: descriptor.model.clone(), permission_mode: Some(descriptor.permission_mode), + cursor_mode: descriptor.cursor_mode, provider_lifetime_fence_candidates: [60_001, 60_002, 60_003], }; let operations = Vec::new(); @@ -2759,6 +2770,7 @@ mod tests { requested_model: "gpt-5.6-sol".to_owned(), effective_model: "gpt-5.6-sol".to_owned(), permission_mode: Some(AcpxPermissionMode::ApproveReads), + cursor_mode: None, provider_lifetime_fence_candidates: [60_001, 60_002, 60_003], }; @@ -2782,7 +2794,7 @@ mod tests { "cursor", "cursor-agent", "2026.09.26-dd393fe", - "sha256:b1440d559ebc4eef5c7a582f1c81fc153270cfbafa1731a8ee76d83713bdf61b", + "sha256:aa8c0b2b84786982bcd06b7634bf95be6f2bc42bb8def48a8751dc50cf739b6b", None, None, "explicit-model", @@ -2817,14 +2829,42 @@ mod tests { let missing: AcpxProviderDescriptor = serde_json::from_value(value.clone()).unwrap(); assert!(missing.validate(&context()).is_err()); value["providerPolicy"] = json!({"readOnly":true}); + if agent == "cursor" { + value["cursorMode"] = json!("agent"); + } let valid: AcpxProviderDescriptor = serde_json::from_value(value.clone()).unwrap(); valid.validate(&context()).unwrap(); + if agent == "cursor" { + assert_eq!(valid.public_descriptor(None)["cursorMode"], json!("agent")); + let mut previous_v4 = value.clone(); + previous_v4["commandDigest"] = json!( + "sha256:b1440d559ebc4eef5c7a582f1c81fc153270cfbafa1731a8ee76d83713bdf61b" + ); + let previous_v4: AcpxProviderDescriptor = + serde_json::from_value(previous_v4).unwrap(); + assert!(previous_v4.validate(&context()).is_err()); + let mut missing = value.clone(); + missing.as_object_mut().unwrap().remove("cursorMode"); + let missing: AcpxProviderDescriptor = serde_json::from_value(missing).unwrap(); + assert!(missing.validate(&context()).is_err()); + let mut unknown = value.clone(); + unknown["cursorMode"] = json!("autopilot"); + assert!(serde_json::from_value::(unknown).is_err()); + } else { + assert!(valid.public_descriptor(None).get("cursorMode").is_none()); + let mut wrong_agent = value.clone(); + wrong_agent["cursorMode"] = json!("plan"); + let wrong_agent: AcpxProviderDescriptor = + serde_json::from_value(wrong_agent).unwrap(); + assert!(wrong_agent.validate(&context()).is_err()); + } if agent == "copilot" { let mut previous_v4 = value.clone(); previous_v4["commandDigest"] = json!( "sha256:a119e436b4ad13ee70e1f58bedad4a0f20761b5fd982b752981f0cb1bc65f797" ); - let previous_v4: AcpxProviderDescriptor = serde_json::from_value(previous_v4).unwrap(); + let previous_v4: AcpxProviderDescriptor = + serde_json::from_value(previous_v4).unwrap(); assert!(previous_v4.validate(&context()).is_err()); let mut legacy = value.clone(); legacy["commandDigest"] = json!( @@ -2979,6 +3019,7 @@ mod tests { requested_model: original_descriptor.model.clone(), effective_model: original_descriptor.model.clone(), permission_mode: Some(original_descriptor.permission_mode), + cursor_mode: original_descriptor.cursor_mode, provider_lifetime_fence_candidates: [60_001, 60_002, 60_003], }; let operations = Vec::new(); @@ -3305,6 +3346,7 @@ mod tests { requested_model: descriptor.model.clone(), effective_model: descriptor.model.clone(), permission_mode: Some(descriptor.permission_mode), + cursor_mode: descriptor.cursor_mode, provider_lifetime_fence_candidates, }; let operations = Vec::new(); @@ -3476,6 +3518,7 @@ mod tests { requested_model: provider_descriptor.model.clone(), effective_model: provider_descriptor.model.clone(), permission_mode: Some(provider_descriptor.permission_mode), + cursor_mode: provider_descriptor.cursor_mode, provider_lifetime_fence_candidates, }); state.provider_exit_unconfirmed = true; diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_checkpoint.rs b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_checkpoint.rs index 0e4c332ce3..ac9cdd83f7 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_checkpoint.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_checkpoint.rs @@ -10,7 +10,7 @@ use std::os::unix::fs::DirBuilderExt; use serde::{Deserialize, Serialize}; use crate::acpx_provider_session::{ - AcpxPermissionMode, AcpxProviderSessionConfig, AcpxProviderSessionIdentity, + AcpxPermissionMode, AcpxProviderSessionConfig, AcpxProviderSessionIdentity, CursorMode, }; use crate::durable::{ create_private_temporary_file, open_private_regular_file, verify_private_directory, @@ -48,6 +48,8 @@ struct PersistedAcpxProviderSessionIdentity { requested_model: String, effective_model: String, permission_mode: AcpxPermissionMode, + #[serde(default, skip_serializing_if = "Option::is_none")] + cursor_mode: Option, provider_lifetime_fence_candidates: [u16; 3], } @@ -70,6 +72,7 @@ impl PersistedAcpxProviderSessionIdentity { requested_model: identity.requested_model, effective_model: identity.effective_model, permission_mode, + cursor_mode: identity.cursor_mode, provider_lifetime_fence_candidates: identity.provider_lifetime_fence_candidates, }) } @@ -86,6 +89,7 @@ impl PersistedAcpxProviderSessionIdentity { requested_model: self.requested_model.clone(), effective_model: self.effective_model.clone(), permission_mode: Some(self.permission_mode), + cursor_mode: self.cursor_mode, provider_lifetime_fence_candidates: self.provider_lifetime_fence_candidates, } } @@ -106,6 +110,7 @@ impl AcpxSuspensionCheckpoint { || identity.requested_model != config.model || identity.effective_model != config.model || identity.permission_mode != Some(config.permission_mode) + || identity.cursor_mode != config.cursor_mode || config .expected_identity .as_ref() diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_session.rs b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_session.rs index c92f044940..9958237a0d 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_session.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_session.rs @@ -34,6 +34,14 @@ pub enum AcpxPermissionMode { DenyAll, } +#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum CursorMode { + Agent, + Plan, + Ask, +} + #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct AcpxProviderSessionIdentity { @@ -48,6 +56,8 @@ pub struct AcpxProviderSessionIdentity { pub effective_model: String, #[serde(default)] pub permission_mode: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cursor_mode: Option, pub provider_lifetime_fence_candidates: [u16; 3], } @@ -68,6 +78,7 @@ pub struct AcpxProviderSessionConfig { pub normalized_session_id: String, pub working_directory: PathBuf, pub permission_mode: AcpxPermissionMode, + pub cursor_mode: Option, pub permission_mode_pinned: bool, pub provider_policy: Option, pub system_instructions: String, @@ -98,6 +109,11 @@ impl AcpxProviderSessionConfig { ))); } validate_text(&self.model, MAX_MODEL_CHARS, "ACPX model")?; + if (self.agent == "cursor") != self.cursor_mode.is_some() { + return Err(LocalRunnerError::invalid( + "ACPX Cursor mode must be explicit for Cursor and absent for other agents", + )); + } if matches!(self.agent.as_str(), "pi" | "cursor" | "copilot") && self.provider_policy.is_none() { @@ -169,6 +185,7 @@ impl AcpxProviderSessionConfig { || expected_identity.requested_model != self.model || expected_identity.effective_model != self.model || expected_identity.permission_mode != Some(self.permission_mode) + || expected_identity.cursor_mode != self.cursor_mode { return Err(LocalRunnerError::invalid( "ACPX expected identity conflicts with the requested session", @@ -1188,6 +1205,27 @@ impl Drop for AcpxProviderSession { } } +fn session_open_params(config: &AcpxProviderSessionConfig, sidecar_tools: &[Value]) -> Value { + let mut params = json!({ + "runtimeDirectory": config.runtime_directory, + "normalizedSessionId": config.normalized_session_id, + "workingDirectory": config.working_directory, + "agent": config.agent, + "model": config.model, + "permissionMode": config.permission_mode, + "permissionModePinned": config.permission_mode_pinned, + "providerPolicy": config.provider_policy, + "systemInstructions": config.system_instructions, + "runtimeContext": config.runtime_context, + "tools": &sidecar_tools, + "expectedIdentity": config.expected_identity, + }); + if let Some(mode) = config.cursor_mode { + params["cursorMode"] = json!(mode); + } + params +} + fn bootstrap( transport: &mut AcpxSidecarTransport, config: &AcpxProviderSessionConfig, @@ -1208,20 +1246,7 @@ fn bootstrap( let opened = transport.request( GeneratedAcpxSidecarCommand::SessionOpen, - json!({ - "runtimeDirectory": config.runtime_directory, - "normalizedSessionId": config.normalized_session_id, - "workingDirectory": config.working_directory, - "agent": config.agent, - "model": config.model, - "permissionMode": config.permission_mode, - "permissionModePinned": config.permission_mode_pinned, - "providerPolicy": config.provider_policy, - "systemInstructions": config.system_instructions, - "runtimeContext": config.runtime_context, - "tools": &sidecar_tools, - "expectedIdentity": config.expected_identity, - }), + session_open_params(config, &sidecar_tools), )?; let identity = verify_open_response(&opened, transport.process_id(), config)?; let turn_controls = verified_turn_controls(opened.get("turnControls"), &config.agent)?; @@ -1307,6 +1332,7 @@ fn verify_open_response( || identity.requested_model != config.model || identity.effective_model != config.model || identity.permission_mode != Some(config.permission_mode) + || identity.cursor_mode != config.cursor_mode || config .expected_identity .as_ref() @@ -1529,3 +1555,142 @@ mod permission_mode_tests { ); } } + +#[cfg(test)] +mod cursor_mode_tests { + use super::*; + + fn config() -> AcpxProviderSessionConfig { + let operations = Vec::new(); + AcpxProviderSessionConfig { + transport: AcpxSidecarTransportConfig { + command: std::env::current_exe().unwrap(), + args: Vec::new(), + verified_launch: None, + request_timeout: Duration::from_secs(1), + shutdown_grace: Duration::from_millis(100), + }, + agent: "cursor".to_owned(), + model: "explicit-model".to_owned(), + run_id: "run-1".to_owned(), + catalog_revision: 1, + runtime_directory: std::env::temp_dir(), + normalized_session_id: "session-1".to_owned(), + working_directory: std::env::temp_dir(), + permission_mode: AcpxPermissionMode::ApproveReads, + cursor_mode: Some(CursorMode::Plan), + permission_mode_pinned: true, + provider_policy: Some(AcpxProviderRuntimePolicy { read_only: false }), + system_instructions: String::new(), + runtime_context: Value::Null, + tool_set: AuthorizedToolSet { + schema: TOOL_SET_SCHEMA.to_owned(), + schema_version: 1, + catalog_digest: authorized_tool_catalog_digest(&operations).unwrap(), + operations, + }, + expected_identity: None, + } + } + fn identity() -> AcpxProviderSessionIdentity { + AcpxProviderSessionIdentity { + kind: "acpx".to_owned(), + normalized_session_id: "session-1".to_owned(), + acpx_record_id: "record-1".to_owned(), + backend_session_id: "backend-1".to_owned(), + agent_session_id: "agent-1".to_owned(), + profile_digest: format!("sha256:{}", "1".repeat(64)), + workspace_digest: format!("sha256:{}", "2".repeat(64)), + requested_model: "explicit-model".to_owned(), + effective_model: "explicit-model".to_owned(), + permission_mode: Some(AcpxPermissionMode::ApproveReads), + cursor_mode: Some(CursorMode::Plan), + provider_lifetime_fence_candidates: [60_001, 60_002, 60_003], + } + } + #[test] + fn cursor_mode_is_closed_and_not_defaulted_in_rust() { + for (name, mode) in [ + ("agent", CursorMode::Agent), + ("plan", CursorMode::Plan), + ("ask", CursorMode::Ask), + ] { + assert_eq!( + serde_json::from_value::(json!(name)).unwrap(), + mode + ); + assert_eq!(serde_json::to_value(mode).unwrap(), json!(name)); + } + for value in [json!("Agent"), json!("autopilot"), json!(null), json!(1)] { + assert!(serde_json::from_value::(value).is_err()); + } + let mut config = config(); + config.validate().unwrap(); + config.cursor_mode = None; + assert!(config.validate().is_err()); + config.agent = "copilot".to_owned(); + config.cursor_mode = Some(CursorMode::Agent); + assert!(config.validate().is_err()); + config.cursor_mode = None; + config.validate().unwrap(); + } + #[test] + fn open_wire_and_identity_bind_exact_cursor_mode() { + let mut config = config(); + for mode in [CursorMode::Agent, CursorMode::Plan, CursorMode::Ask] { + config.cursor_mode = Some(mode); + assert_eq!(session_open_params(&config, &[])["cursorMode"], json!(mode)); + let mut identity = identity(); + identity.cursor_mode = Some(mode); + let response = json!({"sidecarPid": 100, "status": {}, "identity": identity}); + assert_eq!( + verify_open_response(&response, 100, &config) + .unwrap() + .cursor_mode, + Some(mode) + ); + for wrong in [ + None, + Some(CursorMode::Agent), + Some(CursorMode::Plan), + Some(CursorMode::Ask), + ] { + if wrong == Some(mode) { + continue; + } + let mut changed = response.clone(); + changed["identity"]["cursorMode"] = json!(wrong); + assert!(verify_open_response(&changed, 100, &config).is_err()); + } + } + config.agent = "copilot".to_owned(); + config.cursor_mode = None; + assert!(session_open_params(&config, &[]) + .get("cursorMode") + .is_none()); + let mut other = identity(); + other.cursor_mode = None; + assert!(serde_json::to_value(&other) + .unwrap() + .get("cursorMode") + .is_none()); + let response = json!({"sidecarPid": 100, "status": {}, "identity": other}); + verify_open_response(&response, 100, &config).unwrap(); + } + #[test] + fn warm_reopen_and_suspension_reject_mode_changes() { + let mut config = config(); + let identity = identity(); + config.expected_identity = Some(identity.clone()); + config.validate().unwrap(); + config.cursor_mode = Some(CursorMode::Ask); + assert!(config.validate().is_err()); + let mut changed = identity.clone(); + changed.cursor_mode = Some(CursorMode::Agent); + assert!(verify_suspend_response( + &json!({"suspended": true, "identity": changed}), + &identity + ) + .is_err()); + } +} diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_checkpoint.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_checkpoint.rs index f00049620d..a1886bd720 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_checkpoint.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_checkpoint.rs @@ -50,6 +50,7 @@ fn config(directory: &std::path::Path) -> AcpxProviderSessionConfig { normalized_session_id: "session-1".to_owned(), working_directory: directory.to_owned(), permission_mode: AcpxPermissionMode::ApproveReads, + cursor_mode: None, permission_mode_pinned: true, provider_policy: None, system_instructions: "Complete the supplied task.".to_owned(), @@ -76,6 +77,7 @@ fn identity() -> AcpxProviderSessionIdentity { requested_model: "gpt-5.6-sol".to_owned(), effective_model: "gpt-5.6-sol".to_owned(), permission_mode: Some(AcpxPermissionMode::ApproveReads), + cursor_mode: None, provider_lifetime_fence_candidates: [60_001, 60_002, 60_003], } } @@ -257,3 +259,34 @@ fn rejects_an_existing_runner_state_directory_that_is_not_private() { ); fs::remove_dir_all(directory).unwrap(); } + +#[test] +fn cursor_mode_round_trips_checkpoint_and_rejects_changed_or_missing_recovery_mode() { + use paperclip_runner_core::acpx_provider_session::{AcpxProviderRuntimePolicy, CursorMode}; + let directory = temporary_directory("cursor-mode"); + let mut config = config(&directory); + config.agent = "cursor".to_owned(); + config.cursor_mode = Some(CursorMode::Plan); + config.provider_policy = Some(AcpxProviderRuntimePolicy { read_only: false }); + let mut identity = identity(); + identity.cursor_mode = Some(CursorMode::Plan); + let checkpoint = AcpxSuspensionCheckpoint::from_suspension(&config, identity.clone()).unwrap(); + let wire = serde_json::to_value(&checkpoint).unwrap(); + assert_eq!(wire["identity"]["cursorMode"], json!("plan")); + let recovered: AcpxSuspensionCheckpoint = serde_json::from_value(wire.clone()).unwrap(); + assert_eq!(recovered.admit_recovery(&config).unwrap(), identity); + for mode in [None, Some(CursorMode::Agent), Some(CursorMode::Ask)] { + let mut changed = config.clone(); + changed.cursor_mode = mode; + assert!(recovered.admit_recovery(&changed).is_err()); + let mut changed = wire.clone(); + changed["identity"]["cursorMode"] = json!(mode); + let changed: AcpxSuspensionCheckpoint = serde_json::from_value(changed).unwrap(); + assert!(changed.admit_recovery(&config).is_err()); + } + let mut other = config.clone(); + other.agent = "copilot".to_owned(); + other.cursor_mode = None; + assert!(recovered.admit_recovery(&other).is_err()); + fs::remove_dir_all(directory).unwrap(); +} diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_resolutions.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_resolutions.rs index 89e4cdee12..9028e29798 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_resolutions.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_resolutions.rs @@ -49,6 +49,7 @@ fn config(mode: &str) -> AcpxProviderSessionConfig { normalized_session_id: "session-1".to_owned(), working_directory: std::env::temp_dir(), permission_mode: AcpxPermissionMode::ApproveReads, + cursor_mode: None, permission_mode_pinned: true, provider_policy: None, system_instructions: "Complete the supplied task.".to_owned(), diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_session.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_session.rs index c9b9ce5933..6a7cfe27a1 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_session.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_session.rs @@ -44,6 +44,7 @@ fn config(mode: &str) -> AcpxProviderSessionConfig { normalized_session_id: "session-1".to_owned(), working_directory: std::env::temp_dir(), permission_mode: AcpxPermissionMode::ApproveReads, + cursor_mode: None, permission_mode_pinned: true, provider_policy: None, system_instructions: "Complete the supplied task.".to_owned(), @@ -65,6 +66,7 @@ fn expected_identity() -> AcpxProviderSessionIdentity { requested_model: "gpt-5.6-sol".to_owned(), effective_model: "gpt-5.6-sol".to_owned(), permission_mode: Some(AcpxPermissionMode::ApproveReads), + cursor_mode: None, provider_lifetime_fence_candidates: [60_001, 60_002, 60_003], } } diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_suspend.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_suspend.rs index eebd2e237f..809c08808c 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_suspend.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_suspend.rs @@ -25,6 +25,7 @@ fn config(mode: &str) -> AcpxProviderSessionConfig { normalized_session_id: "session-1".to_owned(), working_directory: std::env::temp_dir(), permission_mode: AcpxPermissionMode::ApproveReads, + cursor_mode: None, permission_mode_pinned: true, provider_policy: None, system_instructions: "Complete the supplied task.".to_owned(), diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_turns.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_turns.rs index f2897a5415..a3b94bc898 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_turns.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/acpx_provider_turns.rs @@ -54,6 +54,7 @@ fn config(mode: &str) -> AcpxProviderSessionConfig { normalized_session_id: "session-1".to_owned(), working_directory: std::env::temp_dir(), permission_mode: AcpxPermissionMode::ApproveReads, + cursor_mode: None, permission_mode_pinned: true, provider_policy: if mode.starts_with("controls") { Some(