knowledge: fix action parsers for markdown-formatted LLM output

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 <kent.overstreet@linux.dev>
This commit is contained in:
ProofOfConcept 2026-03-14 12:34:15 -04:00
parent 51ee082faf
commit 2d1edffdeb

View file

@ -97,7 +97,8 @@ impl Confidence {
// ---------------------------------------------------------------------------
pub fn parse_write_nodes(text: &str) -> Vec<Action> {
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<Action> {
}
pub fn parse_links(text: &str) -> Vec<Action> {
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,