tryassay 0.33.2 → 0.35.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 (164) hide show
  1. package/dist/bayesian/__tests__/bas-calculator.test.d.ts +1 -0
  2. package/dist/bayesian/__tests__/bas-calculator.test.js +63 -0
  3. package/dist/bayesian/__tests__/bas-calculator.test.js.map +1 -0
  4. package/dist/bayesian/__tests__/structural-entropy.test.d.ts +1 -0
  5. package/dist/bayesian/__tests__/structural-entropy.test.js +21 -0
  6. package/dist/bayesian/__tests__/structural-entropy.test.js.map +1 -0
  7. package/dist/bayesian/bas-calculator.d.ts +41 -0
  8. package/dist/bayesian/bas-calculator.js +198 -0
  9. package/dist/bayesian/bas-calculator.js.map +1 -0
  10. package/dist/bayesian/index.d.ts +3 -0
  11. package/dist/bayesian/index.js +3 -0
  12. package/dist/bayesian/index.js.map +1 -0
  13. package/dist/bayesian/structural-entropy.d.ts +12 -0
  14. package/dist/bayesian/structural-entropy.js +37 -0
  15. package/dist/bayesian/structural-entropy.js.map +1 -0
  16. package/dist/bayesian/types.d.ts +37 -0
  17. package/dist/bayesian/types.js +6 -0
  18. package/dist/bayesian/types.js.map +1 -0
  19. package/dist/cli.js +46 -0
  20. package/dist/cli.js.map +1 -1
  21. package/dist/commands/__tests__/assess-formal.test.d.ts +1 -0
  22. package/dist/commands/__tests__/assess-formal.test.js +72 -0
  23. package/dist/commands/__tests__/assess-formal.test.js.map +1 -0
  24. package/dist/commands/activate.d.ts +1 -0
  25. package/dist/commands/activate.js +48 -0
  26. package/dist/commands/activate.js.map +1 -0
  27. package/dist/commands/assess.js +100 -5
  28. package/dist/commands/assess.js.map +1 -1
  29. package/dist/commands/bas-score.d.ts +13 -0
  30. package/dist/commands/bas-score.js +310 -0
  31. package/dist/commands/bas-score.js.map +1 -0
  32. package/dist/commands/bounty-watch.js.map +1 -1
  33. package/dist/commands/hunt.js +32 -0
  34. package/dist/commands/hunt.js.map +1 -1
  35. package/dist/commands/mcp.d.ts +14 -0
  36. package/dist/commands/mcp.js +18 -0
  37. package/dist/commands/mcp.js.map +1 -0
  38. package/dist/commands/runtime.js +11 -10
  39. package/dist/commands/runtime.js.map +1 -1
  40. package/dist/commands/stream-verify.d.ts +16 -0
  41. package/dist/commands/stream-verify.js +228 -0
  42. package/dist/commands/stream-verify.js.map +1 -0
  43. package/dist/commands/watch.d.ts +19 -0
  44. package/dist/commands/watch.js +158 -0
  45. package/dist/commands/watch.js.map +1 -0
  46. package/dist/hunt/__tests__/deep-dive.test.js.map +1 -1
  47. package/dist/hunt/__tests__/e2e.test.js.map +1 -1
  48. package/dist/hunt/__tests__/finding-to-template.test.js +10 -1
  49. package/dist/hunt/__tests__/finding-to-template.test.js.map +1 -1
  50. package/dist/hunt/__tests__/orchestrator.test.js.map +1 -1
  51. package/dist/hunt/__tests__/templates.test.js +2 -2
  52. package/dist/hunt/__tests__/triage.test.js.map +1 -1
  53. package/dist/hunt/deep-dive.js +7 -7
  54. package/dist/hunt/deep-dive.js.map +1 -1
  55. package/dist/hunt/parse-utils.d.ts +1 -1
  56. package/dist/hunt/state.js.map +1 -1
  57. package/dist/hunt/templates/injection.js +1 -1
  58. package/dist/hunt/templates/injection.js.map +1 -1
  59. package/dist/hunt/triage.js +5 -5
  60. package/dist/hunt/triage.js.map +1 -1
  61. package/dist/lib/__tests__/arithmetic-quick-test.js +10 -9
  62. package/dist/lib/__tests__/arithmetic-quick-test.js.map +1 -1
  63. package/dist/lib/__tests__/arithmetic-real-llm-test.js +8 -8
  64. package/dist/lib/__tests__/arithmetic-real-llm-test.js.map +1 -1
  65. package/dist/lib/__tests__/formal-verifier-behavioral.test.d.ts +18 -0
  66. package/dist/lib/__tests__/formal-verifier-behavioral.test.js +576 -0
  67. package/dist/lib/__tests__/formal-verifier-behavioral.test.js.map +1 -0
  68. package/dist/lib/__tests__/formal-verifier-claimless-async.test.d.ts +1 -0
  69. package/dist/lib/__tests__/formal-verifier-claimless-async.test.js +154 -0
  70. package/dist/lib/__tests__/formal-verifier-claimless-async.test.js.map +1 -0
  71. package/dist/lib/__tests__/formal-verifier-claimless-quality.test.d.ts +1 -0
  72. package/dist/lib/__tests__/formal-verifier-claimless-quality.test.js +121 -0
  73. package/dist/lib/__tests__/formal-verifier-claimless-quality.test.js.map +1 -0
  74. package/dist/lib/__tests__/formal-verifier-claimless-realworld.test.d.ts +1 -0
  75. package/dist/lib/__tests__/formal-verifier-claimless-realworld.test.js +119 -0
  76. package/dist/lib/__tests__/formal-verifier-claimless-realworld.test.js.map +1 -0
  77. package/dist/lib/__tests__/formal-verifier-claimless.test.d.ts +1 -0
  78. package/dist/lib/__tests__/formal-verifier-claimless.test.js +667 -0
  79. package/dist/lib/__tests__/formal-verifier-claimless.test.js.map +1 -0
  80. package/dist/lib/__tests__/mr-gsm8k-benchmark.js +6 -6
  81. package/dist/lib/__tests__/mr-gsm8k-benchmark.js.map +1 -1
  82. package/dist/lib/__tests__/pr-harvester.test.js.map +1 -1
  83. package/dist/lib/assessment-reporter.d.ts +1 -1
  84. package/dist/lib/assessment-reporter.js +2 -1
  85. package/dist/lib/assessment-reporter.js.map +1 -1
  86. package/dist/lib/chain-analyzer.d.ts +4 -3
  87. package/dist/lib/chain-analyzer.js.map +1 -1
  88. package/dist/lib/formal-verifier.d.ts +20 -1
  89. package/dist/lib/formal-verifier.js +1180 -23
  90. package/dist/lib/formal-verifier.js.map +1 -1
  91. package/dist/lib/issue-reporter.d.ts +2 -1
  92. package/dist/lib/issue-reporter.js.map +1 -1
  93. package/dist/lib/remediation-generator.js.map +1 -1
  94. package/dist/lib/report-generator.js.map +1 -1
  95. package/dist/lib/rule-harvester/ground-truth.js +13 -2
  96. package/dist/lib/rule-harvester/ground-truth.js.map +1 -1
  97. package/dist/lib/rule-harvester/scanner.d.ts +1 -1
  98. package/dist/lib/user-config.d.ts +1 -0
  99. package/dist/lib/user-config.js.map +1 -1
  100. package/dist/realtime/__tests__/catch-real-bugs.test.d.ts +9 -0
  101. package/dist/realtime/__tests__/catch-real-bugs.test.js +205 -0
  102. package/dist/realtime/__tests__/catch-real-bugs.test.js.map +1 -0
  103. package/dist/realtime/__tests__/code-buffer.test.d.ts +1 -0
  104. package/dist/realtime/__tests__/code-buffer.test.js +202 -0
  105. package/dist/realtime/__tests__/code-buffer.test.js.map +1 -0
  106. package/dist/realtime/__tests__/correction-injector.test.d.ts +1 -0
  107. package/dist/realtime/__tests__/correction-injector.test.js +168 -0
  108. package/dist/realtime/__tests__/correction-injector.test.js.map +1 -0
  109. package/dist/realtime/__tests__/entropy-detector.test.d.ts +1 -0
  110. package/dist/realtime/__tests__/entropy-detector.test.js +200 -0
  111. package/dist/realtime/__tests__/entropy-detector.test.js.map +1 -0
  112. package/dist/realtime/__tests__/entropy-live-demo.d.ts +1 -0
  113. package/dist/realtime/__tests__/entropy-live-demo.js +103 -0
  114. package/dist/realtime/__tests__/entropy-live-demo.js.map +1 -0
  115. package/dist/realtime/__tests__/entropy-live.d.ts +8 -0
  116. package/dist/realtime/__tests__/entropy-live.js +114 -0
  117. package/dist/realtime/__tests__/entropy-live.js.map +1 -0
  118. package/dist/realtime/__tests__/stream-interceptor.test.d.ts +1 -0
  119. package/dist/realtime/__tests__/stream-interceptor.test.js +193 -0
  120. package/dist/realtime/__tests__/stream-interceptor.test.js.map +1 -0
  121. package/dist/realtime/__tests__/streaming-checks.test.d.ts +1 -0
  122. package/dist/realtime/__tests__/streaming-checks.test.js +478 -0
  123. package/dist/realtime/__tests__/streaming-checks.test.js.map +1 -0
  124. package/dist/realtime/__tests__/streaming-verifier.test.d.ts +1 -0
  125. package/dist/realtime/__tests__/streaming-verifier.test.js +157 -0
  126. package/dist/realtime/__tests__/streaming-verifier.test.js.map +1 -0
  127. package/dist/realtime/code-buffer.d.ts +52 -0
  128. package/dist/realtime/code-buffer.js +276 -0
  129. package/dist/realtime/code-buffer.js.map +1 -0
  130. package/dist/realtime/correction-injector.d.ts +56 -0
  131. package/dist/realtime/correction-injector.js +96 -0
  132. package/dist/realtime/correction-injector.js.map +1 -0
  133. package/dist/realtime/entropy-detector.d.ts +143 -0
  134. package/dist/realtime/entropy-detector.js +504 -0
  135. package/dist/realtime/entropy-detector.js.map +1 -0
  136. package/dist/realtime/index.d.ts +14 -0
  137. package/dist/realtime/index.js +11 -0
  138. package/dist/realtime/index.js.map +1 -0
  139. package/dist/realtime/mcp-server.d.ts +20 -0
  140. package/dist/realtime/mcp-server.js +576 -0
  141. package/dist/realtime/mcp-server.js.map +1 -0
  142. package/dist/realtime/stream-interceptor.d.ts +93 -0
  143. package/dist/realtime/stream-interceptor.js +378 -0
  144. package/dist/realtime/stream-interceptor.js.map +1 -0
  145. package/dist/realtime/streaming-checks.d.ts +55 -0
  146. package/dist/realtime/streaming-checks.js +480 -0
  147. package/dist/realtime/streaming-checks.js.map +1 -0
  148. package/dist/realtime/streaming-verifier.d.ts +102 -0
  149. package/dist/realtime/streaming-verifier.js +227 -0
  150. package/dist/realtime/streaming-verifier.js.map +1 -0
  151. package/dist/realtime/types.d.ts +155 -0
  152. package/dist/realtime/types.js +8 -0
  153. package/dist/realtime/types.js.map +1 -0
  154. package/dist/runtime/agents/research-agent.js +10 -1
  155. package/dist/runtime/agents/research-agent.js.map +1 -1
  156. package/dist/runtime/agents/test-agent.js +10 -7
  157. package/dist/runtime/agents/test-agent.js.map +1 -1
  158. package/dist/runtime/composition-verifier.js +13 -3
  159. package/dist/runtime/composition-verifier.js.map +1 -1
  160. package/dist/runtime/fs-helpers.js.map +1 -1
  161. package/dist/runtime/prompt-safety-analyzer.js.map +1 -1
  162. package/dist/sdk/verified-generate.js.map +1 -1
  163. package/dist/types.d.ts +14 -0
  164. package/package.json +4 -2
@@ -0,0 +1,200 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { EntropyDetector, computeEntropy } from '../entropy-detector.js';
3
+ describe('computeEntropy', () => {
4
+ it('returns 0 for empty input', () => {
5
+ expect(computeEntropy([])).toBe(0);
6
+ });
7
+ it('returns 0 for single token with all probability', () => {
8
+ expect(computeEntropy([{ logprob: 0 }])).toBe(0);
9
+ });
10
+ it('returns max entropy for uniform distribution', () => {
11
+ const uniform = [
12
+ { logprob: Math.log(0.25) },
13
+ { logprob: Math.log(0.25) },
14
+ { logprob: Math.log(0.25) },
15
+ { logprob: Math.log(0.25) },
16
+ ];
17
+ expect(computeEntropy(uniform)).toBeCloseTo(2.0, 3);
18
+ });
19
+ it('returns low entropy for confident prediction', () => {
20
+ const confident = [
21
+ { logprob: Math.log(0.95) },
22
+ { logprob: Math.log(0.03) },
23
+ { logprob: Math.log(0.01) },
24
+ { logprob: Math.log(0.01) },
25
+ ];
26
+ const e = computeEntropy(confident);
27
+ expect(e).toBeLessThan(0.5);
28
+ expect(e).toBeGreaterThan(0);
29
+ });
30
+ it('returns higher entropy for uncertain prediction', () => {
31
+ const uncertain = [
32
+ { logprob: Math.log(0.3) },
33
+ { logprob: Math.log(0.25) },
34
+ { logprob: Math.log(0.25) },
35
+ { logprob: Math.log(0.2) },
36
+ ];
37
+ expect(computeEntropy(uncertain)).toBeGreaterThan(1.5);
38
+ });
39
+ });
40
+ describe('EntropyDetector', () => {
41
+ function makeToken(token, topProbs) {
42
+ return {
43
+ token,
44
+ logprob: Math.log(topProbs[0]),
45
+ topLogprobs: topProbs.map((p, i) => ({
46
+ token: `t${i}`,
47
+ logprob: Math.log(p),
48
+ })),
49
+ };
50
+ }
51
+ // Confident token: entropy ≈ 0.29 (below 0.5 threshold)
52
+ const confidentToken = () => makeToken('x', [0.95, 0.03, 0.01, 0.01]);
53
+ // Uncertain token: entropy ≈ 2.32 (above 0.5 threshold)
54
+ const uncertainToken = () => makeToken('?', [0.2, 0.2, 0.2, 0.2, 0.2]);
55
+ it('does not fire on confident tokens', () => {
56
+ const detector = new EntropyDetector({
57
+ tokenThreshold: 0.5,
58
+ fractionThreshold: 0.35,
59
+ windowSize: 8,
60
+ minTokens: 4,
61
+ });
62
+ for (let i = 0; i < 20; i++) {
63
+ const event = detector.pushToken(confidentToken());
64
+ expect(event).toBeNull();
65
+ }
66
+ expect(detector.getStats().alerts).toBe(0);
67
+ });
68
+ it('fires when enough tokens are uncertain (fraction-only, dynamics disabled)', () => {
69
+ const detector = new EntropyDetector({
70
+ tokenThreshold: 0.5,
71
+ fractionThreshold: 0.35,
72
+ windowSize: 8,
73
+ minTokens: 4,
74
+ dynamicsThreshold: 1.1, // Disable dynamics to test fraction path
75
+ });
76
+ // Push 8 uncertain tokens — all high entropy, fraction = 100% > 35%
77
+ const events = [];
78
+ for (let i = 0; i < 20; i++) {
79
+ const event = detector.pushToken(uncertainToken());
80
+ if (event)
81
+ events.push(event);
82
+ }
83
+ expect(events.length).toBeGreaterThan(0);
84
+ expect(events[0].checkId).toBe('entropy_hallucination');
85
+ expect(events[0].verdict).toBe('FAIL');
86
+ expect(events[0].evidence).toMatch(/high entropy/);
87
+ });
88
+ it('respects minTokens — no alert before enough tokens', () => {
89
+ const detector = new EntropyDetector({
90
+ tokenThreshold: 0.5,
91
+ fractionThreshold: 0.35,
92
+ windowSize: 8,
93
+ minTokens: 10,
94
+ dynamicsThreshold: 1.1, // Disable dynamics to test fraction minTokens
95
+ });
96
+ // Push 9 uncertain tokens — should NOT fire (minTokens=10)
97
+ for (let i = 0; i < 9; i++) {
98
+ const event = detector.pushToken(uncertainToken());
99
+ expect(event).toBeNull();
100
+ }
101
+ // 10th should fire
102
+ const event = detector.pushToken(uncertainToken());
103
+ expect(event).not.toBeNull();
104
+ });
105
+ it('does not fire when fraction is below threshold and dynamics disabled', () => {
106
+ const detector = new EntropyDetector({
107
+ tokenThreshold: 0.5,
108
+ fractionThreshold: 0.5, // Need >50% high-entropy tokens
109
+ windowSize: 8,
110
+ minTokens: 1,
111
+ dynamicsThreshold: 1.1, // Disable dynamics detection
112
+ });
113
+ // Alternate: confident, uncertain — fraction ≈ 50% (not > 50%)
114
+ for (let i = 0; i < 16; i++) {
115
+ const token = i % 2 === 0 ? confidentToken() : uncertainToken();
116
+ const event = detector.pushToken(token);
117
+ expect(event).toBeNull();
118
+ }
119
+ });
120
+ it('dynamics detector fires on high-variance alternating pattern', () => {
121
+ const detector = new EntropyDetector({
122
+ tokenThreshold: 0.5,
123
+ fractionThreshold: 1.0, // Disable fraction detection
124
+ windowSize: 8,
125
+ minTokens: 4,
126
+ dynamicsThreshold: 0.5,
127
+ });
128
+ // Alternate confident/uncertain — creates high entropy variance
129
+ const events = [];
130
+ for (let i = 0; i < 20; i++) {
131
+ const token = i % 2 === 0 ? confidentToken() : uncertainToken();
132
+ const event = detector.pushToken(token);
133
+ if (event)
134
+ events.push(event);
135
+ }
136
+ // High variance from alternation should trigger dynamics
137
+ expect(events.length).toBeGreaterThan(0);
138
+ expect(events[0].evidence).toContain('Dynamics score');
139
+ });
140
+ it('debounces alerts — one per window', () => {
141
+ const detector = new EntropyDetector({
142
+ tokenThreshold: 0.5,
143
+ fractionThreshold: 0.35,
144
+ windowSize: 8,
145
+ minTokens: 4,
146
+ dynamicsThreshold: 1.1, // Disable dynamics to test fraction debouncing
147
+ });
148
+ const events = [];
149
+ // Push 40 uncertain tokens — should only get a few alerts (debounced)
150
+ for (let i = 0; i < 40; i++) {
151
+ const event = detector.pushToken(uncertainToken());
152
+ if (event)
153
+ events.push(event);
154
+ }
155
+ // With window=8 and debounce, should fire at most ~4 times in 40 tokens
156
+ expect(events.length).toBeLessThanOrEqual(5);
157
+ expect(events.length).toBeGreaterThan(0);
158
+ });
159
+ it('resets state correctly', () => {
160
+ const detector = new EntropyDetector();
161
+ for (let i = 0; i < 20; i++) {
162
+ detector.pushToken(uncertainToken());
163
+ }
164
+ expect(detector.getStats().tokensProcessed).toBe(20);
165
+ detector.reset();
166
+ expect(detector.getStats().tokensProcessed).toBe(0);
167
+ expect(detector.getStats().alerts).toBe(0);
168
+ });
169
+ it('fires onEntropy callback for every token', () => {
170
+ const measurements = [];
171
+ const detector = new EntropyDetector({
172
+ onEntropy: (info) => measurements.push(info),
173
+ minTokens: 1,
174
+ windowSize: 4,
175
+ });
176
+ detector.pushToken(confidentToken());
177
+ detector.pushToken(uncertainToken());
178
+ expect(measurements).toHaveLength(2);
179
+ });
180
+ it('includes severity in events', () => {
181
+ const detector = new EntropyDetector({
182
+ tokenThreshold: 0.5,
183
+ fractionThreshold: 0.1,
184
+ windowSize: 4,
185
+ minTokens: 1,
186
+ severity: 'high',
187
+ dynamicsThreshold: 1.1, // Disable dynamics to test fraction severity
188
+ });
189
+ // Push enough uncertain tokens
190
+ let event = null;
191
+ for (let i = 0; i < 5; i++) {
192
+ event = detector.pushToken(uncertainToken());
193
+ if (event)
194
+ break;
195
+ }
196
+ expect(event).not.toBeNull();
197
+ expect(event.severity).toBe('high');
198
+ });
199
+ });
200
+ //# sourceMappingURL=entropy-detector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy-detector.test.js","sourceRoot":"","sources":["../../../src/realtime/__tests__/entropy-detector.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Live "Confident Liar" demo — runs real vs fake prompts through GPT-5.4
3
+ * and writes results to /tmp/entropy-results.json for the dashboard.
4
+ */
5
+ import { createVerifiedStreamAuto } from '../stream-interceptor.js';
6
+ import { writeFileSync } from 'fs';
7
+ const RESULTS_FILE = '/tmp/entropy-results.json';
8
+ const tests = [
9
+ {
10
+ label: 'Real API — Express REST endpoints',
11
+ prompt: 'Write a TypeScript Express REST API with GET /users, POST /users, and DELETE /users/:id endpoints. Use an in-memory array as the data store. Include proper status codes and JSON responses. Just the code, no explanation.',
12
+ expectHallucination: false,
13
+ },
14
+ {
15
+ label: 'Fake API — Supabase .withGraphQL() + .connectMesh()',
16
+ prompt: 'Write TypeScript code using the Supabase JS client that calls supabase.from("users").select().withGraphQL({ depth: 3, fragments: true }) to fetch nested user relationships. Use supabase.realtime.connectMesh() to set up peer-to-peer sync between browser tabs. Just the code, no explanation.',
17
+ expectHallucination: true,
18
+ },
19
+ {
20
+ label: 'Real API — React useState counter',
21
+ prompt: 'Write a React TypeScript component called Counter with increment/decrement buttons and a display. Use useState. Just the code, no explanation.',
22
+ expectHallucination: false,
23
+ },
24
+ {
25
+ label: 'Fake API — Node.js fs.createSecureWriteStream()',
26
+ prompt: 'Write TypeScript code that uses Node.js fs.createSecureWriteStream() with encryption options { algorithm: "aes-256-gcm", keyDerivation: "argon2" } to write an encrypted file. Use the stream.pipeline() autoRetry option with maxRetries: 3 and backoffMs: 1000. Include the onIntegrityCheck callback. Just the code, no explanation.',
27
+ expectHallucination: true,
28
+ },
29
+ {
30
+ label: 'Mixed — Next.js + invented next/ai/guards',
31
+ prompt: 'Write a Next.js API route at /api/analyze that uses the next/ai package\'s streamInference() function with model "gpt-4o" and the built-in hallucination guard middleware next/ai/guards. Call guards.factCheck() on the response before returning. Just the code, no explanation.',
32
+ expectHallucination: true,
33
+ },
34
+ ];
35
+ function writeResults(results, done) {
36
+ writeFileSync(RESULTS_FILE, JSON.stringify({
37
+ tests: results,
38
+ done,
39
+ totalTests: tests.length,
40
+ }, null, 2));
41
+ }
42
+ async function runTest(test) {
43
+ console.log(`\n>>> Running: ${test.label}`);
44
+ const start = Date.now();
45
+ let dynamicsScore;
46
+ let confidence;
47
+ let evidenceText = '';
48
+ const result = await createVerifiedStreamAuto({
49
+ provider: 'openai',
50
+ model: 'gpt-5.4',
51
+ language: 'typescript',
52
+ userPrompt: test.prompt,
53
+ maxTokens: 400,
54
+ entropyDetector: {
55
+ tokenThreshold: 0.5,
56
+ fractionThreshold: 0.35,
57
+ windowSize: 32,
58
+ minTokens: 16,
59
+ severity: 'medium',
60
+ onEntropy: () => { },
61
+ },
62
+ onVerification: (event) => {
63
+ if (event.verdict === 'FAIL') {
64
+ if (event.entropyContext) {
65
+ dynamicsScore = event.entropyContext.dynamicsScore;
66
+ confidence = event.entropyContext.confidence;
67
+ }
68
+ evidenceText += event.evidence.slice(0, 200) + '\n';
69
+ }
70
+ },
71
+ });
72
+ const entropyAlerts = result.findings.filter(f => f.checkId === 'entropy_hallucination').length;
73
+ const dynamicsAlerts = result.findings.filter(f => f.checkId === 'entropy_hallucination' && f.evidence?.includes('dynamics')).length;
74
+ const reviewFlags = result.findings.filter(f => f.checkId === 'entropy_review').length;
75
+ const elapsed = Date.now() - start;
76
+ console.log(` Tokens: ${result.outputTokens}, Entropy: ${entropyAlerts}, Dynamics: ${dynamicsAlerts}, Review: ${reviewFlags}, ${elapsed}ms`);
77
+ return {
78
+ label: test.label,
79
+ expectHallucination: test.expectHallucination,
80
+ tokens: result.outputTokens,
81
+ entropyAlerts,
82
+ dynamicsAlerts,
83
+ reviewFlags,
84
+ durationMs: elapsed,
85
+ dynamicsScore,
86
+ confidence,
87
+ evidence: evidenceText || undefined,
88
+ };
89
+ }
90
+ async function main() {
91
+ // Clear previous results
92
+ writeResults([], false);
93
+ const results = [];
94
+ for (const test of tests) {
95
+ const r = await runTest(test);
96
+ results.push(r);
97
+ writeResults(results, false);
98
+ }
99
+ writeResults(results, true);
100
+ console.log('\n✅ All tests complete. Dashboard updated.');
101
+ }
102
+ main().catch(console.error);
103
+ //# sourceMappingURL=entropy-live-demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy-live-demo.js","sourceRoot":"","sources":["../../../src/realtime/__tests__/entropy-live-demo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Quick live test of the entropy hallucination detector through the
3
+ * full streaming verifier pipeline.
4
+ *
5
+ * Usage:
6
+ * OPENAI_API_KEY=sk-... npx tsx src/realtime/__tests__/entropy-live.ts
7
+ */
8
+ export {};
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Quick live test of the entropy hallucination detector through the
3
+ * full streaming verifier pipeline.
4
+ *
5
+ * Usage:
6
+ * OPENAI_API_KEY=sk-... npx tsx src/realtime/__tests__/entropy-live.ts
7
+ */
8
+ import { createVerifiedStreamAuto } from '../stream-interceptor.js';
9
+ const GREEN = '\x1b[32m';
10
+ const YELLOW = '\x1b[33m';
11
+ const RED = '\x1b[31m';
12
+ const BOLD = '\x1b[1m';
13
+ const DIM = '\x1b[2m';
14
+ const RESET = '\x1b[0m';
15
+ async function runTest(label, prompt) {
16
+ console.log(`\n${BOLD}${'='.repeat(70)}${RESET}`);
17
+ console.log(`${BOLD} ${label}${RESET}`);
18
+ console.log(`${BOLD}${'='.repeat(70)}${RESET}`);
19
+ console.log(`${DIM}Prompt: ${prompt.slice(0, 80)}...${RESET}\n`);
20
+ let tokenCount = 0;
21
+ const result = await createVerifiedStreamAuto({
22
+ provider: 'openai',
23
+ model: 'gpt-5.4',
24
+ language: 'typescript',
25
+ userPrompt: prompt,
26
+ maxTokens: 400,
27
+ entropyDetector: {
28
+ tokenThreshold: 0.5,
29
+ fractionThreshold: 0.35,
30
+ windowSize: 32,
31
+ minTokens: 16,
32
+ severity: 'medium',
33
+ onEntropy: (info) => {
34
+ tokenCount++;
35
+ if (tokenCount % 20 === 0) {
36
+ const color = info.exceedsThreshold ? RED : info.windowEntropy > 0.25 ? YELLOW : GREEN;
37
+ process.stdout.write(`${DIM}[${tokenCount}]${RESET} ` +
38
+ `frac=${color}${(info.windowEntropy * 100).toFixed(0)}%${RESET} ` +
39
+ `e=${info.entropy.toFixed(2)} ` +
40
+ `${DIM}${info.token}${RESET}\n`);
41
+ }
42
+ },
43
+ },
44
+ onVerification: (event) => {
45
+ if (event.verdict === 'FAIL') {
46
+ const icon = event.checkId === 'entropy_hallucination' ? '🧠'
47
+ : event.checkId === 'entropy_review' ? '👀'
48
+ : '🔍';
49
+ const ctx = event.entropyContext
50
+ ? ` [confidence=${event.entropyContext.confidence}, entropy_frac=${(event.entropyContext.highEntropyFraction * 100).toFixed(0)}%]`
51
+ : '';
52
+ console.log(`\n${RED}${icon} ${event.checkName} (${event.severity})${ctx}${RESET}`);
53
+ console.log(` ${event.evidence.slice(0, 150)}`);
54
+ }
55
+ },
56
+ });
57
+ // Summary
58
+ const entropyFindings = result.findings.filter(f => f.checkId === 'entropy_hallucination');
59
+ const reviewFindings = result.findings.filter(f => f.checkId === 'entropy_review');
60
+ const patternFindings = result.findings.filter(f => f.checkId !== 'entropy_hallucination' && f.checkId !== 'entropy_review');
61
+ console.log(`\n${BOLD}--- Results ---${RESET}`);
62
+ console.log(`Tokens: ${result.outputTokens}`);
63
+ console.log(`Pattern findings: ${patternFindings.length}`);
64
+ console.log(`Entropy alerts: ${entropyFindings.length}`);
65
+ console.log(`Review flags: ${reviewFindings.length}`);
66
+ console.log(`Duration: ${result.durationMs}ms`);
67
+ return {
68
+ entropyFindings: entropyFindings.length,
69
+ reviewFindings: reviewFindings.length,
70
+ patternFindings: patternFindings.length,
71
+ };
72
+ }
73
+ async function main() {
74
+ const tests = [
75
+ {
76
+ label: 'CONFIDENT — Express REST API (well-known pattern)',
77
+ prompt: 'Write a TypeScript Express REST API with GET /users, POST /users, and DELETE /users/:id endpoints. Use an in-memory array as the data store. Include proper status codes and JSON responses. Just the code, no explanation.',
78
+ },
79
+ {
80
+ label: 'SUBTLE HALLUCINATION — real library, wrong API',
81
+ prompt: 'Write TypeScript code using the Supabase JS client that calls supabase.from("users").select().withGraphQL({ depth: 3, fragments: true }) to fetch nested user relationships. Use supabase.realtime.connectMesh() to set up peer-to-peer sync between browser tabs. Just the code, no explanation.',
82
+ },
83
+ {
84
+ label: 'CONFIDENT — React useState counter',
85
+ prompt: 'Write a React TypeScript component called Counter with increment/decrement buttons and a display. Use useState. Just the code, no explanation.',
86
+ },
87
+ {
88
+ label: 'HARD HALLUCINATION — plausible but wrong Node.js APIs',
89
+ prompt: 'Write TypeScript code that uses Node.js fs.createSecureWriteStream() with encryption options { algorithm: "aes-256-gcm", keyDerivation: "argon2" } to write an encrypted file. Use the stream.pipeline() autoRetry option with maxRetries: 3 and backoffMs: 1000. Include the onIntegrityCheck callback. Just the code, no explanation.',
90
+ },
91
+ {
92
+ label: 'MIXED — real framework, invented plugin',
93
+ prompt: 'Write a Next.js API route at /api/analyze that uses the next/ai package\'s streamInference() function with model "gpt-4o" and the built-in hallucination guard middleware next/ai/guards. Call guards.factCheck() on the response before returning. Just the code, no explanation.',
94
+ },
95
+ ];
96
+ const results = [];
97
+ for (const test of tests) {
98
+ const r = await runTest(test.label, test.prompt);
99
+ results.push({ label: test.label, entropy: r.entropyFindings, review: r.reviewFindings, pattern: r.patternFindings });
100
+ }
101
+ // Comparison
102
+ console.log(`\n${BOLD}${'='.repeat(78)}${RESET}`);
103
+ console.log(`${BOLD} COMPARISON${RESET}`);
104
+ console.log(`${BOLD}${'='.repeat(78)}${RESET}`);
105
+ console.log('Test Entropy Review Pattern Total');
106
+ console.log('-'.repeat(78));
107
+ for (const r of results) {
108
+ const short = r.label.length > 42 ? r.label.slice(0, 39) + '...' : r.label;
109
+ const total = r.entropy + r.review + r.pattern;
110
+ console.log(`${short.padEnd(44)} ${String(r.entropy).padStart(7)} ${String(r.review).padStart(7)} ${String(r.pattern).padStart(8)} ${String(total).padStart(6)}`);
111
+ }
112
+ }
113
+ main().catch(console.error);
114
+ //# sourceMappingURL=entropy-live.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy-live.js","sourceRoot":"","sources":["../../../src/realtime/__tests__/entropy-live.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,193 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createVerifiedStreamFromTokens } from '../stream-interceptor.js';
3
+ // ── Helpers ─────────────────────────────────────────────────────
4
+ /**
5
+ * Split a string into token-like chunks (3-5 chars each) to simulate
6
+ * realistic streaming granularity.
7
+ */
8
+ function tokenize(code, chunkSize = 4) {
9
+ const tokens = [];
10
+ for (let i = 0; i < code.length; i += chunkSize) {
11
+ tokens.push(code.slice(i, i + chunkSize));
12
+ }
13
+ return tokens;
14
+ }
15
+ // ── Tests ─────────────────────────────────────────────────────────
16
+ describe('StreamInterceptor', () => {
17
+ // 1. Clean code stream
18
+ it('produces 0 findings for clean code', () => {
19
+ const code = 'const x = 1;\nconst y = 2;\n';
20
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
21
+ language: 'typescript',
22
+ });
23
+ expect(result.findings).toHaveLength(0);
24
+ expect(result.text).toBe(code);
25
+ });
26
+ // 2. SQL injection detected
27
+ it('detects SQL injection via string concatenation', () => {
28
+ const code = 'const q = "SELECT * FROM users WHERE id = " + userId;\n';
29
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
30
+ language: 'typescript',
31
+ });
32
+ expect(result.findings.length).toBeGreaterThanOrEqual(1);
33
+ const sqlFinding = result.findings.find(e => e.checkId.includes('sql'));
34
+ expect(sqlFinding).toBeDefined();
35
+ expect(sqlFinding.severity).toBe('critical');
36
+ });
37
+ // 3. onText callback fires for each chunk
38
+ it('fires onText callback for every token chunk', () => {
39
+ const code = 'const x = 1;\n';
40
+ const chunks = tokenize(code);
41
+ const received = [];
42
+ createVerifiedStreamFromTokens(chunks, {
43
+ language: 'typescript',
44
+ onText: (text) => received.push(text),
45
+ });
46
+ expect(received).toEqual(chunks);
47
+ });
48
+ // 4. onVerification callback fires for findings
49
+ it('fires onVerification callback for findings', () => {
50
+ const code = 'const q = "SELECT * FROM users WHERE id = " + userId;\n';
51
+ const verificationEvents = [];
52
+ createVerifiedStreamFromTokens(tokenize(code), {
53
+ language: 'typescript',
54
+ onVerification: (event) => verificationEvents.push(event),
55
+ });
56
+ const findings = verificationEvents.filter(e => e.verdict === 'FAIL');
57
+ expect(findings.length).toBeGreaterThanOrEqual(1);
58
+ expect(findings[0].checkId).toContain('sql');
59
+ });
60
+ // 5. Stats populated
61
+ it('populates stats with non-zero values for non-empty streams', () => {
62
+ const code = 'const x = 1;\nconst y = 2;\n';
63
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
64
+ language: 'typescript',
65
+ });
66
+ expect(result.stats.unitsProcessed).toBeGreaterThan(0);
67
+ expect(result.stats.checksRun).toBeGreaterThan(0);
68
+ expect(result.stats.totalTimeMs).toBeGreaterThanOrEqual(0);
69
+ });
70
+ // 6. Flush catches trailing code without structural boundary
71
+ it('catches findings in trailing code via flush', () => {
72
+ // No trailing newline or semicolon — the secret must be caught by flush
73
+ const code = 'const secret = "sk-abc123456789abcdef"';
74
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
75
+ language: 'typescript',
76
+ });
77
+ const secretFinding = result.findings.find(e => e.checkId.includes('secret'));
78
+ expect(secretFinding).toBeDefined();
79
+ expect(secretFinding.severity).toBe('critical');
80
+ });
81
+ // 7. Multiple statements — mix of clean and bad
82
+ it('handles a mix of clean and bad statements', () => {
83
+ const code = [
84
+ 'const name = "Alice";',
85
+ 'const q = "SELECT * FROM users WHERE id = " + userId;',
86
+ 'const y = 42;',
87
+ 'const token = "sk-ant-secret1234567890";',
88
+ '',
89
+ ].join('\n');
90
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
91
+ language: 'typescript',
92
+ });
93
+ // Should have at least 2 findings: SQL injection + hardcoded secret
94
+ expect(result.findings.length).toBeGreaterThanOrEqual(2);
95
+ const sqlFinding = result.findings.find(e => e.checkId.includes('sql'));
96
+ const secretFinding = result.findings.find(e => e.checkId.includes('secret'));
97
+ expect(sqlFinding).toBeDefined();
98
+ expect(secretFinding).toBeDefined();
99
+ });
100
+ // 8. Result shape — all fields present and correctly typed
101
+ it('returns a correctly shaped VerifiedStreamResult', () => {
102
+ const code = 'const x = 1;\n';
103
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
104
+ language: 'typescript',
105
+ });
106
+ // All required fields exist
107
+ expect(typeof result.text).toBe('string');
108
+ expect(Array.isArray(result.events)).toBe(true);
109
+ expect(Array.isArray(result.findings)).toBe(true);
110
+ expect(typeof result.stats).toBe('object');
111
+ expect(typeof result.inputTokens).toBe('number');
112
+ expect(typeof result.outputTokens).toBe('number');
113
+ expect(typeof result.durationMs).toBe('number');
114
+ // Stats shape
115
+ expect(typeof result.stats.unitsProcessed).toBe('number');
116
+ expect(typeof result.stats.checksRun).toBe('number');
117
+ expect(typeof result.stats.findings).toBe('number');
118
+ expect(typeof result.stats.avgLatencyMs).toBe('number');
119
+ expect(typeof result.stats.maxLatencyMs).toBe('number');
120
+ expect(typeof result.stats.totalTimeMs).toBe('number');
121
+ // Token counts are 0 for the test helper (no real API)
122
+ expect(result.inputTokens).toBe(0);
123
+ expect(result.outputTokens).toBe(0);
124
+ // Duration is a non-negative number
125
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
126
+ });
127
+ // 9. Empty stream
128
+ it('handles an empty token stream gracefully', () => {
129
+ const result = createVerifiedStreamFromTokens([], {
130
+ language: 'typescript',
131
+ });
132
+ expect(result.text).toBe('');
133
+ expect(result.findings).toHaveLength(0);
134
+ expect(result.events).toHaveLength(0);
135
+ expect(result.stats.unitsProcessed).toBe(0);
136
+ });
137
+ // 10. Function with bug inside
138
+ it('detects SQL injection inside a complete function', () => {
139
+ const code = [
140
+ 'function getUser(userId: string) {',
141
+ ' const query = "SELECT * FROM users WHERE id = " + userId;',
142
+ ' return db.execute(query);',
143
+ '}',
144
+ '',
145
+ ].join('\n');
146
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
147
+ language: 'typescript',
148
+ });
149
+ const sqlFinding = result.findings.find(e => e.checkId.includes('sql'));
150
+ expect(sqlFinding).toBeDefined();
151
+ expect(sqlFinding.verdict).toBe('FAIL');
152
+ });
153
+ // ── Auto-correction callback ──────────────────────────────────
154
+ it('fires onCorrection for high+ severity findings when autoCorrect is enabled', () => {
155
+ const code = 'const q = "SELECT * FROM users WHERE id = " + userId;\n';
156
+ const corrections = [];
157
+ createVerifiedStreamFromTokens(tokenize(code), {
158
+ language: 'typescript',
159
+ autoCorrect: true,
160
+ minCorrectionSeverity: 'high',
161
+ onCorrection: (info) => corrections.push(info),
162
+ });
163
+ expect(corrections.length).toBeGreaterThanOrEqual(1);
164
+ expect(corrections[0].finding.verdict).toBe('FAIL');
165
+ expect(corrections[0].generatedSoFar.length).toBeGreaterThan(0);
166
+ });
167
+ it('does not fire onCorrection when autoCorrect is false', () => {
168
+ const code = 'const q = "SELECT * FROM users WHERE id = " + userId;\n';
169
+ const corrections = [];
170
+ createVerifiedStreamFromTokens(tokenize(code), {
171
+ language: 'typescript',
172
+ autoCorrect: false,
173
+ onCorrection: (info) => corrections.push(info),
174
+ });
175
+ expect(corrections).toHaveLength(0);
176
+ });
177
+ // ── Findings is a strict subset of events ──────────────────────
178
+ it('findings array contains only FAIL events from events array', () => {
179
+ const code = 'const q = "SELECT * FROM users WHERE id = " + userId;\n';
180
+ const result = createVerifiedStreamFromTokens(tokenize(code), {
181
+ language: 'typescript',
182
+ });
183
+ // Every finding should be in events
184
+ for (const finding of result.findings) {
185
+ expect(result.events).toContain(finding);
186
+ expect(finding.verdict).toBe('FAIL');
187
+ }
188
+ // findings count should match FAIL events in events array
189
+ const failEvents = result.events.filter(e => e.verdict === 'FAIL');
190
+ expect(result.findings).toHaveLength(failEvents.length);
191
+ });
192
+ });
193
+ //# sourceMappingURL=stream-interceptor.test.js.map