メモリーに関するクレート作成・ファイル構造の実装

This commit is contained in:
2026-04-27 13:33:31 +09:00
parent c7a873bcf9
commit f2e47629d0
33 changed files with 2780 additions and 32 deletions
+23 -1
View File
@@ -14,7 +14,10 @@ use serde::{Deserialize, Serialize};
use crate::defaults;
use crate::model::{AuthRef, ModelManifest};
use crate::{CompactionConfig, PodManifest, PodMeta, ScopeConfig, ToolOutputLimits, WorkerManifest};
use crate::{
CompactionConfig, MemoryConfig, PodManifest, PodMeta, ScopeConfig, ToolOutputLimits,
WorkerManifest,
};
/// Partial-form Pod manifest. Every field is optional; one or more
/// instances merge via [`PodManifestConfig::merge`] before being
@@ -35,6 +38,9 @@ pub struct PodManifestConfig {
pub scope: ScopeConfig,
#[serde(default)]
pub compaction: Option<CompactionConfigPartial>,
/// Memory subsystem opt-in. See [`MemoryConfig`].
#[serde(default)]
pub memory: Option<MemoryConfig>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -162,6 +168,11 @@ impl PodManifestConfig {
for rule in &mut self.scope.deny {
rule.target = join_if_relative(base, &rule.target);
}
if let Some(ref mut memory) = self.memory
&& let Some(ref mut root) = memory.workspace_root
{
*root = join_if_relative(base, root);
}
if let Some(ref mut compaction) = self.compaction
&& let Some(ref mut cp) = compaction.model
{
@@ -185,6 +196,15 @@ impl PodManifestConfig {
upper.compaction,
CompactionConfigPartial::merge,
),
memory: merge_option(self.memory, upper.memory, MemoryConfig::merge),
}
}
}
impl MemoryConfig {
fn merge(self, upper: Self) -> Self {
Self {
workspace_root: upper.workspace_root.or(self.workspace_root),
}
}
}
@@ -375,6 +395,7 @@ impl TryFrom<PodManifestConfig> for PodManifest {
worker,
scope: cfg.scope,
compaction,
memory: cfg.memory,
})
}
}
@@ -417,6 +438,7 @@ mod tests {
deny: Vec::new(),
},
compaction: None,
memory: None,
}
}
+46
View File
@@ -31,6 +31,25 @@ pub struct PodManifest {
pub scope: ScopeConfig,
#[serde(default)]
pub compaction: Option<CompactionConfig>,
/// Memory subsystem opt-in. Presence of `[memory]` in TOML enables
/// the memory tools (MemoryRead / MemoryWrite / MemoryEdit) and
/// causes Pod to deny generic write access to `<workspace>/memory/`
/// and `<workspace>/knowledge/`. Absent ⇒ legacy behaviour, no
/// memory tools registered.
#[serde(default)]
pub memory: Option<MemoryConfig>,
}
/// Memory subsystem configuration. Presence in the manifest enables
/// memory; the workspace root defaults to the Pod's pwd unless an
/// explicit override is given.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct MemoryConfig {
/// Override for the workspace root. When `None`, the Pod's pwd
/// (resolved at construction time) is used. When set, must be an
/// absolute path.
#[serde(default)]
pub workspace_root: Option<PathBuf>,
}
/// Pod metadata.
@@ -411,6 +430,33 @@ model_id = "claude-sonnet-4-20250514"
assert!(manifest.compaction.is_none());
}
#[test]
fn omitted_memory_is_none() {
let manifest = PodManifest::from_toml(MINIMAL_REQUIRED).unwrap();
assert!(manifest.memory.is_none());
}
#[test]
fn empty_memory_section_enables_with_default_root() {
let toml = format!("{MINIMAL_REQUIRED}\n[memory]\n");
let manifest = PodManifest::from_toml(&toml).unwrap();
let mem = manifest.memory.expect("memory section parsed");
assert!(mem.workspace_root.is_none());
}
#[test]
fn memory_section_with_explicit_root() {
let toml = format!(
"{MINIMAL_REQUIRED}\n[memory]\nworkspace_root = \"/some/where\"\n"
);
let manifest = PodManifest::from_toml(&toml).unwrap();
let mem = manifest.memory.unwrap();
assert_eq!(
mem.workspace_root.unwrap(),
std::path::PathBuf::from("/some/where")
);
}
#[test]
fn reject_unknown_scheme() {
let toml =