verifiable-thinking-mcp 0.4.0
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/LICENSE +21 -0
- package/README.md +339 -0
- package/package.json +75 -0
- package/src/index.ts +38 -0
- package/src/lib/cache.ts +246 -0
- package/src/lib/compression.ts +804 -0
- package/src/lib/compute/cache.ts +86 -0
- package/src/lib/compute/classifier.ts +555 -0
- package/src/lib/compute/confidence.ts +79 -0
- package/src/lib/compute/context.ts +154 -0
- package/src/lib/compute/extract.ts +200 -0
- package/src/lib/compute/filter.ts +224 -0
- package/src/lib/compute/index.ts +171 -0
- package/src/lib/compute/math.ts +247 -0
- package/src/lib/compute/patterns.ts +564 -0
- package/src/lib/compute/registry.ts +145 -0
- package/src/lib/compute/solvers/arithmetic.ts +65 -0
- package/src/lib/compute/solvers/calculus.ts +249 -0
- package/src/lib/compute/solvers/derivation-core.ts +371 -0
- package/src/lib/compute/solvers/derivation-latex.ts +160 -0
- package/src/lib/compute/solvers/derivation-mistakes.ts +1046 -0
- package/src/lib/compute/solvers/derivation-simplify.ts +451 -0
- package/src/lib/compute/solvers/derivation-transform.ts +620 -0
- package/src/lib/compute/solvers/derivation.ts +67 -0
- package/src/lib/compute/solvers/facts.ts +120 -0
- package/src/lib/compute/solvers/formula.ts +728 -0
- package/src/lib/compute/solvers/index.ts +36 -0
- package/src/lib/compute/solvers/logic.ts +422 -0
- package/src/lib/compute/solvers/probability.ts +307 -0
- package/src/lib/compute/solvers/statistics.ts +262 -0
- package/src/lib/compute/solvers/word-problems.ts +408 -0
- package/src/lib/compute/types.ts +107 -0
- package/src/lib/concepts.ts +111 -0
- package/src/lib/domain.ts +731 -0
- package/src/lib/extraction.ts +912 -0
- package/src/lib/index.ts +122 -0
- package/src/lib/judge.ts +260 -0
- package/src/lib/math/ast.ts +842 -0
- package/src/lib/math/index.ts +8 -0
- package/src/lib/math/operators.ts +171 -0
- package/src/lib/math/tokenizer.ts +477 -0
- package/src/lib/patterns.ts +200 -0
- package/src/lib/session.ts +825 -0
- package/src/lib/think/challenge.ts +323 -0
- package/src/lib/think/complexity.ts +504 -0
- package/src/lib/think/confidence-drift.ts +507 -0
- package/src/lib/think/consistency.ts +347 -0
- package/src/lib/think/guidance.ts +188 -0
- package/src/lib/think/helpers.ts +568 -0
- package/src/lib/think/hypothesis.ts +216 -0
- package/src/lib/think/index.ts +127 -0
- package/src/lib/think/prompts.ts +262 -0
- package/src/lib/think/route.ts +358 -0
- package/src/lib/think/schema.ts +98 -0
- package/src/lib/think/scratchpad-schema.ts +662 -0
- package/src/lib/think/spot-check.ts +961 -0
- package/src/lib/think/types.ts +93 -0
- package/src/lib/think/verification.ts +260 -0
- package/src/lib/tokens.ts +177 -0
- package/src/lib/verification.ts +620 -0
- package/src/prompts/index.ts +10 -0
- package/src/prompts/templates.ts +336 -0
- package/src/resources/index.ts +8 -0
- package/src/resources/sessions.ts +196 -0
- package/src/tools/compress.ts +138 -0
- package/src/tools/index.ts +5 -0
- package/src/tools/scratchpad.ts +2659 -0
- package/src/tools/sessions.ts +144 -0
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Domain Detector
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for domain detection used by:
|
|
5
|
+
* - Complexity router (think/complexity.ts) → complexity weight
|
|
6
|
+
* - Compute engine (compute/) → solver relevance filtering
|
|
7
|
+
* - Verification (verification.ts) → domain-specific checks
|
|
8
|
+
*
|
|
9
|
+
* Architecture: O(n) keyword matching with precomputed lowercase
|
|
10
|
+
* Returns both granular domain and meta-category for different consumers.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { type SolverMask, SolverType } from "./compute/classifier.ts";
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// TYPES
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
/** Granular domain for complexity scoring */
|
|
20
|
+
export type GranularDomain =
|
|
21
|
+
| "quantum_computing"
|
|
22
|
+
| "cryptography"
|
|
23
|
+
| "complexity_theory"
|
|
24
|
+
| "distributed_systems"
|
|
25
|
+
| "networking"
|
|
26
|
+
| "competitive_analysis"
|
|
27
|
+
| "paradox"
|
|
28
|
+
| "probability_statistics"
|
|
29
|
+
| "machine_learning"
|
|
30
|
+
| "cognitive_reasoning"
|
|
31
|
+
| "algorithms"
|
|
32
|
+
| "calculus"
|
|
33
|
+
| "linear_algebra"
|
|
34
|
+
| "logic_puzzle"
|
|
35
|
+
| "game_theory"
|
|
36
|
+
| "number_theory"
|
|
37
|
+
| "combinatorics"
|
|
38
|
+
| "constraint_reasoning"
|
|
39
|
+
| "conditional_probability"
|
|
40
|
+
| "lateral_thinking"
|
|
41
|
+
| "rate_problems"
|
|
42
|
+
| "clock_problems"
|
|
43
|
+
| "common_knowledge"
|
|
44
|
+
| "financial"
|
|
45
|
+
| "teaching"
|
|
46
|
+
| "general";
|
|
47
|
+
|
|
48
|
+
/** Meta-category for compute filtering */
|
|
49
|
+
export type MetaDomain = "financial" | "coding" | "scientific" | "educational" | "general";
|
|
50
|
+
|
|
51
|
+
/** Verification domain (legacy compat) */
|
|
52
|
+
export type VerificationDomain = "math" | "logic" | "code" | "general";
|
|
53
|
+
|
|
54
|
+
/** Full detection result */
|
|
55
|
+
export interface DomainResult {
|
|
56
|
+
/** Granular domain name */
|
|
57
|
+
domain: GranularDomain;
|
|
58
|
+
/** Complexity weight (0-1) for router */
|
|
59
|
+
weight: number;
|
|
60
|
+
/** Meta-category for compute filtering */
|
|
61
|
+
meta: MetaDomain;
|
|
62
|
+
/** Verification domain for legacy compat */
|
|
63
|
+
verification: VerificationDomain;
|
|
64
|
+
/** Solver types relevant for this domain */
|
|
65
|
+
relevantSolvers: SolverMask;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// DOMAIN DEFINITIONS
|
|
70
|
+
// =============================================================================
|
|
71
|
+
|
|
72
|
+
interface DomainDef {
|
|
73
|
+
keywords: string[];
|
|
74
|
+
weight: number;
|
|
75
|
+
meta: MetaDomain;
|
|
76
|
+
verification: VerificationDomain;
|
|
77
|
+
/** Which solver types are relevant (bitmask) */
|
|
78
|
+
solvers: SolverMask;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** All solver types - for educational/general where we want everything */
|
|
82
|
+
const ALL_SOLVERS =
|
|
83
|
+
SolverType.ARITHMETIC |
|
|
84
|
+
SolverType.FORMULA_TIER1 |
|
|
85
|
+
SolverType.FORMULA_TIER2 |
|
|
86
|
+
SolverType.FORMULA_TIER3 |
|
|
87
|
+
SolverType.FORMULA_TIER4 |
|
|
88
|
+
SolverType.WORD_PROBLEM |
|
|
89
|
+
SolverType.MULTI_STEP |
|
|
90
|
+
SolverType.CALCULUS |
|
|
91
|
+
SolverType.FACTS |
|
|
92
|
+
SolverType.LOGIC |
|
|
93
|
+
SolverType.PROBABILITY;
|
|
94
|
+
|
|
95
|
+
/** Basic math only - for general questions */
|
|
96
|
+
const BASIC_MATH =
|
|
97
|
+
SolverType.ARITHMETIC | SolverType.FORMULA_TIER1 | SolverType.FORMULA_TIER2 | SolverType.FACTS;
|
|
98
|
+
|
|
99
|
+
/** Financial computations */
|
|
100
|
+
const FINANCIAL_SOLVERS =
|
|
101
|
+
SolverType.ARITHMETIC |
|
|
102
|
+
SolverType.FORMULA_TIER1 | // percentage
|
|
103
|
+
SolverType.FORMULA_TIER4 | // interest
|
|
104
|
+
SolverType.WORD_PROBLEM;
|
|
105
|
+
|
|
106
|
+
/** Coding-relevant computations */
|
|
107
|
+
const CODING_SOLVERS =
|
|
108
|
+
SolverType.ARITHMETIC |
|
|
109
|
+
SolverType.FORMULA_TIER1 | // modulo, factorial
|
|
110
|
+
SolverType.FORMULA_TIER2 | // power, gcd, lcm
|
|
111
|
+
SolverType.FORMULA_TIER3; // log, combinations
|
|
112
|
+
|
|
113
|
+
/** Scientific computations (all math) */
|
|
114
|
+
const SCIENTIFIC_SOLVERS = ALL_SOLVERS;
|
|
115
|
+
|
|
116
|
+
/** Logic and probability */
|
|
117
|
+
const LOGIC_SOLVERS =
|
|
118
|
+
SolverType.LOGIC | SolverType.PROBABILITY | SolverType.FACTS | SolverType.ARITHMETIC;
|
|
119
|
+
|
|
120
|
+
const DOMAINS: Record<GranularDomain, DomainDef> = {
|
|
121
|
+
// === HIGH COMPLEXITY (0.9+) ===
|
|
122
|
+
quantum_computing: {
|
|
123
|
+
keywords: ["quantum", "qubit", "superposition", "entanglement", "shor's algorithm"],
|
|
124
|
+
weight: 0.95,
|
|
125
|
+
meta: "scientific",
|
|
126
|
+
verification: "math",
|
|
127
|
+
solvers: SCIENTIFIC_SOLVERS,
|
|
128
|
+
},
|
|
129
|
+
cryptography: {
|
|
130
|
+
keywords: [
|
|
131
|
+
"cryptograph",
|
|
132
|
+
"rsa",
|
|
133
|
+
"lattice",
|
|
134
|
+
"zero-knowledge",
|
|
135
|
+
"discrete logarithm",
|
|
136
|
+
"public-key",
|
|
137
|
+
"security reduction",
|
|
138
|
+
],
|
|
139
|
+
weight: 0.95,
|
|
140
|
+
meta: "coding",
|
|
141
|
+
verification: "math",
|
|
142
|
+
solvers: CODING_SOLVERS,
|
|
143
|
+
},
|
|
144
|
+
common_knowledge: {
|
|
145
|
+
keywords: [
|
|
146
|
+
"blue eyes",
|
|
147
|
+
"blue-eyed",
|
|
148
|
+
"islanders",
|
|
149
|
+
"leave at midnight",
|
|
150
|
+
"know your",
|
|
151
|
+
"common knowledge",
|
|
152
|
+
"induction",
|
|
153
|
+
"eye color",
|
|
154
|
+
"days until",
|
|
155
|
+
],
|
|
156
|
+
weight: 0.95,
|
|
157
|
+
meta: "educational",
|
|
158
|
+
verification: "logic",
|
|
159
|
+
solvers: ALL_SOLVERS,
|
|
160
|
+
},
|
|
161
|
+
complexity_theory: {
|
|
162
|
+
keywords: [
|
|
163
|
+
"p ≠ np",
|
|
164
|
+
"p vs np",
|
|
165
|
+
"np-complete",
|
|
166
|
+
"np-hard",
|
|
167
|
+
"polynomial-time",
|
|
168
|
+
"exponential time",
|
|
169
|
+
"sat solver",
|
|
170
|
+
"sat instance",
|
|
171
|
+
"halting problem",
|
|
172
|
+
"undecidable",
|
|
173
|
+
"computability",
|
|
174
|
+
"turing machine",
|
|
175
|
+
],
|
|
176
|
+
weight: 0.9,
|
|
177
|
+
meta: "coding",
|
|
178
|
+
verification: "logic",
|
|
179
|
+
solvers: CODING_SOLVERS,
|
|
180
|
+
},
|
|
181
|
+
distributed_systems: {
|
|
182
|
+
keywords: [
|
|
183
|
+
"lock-free",
|
|
184
|
+
"consensus",
|
|
185
|
+
"distributed",
|
|
186
|
+
"byzantine",
|
|
187
|
+
"memory ordering",
|
|
188
|
+
"cache coherence",
|
|
189
|
+
"two-phase commit",
|
|
190
|
+
"paxos",
|
|
191
|
+
"raft",
|
|
192
|
+
],
|
|
193
|
+
weight: 0.9,
|
|
194
|
+
meta: "coding",
|
|
195
|
+
verification: "code",
|
|
196
|
+
solvers: CODING_SOLVERS,
|
|
197
|
+
},
|
|
198
|
+
paradox: {
|
|
199
|
+
keywords: [
|
|
200
|
+
"two envelopes",
|
|
201
|
+
"envelope paradox",
|
|
202
|
+
"sleeping beauty",
|
|
203
|
+
"halfers",
|
|
204
|
+
"thirders",
|
|
205
|
+
"monty hall",
|
|
206
|
+
"naive argument",
|
|
207
|
+
"symmetrically",
|
|
208
|
+
"prisoners",
|
|
209
|
+
"loop-following",
|
|
210
|
+
"survival probability",
|
|
211
|
+
"100 boxes",
|
|
212
|
+
"boy born on tuesday",
|
|
213
|
+
"born on",
|
|
214
|
+
"probability both are boys",
|
|
215
|
+
"both children",
|
|
216
|
+
"two children",
|
|
217
|
+
"this statement",
|
|
218
|
+
"self-referential",
|
|
219
|
+
"liar paradox",
|
|
220
|
+
"sorites",
|
|
221
|
+
"heap paradox",
|
|
222
|
+
"grain",
|
|
223
|
+
"simpson",
|
|
224
|
+
"aggregation paradox",
|
|
225
|
+
],
|
|
226
|
+
weight: 0.92,
|
|
227
|
+
meta: "educational",
|
|
228
|
+
verification: "logic",
|
|
229
|
+
solvers: ALL_SOLVERS,
|
|
230
|
+
},
|
|
231
|
+
logic_puzzle: {
|
|
232
|
+
keywords: [
|
|
233
|
+
"knight",
|
|
234
|
+
"knave",
|
|
235
|
+
"liar",
|
|
236
|
+
"truth-teller",
|
|
237
|
+
"truthteller",
|
|
238
|
+
"syllogism",
|
|
239
|
+
"valid argument",
|
|
240
|
+
"sound argument",
|
|
241
|
+
"premise",
|
|
242
|
+
"conclusion follows",
|
|
243
|
+
"logically",
|
|
244
|
+
"VALID",
|
|
245
|
+
"INVALID",
|
|
246
|
+
"UNSOUND",
|
|
247
|
+
"valid or invalid",
|
|
248
|
+
"sound or unsound",
|
|
249
|
+
],
|
|
250
|
+
weight: 0.92,
|
|
251
|
+
meta: "educational",
|
|
252
|
+
verification: "logic",
|
|
253
|
+
solvers: LOGIC_SOLVERS,
|
|
254
|
+
},
|
|
255
|
+
game_theory: {
|
|
256
|
+
keywords: [
|
|
257
|
+
"prisoner's dilemma",
|
|
258
|
+
"nash equilibrium",
|
|
259
|
+
"payoff",
|
|
260
|
+
"dominant strategy",
|
|
261
|
+
"zero-sum",
|
|
262
|
+
"minimax",
|
|
263
|
+
"game theory",
|
|
264
|
+
],
|
|
265
|
+
weight: 0.9,
|
|
266
|
+
meta: "scientific",
|
|
267
|
+
verification: "math",
|
|
268
|
+
solvers: SCIENTIFIC_SOLVERS,
|
|
269
|
+
},
|
|
270
|
+
conditional_probability: {
|
|
271
|
+
keywords: [
|
|
272
|
+
"given that",
|
|
273
|
+
"conditional",
|
|
274
|
+
"revolver",
|
|
275
|
+
"russian roulette",
|
|
276
|
+
"chamber",
|
|
277
|
+
"bullet",
|
|
278
|
+
"envelope",
|
|
279
|
+
"adjacent",
|
|
280
|
+
"spin",
|
|
281
|
+
"fire",
|
|
282
|
+
],
|
|
283
|
+
weight: 0.9,
|
|
284
|
+
meta: "scientific",
|
|
285
|
+
verification: "math",
|
|
286
|
+
solvers: SolverType.PROBABILITY | SolverType.ARITHMETIC,
|
|
287
|
+
},
|
|
288
|
+
competitive_analysis: {
|
|
289
|
+
keywords: ["competitive ratio", "online algorithm", "ski-rental", "adversarial"],
|
|
290
|
+
weight: 0.88,
|
|
291
|
+
meta: "coding",
|
|
292
|
+
verification: "math",
|
|
293
|
+
solvers: CODING_SOLVERS,
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
// === MODERATE-HIGH COMPLEXITY (0.7-0.89) ===
|
|
297
|
+
number_theory: {
|
|
298
|
+
keywords: [
|
|
299
|
+
"prime",
|
|
300
|
+
"factorial",
|
|
301
|
+
"divisible",
|
|
302
|
+
"remainder",
|
|
303
|
+
"modulo",
|
|
304
|
+
"mod ",
|
|
305
|
+
"trailing zero",
|
|
306
|
+
"integer",
|
|
307
|
+
"divisor",
|
|
308
|
+
"gcd",
|
|
309
|
+
"lcm",
|
|
310
|
+
"last digit",
|
|
311
|
+
"^100",
|
|
312
|
+
"^10",
|
|
313
|
+
],
|
|
314
|
+
weight: 0.85,
|
|
315
|
+
meta: "scientific",
|
|
316
|
+
verification: "math",
|
|
317
|
+
solvers:
|
|
318
|
+
SolverType.FORMULA_TIER1 |
|
|
319
|
+
SolverType.FORMULA_TIER2 |
|
|
320
|
+
SolverType.FORMULA_TIER3 |
|
|
321
|
+
SolverType.ARITHMETIC,
|
|
322
|
+
},
|
|
323
|
+
combinatorics: {
|
|
324
|
+
keywords: [
|
|
325
|
+
"arrange",
|
|
326
|
+
"permutation",
|
|
327
|
+
"combination",
|
|
328
|
+
"ways to",
|
|
329
|
+
"how many ways",
|
|
330
|
+
"choose",
|
|
331
|
+
"select",
|
|
332
|
+
"distribute",
|
|
333
|
+
"partition",
|
|
334
|
+
"letters in",
|
|
335
|
+
"anagram",
|
|
336
|
+
"mississippi",
|
|
337
|
+
"arrange the letters",
|
|
338
|
+
],
|
|
339
|
+
weight: 0.85,
|
|
340
|
+
meta: "scientific",
|
|
341
|
+
verification: "math",
|
|
342
|
+
solvers: SolverType.FORMULA_TIER3 | SolverType.ARITHMETIC,
|
|
343
|
+
},
|
|
344
|
+
constraint_reasoning: {
|
|
345
|
+
keywords: [
|
|
346
|
+
"minimum number",
|
|
347
|
+
"guarantee",
|
|
348
|
+
"worst case",
|
|
349
|
+
"at least",
|
|
350
|
+
"at most",
|
|
351
|
+
"balance scale",
|
|
352
|
+
"weighing",
|
|
353
|
+
"pigeonhole",
|
|
354
|
+
"must draw",
|
|
355
|
+
"must flip",
|
|
356
|
+
],
|
|
357
|
+
weight: 0.85,
|
|
358
|
+
meta: "educational",
|
|
359
|
+
verification: "logic",
|
|
360
|
+
solvers: ALL_SOLVERS,
|
|
361
|
+
},
|
|
362
|
+
clock_problems: {
|
|
363
|
+
keywords: ["clock hands", "hour hand", "minute hand", "overlap", "12 hours", "24 hours"],
|
|
364
|
+
weight: 0.85,
|
|
365
|
+
meta: "scientific",
|
|
366
|
+
verification: "math",
|
|
367
|
+
solvers: SolverType.ARITHMETIC | SolverType.FORMULA_TIER1,
|
|
368
|
+
},
|
|
369
|
+
probability_statistics: {
|
|
370
|
+
keywords: [
|
|
371
|
+
"probability",
|
|
372
|
+
"bayesian",
|
|
373
|
+
"conditional probability",
|
|
374
|
+
"bayes",
|
|
375
|
+
"distribution",
|
|
376
|
+
"regression",
|
|
377
|
+
"statistical",
|
|
378
|
+
"expected value",
|
|
379
|
+
"variance",
|
|
380
|
+
"sample size",
|
|
381
|
+
"more reliable",
|
|
382
|
+
"less reliable",
|
|
383
|
+
"survey of",
|
|
384
|
+
"expected number",
|
|
385
|
+
"expected flips",
|
|
386
|
+
"expected rolls",
|
|
387
|
+
// Econometrics / causal inference
|
|
388
|
+
"instrumental variable",
|
|
389
|
+
"instrument",
|
|
390
|
+
"causal effect",
|
|
391
|
+
"causal inference",
|
|
392
|
+
"endogenous",
|
|
393
|
+
"exogenous",
|
|
394
|
+
"confound",
|
|
395
|
+
"confounder",
|
|
396
|
+
"treatment effect",
|
|
397
|
+
"randomized",
|
|
398
|
+
"observational",
|
|
399
|
+
"selection bias",
|
|
400
|
+
"omitted variable",
|
|
401
|
+
"estimate effect",
|
|
402
|
+
"estimate the effect",
|
|
403
|
+
],
|
|
404
|
+
weight: 0.85, // Slightly higher than teaching (0.6) to win keyword conflicts
|
|
405
|
+
meta: "scientific",
|
|
406
|
+
verification: "math",
|
|
407
|
+
solvers: SolverType.PROBABILITY | SolverType.ARITHMETIC | SolverType.FORMULA_TIER1,
|
|
408
|
+
},
|
|
409
|
+
lateral_thinking: {
|
|
410
|
+
keywords: ["trick", "lateral", "only enter once", "can only", "how do you", "determine which"],
|
|
411
|
+
weight: 0.8,
|
|
412
|
+
meta: "educational",
|
|
413
|
+
verification: "logic",
|
|
414
|
+
solvers: ALL_SOLVERS,
|
|
415
|
+
},
|
|
416
|
+
machine_learning: {
|
|
417
|
+
keywords: [
|
|
418
|
+
"backpropagation",
|
|
419
|
+
"gradient",
|
|
420
|
+
"neural network",
|
|
421
|
+
"deep learning",
|
|
422
|
+
"optimization",
|
|
423
|
+
"loss function",
|
|
424
|
+
"transformer",
|
|
425
|
+
"attention mechanism",
|
|
426
|
+
],
|
|
427
|
+
weight: 0.75,
|
|
428
|
+
meta: "coding",
|
|
429
|
+
verification: "math",
|
|
430
|
+
solvers: SCIENTIFIC_SOLVERS,
|
|
431
|
+
},
|
|
432
|
+
cognitive_reasoning: {
|
|
433
|
+
keywords: [
|
|
434
|
+
"cognitive",
|
|
435
|
+
"psychology",
|
|
436
|
+
"logical fallacy",
|
|
437
|
+
"fallacy",
|
|
438
|
+
"inference",
|
|
439
|
+
"heuristic",
|
|
440
|
+
"bias",
|
|
441
|
+
],
|
|
442
|
+
weight: 0.75,
|
|
443
|
+
meta: "educational",
|
|
444
|
+
verification: "logic",
|
|
445
|
+
solvers: LOGIC_SOLVERS,
|
|
446
|
+
},
|
|
447
|
+
rate_problems: {
|
|
448
|
+
keywords: [
|
|
449
|
+
"machines",
|
|
450
|
+
"widgets",
|
|
451
|
+
"workers",
|
|
452
|
+
"mph",
|
|
453
|
+
"speed",
|
|
454
|
+
"rate",
|
|
455
|
+
"per hour",
|
|
456
|
+
"per minute",
|
|
457
|
+
"round trip",
|
|
458
|
+
"average speed",
|
|
459
|
+
],
|
|
460
|
+
weight: 0.75,
|
|
461
|
+
meta: "scientific",
|
|
462
|
+
verification: "math",
|
|
463
|
+
solvers: SolverType.WORD_PROBLEM | SolverType.ARITHMETIC | SolverType.FORMULA_TIER1,
|
|
464
|
+
},
|
|
465
|
+
calculus: {
|
|
466
|
+
keywords: [
|
|
467
|
+
"derivative",
|
|
468
|
+
"integral",
|
|
469
|
+
"limit",
|
|
470
|
+
"differentiation",
|
|
471
|
+
"integration",
|
|
472
|
+
"calculus",
|
|
473
|
+
"d/dx",
|
|
474
|
+
"integral of",
|
|
475
|
+
"∫",
|
|
476
|
+
],
|
|
477
|
+
weight: 0.72,
|
|
478
|
+
meta: "scientific",
|
|
479
|
+
verification: "math",
|
|
480
|
+
solvers:
|
|
481
|
+
SolverType.CALCULUS |
|
|
482
|
+
SolverType.ARITHMETIC |
|
|
483
|
+
SolverType.FORMULA_TIER1 |
|
|
484
|
+
SolverType.FORMULA_TIER2,
|
|
485
|
+
},
|
|
486
|
+
algorithms: {
|
|
487
|
+
keywords: [
|
|
488
|
+
"algorithm",
|
|
489
|
+
"time complexity",
|
|
490
|
+
"space complexity",
|
|
491
|
+
"big-o",
|
|
492
|
+
"recursion",
|
|
493
|
+
"dynamic programming",
|
|
494
|
+
"graph traversal",
|
|
495
|
+
],
|
|
496
|
+
weight: 0.7,
|
|
497
|
+
meta: "coding",
|
|
498
|
+
verification: "code",
|
|
499
|
+
solvers: CODING_SOLVERS,
|
|
500
|
+
},
|
|
501
|
+
linear_algebra: {
|
|
502
|
+
keywords: [
|
|
503
|
+
"matrix",
|
|
504
|
+
"determinant",
|
|
505
|
+
"eigenvalue",
|
|
506
|
+
"eigenvector",
|
|
507
|
+
"inverse matrix",
|
|
508
|
+
"transpose",
|
|
509
|
+
"linear transformation",
|
|
510
|
+
],
|
|
511
|
+
weight: 0.7,
|
|
512
|
+
meta: "scientific",
|
|
513
|
+
verification: "math",
|
|
514
|
+
solvers: SolverType.FORMULA_TIER4 | SolverType.ARITHMETIC,
|
|
515
|
+
},
|
|
516
|
+
networking: {
|
|
517
|
+
keywords: ["tcp", "udp", "three-way handshake", "protocol", "packet", "routing", "dns", "http"],
|
|
518
|
+
weight: 0.7,
|
|
519
|
+
meta: "coding",
|
|
520
|
+
verification: "code",
|
|
521
|
+
solvers: BASIC_MATH,
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
// === FINANCIAL (special category) ===
|
|
525
|
+
financial: {
|
|
526
|
+
keywords: [
|
|
527
|
+
"interest",
|
|
528
|
+
"compound",
|
|
529
|
+
"investment",
|
|
530
|
+
"roi",
|
|
531
|
+
"return on",
|
|
532
|
+
"savings",
|
|
533
|
+
"loan",
|
|
534
|
+
"mortgage",
|
|
535
|
+
"amortization",
|
|
536
|
+
"apr",
|
|
537
|
+
"apy",
|
|
538
|
+
"stock",
|
|
539
|
+
"portfolio",
|
|
540
|
+
"dividend",
|
|
541
|
+
"inflation",
|
|
542
|
+
"present value",
|
|
543
|
+
"future value",
|
|
544
|
+
"npv",
|
|
545
|
+
"irr",
|
|
546
|
+
"financial advisor",
|
|
547
|
+
"finance",
|
|
548
|
+
"budget",
|
|
549
|
+
"expense",
|
|
550
|
+
"revenue",
|
|
551
|
+
"profit margin",
|
|
552
|
+
"break-even",
|
|
553
|
+
],
|
|
554
|
+
weight: 0.65,
|
|
555
|
+
meta: "financial",
|
|
556
|
+
verification: "math",
|
|
557
|
+
solvers: FINANCIAL_SOLVERS,
|
|
558
|
+
},
|
|
559
|
+
|
|
560
|
+
// === TEACHING/EDUCATIONAL (show all work) ===
|
|
561
|
+
teaching: {
|
|
562
|
+
keywords: [
|
|
563
|
+
"tutor",
|
|
564
|
+
"teacher",
|
|
565
|
+
"student",
|
|
566
|
+
"homework",
|
|
567
|
+
"assignment",
|
|
568
|
+
"lesson",
|
|
569
|
+
"learn",
|
|
570
|
+
"explain",
|
|
571
|
+
"teach",
|
|
572
|
+
"class",
|
|
573
|
+
"course",
|
|
574
|
+
"education",
|
|
575
|
+
"school",
|
|
576
|
+
"university",
|
|
577
|
+
"college",
|
|
578
|
+
"exam",
|
|
579
|
+
"test prep",
|
|
580
|
+
"study",
|
|
581
|
+
"practice problem",
|
|
582
|
+
"exercise",
|
|
583
|
+
"worksheet",
|
|
584
|
+
"step by step",
|
|
585
|
+
"show your work",
|
|
586
|
+
"show work",
|
|
587
|
+
"solve step",
|
|
588
|
+
"walk through",
|
|
589
|
+
"walkthrough",
|
|
590
|
+
],
|
|
591
|
+
weight: 0.55, // Lower than most domains - should be overridden by specific math domains
|
|
592
|
+
meta: "educational",
|
|
593
|
+
verification: "general",
|
|
594
|
+
solvers: ALL_SOLVERS,
|
|
595
|
+
},
|
|
596
|
+
|
|
597
|
+
// === DEFAULT ===
|
|
598
|
+
general: {
|
|
599
|
+
keywords: [],
|
|
600
|
+
weight: 0.5,
|
|
601
|
+
meta: "general",
|
|
602
|
+
verification: "general",
|
|
603
|
+
solvers: BASIC_MATH,
|
|
604
|
+
},
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// Precompute domain list for iteration (excludes "general" which is fallback)
|
|
608
|
+
const DOMAIN_LIST = Object.entries(DOMAINS).filter(([name]) => name !== "general") as [
|
|
609
|
+
GranularDomain,
|
|
610
|
+
DomainDef,
|
|
611
|
+
][];
|
|
612
|
+
|
|
613
|
+
// =============================================================================
|
|
614
|
+
// OPTIMIZED KEYWORD INDEX
|
|
615
|
+
// Build a keyword→domain map for O(1) exact-match lookups.
|
|
616
|
+
// Keywords sorted by length (longest first) for substring matching.
|
|
617
|
+
// =============================================================================
|
|
618
|
+
|
|
619
|
+
interface KeywordEntry {
|
|
620
|
+
keyword: string;
|
|
621
|
+
domain: GranularDomain;
|
|
622
|
+
def: DomainDef;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Build keyword index at module load time
|
|
626
|
+
const KEYWORD_INDEX: KeywordEntry[] = [];
|
|
627
|
+
|
|
628
|
+
for (const [domain, def] of DOMAIN_LIST) {
|
|
629
|
+
for (const kw of def.keywords) {
|
|
630
|
+
KEYWORD_INDEX.push({ keyword: kw.toLowerCase(), domain, def });
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Sort by:
|
|
635
|
+
// 1. Domain weight descending (higher complexity domains match first)
|
|
636
|
+
// 2. Keyword length descending (longer matches take priority within same weight tier)
|
|
637
|
+
// This ensures "conditional probability" matches before "probability",
|
|
638
|
+
// and higher-weight domains like "financial" match before lower-weight ones like "teaching"
|
|
639
|
+
KEYWORD_INDEX.sort((a, b) => {
|
|
640
|
+
const weightDiff = b.def.weight - a.def.weight;
|
|
641
|
+
if (Math.abs(weightDiff) > 0.01) return weightDiff;
|
|
642
|
+
return b.keyword.length - a.keyword.length;
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
// =============================================================================
|
|
646
|
+
// MAIN DETECTION FUNCTION
|
|
647
|
+
// =============================================================================
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Detect domain from text with optimized keyword matching.
|
|
651
|
+
* Uses pre-sorted keyword index for O(k) complexity where k = number of keywords.
|
|
652
|
+
* Keywords are checked longest-first to prefer more specific matches.
|
|
653
|
+
*
|
|
654
|
+
* @param text - Text to analyze (question, system prompt, or thought)
|
|
655
|
+
* @returns Full domain detection result
|
|
656
|
+
*/
|
|
657
|
+
export function detectDomainFull(text: string): DomainResult {
|
|
658
|
+
const lower = text.toLowerCase();
|
|
659
|
+
|
|
660
|
+
// Optimized: iterate pre-sorted keywords (longest first)
|
|
661
|
+
// First match wins, ensuring "conditional probability" beats "probability"
|
|
662
|
+
for (const { keyword, domain, def } of KEYWORD_INDEX) {
|
|
663
|
+
if (lower.includes(keyword)) {
|
|
664
|
+
return {
|
|
665
|
+
domain,
|
|
666
|
+
weight: def.weight,
|
|
667
|
+
meta: def.meta,
|
|
668
|
+
verification: def.verification,
|
|
669
|
+
relevantSolvers: def.solvers,
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Fallback to general
|
|
675
|
+
const general = DOMAINS.general;
|
|
676
|
+
return {
|
|
677
|
+
domain: "general",
|
|
678
|
+
weight: general.weight,
|
|
679
|
+
meta: general.meta,
|
|
680
|
+
verification: general.verification,
|
|
681
|
+
relevantSolvers: general.solvers,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// =============================================================================
|
|
686
|
+
// CONVENIENCE FUNCTIONS
|
|
687
|
+
// =============================================================================
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Get just the granular domain name (for complexity router)
|
|
691
|
+
*/
|
|
692
|
+
export function detectGranularDomain(text: string): GranularDomain {
|
|
693
|
+
return detectDomainFull(text).domain;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Get domain weight for complexity scoring
|
|
698
|
+
*/
|
|
699
|
+
export function getDomainWeight(text: string): { domain: string; weight: number } {
|
|
700
|
+
const result = detectDomainFull(text);
|
|
701
|
+
return { domain: result.domain, weight: result.weight };
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Get meta-domain for compute filtering
|
|
706
|
+
*/
|
|
707
|
+
export function detectMetaDomain(text: string): MetaDomain {
|
|
708
|
+
return detectDomainFull(text).meta;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Get verification domain (legacy compat with verification.ts)
|
|
713
|
+
*/
|
|
714
|
+
export function detectVerificationDomain(text: string): VerificationDomain {
|
|
715
|
+
return detectDomainFull(text).verification;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Get relevant solver bitmask for a text's domain
|
|
720
|
+
*/
|
|
721
|
+
export function getRelevantSolvers(text: string): SolverMask {
|
|
722
|
+
return detectDomainFull(text).relevantSolvers;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Check if a solver type is relevant for the detected domain
|
|
727
|
+
*/
|
|
728
|
+
export function isSolverRelevant(text: string, solverType: SolverMask): boolean {
|
|
729
|
+
const relevant = detectDomainFull(text).relevantSolvers;
|
|
730
|
+
return (relevant & solverType) !== 0;
|
|
731
|
+
}
|