experience-mine: link at creation time, remove # from new keys
Update the experience mining prompt to output links alongside journal entries. The LLM now returns a "links" array per entry pointing to existing semantic nodes. Rust code creates the links immediately after node creation — new nodes arrive pre-connected instead of orphaned. Also: remove # from all key generation paths (experience miner, digest section keys, observed transcript keys). New nodes get clean dash-separated keys. Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
ce94e1cac1
commit
83342897c8
4 changed files with 37 additions and 9 deletions
|
|
@ -365,7 +365,7 @@ fn normalize_link_key(raw: &str) -> String {
|
|||
} else if key.contains('#') {
|
||||
let (file, section) = key.split_once('#').unwrap();
|
||||
if let Some(bare) = file.strip_suffix(".md") {
|
||||
key = format!("{}#{}", bare, section);
|
||||
key = format!("{}-{}", bare, section);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn transcript_dedup_key(path: &str) -> Result<String, String> {
|
|||
let bytes = fs::read(path).map_err(|e| format!("read {}: {}", path, e))?;
|
||||
let mut hasher = DefaultHasher::new();
|
||||
bytes.hash(&mut hasher);
|
||||
Ok(format!("_mined-transcripts#h-{:016x}", hasher.finish()))
|
||||
Ok(format!("_mined-transcripts-h-{:016x}", hasher.finish()))
|
||||
}
|
||||
|
||||
/// Check if a transcript has already been mined (dedup key exists in store).
|
||||
|
|
@ -111,7 +111,7 @@ pub fn mark_segment(
|
|||
/// Get the set of all mined transcript keys (both content-hash and filename)
|
||||
/// from the store. Load once per daemon tick, check many.
|
||||
pub fn mined_transcript_keys() -> HashSet<String> {
|
||||
keys_with_prefix("_mined-transcripts#")
|
||||
keys_with_prefix("_mined-transcripts-")
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ pub fn experience_mine(
|
|||
let mut hasher = DefaultHasher::new();
|
||||
transcript_bytes.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
let dedup_key = format!("_mined-transcripts#h-{:016x}", hash);
|
||||
let dedup_key = format!("_mined-transcripts-h-{:016x}", hash);
|
||||
|
||||
if store.nodes.contains_key(&dedup_key) {
|
||||
// Backfill per-segment key if called with a specific segment
|
||||
|
|
@ -390,9 +390,9 @@ pub fn experience_mine(
|
|||
.to_lowercase()
|
||||
.replace(' ', "-");
|
||||
let key = if ts.is_empty() {
|
||||
format!("journal#j-mined-{}", key_slug)
|
||||
format!("journal-j-mined-{}", key_slug)
|
||||
} else {
|
||||
format!("journal#j-{}-{}", ts.to_lowercase().replace(':', "-"), key_slug)
|
||||
format!("journal-j-{}-{}", ts.to_lowercase().replace(':', "-"), key_slug)
|
||||
};
|
||||
|
||||
// Check for duplicate
|
||||
|
|
@ -413,6 +413,25 @@ pub fn experience_mine(
|
|||
let _ = store.upsert_node(node);
|
||||
count += 1;
|
||||
|
||||
// Apply links from LLM output
|
||||
if let Some(links) = entry.get("links").and_then(|v| v.as_array()) {
|
||||
for link_val in links {
|
||||
if let Some(target) = link_val.as_str() {
|
||||
let target = target.to_string();
|
||||
if let Some(target_node) = store.nodes.get(&target) {
|
||||
let source_uuid = store.nodes.get(&key).map(|n| n.uuid).unwrap_or_default();
|
||||
let target_uuid = target_node.uuid;
|
||||
let rel = store::new_relation(
|
||||
source_uuid, target_uuid,
|
||||
store::RelationType::Link, 0.3,
|
||||
&key, &target,
|
||||
);
|
||||
let _ = store.add_relation(rel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let preview = crate::util::truncate(content, 77, "...");
|
||||
println!(" + [{}] {}", ts, preview);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -684,7 +684,7 @@ pub fn select_conversation_fragments(n: usize) -> Vec<(String, String)> {
|
|||
let projects = crate::config::get().projects_dir.clone();
|
||||
if !projects.exists() { return Vec::new(); }
|
||||
|
||||
let observed = super::enrich::keys_with_prefix(&format!("{}#", OBSERVED_PREFIX));
|
||||
let observed = super::enrich::keys_with_prefix(&format!("{}-", OBSERVED_PREFIX));
|
||||
|
||||
let mut jsonl_files: Vec<PathBuf> = Vec::new();
|
||||
if let Ok(dirs) = fs::read_dir(&projects) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue