From 2d1edffdeb2ade1b4852e1e6e0eb7e714e483eea Mon Sep 17 00:00:00 2001 From: ProofOfConcept Date: Sat, 14 Mar 2026 12:34:15 -0400 Subject: [PATCH] knowledge: fix action parsers for markdown-formatted LLM output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linker agents output **LINK** (bold) with backtick-wrapped keys, and **WRITE_NODE**/**END_NODE** with bold markers. The parsers expected plain LINK/WRITE_NODE without markdown formatting, silently dropping all actions from tool-enabled agents. Updated regexes to accept optional ** bold markers and backtick key wrapping. Also reverted per-link Jaccard computation (too expensive in batch) — normalize-strengths should be run periodically instead. This was causing ~600 links and ~40 new semantic nodes per overnight batch to be silently lost. Co-Authored-By: Kent Overstreet --- poc-memory/src/agents/knowledge.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/poc-memory/src/agents/knowledge.rs b/poc-memory/src/agents/knowledge.rs index cbefe2b..3fa4b53 100644 --- a/poc-memory/src/agents/knowledge.rs +++ b/poc-memory/src/agents/knowledge.rs @@ -97,7 +97,8 @@ impl Confidence { // --------------------------------------------------------------------------- pub fn parse_write_nodes(text: &str) -> Vec { - let re = Regex::new(r"(?s)WRITE_NODE\s+(\S+)\s*\n(.*?)END_NODE").unwrap(); + // Match WRITE_NODE or **WRITE_NODE** with optional backtick-wrapped key + let re = Regex::new(r"(?s)\*{0,2}WRITE_NODE\*{0,2}\s+`?(\S+?)`?\s*\n(.*?)\*{0,2}END_NODE\*{0,2}").unwrap(); let conf_re = Regex::new(r"(?i)CONFIDENCE:\s*(high|medium|low)").unwrap(); let covers_re = Regex::new(r"COVERS:\s*(.+)").unwrap(); @@ -131,7 +132,8 @@ pub fn parse_write_nodes(text: &str) -> Vec { } pub fn parse_links(text: &str) -> Vec { - let re = Regex::new(r"(?m)^LINK\s+(\S+)\s+(\S+)").unwrap(); + // Match LINK or **LINK** with optional backtick-wrapped keys + let re = Regex::new(r"(?m)^\*{0,2}LINK\*{0,2}\s+`?([^\s`]+)`?\s+`?([^\s`]+)`?").unwrap(); re.captures_iter(text) .map(|cap| Action { kind: ActionKind::Link { @@ -333,6 +335,8 @@ pub fn apply_action( Some(n) => n.uuid, None => return false, }; + // Default strength 0.3 — caller should run Jaccard normalization + // after batch apply if needed (building graph per-link is too expensive) let mut rel = new_relation( source_uuid, target_uuid, RelationType::Link,