@seanhogg/builderforce-memory 2026.9.31 → 2026.9.33
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/dist/evermind/index.d.ts +6 -0
- package/dist/evermind/index.d.ts.map +1 -1
- package/dist/evermind/index.js +5 -0
- package/dist/evermind/index.js.map +1 -1
- package/dist/evermind/runtime.d.ts +158 -0
- package/dist/evermind/runtime.d.ts.map +1 -0
- package/dist/evermind/runtime.js +236 -0
- package/dist/evermind/runtime.js.map +1 -0
- package/dist/evermind/textCoherence.d.ts +55 -0
- package/dist/evermind/textCoherence.d.ts.map +1 -0
- package/dist/evermind/textCoherence.js +218 -0
- package/dist/evermind/textCoherence.js.map +1 -0
- package/dist/evermind/toolCall.d.ts +175 -0
- package/dist/evermind/toolCall.d.ts.map +1 -0
- package/dist/evermind/toolCall.js +398 -0
- package/dist/evermind/toolCall.js.map +1 -0
- package/dist/evermind/wordLexicon.d.ts +103 -0
- package/dist/evermind/wordLexicon.d.ts.map +1 -0
- package/dist/evermind/wordLexicon.js +361 -0
- package/dist/evermind/wordLexicon.js.map +1 -0
- package/dist/limbic/LimbicSession.d.ts +2 -2
- package/package.json +3 -3
- package/src/evermind/index.ts +48 -0
- package/src/evermind/runtime.ts +364 -0
- package/src/evermind/textCoherence.ts +248 -0
- package/src/evermind/toolCall.ts +523 -0
- package/src/evermind/wordLexicon.ts +395 -0
- package/src/limbic/LimbicSession.ts +2 -2
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wordLexicon — a compact, zero-dependency lexicon + language guard used by the text
|
|
3
|
+
* coherence gate to catch the ONE failure mode the structural checks cannot see: an
|
|
4
|
+
* under-trained byte-BPE head emitting fluent-SHAPED prose made of INVENTED WORDS that
|
|
5
|
+
* balances its punctuation and never repeats itself ("…oredionisiing chats code related
|
|
6
|
+
* tot, bound reposea this inatic exie. The cainstiel.ts, ore…").
|
|
7
|
+
*
|
|
8
|
+
* Every structural signal (repetition, dominant-token collapse, replacement chars,
|
|
9
|
+
* orphaned delimiters) is blind to that text, and — measured on real samples —
|
|
10
|
+
* no dictionary-free feature separates it: long-token share, type-token ratio and
|
|
11
|
+
* character-cluster anomalies all score German/technical prose *worse* than the
|
|
12
|
+
* gibberish. So this module supplies the missing signal: **is this token a word?**
|
|
13
|
+
*
|
|
14
|
+
* Three deliberate design constraints, because a false positive here silently drops a
|
|
15
|
+
* legitimate reply:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Language guard.** The lexicon is English-only, so it is consulted ONLY when the
|
|
18
|
+
* text is Latin-script AND English wins the function-word vote against es/fr/de/pt/it.
|
|
19
|
+
* A Spanish, French, German or Chinese reply is never judged by it. See
|
|
20
|
+
* {@link detectLatinLanguage}.
|
|
21
|
+
* 2. **Small lexicon + generous escapes.** ~2.5k high-frequency stems (plus suffix
|
|
22
|
+
* stripping) can't possibly cover domain jargon, so a token also counts as known
|
|
23
|
+
* when it REPEATS in the text or appears in the caller's context (the prompt/question).
|
|
24
|
+
* Real jargon echoes the question or recurs; invented gibberish words are each
|
|
25
|
+
* different — that asymmetry is the observed signature.
|
|
26
|
+
* 3. **Code is excluded, not judged.** Identifiers, paths, URLs, numbers and fenced
|
|
27
|
+
* blocks are stripped before scoring — they are legitimately non-words.
|
|
28
|
+
*
|
|
29
|
+
* Zero-dep and pure (no db/env/engine imports) so it can sit under `textCoherence`,
|
|
30
|
+
* which every surface imports.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* High-frequency English stems. Deliberately a STEM list — {@link isKnownEnglishWord}
|
|
35
|
+
* strips regular inflections, so `merge` covers merged/merges/merging/merger(s).
|
|
36
|
+
* Written as space-separated groups purely for readability; deduped by the Set.
|
|
37
|
+
*/
|
|
38
|
+
const ENGLISH_STEMS_RAW = [
|
|
39
|
+
// Function words / pronouns / determiners / prepositions / conjunctions.
|
|
40
|
+
`a an the this that these those there here it its it's they them their theirs he him his she her hers we us our ours you your yours i me my mine who whom whose which what when where why how
|
|
41
|
+
and or but nor so yet for as if then than because while although though unless until since whether either neither both each every all any some none no not none other another same such own
|
|
42
|
+
is am are was were be been being do does did done doing have has had having will would shall should can could may might must ought need dare used
|
|
43
|
+
in on at by to from of with without within into onto out off over under above below between among across through during before after around near behind beyond against about upon toward towards along beside besides despite per via versus
|
|
44
|
+
very too also just only even still already almost enough quite rather almost mostly always never often sometimes usually rarely again once twice more most less least much many few several little lot lots
|
|
45
|
+
here there now then today tonight tomorrow yesterday soon later early late ago
|
|
46
|
+
yes no maybe perhaps please thanks thank hello hi okay ok sure`,
|
|
47
|
+
|
|
48
|
+
// Core verbs.
|
|
49
|
+
`accept access add adjust admit adopt advise affect afford agree allow analyse analyze announce answer apply appear approve argue arise arrange arrive ask assign assume attach attempt attend avoid
|
|
50
|
+
base become begin believe belong break bring build buy calculate call cancel capture carry catch cause change charge check choose claim clean clear click close collect combine come comment commit compare complete compute concern confirm connect consider consist contain continue contribute control convert copy correct cost cover create cut
|
|
51
|
+
deal decide declare decrease define delete deliver depend describe design detect determine develop die differ disable discover discuss display divide document download draw drive drop
|
|
52
|
+
earn edit effect elect enable encourage end enforce engage enjoy ensure enter escape establish estimate evaluate examine exceed exchange exclude execute exist expand expect experience explain explore export express extend extract
|
|
53
|
+
face fail fall fetch fight fill filter find finish fit fix flag flow focus follow force forget form format forward free fund
|
|
54
|
+
gain gather generate get give go grant grow guess guide handle happen help hide hire hit hold hope host identify ignore illustrate imagine implement import improve include increase indicate influence inform initialise initialize insert inspect install instruct intend introduce invest invite involve issue
|
|
55
|
+
join judge keep kill know label last launch lead learn leave lend let level lie lift like limit link list listen live load locate lock log look lose love
|
|
56
|
+
maintain make manage map mark match matter mean measure meet mention merge migrate mind miss mix modify monitor move
|
|
57
|
+
name navigate need note notice notify observe obtain occur offer open operate order organise organize outline overwrite own
|
|
58
|
+
pack parse partner pass pause pay perform permit persist pick place plan play point poll post practise practice predict prefer prepare present preserve press prevent print process produce program promise promote propose protect prove provide publish pull purchase push put
|
|
59
|
+
qualify query queue quit quote raise rank reach react read realise realize receive recognise recognize recommend record recover reduce refer reflect refresh refuse register regret reject relate release rely remain remember remind remove rename render repair repeat replace reply report represent request require reset resolve respond rest restart restore restrict result resume retain retry return reveal review revert reward rewrite roll run
|
|
60
|
+
save say scale scan schedule score search secure seed seek seem select sell send separate serve set settle share ship show shut sign signal simplify sit skip sleep slow solve sort sound speak specify spend split spread stand start state stay step stick stop store stream stretch strike study submit succeed suggest supply support suppose surface survive suspend sustain switch sync
|
|
61
|
+
take talk target teach tell tend test thank think threaten throw tie touch trace track trade train transfer transform translate travel treat trigger trust try turn
|
|
62
|
+
understand undo unlock update upgrade upload use validate value verify view visit vote wait wake walk want warn wash watch wear win wish wonder work worry wrap write`,
|
|
63
|
+
|
|
64
|
+
// Core nouns.
|
|
65
|
+
`ability access account action activity address advantage advice age agency agent agreement aim air alert amount analysis answer api app application approach approval area argument array article aspect asset assistant attempt attention audience audit author authority availability average
|
|
66
|
+
background backup balance bar base baseline batch behaviour behavior benchmark benefit bill block board body book bottom boundary branch brand break budget bug build building business button
|
|
67
|
+
cache calendar call capability capacity card care career case cash category cause cell center centre chain chance change channel chapter character chart chat check child choice church city claim class client cloud code collection college colour color column combination command comment commit committee community company comparison competition component computer concept concern condition conference config configuration confidence connection consequence consideration content context contract contrast contribution control conversation copy core corner cost council count country couple course court cover credit crisis criteria culture currency current customer cycle
|
|
68
|
+
damage data database date day deal debt decade decision default defence defense degree delay demand department dependency deployment depth description design desk detail development device diagram dialog difference difficulty direction director discussion disk display distance distribution district document documentation dollar domain door draft drive driver drop duration duty
|
|
69
|
+
earth economy edge edition editor education effect effort element email emergency employee employer end energy engine engineer entry environment episode equipment error estate estimate evaluation evening event evidence example exception exchange exercise existence expense experience experiment expert explanation export expression extension
|
|
70
|
+
face fact factor failure family fault feature fee feed feedback field figure file film filter finance finding fix flag flow focus folder food foot force forecast form format formula forum foundation frame framework friend front function fund future
|
|
71
|
+
game gap gateway generation girl goal government grade graph group growth guide
|
|
72
|
+
habit half hand handler hardware head header health heart height help history hit hold home hook hope host hour house human hypothesis
|
|
73
|
+
icon idea identity image impact implementation import importance improvement incident income increase index indicator individual industry influence information infrastructure initiative input insight instance institution instruction integration intent interaction interest interface internet interval interview introduction investment issue item
|
|
74
|
+
job join journey judgement judgment jump
|
|
75
|
+
key keyword kind king kitchen knowledge
|
|
76
|
+
lab label lack land language latency law layer layout leader leadership league learning length lesson letter level library licence license life light limit line link list literature load loan location lock log logic login loop loss love
|
|
77
|
+
machine magazine mail main maintenance majority manager map margin mark market material matter meaning measure media meeting member memory message metadata method metric middle migration milestone military million mind minute mission mistake mode model module moment money monitor month morning mother motion mountain mouse movement movie music
|
|
78
|
+
name nation nature need network news night node noise note notice notification number
|
|
79
|
+
object objective observation offer office officer operation opinion opportunity option order organisation organization origin outcome output overhead overview owner
|
|
80
|
+
package page pain pair panel paper paragraph parameter parent park part participant partner party password patch path pattern payment peace people percent performance period permission person perspective phase phone photo phrase picture piece pipeline place plan plant platform player point policy politics pool population port portfolio position possibility post potential power practice practise prediction preference presence president pressure price principle priority privacy problem procedure process product profile program progress project promise proof property proposal protection protocol provider public purpose
|
|
81
|
+
quality quantity query question queue quota
|
|
82
|
+
race radio range rank rate ratio reaction reader reality reason record recovery reference region registry regression relation relationship release relevance reliability remainder report repository representation request requirement research resolution resource response responsibility rest restriction result retry return revenue review reward risk road role room root round route row rule run runtime
|
|
83
|
+
safety sale sample scale scenario schedule scheme school science scope score screen script search season seat second secret section sector security seed segment selection sense sentence sequence series server service session set setting shape share sheet shell shift ship shop side sign signal significance similarity site situation size skill sky sleep slot snapshot society software solution son song sound source space span speaker specification speech speed spirit sport spot spread stack staff stage standard star start state statement station statistic status step stock storage store story strategy stream street strength stress string structure student study style subject subset success summary supply support surface survey symbol syntax system
|
|
84
|
+
table tag target task tax team technique technology telephone television temperature template term test text theme theory thing thought thread threshold ticket time timeline timeout title today token tool top topic total town track trade traffic training transaction transfer transition tree trend trial trip trouble truth turn type
|
|
85
|
+
understanding union unit university update upgrade usage user utility
|
|
86
|
+
value variable variant variety vector vendor version video view viewer village vision visitor voice volume vote
|
|
87
|
+
wall war warning water wave way weather web website week weight west wheel while window winter woman word work worker workflow world worth writer writing
|
|
88
|
+
yard year youth zone`,
|
|
89
|
+
|
|
90
|
+
// Adjectives / adverbs / qualifiers.
|
|
91
|
+
`able absolute abstract active actual additional adequate advanced adverse affordable aggregate alternative ambiguous ancient annual anonymous apparent appropriate arbitrary asynchronous atomic automatic available average aware awful
|
|
92
|
+
bad basic beautiful best better big binary blank blue bold boring bottom brief bright broad broken busy
|
|
93
|
+
calm capable careful central certain cheap chief civil classic clean clear clever close closed cold collective comfortable commercial common competitive complete complex comprehensive concrete confident confusing conscious consistent constant convenient cool core correct costly creative critical crucial cultural current custom
|
|
94
|
+
daily dangerous dark dead deep default defensive deliberate dense dependent desirable detailed different difficult digital direct dirty disabled distinct distributed diverse domestic dominant double downstream dry due dynamic
|
|
95
|
+
eager early easy economic effective efficient elaborate electric elegant eligible embedded empty enabled entire environmental equal equivalent essential eventual evident exact excellent exceptional excited exclusive existing expensive experimental explicit extensive external extra extreme
|
|
96
|
+
fair false familiar famous fast fatal favourite favorite federal final financial fine firm first fit fixed flat flexible foreign formal former forward fragile free frequent fresh friendly full functional fundamental funny future fuzzy
|
|
97
|
+
general generic gentle genuine giant global golden good graceful gradual grand grateful great green gross
|
|
98
|
+
happy hard harmful healthy heavy helpful hidden high historical hollow honest horizontal hostile hot huge human hybrid
|
|
99
|
+
ideal identical idle illegal immediate immutable important impossible improper inactive inclusive incoherent incomplete inconsistent incorrect independent indirect individual industrial inevitable infinite informal initial inner innovative input insufficient intact integral intelligent intended interactive interesting interim intermediate internal international invalid inverse isolated
|
|
100
|
+
joint junior just
|
|
101
|
+
key kind known
|
|
102
|
+
large last late later latest lawful lazy leading legal legitimate lengthy level liable light likely limited linear liquid literal little live lively living local logical long loose lost loud low lower loyal
|
|
103
|
+
main major manual massive mature maximum mean meaningful measurable mechanical medical medium mental mere middle mild military minimal minimum minor missing mixed mobile modern modest modular monthly moral multiple mutual
|
|
104
|
+
narrow national native natural near nearby necessary negative net neutral new next nice noisy normal notable novel numerous
|
|
105
|
+
objective obvious occasional odd official old ongoing online only open operational opposite optimal optional ordinary organic original other outer outstanding overall
|
|
106
|
+
parallel partial particular passive past patient perfect periodic permanent persistent personal physical plain pleasant plural political poor popular positive possible potential powerful practical precise predictable preferred premium present previous primary prime principal prior private probable productive professional profitable progressive prominent proper proportional protective proud public pure
|
|
107
|
+
qualified quality quick quiet
|
|
108
|
+
random rapid rare raw ready real realistic reasonable recent redundant regional regular related relative relevant reliable remaining remote repeated representative required resilient responsible restricted retail reverse rich right rigid robust rough round routine royal rural
|
|
109
|
+
sad safe same satisfied scarce scientific secondary secret secure select selective senior sensible sensitive separate serious severe shallow shared sharp short sick significant silent similar simple single skilled slight slow small smart smooth social soft solid sophisticated sound sour southern spare spatial special specific stable standard static steady steep sticky still straight strange strategic strict strong structural stuck subsequent substantial subtle successful sudden sufficient suitable superior supportive supposed sure surprising suspicious sustainable sweet swift synthetic systematic
|
|
110
|
+
tall technical temporary terrible thick thin third thorough tight tiny tired top total tough toxic traditional transparent tremendous tricky trivial true typical
|
|
111
|
+
ugly ultimate unable unavailable uncertain unclear uncommon underlying undesirable unexpected unfair unfortunate uniform unique universal unknown unlikely unnecessary unrelated unsafe unstable unusual upcoming upper upstream urban urgent useful useless usual
|
|
112
|
+
vague valid valuable variable various vast verbal vertical viable visible visual vital vocal void volatile voluntary vulnerable
|
|
113
|
+
warm weak wealthy weekly weird western wet white whole wide widespread wild willing wise wooden worse worst worthy written wrong
|
|
114
|
+
yearly young zero`,
|
|
115
|
+
|
|
116
|
+
// Software / product / business vocabulary the assistant genuinely uses.
|
|
117
|
+
`agent agile algorithm allocation analytics annotation architecture archive argument artifact assertion assignment async attribute authentication authorization automation availability
|
|
118
|
+
backend backlog bandwidth binary boolean bootstrap bottleneck breakpoint broker browser buffer bundle
|
|
119
|
+
callback capacity certificate changelog checkpoint checksum classifier cluster codebase collaboration commit compiler compliance component composite compression concurrency connector console constant constraint container context contributor controller cookie coordinator corpus coverage credential cron cursor
|
|
120
|
+
daemon dashboard debug debugger decorator delegate dependency deploy deployment deprecation descriptor developer diff directory dispatch distribution docker domain driver duplicate
|
|
121
|
+
embedding encoder encryption endpoint entity enumeration environment escalation event exception executor exporter extension
|
|
122
|
+
fallback feature federation fetch fixture flag fork formatter forwarding fragment framework frontend function
|
|
123
|
+
garbage gateway generator governance gradient granularity graph grid guard
|
|
124
|
+
handler hash header heap heuristic hook hostname hypervisor
|
|
125
|
+
identifier idempotent image importer index inference ingestion inheritance initialiser initializer injection instance instrumentation integer integration interceptor interface interpreter invariant iteration iterator
|
|
126
|
+
json kernel keyword kubernetes
|
|
127
|
+
latency layer ledger lexicon lifecycle linter listener literal locale localisation localization locking logger lookup
|
|
128
|
+
manifest mapper marshalling matrix memoization merge metadata microservice middleware migration mock modality model modifier monolith mutation mutex
|
|
129
|
+
namespace neural nightly normalisation normalization notation nullable
|
|
130
|
+
observability observer offset onboarding operator optimisation optimization orchestration ordering overflow override
|
|
131
|
+
packet parameter parser partition payload permission persistence pipeline plugin pointer policy polling pooling portal predicate prefix preprocessing primitive priority procedure processor producer profiler prompt provider provisioning proxy publisher
|
|
132
|
+
quantisation quantization quota
|
|
133
|
+
race recall reconciliation recursion redirect refactor reference regex registry regression release rendering replica repository request resolver response retention retry rollback rollout router routing runbook runtime
|
|
134
|
+
sandbox scaffolding schema scheduler scope screenshot sdk secret selector semantic serialisation serialization serverless service session shard signature simulation singleton snapshot socket specification sprint stack stakeholder standup state stateless storage strategy stream subscription subsystem suite superset supervisor swagger symbol synchronisation synchronization
|
|
135
|
+
telemetry template tenant terminal test testing throughput throttle timestamp tokeniser tokenizer topology trace transaction transformer transpiler traversal trigger tuple typescript
|
|
136
|
+
unit upstream uptime usage utilisation utilization
|
|
137
|
+
validation validator variable vector versioning viewport virtualisation virtualization visualisation visualization
|
|
138
|
+
warehouse watcher webhook websocket widget worker workspace wrapper
|
|
139
|
+
yaml
|
|
140
|
+
ticket sprint roadmap milestone stakeholder retrospective onboarding offboarding compliance invoice payroll headcount revenue margin forecast pipeline quota churn retention acquisition conversion engagement adoption`,
|
|
141
|
+
].join(' ');
|
|
142
|
+
|
|
143
|
+
/** The lexicon set — lowercase stems only. */
|
|
144
|
+
const ENGLISH_STEMS: ReadonlySet<string> = new Set(
|
|
145
|
+
ENGLISH_STEMS_RAW.split(/\s+/u).map((w) => w.trim().toLowerCase()).filter(Boolean),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Regular inflectional/derivational suffixes stripped before a lexicon lookup, longest
|
|
150
|
+
* first. Keeping the lexicon as STEMS (and stripping here) is what lets ~2.5k entries
|
|
151
|
+
* cover ordinary English text without a megabyte of word forms.
|
|
152
|
+
*/
|
|
153
|
+
const SUFFIXES: readonly string[] = [
|
|
154
|
+
'ationally', 'ability', 'ibility', 'ational', 'iveness', 'fulness', 'lessness',
|
|
155
|
+
'ations', 'ments', 'nesses', 'ingly', 'ation', 'ition', 'ement', 'ments', 'ition',
|
|
156
|
+
'ings', 'ness', 'ment', 'able', 'ible', 'ally', 'ical', 'ance', 'ence', 'sion', 'tion',
|
|
157
|
+
'ised', 'ized', 'ises', 'izes', 'ising', 'izing', 'ise', 'ize',
|
|
158
|
+
'ing', 'ers', 'est', 'ies', 'ied', 'ive', 'ous', 'ful', 'ity', 'ary', 'ory', 'ent', 'ant',
|
|
159
|
+
'ed', 'er', 'es', 'ly', 'al', 'ic', 's', 'y',
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
/** Undo consonant doubling ("commit" + "ing" → "committ" → "commit"). */
|
|
163
|
+
function undouble(stem: string): string {
|
|
164
|
+
const n = stem.length;
|
|
165
|
+
if (n >= 4 && stem[n - 1] === stem[n - 2] && !'aeiou'.includes(stem[n - 1] as string)) return stem.slice(0, -1);
|
|
166
|
+
return stem;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Does the lexicon know this stem, allowing the usual spelling repairs (drop-e, y→i)? */
|
|
170
|
+
function stemKnown(stem: string): boolean {
|
|
171
|
+
if (stem.length < 3) return false;
|
|
172
|
+
if (ENGLISH_STEMS.has(stem)) return true;
|
|
173
|
+
if (ENGLISH_STEMS.has(`${stem}e`)) return true; // us + e → use
|
|
174
|
+
const un = undouble(stem);
|
|
175
|
+
if (un !== stem && ENGLISH_STEMS.has(un)) return true; // committ → commit
|
|
176
|
+
if (stem.endsWith('i') && ENGLISH_STEMS.has(`${stem.slice(0, -1)}y`)) return true; // appli → apply
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Is `word` a plausible English word — either present in the lexicon directly, or a
|
|
182
|
+
* regular inflection of a stem that is? Lowercase input; punctuation already stripped.
|
|
183
|
+
* Deliberately GENEROUS (it decides whether to *accuse* text of being gibberish).
|
|
184
|
+
*/
|
|
185
|
+
export function isKnownEnglishWord(word: string): boolean {
|
|
186
|
+
const w = word.toLowerCase();
|
|
187
|
+
if (w.length < 3) return true; // too short to judge — never an accusation
|
|
188
|
+
if (ENGLISH_STEMS.has(w)) return true;
|
|
189
|
+
for (const suf of SUFFIXES) {
|
|
190
|
+
if (w.length > suf.length + 2 && w.endsWith(suf) && stemKnown(w.slice(0, -suf.length))) return true;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Function words for each supported Latin-script language, used ONLY to decide which
|
|
197
|
+
* language (if any) the text is in — never to score quality. Kept deliberately short:
|
|
198
|
+
* these are the highest-frequency, most distinctive markers of each language.
|
|
199
|
+
*/
|
|
200
|
+
const FUNCTION_WORDS: Readonly<Record<string, readonly string[]>> = {
|
|
201
|
+
en: ['the', 'and', 'that', 'with', 'this', 'for', 'you', 'not', 'are', 'was', 'have', 'from', 'they', 'but', 'what', 'when', 'which', 'there', 'their', 'would', 'about', 'your', 'been', 'will', 'can', 'has', 'its', 'it', 'is', 'of', 'to', 'in', 'on', 'at', 'as', 'by', 'or', 'an', 'be', 'if'],
|
|
202
|
+
es: ['que', 'los', 'las', 'del', 'una', 'por', 'con', 'para', 'como', 'pero', 'este', 'esta', 'son', 'más', 'sus', 'sobre', 'todo', 'ser', 'hay', 'el', 'la', 'de', 'un', 'se', 'no', 'lo', 'al', 'es', 'y'],
|
|
203
|
+
fr: ['les', 'des', 'est', 'une', 'que', 'pour', 'dans', 'sur', 'pas', 'avec', 'sont', 'plus', 'vous', 'nous', 'cette', 'mais', 'aux', 'par', 'ils', 'ce', 'le', 'la', 'de', 'un', 'et', 'du', 'au', 'en', 'il'],
|
|
204
|
+
de: ['der', 'die', 'das', 'und', 'ist', 'nicht', 'mit', 'den', 'von', 'für', 'auf', 'ein', 'eine', 'sich', 'auch', 'dem', 'werden', 'wird', 'aber', 'oder', 'sie', 'wir', 'zu', 'im', 'es', 'als', 'bei', 'nach', 'sind'],
|
|
205
|
+
pt: ['que', 'não', 'uma', 'com', 'para', 'como', 'mais', 'dos', 'das', 'por', 'este', 'esta', 'são', 'ser', 'seu', 'sua', 'pelo', 'ao', 'os', 'as', 'de', 'do', 'da', 'em', 'um', 'no', 'na'],
|
|
206
|
+
it: ['che', 'per', 'con', 'del', 'della', 'una', 'sono', 'più', 'come', 'anche', 'nella', 'questo', 'questa', 'gli', 'nel', 'il', 'la', 'di', 'un', 'da', 'si', 'le', 'ed', 'ma'],
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/** How many alphabetic characters are Latin-script (a–z plus the accented Latin range). */
|
|
210
|
+
function latinLetterShare(text: string): number {
|
|
211
|
+
let letters = 0;
|
|
212
|
+
let latin = 0;
|
|
213
|
+
for (const ch of text) {
|
|
214
|
+
if (!/\p{L}/u.test(ch)) continue;
|
|
215
|
+
letters++;
|
|
216
|
+
if (/[A-Za-zÀ-ɏ]/u.test(ch)) latin++;
|
|
217
|
+
}
|
|
218
|
+
return letters === 0 ? 0 : latin / letters;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** The verdict of the language guard — which Latin language won, and how strongly. */
|
|
222
|
+
export interface LanguageVerdict {
|
|
223
|
+
/** Winning language code, or null when the text isn't Latin-script or no language wins. */
|
|
224
|
+
language: string | null;
|
|
225
|
+
/** Share of tokens that are function words of the winning language (0..1). */
|
|
226
|
+
share: number;
|
|
227
|
+
/** Share of tokens that are function words of ANY supported language (0..1). */
|
|
228
|
+
anyShare: number;
|
|
229
|
+
/** True when the text is predominantly Latin-script (so the guard even applies). */
|
|
230
|
+
latin: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* True when English is the LEADING candidate — no other supported language scored
|
|
233
|
+
* strictly more function-word hits. This, not {@link language}, is what gates the
|
|
234
|
+
* English lexicon, because the two things it must separate are "a genuine Spanish
|
|
235
|
+
* reply" and "English-shaped gibberish", and only the former votes decisively for
|
|
236
|
+
* another language. Gibberish sprays short tokens that happen to be Spanish or
|
|
237
|
+
* French function words (`se`, `te`, `al`, `mis`), which is enough to TIE the vote
|
|
238
|
+
* or squeak past English — and treating that ambiguity as "not English, don't
|
|
239
|
+
* judge it" is exactly how invented-word output escapes the dictionary.
|
|
240
|
+
*/
|
|
241
|
+
englishLeads: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* How many DISTINCT function words a language needs before it wins outright. Raw hit
|
|
246
|
+
* counts are not enough: two occurrences of `se` plus one `al` outvoted English on a
|
|
247
|
+
* real gibberish sample, so the passage was measured against no lexicon at all.
|
|
248
|
+
* Genuine prose in any of these languages uses many different function words (the
|
|
249
|
+
* shortest real Spanish/French replies observed still clear 3), while gibberish
|
|
250
|
+
* repeats the same one or two accidental fragments.
|
|
251
|
+
*/
|
|
252
|
+
const MIN_DISTINCT_FUNCTION_WORDS = 3;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Decide which supported Latin-script language a text is in, by function-word vote.
|
|
256
|
+
* Returns `language: null` for non-Latin scripts (CJK, Cyrillic, Arabic, …) and when
|
|
257
|
+
* no language clears the floor — in both cases the English lexicon must NOT be applied.
|
|
258
|
+
*/
|
|
259
|
+
export function detectLatinLanguage(words: readonly string[], text: string): LanguageVerdict {
|
|
260
|
+
const latin = latinLetterShare(text) >= 0.6;
|
|
261
|
+
if (!latin || words.length === 0) return { language: null, share: 0, anyShare: 0, latin, englishLeads: false };
|
|
262
|
+
|
|
263
|
+
const counts = new Map<string, number>();
|
|
264
|
+
const distinct = new Map<string, number>();
|
|
265
|
+
const anyHit = new Set<number>();
|
|
266
|
+
for (const [lang, list] of Object.entries(FUNCTION_WORDS)) {
|
|
267
|
+
const set = new Set(list);
|
|
268
|
+
let hits = 0;
|
|
269
|
+
const seen = new Set<string>();
|
|
270
|
+
words.forEach((w, i) => {
|
|
271
|
+
if (set.has(w)) { hits++; seen.add(w); anyHit.add(i); }
|
|
272
|
+
});
|
|
273
|
+
counts.set(lang, hits);
|
|
274
|
+
distinct.set(lang, seen.size);
|
|
275
|
+
}
|
|
276
|
+
let best: string | null = null;
|
|
277
|
+
let bestHits = 0;
|
|
278
|
+
let runnerUp = 0;
|
|
279
|
+
for (const [lang, hits] of counts) {
|
|
280
|
+
if (hits > bestHits) { runnerUp = bestHits; bestHits = hits; best = lang; }
|
|
281
|
+
else if (hits > runnerUp) runnerUp = hits;
|
|
282
|
+
}
|
|
283
|
+
const share = bestHits / words.length;
|
|
284
|
+
const anyShare = anyHit.size / words.length;
|
|
285
|
+
// English leads unless some other language beat it on EVIDENCE — more hits AND enough
|
|
286
|
+
// different function words to be a language rather than one repeated fragment. A tie
|
|
287
|
+
// counts as a lead, and so does losing to a single token sprayed three times: see
|
|
288
|
+
// {@link LanguageVerdict.englishLeads}.
|
|
289
|
+
const englishHits = counts.get('en') ?? 0;
|
|
290
|
+
const englishLeads = [...counts].every(([lang, hits]) => (
|
|
291
|
+
lang === 'en'
|
|
292
|
+
|| hits <= englishHits
|
|
293
|
+
|| (distinct.get(lang) ?? 0) < MIN_DISTINCT_FUNCTION_WORDS
|
|
294
|
+
));
|
|
295
|
+
// A win must be present (≥8% of tokens), unambiguous (strictly beats the runner-up)
|
|
296
|
+
// — "in/an/no/de" are shared across languages, so a tie decides nothing — and backed
|
|
297
|
+
// by enough DIFFERENT function words to be a language rather than a repeated fragment.
|
|
298
|
+
const decisive = !!best
|
|
299
|
+
&& share >= 0.08
|
|
300
|
+
&& bestHits > runnerUp
|
|
301
|
+
&& (distinct.get(best) ?? 0) >= MIN_DISTINCT_FUNCTION_WORDS;
|
|
302
|
+
if (!decisive) return { language: null, share, anyShare, latin, englishLeads };
|
|
303
|
+
return { language: best, share, anyShare, latin, englishLeads };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Every supported language's function words in one set, built from the SAME table the
|
|
307
|
+
* language vote uses so the two can never disagree about what a function word is. */
|
|
308
|
+
const ANY_FUNCTION_WORD: ReadonlySet<string> = new Set(Object.values(FUNCTION_WORDS).flat());
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Is this token a function word in ANY supported Latin-script language?
|
|
312
|
+
*
|
|
313
|
+
* Used to tell CONTENT words from grammar. Repetition is what function words are FOR
|
|
314
|
+
* ("the … the … the"), so counting them as evidence of a collapsed head is a category
|
|
315
|
+
* error — and the length-based proxy that stood in for this (any token of 3+ letters)
|
|
316
|
+
* quietly classified `the`, `and`, `for`, `was` and `not` as content.
|
|
317
|
+
*/
|
|
318
|
+
export function isFunctionWord(word: string): boolean {
|
|
319
|
+
return ANY_FUNCTION_WORD.has(word.toLowerCase());
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Tokens that are legitimately not words: identifiers, paths, urls, numbers, versions. */
|
|
323
|
+
const CODEISH = /[0-9_@#$/\\<>{}[\]|`~^*+=]|::|\.\w|--/u;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Is this raw token code rather than prose? Used to EXCLUDE tokens from word scoring —
|
|
327
|
+
* `projectEvermindRef`, `api/src/foo.ts`, `v2.1`, `https://…` are all legitimately
|
|
328
|
+
* absent from any dictionary.
|
|
329
|
+
*/
|
|
330
|
+
export function isCodeishToken(raw: string): boolean {
|
|
331
|
+
if (CODEISH.test(raw)) return true;
|
|
332
|
+
// camelCase / PascalCase with an internal capital → an identifier, not a word.
|
|
333
|
+
if (/^[A-Za-z]+$/u.test(raw) && /[a-z][A-Z]/u.test(raw)) return true;
|
|
334
|
+
// ALLCAPS acronyms (SSM, HTTP, R2) — real, just not lexicon entries.
|
|
335
|
+
if (/^[A-Z]{2,}$/u.test(raw)) return true;
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** The measured outcome of {@link scoreEnglishWordiness}. */
|
|
340
|
+
export interface WordinessScore {
|
|
341
|
+
/** True when the scorer actually ran (English text, enough eligible tokens). */
|
|
342
|
+
scored: boolean;
|
|
343
|
+
/** Eligible content tokens considered. */
|
|
344
|
+
eligible: number;
|
|
345
|
+
/** How many of them matched nothing — not the lexicon, not the context, not a repeat. */
|
|
346
|
+
unknown: number;
|
|
347
|
+
/** unknown / eligible (0 when not scored). */
|
|
348
|
+
unknownShare: number;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Score what fraction of a text's CONTENT words are unrecognisable. Only meaningful for
|
|
353
|
+
* confidently-English text — the caller must consult {@link detectLatinLanguage} first.
|
|
354
|
+
*
|
|
355
|
+
* A token counts as KNOWN when any of these hold, in order of cost:
|
|
356
|
+
* - it is code-ish (identifier / path / acronym) → excluded from scoring entirely;
|
|
357
|
+
* - the lexicon recognises it (with inflection stripping);
|
|
358
|
+
* - it appears in `context` (the prompt/question) — domain jargon echoes the ask;
|
|
359
|
+
* - it occurs more than once in the text — real jargon recurs, invented words don't.
|
|
360
|
+
*/
|
|
361
|
+
export function scoreEnglishWordiness(
|
|
362
|
+
words: readonly string[],
|
|
363
|
+
rawTokens: readonly string[],
|
|
364
|
+
context?: string,
|
|
365
|
+
): WordinessScore {
|
|
366
|
+
const contextWords = new Set(
|
|
367
|
+
(context ?? '').toLowerCase().match(/\p{L}[\p{L}'-]*/gu)?.map((w) => w.replace(/[''-]/gu, '')) ?? [],
|
|
368
|
+
);
|
|
369
|
+
const freq = new Map<string, number>();
|
|
370
|
+
for (const w of words) freq.set(w, (freq.get(w) ?? 0) + 1);
|
|
371
|
+
|
|
372
|
+
let eligible = 0;
|
|
373
|
+
let unknown = 0;
|
|
374
|
+
words.forEach((w, i) => {
|
|
375
|
+
// Judge exactly the words the lexicon is willing to judge. {@link isKnownEnglishWord}
|
|
376
|
+
// already forgives everything under 3 characters outright, so excluding 3-letter
|
|
377
|
+
// tokens on top of that discarded a third of the tokens in a short reply and left
|
|
378
|
+
// the probe-length samples below the evidence floor — unscoreable, hence "coherent".
|
|
379
|
+
// Measured on real samples, including them RAISES the unknown share of gibberish and
|
|
380
|
+
// LOWERS it for genuine English (3-letter English words are almost all in the
|
|
381
|
+
// lexicon), so it widens the margin in both directions.
|
|
382
|
+
if (w.length < 3) return;
|
|
383
|
+
const raw = rawTokens[i] ?? w;
|
|
384
|
+
if (isCodeishToken(raw)) return;
|
|
385
|
+
eligible++;
|
|
386
|
+
if (isKnownEnglishWord(w)) return;
|
|
387
|
+
if (contextWords.has(w)) return;
|
|
388
|
+
if ((freq.get(w) ?? 0) > 1) return;
|
|
389
|
+
unknown++;
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Below this there isn't enough evidence for a verdict either way.
|
|
393
|
+
if (eligible < 10) return { scored: false, eligible, unknown, unknownShare: 0 };
|
|
394
|
+
return { scored: true, eligible, unknown, unknownShare: unknown / eligible };
|
|
395
|
+
}
|
|
@@ -62,8 +62,8 @@ export interface LimbicSessionOptions {
|
|
|
62
62
|
*/
|
|
63
63
|
personalityTraits?: PersonalityTraits;
|
|
64
64
|
/**
|
|
65
|
-
* An explicit 8-dim resting setpoint (e.g. one already derived
|
|
66
|
-
* `
|
|
65
|
+
* An explicit 8-dim resting setpoint (e.g. one already derived with the
|
|
66
|
+
* engine's `limbicSetpoints`). Overrides {@link personalityTraits}. Clamped to bounds.
|
|
67
67
|
*/
|
|
68
68
|
personalitySetpoint?: ArrayLike<number>;
|
|
69
69
|
}
|