memory: gate staging tools by profile
This commit is contained in:
@@ -18,9 +18,9 @@ use crate::model::{AuthRef, ModelManifest, ReasoningControl};
|
||||
use crate::plugin::PluginConfig;
|
||||
use crate::{
|
||||
CompactionConfig, EngineManifest, FeatureConfig, FeatureFlagConfig, FileUploadLimits,
|
||||
McpConfig, McpEnvValue, McpStdioCwdPolicy, MemoryConfig, ScopeConfig, SessionConfig,
|
||||
SkillsConfig, TicketFeatureConfig, ToolOutputLimits, ToolPermissionConfig, ToolPermissionRule,
|
||||
WebConfig, WorkerManifest, WorkerMeta,
|
||||
McpConfig, McpEnvValue, McpStdioCwdPolicy, MemoryConfig, MemoryFeatureConfig, ScopeConfig,
|
||||
SessionConfig, SkillsConfig, TicketFeatureConfig, ToolOutputLimits, ToolPermissionConfig,
|
||||
ToolPermissionRule, WebConfig, WorkerManifest, WorkerMeta,
|
||||
};
|
||||
|
||||
/// Partial-form Worker manifest. Every field is optional; one or more
|
||||
@@ -79,7 +79,7 @@ pub struct FeatureConfigPartial {
|
||||
#[serde(default)]
|
||||
pub task: Option<FeatureFlagConfigPartial>,
|
||||
#[serde(default)]
|
||||
pub memory: Option<FeatureFlagConfigPartial>,
|
||||
pub memory: Option<MemoryFeatureConfigPartial>,
|
||||
#[serde(default)]
|
||||
pub web: Option<FeatureFlagConfigPartial>,
|
||||
#[serde(default)]
|
||||
@@ -94,7 +94,7 @@ impl FeatureConfigPartial {
|
||||
fn merge(self, other: Self) -> Self {
|
||||
Self {
|
||||
task: merge_option(self.task, other.task, FeatureFlagConfigPartial::merge),
|
||||
memory: merge_option(self.memory, other.memory, FeatureFlagConfigPartial::merge),
|
||||
memory: merge_option(self.memory, other.memory, MemoryFeatureConfigPartial::merge),
|
||||
web: merge_option(self.web, other.web, FeatureFlagConfigPartial::merge),
|
||||
workers: merge_option(self.workers, other.workers, FeatureFlagConfigPartial::merge),
|
||||
ticket: merge_option(self.ticket, other.ticket, TicketFeatureConfigPartial::merge),
|
||||
@@ -117,6 +117,23 @@ impl FeatureFlagConfigPartial {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct MemoryFeatureConfigPartial {
|
||||
#[serde(default)]
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub staging: Option<bool>,
|
||||
}
|
||||
|
||||
impl MemoryFeatureConfigPartial {
|
||||
fn merge(self, other: Self) -> Self {
|
||||
Self {
|
||||
enabled: other.enabled.or(self.enabled),
|
||||
staging: other.staging.or(self.staging),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct TicketFeatureConfigPartial {
|
||||
@@ -145,7 +162,7 @@ impl From<FeatureConfigPartial> for FeatureConfig {
|
||||
task: value.task.map(FeatureFlagConfig::from).unwrap_or_default(),
|
||||
memory: value
|
||||
.memory
|
||||
.map(FeatureFlagConfig::from)
|
||||
.map(MemoryFeatureConfig::from)
|
||||
.unwrap_or_default(),
|
||||
web: value.web.map(FeatureFlagConfig::from).unwrap_or_default(),
|
||||
workers: value
|
||||
@@ -180,6 +197,24 @@ impl From<FeatureFlagConfig> for FeatureFlagConfigPartial {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MemoryFeatureConfigPartial> for MemoryFeatureConfig {
|
||||
fn from(value: MemoryFeatureConfigPartial) -> Self {
|
||||
Self {
|
||||
enabled: value.enabled.unwrap_or_default(),
|
||||
staging: value.staging.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MemoryFeatureConfig> for MemoryFeatureConfigPartial {
|
||||
fn from(value: MemoryFeatureConfig) -> Self {
|
||||
Self {
|
||||
enabled: Some(value.enabled),
|
||||
staging: Some(value.staging),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TicketFeatureConfigPartial> for TicketFeatureConfig {
|
||||
fn from(value: TicketFeatureConfigPartial) -> Self {
|
||||
Self {
|
||||
@@ -1806,6 +1841,7 @@ orchestration_control = false
|
||||
assert!(!manifest.feature.ticket.intake);
|
||||
assert!(!manifest.feature.ticket.orchestration_control);
|
||||
assert!(!manifest.feature.memory.enabled);
|
||||
assert!(!manifest.feature.memory.staging);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1830,6 +1866,9 @@ orchestration_control = false
|
||||
thread = true
|
||||
orchestration_control = true
|
||||
|
||||
[feature.memory]
|
||||
staging = true
|
||||
|
||||
[feature.web]
|
||||
enabled = true
|
||||
"#,
|
||||
@@ -1861,6 +1900,7 @@ enabled = true
|
||||
.try_into()
|
||||
.unwrap();
|
||||
assert!(manifest.feature.memory.enabled);
|
||||
assert!(manifest.feature.memory.staging);
|
||||
assert!(manifest.feature.ticket.enabled);
|
||||
assert!(!manifest.feature.ticket.authoring);
|
||||
assert!(manifest.feature.ticket.thread);
|
||||
|
||||
@@ -107,7 +107,7 @@ pub struct FeatureConfig {
|
||||
#[serde(default)]
|
||||
pub task: FeatureFlagConfig,
|
||||
#[serde(default)]
|
||||
pub memory: FeatureFlagConfig,
|
||||
pub memory: MemoryFeatureConfig,
|
||||
#[serde(default)]
|
||||
pub web: FeatureFlagConfig,
|
||||
#[serde(default)]
|
||||
@@ -122,7 +122,7 @@ impl Default for FeatureConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
task: FeatureFlagConfig::disabled(),
|
||||
memory: FeatureFlagConfig::disabled(),
|
||||
memory: MemoryFeatureConfig::disabled(),
|
||||
web: FeatureFlagConfig::disabled(),
|
||||
workers: FeatureFlagConfig::disabled(),
|
||||
ticket: TicketFeatureConfig::default(),
|
||||
@@ -153,6 +153,37 @@ impl Default for FeatureFlagConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct MemoryFeatureConfig {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
/// Exposes Memory staging queue tools in addition to normal Memory CRUD/query tools.
|
||||
#[serde(default)]
|
||||
pub staging: bool,
|
||||
}
|
||||
|
||||
impl MemoryFeatureConfig {
|
||||
pub const fn disabled() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
staging: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn enabled() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
staging: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MemoryFeatureConfig {
|
||||
fn default() -> Self {
|
||||
Self::disabled()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
|
||||
pub struct TicketFeatureConfig {
|
||||
#[serde(default)]
|
||||
|
||||
@@ -954,6 +954,17 @@ fn builtin_profile_artifact(label: &str) -> Option<serde_json::Value> {
|
||||
);
|
||||
Some(value)
|
||||
}
|
||||
"builtin:memory-consolidation" | "memory-consolidation" => {
|
||||
value["slug"] = serde_json::Value::String("memory-consolidation".to_string());
|
||||
value["description"] =
|
||||
serde_json::Value::String("Memory staging consolidation profile.".to_string());
|
||||
value["feature"]["task"] = serde_json::json!({ "enabled": false });
|
||||
value["feature"]["memory"] = serde_json::json!({ "enabled": true, "staging": true });
|
||||
value["feature"]["web"] = serde_json::json!({ "enabled": false });
|
||||
value["feature"]["workers"] = serde_json::json!({ "enabled": false });
|
||||
value["feature"]["ticket"] = serde_json::json!({ "enabled": false, "thread": false });
|
||||
Some(value)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1425,6 +1436,29 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_memory_consolidation_profile_enables_staging_by_feature() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let resolved = ProfileResolver::new()
|
||||
.with_workspace_base(tmp.path())
|
||||
.resolve(
|
||||
&ProfileSelector::source_named(
|
||||
ProfileRegistrySource::Builtin,
|
||||
"memory-consolidation",
|
||||
),
|
||||
ProfileResolveOptions::with_worker_name("arbitrary-worker-name"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
resolved.profile.as_ref().unwrap().name.as_deref(),
|
||||
Some("memory-consolidation")
|
||||
);
|
||||
assert_eq!(resolved.manifest.worker.name, "arbitrary-worker-name");
|
||||
assert!(resolved.manifest.feature.memory.enabled);
|
||||
assert!(resolved.manifest.feature.memory.staging);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_role_profiles_preserve_role_tool_policy() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user