worker: add workspace workdir management feature

This commit is contained in:
2026-08-04 19:28:59 +09:00
parent e6a2da548f
commit da90ac74b4
9 changed files with 821 additions and 10 deletions
+24
View File
@@ -87,6 +87,8 @@ pub struct FeatureConfigPartial {
#[serde(default)]
pub objective: Option<FeatureFlagConfigPartial>,
#[serde(default)]
pub manage_workdir: Option<FeatureFlagConfigPartial>,
#[serde(default)]
pub ticket: Option<TicketFeatureConfigPartial>,
#[serde(default)]
pub plugins: Option<FeatureFlagConfigPartial>,
@@ -104,6 +106,11 @@ impl FeatureConfigPartial {
other.objective,
FeatureFlagConfigPartial::merge,
),
manage_workdir: merge_option(
self.manage_workdir,
other.manage_workdir,
FeatureFlagConfigPartial::merge,
),
ticket: merge_option(self.ticket, other.ticket, TicketFeatureConfigPartial::merge),
plugins: merge_option(self.plugins, other.plugins, FeatureFlagConfigPartial::merge),
}
@@ -180,6 +187,10 @@ impl From<FeatureConfigPartial> for FeatureConfig {
.objective
.map(FeatureFlagConfig::from)
.unwrap_or_default(),
manage_workdir: value
.manage_workdir
.map(FeatureFlagConfig::from)
.unwrap_or_default(),
ticket: value
.ticket
.map(TicketFeatureConfig::from)
@@ -258,6 +269,7 @@ impl From<FeatureConfig> for FeatureConfigPartial {
web: Some(value.web.into()),
workers: Some(value.workers.into()),
objective: Some(value.objective.into()),
manage_workdir: Some(value.manage_workdir.into()),
ticket: Some(value.ticket.into()),
plugins: Some(value.plugins.into()),
}
@@ -1804,6 +1816,7 @@ worker_max_turns = 7
assert!(!manifest.feature.web.enabled);
assert!(!manifest.feature.workers.enabled);
assert!(!manifest.feature.objective.enabled);
assert!(!manifest.feature.manage_workdir.enabled);
assert!(!manifest.feature.ticket.enabled);
}
@@ -1814,6 +1827,9 @@ worker_max_turns = 7
[feature.task]
enabled = true
[feature.manage_workdir]
enabled = true
[feature.ticket]
enabled = true
authoring = false
@@ -1848,6 +1864,7 @@ orchestration_control = false
.try_into()
.unwrap();
assert!(manifest.feature.task.enabled);
assert!(manifest.feature.manage_workdir.enabled);
assert!(manifest.feature.ticket.enabled);
assert!(!manifest.feature.ticket.authoring);
assert!(!manifest.feature.ticket.thread);
@@ -1865,6 +1882,9 @@ orchestration_control = false
[feature.memory]
enabled = true
[feature.manage_workdir]
enabled = false
[feature.ticket]
enabled = true
authoring = false
@@ -1883,6 +1903,9 @@ orchestration_control = true
[feature.memory]
staging = true
[feature.manage_workdir]
enabled = true
[feature.objective]
enabled = true
@@ -1918,6 +1941,7 @@ enabled = true
.unwrap();
assert!(manifest.feature.memory.enabled);
assert!(manifest.feature.memory.staging);
assert!(manifest.feature.manage_workdir.enabled);
assert!(manifest.feature.ticket.enabled);
assert!(!manifest.feature.ticket.authoring);
assert!(manifest.feature.ticket.thread);
+3
View File
@@ -115,6 +115,8 @@ pub struct FeatureConfig {
#[serde(default)]
pub objective: FeatureFlagConfig,
#[serde(default)]
pub manage_workdir: FeatureFlagConfig,
#[serde(default)]
pub ticket: TicketFeatureConfig,
#[serde(default)]
pub plugins: FeatureFlagConfig,
@@ -128,6 +130,7 @@ impl Default for FeatureConfig {
web: FeatureFlagConfig::disabled(),
workers: FeatureFlagConfig::disabled(),
objective: FeatureFlagConfig::disabled(),
manage_workdir: FeatureFlagConfig::disabled(),
ticket: TicketFeatureConfig::default(),
plugins: FeatureFlagConfig::disabled(),
}
+5
View File
@@ -998,6 +998,7 @@ fn apply_role_profile(
value["feature"]["memory"] = serde_json::json!({ "enabled": memory });
value["feature"]["web"] = serde_json::json!({ "enabled": web });
value["feature"]["workers"] = serde_json::json!({ "enabled": workers });
value["feature"]["manage_workdir"] = serde_json::json!({ "enabled": slug == "orchestrator" });
let ticket = match slug {
"companion" => serde_json::json!({ "enabled": true, "authoring": true, "thread": true }),
"intake" => {
@@ -1492,6 +1493,7 @@ mod tests {
assert!(intake.feature.ticket.authoring);
assert!(intake.feature.ticket.thread);
assert!(intake.feature.objective.enabled);
assert!(!intake.feature.manage_workdir.enabled);
assert!(intake.feature.ticket.intake);
assert!(!intake.feature.ticket.orchestration_control);
assert!(intake.scope.allow.is_empty());
@@ -1508,6 +1510,7 @@ mod tests {
assert!(!orchestrator.feature.ticket.authoring);
assert!(orchestrator.feature.ticket.thread);
assert!(orchestrator.feature.objective.enabled);
assert!(orchestrator.feature.manage_workdir.enabled);
assert!(!orchestrator.feature.ticket.intake);
assert!(orchestrator.feature.ticket.orchestration_control);
assert!(orchestrator.scope.allow.is_empty());
@@ -1532,6 +1535,7 @@ mod tests {
assert!(!coder.feature.ticket.authoring);
assert!(coder.feature.ticket.thread);
assert!(coder.feature.objective.enabled);
assert!(!coder.feature.manage_workdir.enabled);
assert!(!coder.feature.ticket.intake);
assert!(!coder.feature.ticket.orchestration_control);
let reviewer = resolve("reviewer");
@@ -1542,6 +1546,7 @@ mod tests {
assert!(!reviewer.feature.ticket.authoring);
assert!(reviewer.feature.ticket.thread);
assert!(reviewer.feature.objective.enabled);
assert!(!reviewer.feature.manage_workdir.enabled);
assert!(!reviewer.feature.ticket.intake);
assert!(!reviewer.feature.ticket.orchestration_control);
assert!(reviewer.scope.allow.is_empty());