consolidate hardcoded paths into config, refactor apply_agent
Move prompts_dir into Config (was hardcoded ~/poc/memory/prompts). Replace hardcoded ~/.claude/memory paths in spectral.rs, graph.rs, and main.rs with store::memory_dir() or config::get(). Replace hardcoded ~/.claude/projects in knowledge.rs and main.rs with config::get().projects_dir. Extract apply_agent_file() from cmd_apply_agent() — separates file scanning from per-file JSON parsing and link application.
This commit is contained in:
parent
52523403c5
commit
2f2c84e1c0
6 changed files with 96 additions and 96 deletions
|
|
@ -51,6 +51,8 @@ pub struct Config {
|
|||
pub context_groups: Vec<ContextGroup>,
|
||||
/// Max concurrent LLM calls in the daemon.
|
||||
pub llm_concurrency: usize,
|
||||
/// Directory containing prompt templates for agents.
|
||||
pub prompts_dir: PathBuf,
|
||||
/// Separate Claude config dir for background agent work (daemon jobs).
|
||||
/// If set, passed as CLAUDE_CONFIG_DIR so the daemon authenticates
|
||||
/// with different OAuth credentials than the interactive session.
|
||||
|
|
@ -81,6 +83,7 @@ impl Default for Config {
|
|||
},
|
||||
],
|
||||
llm_concurrency: 1,
|
||||
prompts_dir: home.join("poc/memory/prompts"),
|
||||
agent_config_dir: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -138,6 +141,9 @@ impl Config {
|
|||
if let Some(n) = cfg.get("llm_concurrency").and_then(|v| v.as_u64()) {
|
||||
config.llm_concurrency = n.max(1) as usize;
|
||||
}
|
||||
if let Some(s) = cfg.get("prompts_dir").and_then(|v| v.as_str()) {
|
||||
config.prompts_dir = expand_home(s);
|
||||
}
|
||||
if let Some(s) = cfg.get("agent_config_dir").and_then(|v| v.as_str()) {
|
||||
config.agent_config_dir = Some(expand_home(s));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -519,8 +519,7 @@ pub struct MetricsSnapshot {
|
|||
}
|
||||
|
||||
fn metrics_log_path() -> std::path::PathBuf {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
std::path::PathBuf::from(home).join(".claude/memory/metrics.jsonl")
|
||||
crate::store::memory_dir().join("metrics.jsonl")
|
||||
}
|
||||
|
||||
/// Load previous metrics snapshots
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ use std::fs;
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn projects_dir() -> PathBuf {
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
|
||||
PathBuf::from(home).join(".claude/projects")
|
||||
crate::config::get().projects_dir.clone()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -19,13 +19,11 @@ use poc_memory::*;
|
|||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use std::env;
|
||||
use std::process;
|
||||
|
||||
/// Find the most recently modified .jsonl transcript in the Claude projects dir.
|
||||
fn find_current_transcript() -> Option<String> {
|
||||
let home = env::var("HOME").ok()?;
|
||||
let projects = std::path::Path::new(&home).join(".claude/projects");
|
||||
let projects = config::get().projects_dir.clone();
|
||||
if !projects.exists() { return None; }
|
||||
|
||||
let mut newest: Option<(std::time::SystemTime, std::path::PathBuf)> = None;
|
||||
|
|
@ -1022,10 +1020,89 @@ fn cmd_link_impact(source: &str, target: &str) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Apply links from a single agent result JSON file.
|
||||
/// Returns (links_applied, errors).
|
||||
fn apply_agent_file(
|
||||
store: &mut store::Store,
|
||||
data: &serde_json::Value,
|
||||
) -> (usize, usize) {
|
||||
let agent_result = data.get("agent_result").or(Some(data));
|
||||
let links = match agent_result.and_then(|r| r.get("links")).and_then(|l| l.as_array()) {
|
||||
Some(l) => l,
|
||||
None => return (0, 0),
|
||||
};
|
||||
|
||||
let entry_text = data.get("entry_text")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if let (Some(start), Some(end)) = (
|
||||
agent_result.and_then(|r| r.get("source_start")).and_then(|v| v.as_u64()),
|
||||
agent_result.and_then(|r| r.get("source_end")).and_then(|v| v.as_u64()),
|
||||
) {
|
||||
println!(" Source: L{}-L{}", start, end);
|
||||
}
|
||||
|
||||
let mut applied = 0;
|
||||
let mut errors = 0;
|
||||
|
||||
for link in links {
|
||||
let target = match link.get("target").and_then(|v| v.as_str()) {
|
||||
Some(t) => t,
|
||||
None => continue,
|
||||
};
|
||||
let reason = link.get("reason").and_then(|v| v.as_str()).unwrap_or("");
|
||||
|
||||
if let Some(note) = target.strip_prefix("NOTE:") {
|
||||
println!(" NOTE: {} — {}", note, reason);
|
||||
continue;
|
||||
}
|
||||
|
||||
let resolved = match store.resolve_key(target) {
|
||||
Ok(r) => r,
|
||||
Err(_) => {
|
||||
println!(" SKIP {} (not found in graph)", target);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let source_key = match store.find_journal_node(entry_text) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
println!(" SKIP {} (no matching journal node)", target);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let source_uuid = match store.nodes.get(&source_key) {
|
||||
Some(n) => n.uuid,
|
||||
None => continue,
|
||||
};
|
||||
let target_uuid = match store.nodes.get(&resolved) {
|
||||
Some(n) => n.uuid,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let rel = store::new_relation(
|
||||
source_uuid, target_uuid,
|
||||
store::RelationType::Link,
|
||||
0.5,
|
||||
&source_key, &resolved,
|
||||
);
|
||||
if let Err(e) = store.add_relation(rel) {
|
||||
eprintln!(" Error adding relation: {}", e);
|
||||
errors += 1;
|
||||
} else {
|
||||
println!(" LINK {} → {} ({})", source_key, resolved, reason);
|
||||
applied += 1;
|
||||
}
|
||||
}
|
||||
|
||||
(applied, errors)
|
||||
}
|
||||
|
||||
fn cmd_apply_agent(process_all: bool) -> Result<(), String> {
|
||||
let home = env::var("HOME").unwrap_or_default();
|
||||
let results_dir = std::path::PathBuf::from(&home)
|
||||
.join(".claude/memory/agent-results");
|
||||
let results_dir = store::memory_dir().join("agent-results");
|
||||
|
||||
if !results_dir.exists() {
|
||||
println!("No agent results directory");
|
||||
|
|
@ -1036,7 +1113,6 @@ fn cmd_apply_agent(process_all: bool) -> Result<(), String> {
|
|||
let mut applied = 0;
|
||||
let mut errors = 0;
|
||||
|
||||
// Find .json result files
|
||||
let mut files: Vec<_> = std::fs::read_dir(&results_dir)
|
||||
.map_err(|e| format!("read results dir: {}", e))?
|
||||
.filter_map(|e| e.ok())
|
||||
|
|
@ -1064,84 +1140,11 @@ fn cmd_apply_agent(process_all: bool) -> Result<(), String> {
|
|||
}
|
||||
};
|
||||
|
||||
// Check for agent_result with links
|
||||
let agent_result = data.get("agent_result").or(Some(&data));
|
||||
let links = match agent_result.and_then(|r| r.get("links")).and_then(|l| l.as_array()) {
|
||||
Some(l) => l,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let entry_text = data.get("entry_text")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
let source_start = agent_result
|
||||
.and_then(|r| r.get("source_start"))
|
||||
.and_then(|v| v.as_u64());
|
||||
let source_end = agent_result
|
||||
.and_then(|r| r.get("source_end"))
|
||||
.and_then(|v| v.as_u64());
|
||||
|
||||
println!("Processing {}:", path.file_name().unwrap().to_string_lossy());
|
||||
if let (Some(start), Some(end)) = (source_start, source_end) {
|
||||
println!(" Source: L{}-L{}", start, end);
|
||||
}
|
||||
let (a, e) = apply_agent_file(&mut store, &data);
|
||||
applied += a;
|
||||
errors += e;
|
||||
|
||||
for link in links {
|
||||
let target = match link.get("target").and_then(|v| v.as_str()) {
|
||||
Some(t) => t,
|
||||
None => continue,
|
||||
};
|
||||
let reason = link.get("reason").and_then(|v| v.as_str()).unwrap_or("");
|
||||
|
||||
// Skip NOTE: targets (new topics, not existing nodes)
|
||||
if let Some(note) = target.strip_prefix("NOTE:") {
|
||||
println!(" NOTE: {} — {}", note, reason);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to resolve the target key and link from journal entry
|
||||
let resolved = match store.resolve_key(target) {
|
||||
Ok(r) => r,
|
||||
Err(_) => {
|
||||
println!(" SKIP {} (not found in graph)", target);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let source_key = match store.find_journal_node(entry_text) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
println!(" SKIP {} (no matching journal node)", target);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Get UUIDs for both nodes
|
||||
let source_uuid = match store.nodes.get(&source_key) {
|
||||
Some(n) => n.uuid,
|
||||
None => continue,
|
||||
};
|
||||
let target_uuid = match store.nodes.get(&resolved) {
|
||||
Some(n) => n.uuid,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let rel = store::new_relation(
|
||||
source_uuid, target_uuid,
|
||||
store::RelationType::Link,
|
||||
0.5,
|
||||
&source_key, &resolved,
|
||||
);
|
||||
if let Err(e) = store.add_relation(rel) {
|
||||
eprintln!(" Error adding relation: {}", e);
|
||||
errors += 1;
|
||||
} else {
|
||||
println!(" LINK {} → {} ({})", source_key, resolved, reason);
|
||||
applied += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Move processed file to avoid re-processing
|
||||
if !process_all {
|
||||
let done_dir = util::memory_subdir("agent-results/done")?;
|
||||
let dest = done_dir.join(path.file_name().unwrap());
|
||||
|
|
|
|||
|
|
@ -11,15 +11,9 @@ use super::scoring::{
|
|||
replay_queue, replay_queue_with_graph, detect_interference,
|
||||
};
|
||||
|
||||
/// Prompt template directory
|
||||
pub fn prompts_dir() -> std::path::PathBuf {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
std::path::PathBuf::from(home).join("poc/memory/prompts")
|
||||
}
|
||||
|
||||
/// Load a prompt template, replacing {{PLACEHOLDER}} with data
|
||||
pub fn load_prompt(name: &str, replacements: &[(&str, &str)]) -> Result<String, String> {
|
||||
let path = prompts_dir().join(format!("{}.md", name));
|
||||
let path = crate::config::get().prompts_dir.join(format!("{}.md", name));
|
||||
let mut content = std::fs::read_to_string(&path)
|
||||
.map_err(|e| format!("load prompt {}: {}", path.display(), e))?;
|
||||
for (placeholder, data) in replacements {
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ pub struct SpectralEmbedding {
|
|||
}
|
||||
|
||||
fn embedding_path() -> PathBuf {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
PathBuf::from(home).join(".claude/memory/spectral-embedding.json")
|
||||
crate::store::memory_dir().join("spectral-embedding.json")
|
||||
}
|
||||
|
||||
/// Compute spectral decomposition of the memory graph.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue