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,371 @@
1
+ /**
2
+ * Derivation Core - verifies multi-step algebraic derivations
3
+ *
4
+ * Uses compareExpressions to check that each step in a derivation is
5
+ * algebraically equivalent to the previous step. Catches "magic" steps
6
+ * in proofs where the transformation isn't valid.
7
+ *
8
+ * @module derivation-core
9
+ */
10
+
11
+ import { compareExpressions } from "../../verification.ts";
12
+ import type { ComputeResult } from "../types.ts";
13
+
14
+ /** Result of verifying a single derivation step */
15
+ export interface StepVerification {
16
+ step: number;
17
+ lhs: string;
18
+ rhs: string;
19
+ valid: boolean;
20
+ error?: string;
21
+ }
22
+
23
+ /** Result of verifying a complete derivation */
24
+ export interface DerivationResult {
25
+ valid: boolean;
26
+ steps: StepVerification[];
27
+ invalidStep?: number;
28
+ error?: string;
29
+ }
30
+
31
+ /**
32
+ * Extract derivation steps from text
33
+ * Looks for patterns like:
34
+ * expr1 = expr2
35
+ * expr3 = expr4
36
+ * ...
37
+ *
38
+ * Or chained: expr1 = expr2 = expr3 = ...
39
+ *
40
+ * Or sentence-separated: expr1 = expr2, then expr3 = expr4
41
+ */
42
+ export function extractDerivationSteps(text: string): Array<{ lhs: string; rhs: string }> {
43
+ const steps: Array<{ lhs: string; rhs: string }> = [];
44
+
45
+ // Pre-process: split on sentence boundaries (comma, semicolon, "then", "so", etc.)
46
+ // to handle multi-step derivations in a single line
47
+ const segments = text
48
+ .split(/[,;]|\bthen\b|\bso\b|\btherefore\b|\bhence\b/i)
49
+ .map((s) => s.trim())
50
+ .filter(Boolean);
51
+
52
+ // Process each segment
53
+ for (const segment of segments) {
54
+ // Pattern 1: Chained equalities (a = b = c = d)
55
+ // Split on "=" and pair consecutive terms
56
+ const chainedMatch = segment.match(
57
+ /([^=\n]+(?:=[^=\n]+){2,})/g, // 3+ terms connected by =
58
+ );
59
+
60
+ if (chainedMatch) {
61
+ for (const chain of chainedMatch) {
62
+ const parts = chain
63
+ .split("=")
64
+ .map((p) => cleanExpressionPart(p))
65
+ .filter(Boolean);
66
+ for (let i = 0; i < parts.length - 1; i++) {
67
+ const lhs = parts[i];
68
+ const rhs = parts[i + 1];
69
+ if (lhs && rhs) {
70
+ steps.push({ lhs, rhs });
71
+ }
72
+ }
73
+ }
74
+ continue; // Move to next segment
75
+ }
76
+
77
+ // Pattern 2: Simple equality (expr = expr)
78
+ const simpleMatch = segment.match(/^\s*([^=\n]+?)\s*=\s*([^=\n]+?)\s*$/);
79
+ if (simpleMatch) {
80
+ const lhs = cleanExpressionPart(simpleMatch[1] ?? "");
81
+ const rhs = cleanExpressionPart(simpleMatch[2] ?? "");
82
+ if (lhs && rhs) {
83
+ steps.push({ lhs, rhs });
84
+ }
85
+ }
86
+ }
87
+
88
+ // If no steps found via segment processing, try original line-by-line approach
89
+ if (steps.length === 0) {
90
+ // Pattern 3: Line-by-line equalities
91
+ const linePattern = /^\s*([^=\n]+?)\s*=\s*([^=\n]+?)\s*$/gm;
92
+ let match: RegExpExecArray | null;
93
+ while ((match = linePattern.exec(text)) !== null) {
94
+ const lhs = cleanExpressionPart(match[1] ?? "");
95
+ const rhs = cleanExpressionPart(match[2] ?? "");
96
+ if (lhs && rhs) {
97
+ steps.push({ lhs, rhs });
98
+ }
99
+ }
100
+ }
101
+
102
+ return steps;
103
+ }
104
+
105
+ /**
106
+ * Clean an expression part by removing non-math prefixes
107
+ * E.g., "prove: x + x" → "x + x"
108
+ */
109
+ export function cleanExpressionPart(part: string): string {
110
+ let cleaned = part.trim();
111
+
112
+ // Remove common prefixes like "prove:", "show that", "verify:", etc.
113
+ cleaned = cleaned.replace(
114
+ /^(?:prove|show(?:\s+that)?|verify|therefore|thus|hence|so|then)[:.]?\s*/i,
115
+ "",
116
+ );
117
+
118
+ // Remove leading non-math characters (but keep negative signs)
119
+ // Match from start: letters/punctuation that aren't part of a variable
120
+ cleaned = cleaned.replace(/^[^a-zA-Z0-9\-.(]+/, "");
121
+
122
+ return cleaned.trim();
123
+ }
124
+
125
+ /**
126
+ * Verify that each step in a derivation is algebraically valid
127
+ *
128
+ * For each step "A = B", we verify:
129
+ * 1. A and B are equivalent (within the same step)
130
+ *
131
+ * For consecutive steps, we verify:
132
+ * 2. The RHS of step N equals the LHS of step N+1 (continuity)
133
+ *
134
+ * @param steps Array of {lhs, rhs} pairs representing the derivation
135
+ * @returns DerivationResult with validity and error details
136
+ */
137
+ export function verifyDerivationSteps(
138
+ steps: Array<{ lhs: string; rhs: string }>,
139
+ ): DerivationResult {
140
+ if (steps.length === 0) {
141
+ return { valid: false, steps: [], error: "No derivation steps found" };
142
+ }
143
+
144
+ const verifiedSteps: StepVerification[] = [];
145
+
146
+ for (let i = 0; i < steps.length; i++) {
147
+ const step = steps[i];
148
+ if (!step) continue;
149
+
150
+ const { lhs, rhs } = step;
151
+ const stepNum = i + 1;
152
+
153
+ // Check 1: LHS and RHS of this step are equivalent
154
+ const equivalent = compareExpressions(lhs, rhs);
155
+
156
+ if (!equivalent) {
157
+ verifiedSteps.push({
158
+ step: stepNum,
159
+ lhs,
160
+ rhs,
161
+ valid: false,
162
+ error: `Step ${stepNum}: "${lhs}" is not equivalent to "${rhs}"`,
163
+ });
164
+ return {
165
+ valid: false,
166
+ steps: verifiedSteps,
167
+ invalidStep: stepNum,
168
+ error: `Invalid step ${stepNum}: ${lhs} ≠ ${rhs}`,
169
+ };
170
+ }
171
+
172
+ // Check 2: Continuity with previous step
173
+ // The LHS of this step should equal the RHS of the previous step
174
+ if (i > 0) {
175
+ const prevStep = steps[i - 1];
176
+ if (prevStep) {
177
+ const continuous = compareExpressions(prevStep.rhs, lhs);
178
+ if (!continuous) {
179
+ verifiedSteps.push({
180
+ step: stepNum,
181
+ lhs,
182
+ rhs,
183
+ valid: false,
184
+ error: `Step ${stepNum} doesn't follow from step ${stepNum - 1}: "${prevStep.rhs}" → "${lhs}"`,
185
+ });
186
+ return {
187
+ valid: false,
188
+ steps: verifiedSteps,
189
+ invalidStep: stepNum,
190
+ error: `Discontinuity at step ${stepNum}: previous RHS "${prevStep.rhs}" ≠ current LHS "${lhs}"`,
191
+ };
192
+ }
193
+ }
194
+ }
195
+
196
+ verifiedSteps.push({
197
+ step: stepNum,
198
+ lhs,
199
+ rhs,
200
+ valid: true,
201
+ });
202
+ }
203
+
204
+ return {
205
+ valid: true,
206
+ steps: verifiedSteps,
207
+ };
208
+ }
209
+
210
+ /**
211
+ * Try to verify a derivation in text
212
+ *
213
+ * Extracts derivation steps and verifies each one is algebraically valid.
214
+ * Useful for checking mathematical proofs and simplification chains.
215
+ *
216
+ * @example
217
+ * // Valid derivation
218
+ * tryDerivation("x + x = 2x = 2*x")
219
+ * // { solved: true, result: "Valid derivation (2 steps)", ... }
220
+ *
221
+ * @example
222
+ * // Invalid derivation
223
+ * tryDerivation("x + x = 2x = 3x")
224
+ * // { solved: true, result: "Invalid step 2: 2x ≠ 3x", ... }
225
+ */
226
+ export function tryDerivation(text: string): ComputeResult {
227
+ const start = performance.now();
228
+ const lower = text.toLowerCase();
229
+
230
+ // Guard: Only try derivation if text looks like a proof/derivation
231
+ const hasDerivationKeywords =
232
+ lower.includes("show") ||
233
+ lower.includes("prove") ||
234
+ lower.includes("verify") ||
235
+ lower.includes("derivation") ||
236
+ lower.includes("simplif") ||
237
+ lower.includes("therefore") ||
238
+ lower.includes("thus") ||
239
+ lower.includes("hence") ||
240
+ text.includes("⟹") ||
241
+ text.includes("→") ||
242
+ text.includes("=>") ||
243
+ // Multiple equals signs suggest a derivation chain
244
+ (text.match(/=/g)?.length ?? 0) >= 2;
245
+
246
+ if (!hasDerivationKeywords) {
247
+ return { solved: false, confidence: 0 };
248
+ }
249
+
250
+ const steps = extractDerivationSteps(text);
251
+
252
+ if (steps.length < 1) {
253
+ return { solved: false, confidence: 0 };
254
+ }
255
+
256
+ const result = verifyDerivationSteps(steps);
257
+ const time_ms = performance.now() - start;
258
+
259
+ if (result.valid) {
260
+ return {
261
+ solved: true,
262
+ result: `Valid derivation (${result.steps.length} steps verified)`,
263
+ method: "derivation_verification",
264
+ confidence: 1.0,
265
+ time_ms,
266
+ };
267
+ }
268
+
269
+ return {
270
+ solved: true,
271
+ result: result.error ?? "Invalid derivation",
272
+ method: "derivation_verification",
273
+ confidence: 0.9, // Slightly lower confidence for invalid results
274
+ time_ms,
275
+ };
276
+ }
277
+
278
+ /** Human-readable explanation of a derivation error */
279
+ export interface DerivationErrorExplanation {
280
+ /** Short summary of the error */
281
+ summary: string;
282
+ /** Detailed explanation suitable for display */
283
+ explanation: string;
284
+ /** The problematic step (1-indexed) */
285
+ stepNumber: number;
286
+ /** What was expected */
287
+ expected?: string;
288
+ /** What was found */
289
+ found?: string;
290
+ /** Specific suggestions to fix the error */
291
+ fixSuggestions: string[];
292
+ }
293
+
294
+ /**
295
+ * Generate a human-readable explanation for a derivation verification error
296
+ *
297
+ * Analyzes the DerivationResult and produces clear, actionable feedback
298
+ * about what went wrong and how to fix it.
299
+ *
300
+ * @param result The DerivationResult from verifyDerivationSteps
301
+ * @returns DerivationErrorExplanation with detailed feedback, or null if valid
302
+ */
303
+ export function explainDerivationError(
304
+ result: DerivationResult,
305
+ ): DerivationErrorExplanation | null {
306
+ // No error to explain if derivation is valid
307
+ if (result.valid) {
308
+ return null;
309
+ }
310
+
311
+ const invalidStep = result.invalidStep ?? 1;
312
+ const errorStep = result.steps.find((s) => !s.valid);
313
+
314
+ if (!errorStep) {
315
+ // Generic error (no steps found, etc.)
316
+ return {
317
+ summary: result.error ?? "Derivation verification failed",
318
+ explanation:
319
+ result.error ??
320
+ "The derivation could not be verified. Ensure each step follows logically from the previous.",
321
+ stepNumber: 0,
322
+ fixSuggestions: [
323
+ "Check that the derivation contains valid mathematical expressions",
324
+ "Ensure each line follows the format 'expression = expression'",
325
+ "Verify that equals signs (=) are used correctly",
326
+ ],
327
+ };
328
+ }
329
+
330
+ const { lhs, rhs, error } = errorStep;
331
+
332
+ // Determine error type and generate appropriate explanation
333
+ const isDiscontinuity = error?.includes("doesn't follow") || error?.includes("Discontinuity");
334
+
335
+ if (isDiscontinuity) {
336
+ // Continuity error: previous RHS doesn't match current LHS
337
+ return {
338
+ summary: `Derivation breaks at step ${invalidStep}`,
339
+ explanation:
340
+ `Step ${invalidStep} doesn't follow from the previous step. ` +
341
+ `The left side of step ${invalidStep} ('${lhs}') should equal the right side of step ${invalidStep - 1}. ` +
342
+ `Each step must connect to the previous step to form a valid chain.`,
343
+ stepNumber: invalidStep,
344
+ expected: `Continue from previous result`,
345
+ found: lhs,
346
+ fixSuggestions: [
347
+ `Ensure step ${invalidStep} starts with the result from step ${invalidStep - 1}`,
348
+ `Check for typos or missing intermediate steps`,
349
+ `If changing variables, show the substitution explicitly`,
350
+ ],
351
+ };
352
+ }
353
+
354
+ // Equivalence error: LHS and RHS of the same step are not equivalent
355
+ return {
356
+ summary: `Invalid algebraic transformation at step ${invalidStep}`,
357
+ explanation:
358
+ `The expression '${lhs}' is not algebraically equivalent to '${rhs}'. ` +
359
+ `This transformation cannot be justified by standard algebraic rules. ` +
360
+ `The two expressions evaluate to different values.`,
361
+ stepNumber: invalidStep,
362
+ expected: lhs,
363
+ found: rhs,
364
+ fixSuggestions: [
365
+ `Verify the algebraic manipulation from '${lhs}' to '${rhs}'`,
366
+ `Check for sign errors or incorrect coefficient handling`,
367
+ `Consider adding intermediate steps to make the transformation clearer`,
368
+ `If this is a substitution, ensure the substituted value is correct`,
369
+ ],
370
+ };
371
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Derivation LaTeX - converts derivations to LaTeX format
3
+ *
4
+ * Produces LaTeX code suitable for mathematical documents with proper
5
+ * alignment of equals signs and optional step numbering.
6
+ *
7
+ * @module derivation-latex
8
+ */
9
+
10
+ import { extractDerivationSteps } from "./derivation-core.ts";
11
+
12
+ /** Options for LaTeX derivation formatting */
13
+ export interface DerivationLatexOptions {
14
+ /** Use align environment for multi-step (default: true) */
15
+ useAlign?: boolean;
16
+ /** Add step numbers as comments (default: false) */
17
+ showStepNumbers?: boolean;
18
+ /** Include "therefore" symbol before final step (default: false) */
19
+ showTherefore?: boolean;
20
+ /** Custom label for the derivation (default: none) */
21
+ label?: string;
22
+ }
23
+
24
+ /**
25
+ * Convert an expression to LaTeX notation
26
+ */
27
+ function toLatex(expr: string): string {
28
+ let result = expr;
29
+
30
+ // Convert multiplication: * or · → \cdot
31
+ result = result.replace(/\s*[*·×]\s*/g, " \\cdot ");
32
+
33
+ // Convert division: ÷ → \div (or could use \frac)
34
+ result = result.replace(/\s*÷\s*/g, " \\div ");
35
+
36
+ // Convert powers: x^2 → x^{2}, x^10 → x^{10}
37
+ result = result.replace(/\^(\d+)/g, "^{$1}");
38
+ result = result.replace(/\^([a-zA-Z])/g, "^{$1}");
39
+
40
+ // Convert sqrt: sqrt(x) → \sqrt{x}
41
+ result = result.replace(/sqrt\(([^)]+)\)/gi, "\\sqrt{$1}");
42
+
43
+ // Convert common functions
44
+ result = result.replace(/\b(sin|cos|tan|log|ln|exp)\b/g, "\\$1");
45
+
46
+ // Convert pi → \pi
47
+ result = result.replace(/\bpi\b/gi, "\\pi");
48
+
49
+ // Convert fractions: a/b → \frac{a}{b} (simple cases only)
50
+ result = result.replace(/(\d+)\s*\/\s*(\d+)/g, "\\frac{$1}{$2}");
51
+
52
+ // Handle minus signs for better rendering
53
+ result = result.replace(/−/g, "-");
54
+
55
+ return result;
56
+ }
57
+
58
+ /**
59
+ * Convert a derivation chain to LaTeX format with aligned equations
60
+ *
61
+ * Produces LaTeX code suitable for mathematical documents with proper
62
+ * alignment of equals signs and optional step numbering.
63
+ *
64
+ * @param steps Array of {lhs, rhs} pairs representing the derivation
65
+ * @param options Formatting options
66
+ * @returns LaTeX string
67
+ *
68
+ * @example
69
+ * derivationToLatex([
70
+ * { lhs: "x + x", rhs: "2x" },
71
+ * { lhs: "2x", rhs: "2 * x" }
72
+ * ])
73
+ * // Returns:
74
+ * // \begin{align}
75
+ * // x + x &= 2x \\
76
+ * // &= 2 \cdot x
77
+ * // \end{align}
78
+ */
79
+ export function derivationToLatex(
80
+ steps: Array<{ lhs: string; rhs: string }>,
81
+ options: DerivationLatexOptions = {},
82
+ ): string {
83
+ const { useAlign = true, showStepNumbers = false, showTherefore = false, label } = options;
84
+
85
+ if (steps.length === 0) {
86
+ return "";
87
+ }
88
+
89
+ const lines: string[] = [];
90
+
91
+ if (useAlign) {
92
+ const envStart = label ? `\\begin{align}\\label{${label}}` : "\\begin{align}";
93
+ lines.push(envStart);
94
+
95
+ for (let i = 0; i < steps.length; i++) {
96
+ const step = steps[i];
97
+ if (!step) continue;
98
+
99
+ const isFirst = i === 0;
100
+ const isLast = i === steps.length - 1;
101
+
102
+ const lhsLatex = toLatex(step.lhs);
103
+ const rhsLatex = toLatex(step.rhs);
104
+
105
+ let line: string;
106
+
107
+ if (isFirst) {
108
+ // First line shows full equation
109
+ line = ` ${lhsLatex} &= ${rhsLatex}`;
110
+ } else {
111
+ // Subsequent lines only show RHS (aligned at =)
112
+ if (showTherefore && isLast) {
113
+ line = ` &\\therefore ${rhsLatex}`;
114
+ } else {
115
+ line = ` &= ${rhsLatex}`;
116
+ }
117
+ }
118
+
119
+ // Add step number comment
120
+ if (showStepNumbers) {
121
+ line += ` && \\text{(${i + 1})}`;
122
+ }
123
+
124
+ // Add line continuation (except last line)
125
+ if (!isLast) {
126
+ line += " \\\\";
127
+ }
128
+
129
+ lines.push(line);
130
+ }
131
+
132
+ lines.push("\\end{align}");
133
+ } else {
134
+ // Simple equation environment (no alignment)
135
+ const allExprs = steps.map((s) => `${toLatex(s.lhs)} = ${toLatex(s.rhs)}`);
136
+ lines.push("\\begin{equation}");
137
+ lines.push(` ${allExprs.join(" = ")}`);
138
+ lines.push("\\end{equation}");
139
+ }
140
+
141
+ return lines.join("\n");
142
+ }
143
+
144
+ /**
145
+ * Convert text containing a derivation to LaTeX
146
+ *
147
+ * @param text Text containing a derivation
148
+ * @param options Formatting options
149
+ * @returns LaTeX string or null if no derivation found
150
+ */
151
+ export function derivationTextToLatex(
152
+ text: string,
153
+ options: DerivationLatexOptions = {},
154
+ ): string | null {
155
+ const steps = extractDerivationSteps(text);
156
+ if (steps.length === 0) {
157
+ return null;
158
+ }
159
+ return derivationToLatex(steps, options);
160
+ }