@polycode-projects/the-mechanical-code-talker 1.10.13 → 1.10.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/chat.mjs +50 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/the-mechanical-code-talker",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The Mechanical Code Talker (tmct) — a tolerant, offline, $0 chat surface that guides you toward precision queries about a software repository. ELIZA/PARRY-style but domain-obsessed with code. No model calls; no codebase index of its own.",
|
package/src/chat.mjs
CHANGED
|
@@ -1533,6 +1533,12 @@ const WALL_MISS_ANYWHERE_RE = /couldn't parse this as a graph question\. Try:/;
|
|
|
1533
1533
|
// instead of the grammar wall or a silent data loss.
|
|
1534
1534
|
const TEACH_RE = /^(?:please\s+)?(?:i\s+(?:want|wanted)\s+you\s+to\s+|i(?:'d|\s+would)\s+like\s+you\s+to\s+)?(?:remember|note|keep in mind|jot down|for the record|fyi|learn)\b(?:\s+(?:this|that|also))?[:,]?\s*(?:that\s+)?(.+?)[.?!]*$/i;
|
|
1535
1535
|
const BARE_DECLARATIVE_RE = /^(?:every |each |all |a |an )?[\w-]+(?: [\w-]+)? (?:is|are) (?:a |an )?[\w-]+$/i;
|
|
1536
|
+
/** "X is <comparative> than Y" — the comparative teach/ask surface. The
|
|
1537
|
+
* comparative slot is closed by SHAPE (-er word, better/worse, or a
|
|
1538
|
+
* more/less + adjective pair), never a hand-list of adjectives. */
|
|
1539
|
+
const COMPARATIVE_SRC = "(?:[a-z]+er|better|worse|(?:more|less)\\s+[a-z]+)";
|
|
1540
|
+
const COMPARATIVE_TEACH_RE = new RegExp(`^(?:the\\s+|an?\\s+)?([\\w'-]+(?:\\s+[\\w'-]+)?)\\s+(?:is|are)\\s+(${COMPARATIVE_SRC})\\s+than\\s+(.+)$`, "i");
|
|
1541
|
+
const COMPARATIVE_ASK_RE = new RegExp(`^(?:is|are)\\s+(.+?)\\s+(${COMPARATIVE_SRC})\\s+than\\s+(.+?)[?.!\\s]*$`, "i");
|
|
1536
1542
|
/** Interrogative / auxiliary leads that make an "X is a Y"-shaped line a QUESTION
|
|
1537
1543
|
* ("what is a cache", "is a module a component"), never a teach declarative. */
|
|
1538
1544
|
const QUESTION_LEAD_RE = /^(?:what|who|which|where|when|why|how|is|are|do|does|did|can|could|should|would|will|has|have)\b/i;
|
|
@@ -2879,7 +2885,7 @@ async function teachLane(query, { memoryDir, sessionId = "", lexicon = null, cac
|
|
|
2879
2885
|
|
|
2880
2886
|
let payload = null;
|
|
2881
2887
|
if (wrapped && /\b(?:is|are)\b/i.test(wrapped)) payload = wrapped;
|
|
2882
|
-
else if (BARE_DECLARATIVE_RE.test(raw) && !QUESTION_LEAD_RE.test(raw) && !(await hasMidSentenceInterrogative(raw))) payload = raw;
|
|
2888
|
+
else if ((BARE_DECLARATIVE_RE.test(raw) || COMPARATIVE_TEACH_RE.test(raw)) && !QUESTION_LEAD_RE.test(raw) && !(await hasMidSentenceInterrogative(raw))) payload = raw;
|
|
2883
2889
|
if (!payload) {
|
|
2884
2890
|
// "remember margo eats ribs", re-escaping here through a combination
|
|
2885
2891
|
// that mechanism's own deliberate subject-shape restriction doesn't
|
|
@@ -2897,6 +2903,19 @@ async function teachLane(query, { memoryDir, sessionId = "", lexicon = null, cac
|
|
|
2897
2903
|
// Try to store it (a live session provides the write target). assertTurn returns
|
|
2898
2904
|
// the "noted — remembered …" confirmation or null (grammar miss / unknown words).
|
|
2899
2905
|
if (memoryDir) {
|
|
2906
|
+
// COMPARATIVE frame — "disk-1 is smaller than disk-2" → mgx:smaller-than.
|
|
2907
|
+
// Checked ahead of the ACE candidates: the copula plus "than" is not in
|
|
2908
|
+
// the ACE fragment at all, and letting it fall through produced the
|
|
2909
|
+
// both-sides-ungrounded decline (honest but unactionable — no phrasing
|
|
2910
|
+
// it could suggest would have stored a comparison).
|
|
2911
|
+
const comp = String(payload).trim().match(COMPARATIVE_TEACH_RE);
|
|
2912
|
+
if (comp) {
|
|
2913
|
+
const compPredicate = `mgx:${comp[2].toLowerCase().replace(/\s+/g, "-")}-than`;
|
|
2914
|
+
const stored = await teachFact(memoryDir, sessionId, {
|
|
2915
|
+
subject: comp[1].trim(), predicate: compPredicate, object: comp[3].trim(),
|
|
2916
|
+
});
|
|
2917
|
+
if (stored) return stored;
|
|
2918
|
+
}
|
|
2900
2919
|
for (const cand of assertCandidates(payload)) {
|
|
2901
2920
|
// assertTurn ITSELF records the "every" quantifier (point 3) on a plain
|
|
2902
2921
|
// universal success, so every caller (this loop AND the top-level
|
|
@@ -3746,7 +3765,12 @@ function thirdPersonSingularSurface(lemma) {
|
|
|
3746
3765
|
}
|
|
3747
3766
|
function predicatePhrase(predicate) {
|
|
3748
3767
|
if (FACT_PREDICATE_PHRASES[predicate]) return FACT_PREDICATE_PHRASES[predicate];
|
|
3749
|
-
const
|
|
3768
|
+
const p = String(predicate || "");
|
|
3769
|
+
// a comparative renders as its copula surface: mgx:smaller-than ->
|
|
3770
|
+
// "is smaller than" (never a 3sg fold — "smallers" isn't a word)
|
|
3771
|
+
const comp = /^mgx:([a-z]+(?:-[a-z]+)*)-than$/i.exec(p);
|
|
3772
|
+
if (comp) return `is ${comp[1].replace(/-/g, " ")} than`;
|
|
3773
|
+
const m = /^mgx:([a-z]+)(?:-([a-z]+))?$/i.exec(p);
|
|
3750
3774
|
if (!m) return predicate;
|
|
3751
3775
|
// a folded preposition renders back naturally: mgx:rest-on -> "rests on"
|
|
3752
3776
|
return `${thirdPersonSingularSurface(m[1])}${m[2] ? ` ${m[2]}` : ""}`;
|
|
@@ -4385,6 +4409,30 @@ export async function factAnswer(memoryDir, query, envelope, miss, biasByBundle
|
|
|
4385
4409
|
}
|
|
4386
4410
|
if (!miss) return null;
|
|
4387
4411
|
|
|
4412
|
+
// (b0-comp) "is disk-1 smaller than disk-2" — yes iff the exact taught
|
|
4413
|
+
// comparative fact exists; otherwise an honest, specific miss whose teach
|
|
4414
|
+
// hint is the EXACT phrasing the comparative teach frame accepts. Never an
|
|
4415
|
+
// inverted guess: "disk-1 is smaller than disk-2" proves nothing here
|
|
4416
|
+
// about "is disk-2 smaller than disk-1" (the frame stores no
|
|
4417
|
+
// antisymmetry), so the reverse question stays a can't-confirm.
|
|
4418
|
+
const compAsk = q.match(COMPARATIVE_ASK_RE);
|
|
4419
|
+
if (compAsk) {
|
|
4420
|
+
const compWord = compAsk[2].toLowerCase().replace(/\s+/g, "-");
|
|
4421
|
+
const compPredicate = `mgx:${compWord}-than`;
|
|
4422
|
+
const facts = await memoryFacts(memoryDir);
|
|
4423
|
+
const subj = factTermVariants(normFactTerm, compAsk[1].replace(/^(?:an?|the)\s+/i, "").trim());
|
|
4424
|
+
const obj = factTermVariants(normFactTerm, compAsk[3].replace(/^(?:an?|the)\s+/i, "").trim());
|
|
4425
|
+
const hit = facts.find((f) => f.predicate === compPredicate && subj.has(f.subject) && obj.has(f.object));
|
|
4426
|
+
if (hit) return { text: `yes — ${renderFactLine(hit)}`, replace: true };
|
|
4427
|
+
const known = facts.filter((f) => f.predicate === compPredicate && (subj.has(f.subject) || subj.has(f.object)));
|
|
4428
|
+
const shown = known.length ? ` I do know: ${known.slice(0, 3).map(renderFactLine).join("; ")}.` : "";
|
|
4429
|
+
return {
|
|
4430
|
+
text: `I can't confirm that — nothing I remember compares them that way.${shown} If it's true, teach me: "${compAsk[1].trim()} is ${compAsk[2].toLowerCase()} than ${compAsk[3].trim()}".`,
|
|
4431
|
+
replace: true,
|
|
4432
|
+
miss: true,
|
|
4433
|
+
};
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4388
4436
|
// (b0) Derived forward yes/no readers — FORWARD_YESNO_MARKERS, one per
|
|
4389
4437
|
// renderable relation. Runs BEFORE the isa lane because ISA_ASK_RE's lazy
|
|
4390
4438
|
// subject otherwise swallows these shapes whole ("is a wheel part of a
|