poc-memory: POC_MEMORY_DRY_RUN=1 for agent testing
All mutating commands (write, delete, rename, link-add, journal write, used, wrong, not-useful, gap) check POC_MEMORY_DRY_RUN after argument validation but before mutation. If set, process exits silently — agent tool calls are visible in the LLM output so we can see what it tried to do without applying changes. Read commands (render, search, graph link, journal tail) work normally in dry-run mode so agents can still explore the graph. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2ab9b78363
commit
7e131862d6
4 changed files with 18 additions and 0 deletions
|
|
@ -134,6 +134,7 @@ pub fn cmd_triangle_close(min_degree: usize, sim_threshold: f32, max_per_hub: us
|
|||
}
|
||||
|
||||
pub fn cmd_link_add(source: &str, target: &str, reason: &[String]) -> Result<(), String> {
|
||||
super::check_dry_run();
|
||||
let mut store = store::Store::load()?;
|
||||
let source = store.resolve_key(source)?;
|
||||
let target = store.resolve_key(target)?;
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ pub fn cmd_journal_write(text: &[String]) -> Result<(), String> {
|
|||
if text.is_empty() {
|
||||
return Err("journal-write requires text".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
let text = text.join(" ");
|
||||
|
||||
let timestamp = crate::store::format_datetime(crate::store::now_epoch());
|
||||
|
|
|
|||
|
|
@ -9,3 +9,10 @@ pub mod agent;
|
|||
pub mod admin;
|
||||
pub mod journal;
|
||||
pub mod misc;
|
||||
|
||||
/// Exit silently if POC_MEMORY_DRY_RUN=1.
|
||||
pub fn check_dry_run() {
|
||||
if std::env::var("POC_MEMORY_DRY_RUN").map_or(false, |v| v == "1" || v == "true") {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub fn cmd_used(key: &[String]) -> Result<(), String> {
|
|||
if key.is_empty() {
|
||||
return Err("used requires a key".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
let key = key.join(" ");
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(&key)?;
|
||||
|
|
@ -38,6 +39,7 @@ pub fn cmd_used(key: &[String]) -> Result<(), String> {
|
|||
|
||||
pub fn cmd_wrong(key: &str, context: &[String]) -> Result<(), String> {
|
||||
let ctx = if context.is_empty() { None } else { Some(context.join(" ")) };
|
||||
super::check_dry_run();
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(key)?;
|
||||
store.mark_wrong(&resolved, ctx.as_deref());
|
||||
|
|
@ -71,6 +73,8 @@ pub fn cmd_not_relevant(key: &str) -> Result<(), String> {
|
|||
}
|
||||
|
||||
pub fn cmd_not_useful(key: &str) -> Result<(), String> {
|
||||
// no args to validate
|
||||
super::check_dry_run();
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(key)?;
|
||||
// Same as wrong but with clearer semantics: node content is bad, edges are fine.
|
||||
|
|
@ -84,6 +88,7 @@ pub fn cmd_gap(description: &[String]) -> Result<(), String> {
|
|||
if description.is_empty() {
|
||||
return Err("gap requires a description".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
let desc = description.join(" ");
|
||||
let mut store = store::Store::load()?;
|
||||
store.record_gap(&desc);
|
||||
|
|
@ -146,6 +151,7 @@ pub fn cmd_node_delete(key: &[String]) -> Result<(), String> {
|
|||
if key.is_empty() {
|
||||
return Err("node-delete requires a key".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
let key = key.join(" ");
|
||||
let mut store = store::Store::load()?;
|
||||
let resolved = store.resolve_key(&key)?;
|
||||
|
|
@ -156,6 +162,8 @@ pub fn cmd_node_delete(key: &[String]) -> Result<(), String> {
|
|||
}
|
||||
|
||||
pub fn cmd_node_rename(old_key: &str, new_key: &str) -> Result<(), String> {
|
||||
// args are positional, always valid if present
|
||||
super::check_dry_run();
|
||||
let mut store = store::Store::load()?;
|
||||
let old_resolved = store.resolve_key(old_key)?;
|
||||
store.rename_node(&old_resolved, new_key)?;
|
||||
|
|
@ -286,6 +294,7 @@ pub fn cmd_write(key: &[String]) -> Result<(), String> {
|
|||
if content.trim().is_empty() {
|
||||
return Err("No content on stdin".into());
|
||||
}
|
||||
super::check_dry_run();
|
||||
|
||||
let mut store = store::Store::load()?;
|
||||
let key = store.resolve_key(&raw_key).unwrap_or(raw_key);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue