code wiki / (root) / nx_convo.nx

nx_convo.nx source

↩ module page · 83 lines · 3384 B

1// nx_convo.nx -- WRITING arc, rung W-CONVO-1: the CONVERSATIONAL TUTOR core. 2// Serves two operator asks with one engine: 3// (1) "a couple doing language learning -- keep topics going" 4// (2) "young people learn positive social skills to overcome anxiety, fun way" 5// 6// Three deterministic, data-driven primitives (the generation seat -- the LLM that 7// actually speaks -- plugs in on top; this organ keeps the SESSION honest): 8// 9// cv_next_topic -- KEEP TOPICS GOING: from a topic bank (each topic has a 10// difficulty + the turn it was last used), pick the eligible 11// topic (difficulty <= level+window) that is LEAST RECENTLY 12// used -> fresh, level-appropriate, never an immediate repeat. 13// cv_rubric -- COACHING SCORE, RESPECT-GATED BY CONSTRUCTION: a weighted 14// score across axes (warmth/authenticity/respect/confidence), 15// BUT if the gate axis (respect / consent-reading) is below its 16// minimum the attempt is DISQUALIFIED (-1) no matter how high 17// "confidence" is. "Positive" is enforced in the math: you 18// cannot win by being pushy. This is the anti-manipulation law. 19// cv_level_adjust-- ADAPTIVE DIFFICULTY: nudge the target level up/down within 20// bounds from the last score (overcome-anxiety pacing). 21// 22// All thresholds/weights/axes are operator DATA (rule 11), passed in -- nothing 23// hardcoded. Pure integer, NO syscalls, NO imports, caller owns buffers. 24// 25// license_tier: ORIGINAL 26// module: nishi-core.write.convo 27// depends: 28// capability: WRITE_CONVO_TUTOR 29 30const CV_DISQUALIFIED: i64 = 0 - 1 31 32// KEEP TOPICS GOING: index of the eligible (diff <= level+window) least-recently- 33// used topic; ties -> lowest index; -1 if none eligible. 34func cv_next_topic(last_used: *i64, diff: *i64, ntopics: i64, level: i64, window: i64) -> i64 { 35 var best: i64 = 0 - 1 36 var best_lu: i64 = 0 37 var i: i64 = 0 38 while i < ntopics { 39 if diff[i] <= level + window { 40 if best < 0 { 41 best = i 42 best_lu = last_used[i] 43 } else { 44 if last_used[i] < best_lu { 45 best = i 46 best_lu = last_used[i] 47 } 48 } 49 } 50 i = i + 1 51 } 52 return best 53} 54 55// RESPECT-GATED COACHING SCORE: weighted average over axes, or CV_DISQUALIFIED if 56// the gate axis is below gate_min (anti-manipulation, by construction). 57func cv_rubric(scores: *i64, weights: *i64, naxes: i64, gate_idx: i64, gate_min: i64) -> i64 { 58 if scores[gate_idx] < gate_min { return CV_DISQUALIFIED } 59 var num: i64 = 0 60 var den: i64 = 0 61 var i: i64 = 0 62 while i < naxes { 63 num = num + (scores[i] * weights[i]) 64 den = den + weights[i] 65 i = i + 1 66 } 67 if den < 1 { den = 1 } 68 return num / den 69} 70 71// ADAPTIVE DIFFICULTY: raise the level on a strong score, lower it on a weak one, 72// clamped to [lvl_min, lvl_max]. 73func cv_level_adjust(level: i64, score: i64, up_th: i64, down_th: i64, lvl_min: i64, lvl_max: i64) -> i64 { 74 var lv: i64 = level 75 if score >= up_th { 76 if lv < lvl_max { lv = lv + 1 } 77 } else { 78 if score < down_th { 79 if lv > lvl_min { lv = lv - 1 } 80 } 81 } 82 return lv 83}