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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +339 -0
  3. package/package.json +75 -0
  4. package/src/index.ts +38 -0
  5. package/src/lib/cache.ts +246 -0
  6. package/src/lib/compression.ts +804 -0
  7. package/src/lib/compute/cache.ts +86 -0
  8. package/src/lib/compute/classifier.ts +555 -0
  9. package/src/lib/compute/confidence.ts +79 -0
  10. package/src/lib/compute/context.ts +154 -0
  11. package/src/lib/compute/extract.ts +200 -0
  12. package/src/lib/compute/filter.ts +224 -0
  13. package/src/lib/compute/index.ts +171 -0
  14. package/src/lib/compute/math.ts +247 -0
  15. package/src/lib/compute/patterns.ts +564 -0
  16. package/src/lib/compute/registry.ts +145 -0
  17. package/src/lib/compute/solvers/arithmetic.ts +65 -0
  18. package/src/lib/compute/solvers/calculus.ts +249 -0
  19. package/src/lib/compute/solvers/derivation-core.ts +371 -0
  20. package/src/lib/compute/solvers/derivation-latex.ts +160 -0
  21. package/src/lib/compute/solvers/derivation-mistakes.ts +1046 -0
  22. package/src/lib/compute/solvers/derivation-simplify.ts +451 -0
  23. package/src/lib/compute/solvers/derivation-transform.ts +620 -0
  24. package/src/lib/compute/solvers/derivation.ts +67 -0
  25. package/src/lib/compute/solvers/facts.ts +120 -0
  26. package/src/lib/compute/solvers/formula.ts +728 -0
  27. package/src/lib/compute/solvers/index.ts +36 -0
  28. package/src/lib/compute/solvers/logic.ts +422 -0
  29. package/src/lib/compute/solvers/probability.ts +307 -0
  30. package/src/lib/compute/solvers/statistics.ts +262 -0
  31. package/src/lib/compute/solvers/word-problems.ts +408 -0
  32. package/src/lib/compute/types.ts +107 -0
  33. package/src/lib/concepts.ts +111 -0
  34. package/src/lib/domain.ts +731 -0
  35. package/src/lib/extraction.ts +912 -0
  36. package/src/lib/index.ts +122 -0
  37. package/src/lib/judge.ts +260 -0
  38. package/src/lib/math/ast.ts +842 -0
  39. package/src/lib/math/index.ts +8 -0
  40. package/src/lib/math/operators.ts +171 -0
  41. package/src/lib/math/tokenizer.ts +477 -0
  42. package/src/lib/patterns.ts +200 -0
  43. package/src/lib/session.ts +825 -0
  44. package/src/lib/think/challenge.ts +323 -0
  45. package/src/lib/think/complexity.ts +504 -0
  46. package/src/lib/think/confidence-drift.ts +507 -0
  47. package/src/lib/think/consistency.ts +347 -0
  48. package/src/lib/think/guidance.ts +188 -0
  49. package/src/lib/think/helpers.ts +568 -0
  50. package/src/lib/think/hypothesis.ts +216 -0
  51. package/src/lib/think/index.ts +127 -0
  52. package/src/lib/think/prompts.ts +262 -0
  53. package/src/lib/think/route.ts +358 -0
  54. package/src/lib/think/schema.ts +98 -0
  55. package/src/lib/think/scratchpad-schema.ts +662 -0
  56. package/src/lib/think/spot-check.ts +961 -0
  57. package/src/lib/think/types.ts +93 -0
  58. package/src/lib/think/verification.ts +260 -0
  59. package/src/lib/tokens.ts +177 -0
  60. package/src/lib/verification.ts +620 -0
  61. package/src/prompts/index.ts +10 -0
  62. package/src/prompts/templates.ts +336 -0
  63. package/src/resources/index.ts +8 -0
  64. package/src/resources/sessions.ts +196 -0
  65. package/src/tools/compress.ts +138 -0
  66. package/src/tools/index.ts +5 -0
  67. package/src/tools/scratchpad.ts +2659 -0
  68. package/src/tools/sessions.ts +144 -0
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Local Compute Engine
3
+ *
4
+ * Solves computable problems instantly without LLM calls.
5
+ * Why ask an LLM to compute 17+28 when TypeScript can do it in 0.001ms?
6
+ *
7
+ * Architecture:
8
+ * 1. Classifier: Fast bitmask routing (~0.01ms)
9
+ * 2. Registry: Auto-discovered solvers by type
10
+ * 3. Cache: LRU cache for repeated questions
11
+ *
12
+ * Capabilities:
13
+ * - Arithmetic: basic math expressions
14
+ * - Formulas: pythagorean, quadratic, fibonacci, logarithms, factorial
15
+ * - Word problems: "twice as many", "half of", "sum of X and Y"
16
+ * - Multi-step word problems: entity extraction + dependency resolution
17
+ * - Multi-expression extraction: finds ALL computable parts in text
18
+ * - Context injection: returns augmented prompt with computed values
19
+ * - LRU caching: avoids recomputing identical questions
20
+ * - Confidence scoring: returns likelihood of successful local compute
21
+ * - Domain filtering: filters computations by domain relevance
22
+ */
23
+
24
+ // Re-export cache utilities
25
+ export { clearCache, computeCache, getCacheStats } from "./cache.ts";
26
+ // Re-export classifier
27
+ export {
28
+ type ClassifierResult,
29
+ classifyQuestion,
30
+ describeMask,
31
+ SolverGroup,
32
+ type SolverMask,
33
+ SolverType,
34
+ shouldTrySolver,
35
+ } from "./classifier.ts";
36
+ // Re-export confidence
37
+ export { computeConfidence, isLikelyComputable } from "./confidence.ts";
38
+ // Re-export context-aware compute
39
+ export {
40
+ type ContextAwareInput,
41
+ type ContextAwareResult,
42
+ computeWithContext,
43
+ contextAwareCompute,
44
+ wouldKeepComputation,
45
+ } from "./context.ts";
46
+
47
+ // Re-export extraction
48
+ export { computeAndReplace, extractAndCompute } from "./extract.ts";
49
+ // Re-export filtering
50
+ export {
51
+ type FilterResult,
52
+ filterByDomainRelevance,
53
+ filterByMask,
54
+ isMethodRelevant,
55
+ methodToSolverType,
56
+ } from "./filter.ts";
57
+ // Re-export math helpers (for testing)
58
+ export {
59
+ combinations,
60
+ factorial,
61
+ fibonacci,
62
+ formatResult,
63
+ gcd,
64
+ isPrime,
65
+ lcm,
66
+ normalizeUnicodeSuperscripts,
67
+ type ParseResult,
68
+ permutations,
69
+ safeEvaluate,
70
+ } from "./math.ts";
71
+ // Re-export registry
72
+ export {
73
+ getRegistryStats,
74
+ getSolvers,
75
+ getSolversForMask,
76
+ registerSolver,
77
+ runSolvers,
78
+ type Solver,
79
+ } from "./registry.ts";
80
+ // Re-export solvers (for direct access / testing)
81
+ export {
82
+ canonicalizeExpression,
83
+ type DerivationErrorExplanation,
84
+ type DerivationLatexOptions,
85
+ type DerivationResult,
86
+ type DetectedMistake,
87
+ derivationTextToLatex,
88
+ derivationToLatex,
89
+ detectCommonMistakes,
90
+ detectCommonMistakesFromText,
91
+ explainDerivationError,
92
+ type MistakeDetectionResult,
93
+ type MistakeType,
94
+ type NextStepSuggestion,
95
+ type SimplificationPath,
96
+ type SimplificationStep,
97
+ type SimplifiedStep,
98
+ type SimplifyDerivationResult,
99
+ simplifyDerivation,
100
+ simplifyDerivationText,
101
+ suggestNextStep,
102
+ suggestNextStepFromText,
103
+ suggestSimplificationPath,
104
+ tryArithmetic,
105
+ tryCalculus,
106
+ tryCRTProblem,
107
+ tryDerivation,
108
+ tryFormula,
109
+ tryLogic,
110
+ tryMathFacts,
111
+ tryMultiStepWordProblem,
112
+ tryProbability,
113
+ trySimplifyToConstant,
114
+ tryWordProblem,
115
+ verifyDerivationSteps,
116
+ } from "./solvers/index.ts";
117
+ // Re-export types
118
+ export type {
119
+ AugmentedResult,
120
+ CacheStats,
121
+ ComputeConfidence,
122
+ ComputeResult,
123
+ ExtractedComputation,
124
+ } from "./types.ts";
125
+
126
+ // Import for main function
127
+ import { computeCache } from "./cache.ts";
128
+ import { classifyQuestion } from "./classifier.ts";
129
+ import { runSolvers } from "./registry.ts";
130
+ import type { ComputeResult } from "./types.ts";
131
+
132
+ /**
133
+ * Try to solve a question locally without LLM
134
+ * Returns immediately if computable, otherwise returns { solved: false }
135
+ *
136
+ * Flow:
137
+ * 1. Check cache (instant return if hit)
138
+ * 2. Classify question → bitmask of likely solver types
139
+ * 3. Run matching solvers in priority order
140
+ * 4. Cache successful results
141
+ *
142
+ * @param text - The question to solve
143
+ * @param useCache - Whether to use LRU cache (default: true)
144
+ */
145
+ export function tryLocalCompute(text: string, useCache = true): ComputeResult {
146
+ // Check cache first
147
+ if (useCache) {
148
+ const cached = computeCache.get(text);
149
+ if (cached) {
150
+ return { ...cached, time_ms: 0 }; // Cache hit is instant
151
+ }
152
+ }
153
+
154
+ // Classify question to get solver mask
155
+ const { mask, lower } = classifyQuestion(text);
156
+
157
+ // No solvers match → quick exit
158
+ if (mask === 0) {
159
+ return { solved: false, confidence: 0 };
160
+ }
161
+
162
+ // Run matching solvers
163
+ const result = runSolvers(text, lower, mask);
164
+
165
+ // Cache successful results
166
+ if (result.solved && useCache) {
167
+ computeCache.set(text, result);
168
+ }
169
+
170
+ return result;
171
+ }
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Pure math helper functions
3
+ * No regex, no side effects - just computation
4
+ */
5
+
6
+ /** Calculate combinations C(n,k) = n! / (k! * (n-k)!) without factorial overflow */
7
+ export function combinations(n: number, k: number): number {
8
+ if (k > n - k) k = n - k; // Optimization: C(n,k) = C(n,n-k)
9
+ let result = 1;
10
+ for (let i = 0; i < k; i++) {
11
+ result = (result * (n - i)) / (i + 1);
12
+ }
13
+ return Math.round(result);
14
+ }
15
+
16
+ /** Calculate permutations P(n,k) = n! / (n-k)! */
17
+ export function permutations(n: number, k: number): number {
18
+ let result = 1;
19
+ for (let i = 0; i < k; i++) {
20
+ result *= n - i;
21
+ }
22
+ return result;
23
+ }
24
+
25
+ /** Calculate nth Fibonacci number (1-indexed) */
26
+ export function fibonacci(n: number): number {
27
+ if (n <= 0) return 0;
28
+ if (n <= 2) return 1;
29
+
30
+ let a = 1,
31
+ b = 1;
32
+ for (let i = 3; i <= n; i++) {
33
+ [a, b] = [b, a + b];
34
+ }
35
+ return b;
36
+ }
37
+
38
+ /** Calculate factorial n! */
39
+ export function factorial(n: number): number {
40
+ if (n <= 1) return 1;
41
+ let result = 1;
42
+ for (let i = 2; i <= n; i++) {
43
+ result *= i;
44
+ }
45
+ return result;
46
+ }
47
+
48
+ /** Calculate greatest common divisor using Euclidean algorithm */
49
+ export function gcd(a: number, b: number): number {
50
+ a = Math.abs(a);
51
+ b = Math.abs(b);
52
+ while (b) {
53
+ [a, b] = [b, a % b];
54
+ }
55
+ return a;
56
+ }
57
+
58
+ /** Calculate least common multiple */
59
+ export function lcm(a: number, b: number): number {
60
+ return Math.abs(a * b) / gcd(a, b);
61
+ }
62
+
63
+ /** Check if n is prime using 6k+-1 optimization */
64
+ export function isPrime(n: number): boolean {
65
+ if (n < 2) return false;
66
+ if (n === 2) return true;
67
+ if (n % 2 === 0) return false;
68
+ if (n === 3) return true;
69
+ if (n % 3 === 0) return false;
70
+
71
+ // Check 6k+-1 up to sqrt(n)
72
+ const sqrt = Math.sqrt(n);
73
+ for (let i = 5; i <= sqrt; i += 6) {
74
+ if (n % i === 0 || n % (i + 2) === 0) return false;
75
+ }
76
+ return true;
77
+ }
78
+
79
+ /** Format a number result: integer if whole, otherwise fixed to 6 decimals */
80
+ export function formatResult(n: number): number {
81
+ return Number.isInteger(n) ? n : +n.toFixed(6);
82
+ }
83
+
84
+ // =============================================================================
85
+ // SAFE EXPRESSION PARSER
86
+ // Recursive descent parser - no eval/Function, pure math operations only
87
+ // Grammar:
88
+ // expr → term (('+' | '-') term)*
89
+ // term → factor (('*' | '/') factor)*
90
+ // factor → base ('^' factor)? // Right-associative exponentiation
91
+ // base → '-' base | primary
92
+ // primary → NUMBER | '(' expr ')'
93
+ // =============================================================================
94
+
95
+ export interface ParseResult {
96
+ success: boolean;
97
+ value?: number;
98
+ error?: string;
99
+ }
100
+
101
+ /**
102
+ * Safe arithmetic expression parser
103
+ * Supports: +, -, *, /, ^, (), negative numbers, decimals
104
+ * NO eval, NO Function constructor - pure recursive descent
105
+ */
106
+ export function safeEvaluate(expression: string): ParseResult {
107
+ // Remove whitespace and normalize
108
+ const input = expression.replace(/\s+/g, "").replace(/\*\*/g, "^");
109
+
110
+ // Quick validation - only allow safe characters
111
+ if (!/^[\d+\-*/^().]+$/.test(input)) {
112
+ return { success: false, error: "Invalid characters" };
113
+ }
114
+
115
+ // Check for empty or invalid patterns
116
+ // Note: We allow +- or -- (e.g., 5+-3 = 5+(-3), --5 = 5)
117
+ // But reject: **, //, */, /*, etc.
118
+ if (input === "" || /\(\)|[*/^]{2}|^[*/^]|[+\-*/^(]$/.test(input)) {
119
+ return { success: false, error: "Invalid expression" };
120
+ }
121
+
122
+ let pos = 0;
123
+
124
+ function peek(): string {
125
+ return input[pos] || "";
126
+ }
127
+
128
+ function consume(): string {
129
+ return input[pos++] || "";
130
+ }
131
+
132
+ function parseNumber(): number | null {
133
+ const start = pos;
134
+ // Handle leading negative that's part of the number (handled in base, but also here for safety)
135
+ if (peek() === "-") consume();
136
+ // Integer part
137
+ while (/\d/.test(peek())) consume();
138
+ // Decimal part
139
+ if (peek() === ".") {
140
+ consume();
141
+ while (/\d/.test(peek())) consume();
142
+ }
143
+ const numStr = input.slice(start, pos);
144
+ if (numStr === "" || numStr === "-" || numStr === ".") {
145
+ pos = start;
146
+ return null;
147
+ }
148
+ return parseFloat(numStr);
149
+ }
150
+
151
+ function parsePrimary(): number | null {
152
+ if (peek() === "(") {
153
+ consume(); // '('
154
+ const result = parseExpr();
155
+ if (result === null) return null;
156
+ if (peek() !== ")") return null;
157
+ consume(); // ')'
158
+ return result;
159
+ }
160
+ return parseNumber();
161
+ }
162
+
163
+ function parseBase(): number | null {
164
+ if (peek() === "-") {
165
+ consume();
166
+ const val = parseBase(); // Recursive for multiple negatives: --5
167
+ return val === null ? null : -val;
168
+ }
169
+ return parsePrimary();
170
+ }
171
+
172
+ function parseFactor(): number | null {
173
+ const left = parseBase();
174
+ if (left === null) return null;
175
+ if (peek() === "^") {
176
+ consume();
177
+ const right = parseFactor(); // Right-associative: 2^3^2 = 2^(3^2) = 512
178
+ if (right === null) return null;
179
+ return left ** right;
180
+ }
181
+ return left;
182
+ }
183
+
184
+ function parseTerm(): number | null {
185
+ let left = parseFactor();
186
+ if (left === null) return null;
187
+ while (peek() === "*" || peek() === "/") {
188
+ const op = consume();
189
+ const right = parseFactor();
190
+ if (right === null) return null;
191
+ if (op === "*") {
192
+ left = left * right;
193
+ } else {
194
+ if (right === 0) return null; // Division by zero
195
+ left = left / right;
196
+ }
197
+ }
198
+ return left;
199
+ }
200
+
201
+ function parseExpr(): number | null {
202
+ let left = parseTerm();
203
+ if (left === null) return null;
204
+ while (peek() === "+" || peek() === "-") {
205
+ const op = consume();
206
+ const right = parseTerm();
207
+ if (right === null) return null;
208
+ left = op === "+" ? left + right : left - right;
209
+ }
210
+ return left;
211
+ }
212
+
213
+ try {
214
+ const result = parseExpr();
215
+ // Ensure we consumed the entire input
216
+ if (result === null || pos !== input.length) {
217
+ return { success: false, error: "Parse error" };
218
+ }
219
+ if (!Number.isFinite(result)) {
220
+ return { success: false, error: "Result not finite" };
221
+ }
222
+ return { success: true, value: result };
223
+ } catch {
224
+ return { success: false, error: "Parse error" };
225
+ }
226
+ }
227
+
228
+ /** Normalize Unicode superscripts to ^n notation */
229
+ export function normalizeUnicodeSuperscripts(text: string): string {
230
+ const superscriptMap: Record<string, string> = {
231
+ "\u2070": "^0",
232
+ "\u00B9": "^1",
233
+ "\u00B2": "^2",
234
+ "\u00B3": "^3",
235
+ "\u2074": "^4",
236
+ "\u2075": "^5",
237
+ "\u2076": "^6",
238
+ "\u2077": "^7",
239
+ "\u2078": "^8",
240
+ "\u2079": "^9",
241
+ };
242
+ let result = text;
243
+ for (const [sup, repl] of Object.entries(superscriptMap)) {
244
+ result = result.replaceAll(sup, repl);
245
+ }
246
+ return result;
247
+ }