causantic 0.9.4 → 0.10.1

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 (218) hide show
  1. package/README.md +70 -56
  2. package/dist/cli/skill-templates.d.ts.map +1 -1
  3. package/dist/cli/skill-templates.js +11 -8
  4. package/dist/cli/skill-templates.js.map +1 -1
  5. package/dist/clusters/cluster-manager.d.ts +16 -0
  6. package/dist/clusters/cluster-manager.d.ts.map +1 -1
  7. package/dist/clusters/cluster-manager.js +119 -1
  8. package/dist/clusters/cluster-manager.js.map +1 -1
  9. package/dist/config/loader.d.ts +16 -0
  10. package/dist/config/loader.d.ts.map +1 -1
  11. package/dist/config/loader.js +51 -0
  12. package/dist/config/loader.js.map +1 -1
  13. package/dist/config/memory-config.d.ts +26 -0
  14. package/dist/config/memory-config.d.ts.map +1 -1
  15. package/dist/config/memory-config.js +40 -0
  16. package/dist/config/memory-config.js.map +1 -1
  17. package/dist/eval/experiments/embedding-model-comparison/run-experiment.d.ts +20 -0
  18. package/dist/eval/experiments/embedding-model-comparison/run-experiment.d.ts.map +1 -0
  19. package/dist/eval/experiments/embedding-model-comparison/run-experiment.js +289 -0
  20. package/dist/eval/experiments/embedding-model-comparison/run-experiment.js.map +1 -0
  21. package/dist/eval/experiments/index-differentiation/alignment-analysis.d.ts +53 -0
  22. package/dist/eval/experiments/index-differentiation/alignment-analysis.d.ts.map +1 -0
  23. package/dist/eval/experiments/index-differentiation/alignment-analysis.js +85 -0
  24. package/dist/eval/experiments/index-differentiation/alignment-analysis.js.map +1 -0
  25. package/dist/eval/experiments/index-differentiation/discrimination-test.d.ts +24 -0
  26. package/dist/eval/experiments/index-differentiation/discrimination-test.d.ts.map +1 -0
  27. package/dist/eval/experiments/index-differentiation/discrimination-test.js +79 -0
  28. package/dist/eval/experiments/index-differentiation/discrimination-test.js.map +1 -0
  29. package/dist/eval/experiments/index-differentiation/index.d.ts +11 -0
  30. package/dist/eval/experiments/index-differentiation/index.d.ts.map +1 -0
  31. package/dist/eval/experiments/index-differentiation/index.js +8 -0
  32. package/dist/eval/experiments/index-differentiation/index.js.map +1 -0
  33. package/dist/eval/experiments/index-differentiation/refinement-test.d.ts +32 -0
  34. package/dist/eval/experiments/index-differentiation/refinement-test.d.ts.map +1 -0
  35. package/dist/eval/experiments/index-differentiation/refinement-test.js +201 -0
  36. package/dist/eval/experiments/index-differentiation/refinement-test.js.map +1 -0
  37. package/dist/eval/experiments/index-differentiation/run-experiment.d.ts +20 -0
  38. package/dist/eval/experiments/index-differentiation/run-experiment.d.ts.map +1 -0
  39. package/dist/eval/experiments/index-differentiation/run-experiment.js +336 -0
  40. package/dist/eval/experiments/index-differentiation/run-experiment.js.map +1 -0
  41. package/dist/eval/experiments/index-differentiation/similarity-analysis.d.ts +31 -0
  42. package/dist/eval/experiments/index-differentiation/similarity-analysis.d.ts.map +1 -0
  43. package/dist/eval/experiments/index-differentiation/similarity-analysis.js +60 -0
  44. package/dist/eval/experiments/index-differentiation/similarity-analysis.js.map +1 -0
  45. package/dist/eval/experiments/index-differentiation/types.d.ts +114 -0
  46. package/dist/eval/experiments/index-differentiation/types.d.ts.map +1 -0
  47. package/dist/eval/experiments/index-differentiation/types.js +8 -0
  48. package/dist/eval/experiments/index-differentiation/types.js.map +1 -0
  49. package/dist/eval/experiments/index-vs-chunk/jeopardy-experiment.d.ts +19 -0
  50. package/dist/eval/experiments/index-vs-chunk/jeopardy-experiment.d.ts.map +1 -0
  51. package/dist/eval/experiments/index-vs-chunk/jeopardy-experiment.js +326 -0
  52. package/dist/eval/experiments/index-vs-chunk/jeopardy-experiment.js.map +1 -0
  53. package/dist/eval/experiments/index-vs-chunk/jeopardy-generator.d.ts +27 -0
  54. package/dist/eval/experiments/index-vs-chunk/jeopardy-generator.d.ts.map +1 -0
  55. package/dist/eval/experiments/index-vs-chunk/jeopardy-generator.js +154 -0
  56. package/dist/eval/experiments/index-vs-chunk/jeopardy-generator.js.map +1 -0
  57. package/dist/eval/experiments/index-vs-chunk/query-generator.d.ts +23 -0
  58. package/dist/eval/experiments/index-vs-chunk/query-generator.d.ts.map +1 -0
  59. package/dist/eval/experiments/index-vs-chunk/query-generator.js +113 -0
  60. package/dist/eval/experiments/index-vs-chunk/query-generator.js.map +1 -0
  61. package/dist/eval/experiments/index-vs-chunk/run-experiment.d.ts +17 -0
  62. package/dist/eval/experiments/index-vs-chunk/run-experiment.d.ts.map +1 -0
  63. package/dist/eval/experiments/index-vs-chunk/run-experiment.js +331 -0
  64. package/dist/eval/experiments/index-vs-chunk/run-experiment.js.map +1 -0
  65. package/dist/eval/experiments/index-vs-chunk/types.d.ts +71 -0
  66. package/dist/eval/experiments/index-vs-chunk/types.d.ts.map +1 -0
  67. package/dist/eval/experiments/index-vs-chunk/types.js +8 -0
  68. package/dist/eval/experiments/index-vs-chunk/types.js.map +1 -0
  69. package/dist/eval/experiments/pipeline-dropout/run-experiment.d.ts +18 -0
  70. package/dist/eval/experiments/pipeline-dropout/run-experiment.d.ts.map +1 -0
  71. package/dist/eval/experiments/pipeline-dropout/run-experiment.js +355 -0
  72. package/dist/eval/experiments/pipeline-dropout/run-experiment.js.map +1 -0
  73. package/dist/eval/experiments/rescorer-ceiling/analyze-misses.d.ts +17 -0
  74. package/dist/eval/experiments/rescorer-ceiling/analyze-misses.d.ts.map +1 -0
  75. package/dist/eval/experiments/rescorer-ceiling/analyze-misses.js +247 -0
  76. package/dist/eval/experiments/rescorer-ceiling/analyze-misses.js.map +1 -0
  77. package/dist/eval/experiments/rescorer-ceiling/benchmark-rescorers.d.ts +18 -0
  78. package/dist/eval/experiments/rescorer-ceiling/benchmark-rescorers.d.ts.map +1 -0
  79. package/dist/eval/experiments/rescorer-ceiling/benchmark-rescorers.js +457 -0
  80. package/dist/eval/experiments/rescorer-ceiling/benchmark-rescorers.js.map +1 -0
  81. package/dist/eval/experiments/rescorer-ceiling/run-experiment.d.ts +16 -0
  82. package/dist/eval/experiments/rescorer-ceiling/run-experiment.d.ts.map +1 -0
  83. package/dist/eval/experiments/rescorer-ceiling/run-experiment.js +226 -0
  84. package/dist/eval/experiments/rescorer-ceiling/run-experiment.js.map +1 -0
  85. package/dist/index-entries/index-generator.d.ts +74 -0
  86. package/dist/index-entries/index-generator.d.ts.map +1 -0
  87. package/dist/index-entries/index-generator.js +321 -0
  88. package/dist/index-entries/index-generator.js.map +1 -0
  89. package/dist/index-entries/index-refresher.d.ts +54 -0
  90. package/dist/index-entries/index-refresher.d.ts.map +1 -0
  91. package/dist/index-entries/index-refresher.js +203 -0
  92. package/dist/index-entries/index-refresher.js.map +1 -0
  93. package/dist/index-entries/index.d.ts +6 -0
  94. package/dist/index-entries/index.d.ts.map +1 -0
  95. package/dist/index-entries/index.js +6 -0
  96. package/dist/index-entries/index.js.map +1 -0
  97. package/dist/index.d.ts +4 -0
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +5 -0
  100. package/dist/index.js.map +1 -1
  101. package/dist/ingest/entity-extractor.d.ts +23 -0
  102. package/dist/ingest/entity-extractor.d.ts.map +1 -0
  103. package/dist/ingest/entity-extractor.js +233 -0
  104. package/dist/ingest/entity-extractor.js.map +1 -0
  105. package/dist/ingest/index-entry-hook.d.ts +15 -0
  106. package/dist/ingest/index-entry-hook.d.ts.map +1 -0
  107. package/dist/ingest/index-entry-hook.js +84 -0
  108. package/dist/ingest/index-entry-hook.js.map +1 -0
  109. package/dist/ingest/ingest-session.d.ts.map +1 -1
  110. package/dist/ingest/ingest-session.js +89 -17
  111. package/dist/ingest/ingest-session.js.map +1 -1
  112. package/dist/ingest/session-state.d.ts +49 -0
  113. package/dist/ingest/session-state.d.ts.map +1 -0
  114. package/dist/ingest/session-state.js +146 -0
  115. package/dist/ingest/session-state.js.map +1 -0
  116. package/dist/maintenance/scheduler.d.ts.map +1 -1
  117. package/dist/maintenance/scheduler.js +25 -0
  118. package/dist/maintenance/scheduler.js.map +1 -1
  119. package/dist/maintenance/tasks/backfill-index.d.ts +27 -0
  120. package/dist/maintenance/tasks/backfill-index.d.ts.map +1 -0
  121. package/dist/maintenance/tasks/backfill-index.js +44 -0
  122. package/dist/maintenance/tasks/backfill-index.js.map +1 -0
  123. package/dist/mcp/services.d.ts.map +1 -1
  124. package/dist/mcp/services.js +9 -0
  125. package/dist/mcp/services.js.map +1 -1
  126. package/dist/mcp/tools.d.ts +4 -0
  127. package/dist/mcp/tools.d.ts.map +1 -1
  128. package/dist/mcp/tools.js +113 -7
  129. package/dist/mcp/tools.js.map +1 -1
  130. package/dist/models/embedder.js +2 -2
  131. package/dist/models/embedder.js.map +1 -1
  132. package/dist/models/model-registry.d.ts +2 -0
  133. package/dist/models/model-registry.d.ts.map +1 -1
  134. package/dist/models/model-registry.js +15 -0
  135. package/dist/models/model-registry.js.map +1 -1
  136. package/dist/repomap/cache.d.ts +58 -0
  137. package/dist/repomap/cache.d.ts.map +1 -0
  138. package/dist/repomap/cache.js +101 -0
  139. package/dist/repomap/cache.js.map +1 -0
  140. package/dist/repomap/graph.d.ts +54 -0
  141. package/dist/repomap/graph.d.ts.map +1 -0
  142. package/dist/repomap/graph.js +113 -0
  143. package/dist/repomap/graph.js.map +1 -0
  144. package/dist/repomap/index.d.ts +83 -0
  145. package/dist/repomap/index.d.ts.map +1 -0
  146. package/dist/repomap/index.js +99 -0
  147. package/dist/repomap/index.js.map +1 -0
  148. package/dist/repomap/parser.d.ts +43 -0
  149. package/dist/repomap/parser.d.ts.map +1 -0
  150. package/dist/repomap/parser.js +1043 -0
  151. package/dist/repomap/parser.js.map +1 -0
  152. package/dist/repomap/regex-parser.d.ts +24 -0
  153. package/dist/repomap/regex-parser.d.ts.map +1 -0
  154. package/dist/repomap/regex-parser.js +214 -0
  155. package/dist/repomap/regex-parser.js.map +1 -0
  156. package/dist/repomap/renderer.d.ts +40 -0
  157. package/dist/repomap/renderer.d.ts.map +1 -0
  158. package/dist/repomap/renderer.js +163 -0
  159. package/dist/repomap/renderer.js.map +1 -0
  160. package/dist/repomap/scanner.d.ts +32 -0
  161. package/dist/repomap/scanner.d.ts.map +1 -0
  162. package/dist/repomap/scanner.js +190 -0
  163. package/dist/repomap/scanner.js.map +1 -0
  164. package/dist/retrieval/chain-assembler.d.ts.map +1 -1
  165. package/dist/retrieval/chain-assembler.js +22 -3
  166. package/dist/retrieval/chain-assembler.js.map +1 -1
  167. package/dist/retrieval/context-assembler.d.ts +1 -1
  168. package/dist/retrieval/context-assembler.d.ts.map +1 -1
  169. package/dist/retrieval/index.d.ts +2 -0
  170. package/dist/retrieval/index.d.ts.map +1 -1
  171. package/dist/retrieval/index.js +2 -0
  172. package/dist/retrieval/index.js.map +1 -1
  173. package/dist/retrieval/mmr.d.ts +1 -0
  174. package/dist/retrieval/mmr.d.ts.map +1 -1
  175. package/dist/retrieval/mmr.js +35 -1
  176. package/dist/retrieval/mmr.js.map +1 -1
  177. package/dist/retrieval/rrf.d.ts +1 -1
  178. package/dist/retrieval/rrf.d.ts.map +1 -1
  179. package/dist/retrieval/rrf.js +1 -1
  180. package/dist/retrieval/rrf.js.map +1 -1
  181. package/dist/retrieval/search-assembler.d.ts +11 -2
  182. package/dist/retrieval/search-assembler.d.ts.map +1 -1
  183. package/dist/retrieval/search-assembler.js +305 -81
  184. package/dist/retrieval/search-assembler.js.map +1 -1
  185. package/dist/retrieval/session-reconstructor.d.ts +36 -0
  186. package/dist/retrieval/session-reconstructor.d.ts.map +1 -1
  187. package/dist/retrieval/session-reconstructor.js +128 -0
  188. package/dist/retrieval/session-reconstructor.js.map +1 -1
  189. package/dist/storage/db.d.ts.map +1 -1
  190. package/dist/storage/db.js +24 -0
  191. package/dist/storage/db.js.map +1 -1
  192. package/dist/storage/entity-store.d.ts +48 -0
  193. package/dist/storage/entity-store.d.ts.map +1 -0
  194. package/dist/storage/entity-store.js +111 -0
  195. package/dist/storage/entity-store.js.map +1 -0
  196. package/dist/storage/index-entry-store.d.ts +71 -0
  197. package/dist/storage/index-entry-store.d.ts.map +1 -0
  198. package/dist/storage/index-entry-store.js +277 -0
  199. package/dist/storage/index-entry-store.js.map +1 -0
  200. package/dist/storage/index.d.ts +5 -2
  201. package/dist/storage/index.d.ts.map +1 -1
  202. package/dist/storage/index.js +5 -1
  203. package/dist/storage/index.js.map +1 -1
  204. package/dist/storage/migrations.d.ts.map +1 -1
  205. package/dist/storage/migrations.js +147 -0
  206. package/dist/storage/migrations.js.map +1 -1
  207. package/dist/storage/schema.sql +104 -2
  208. package/dist/storage/session-state-store.d.ts +61 -0
  209. package/dist/storage/session-state-store.d.ts.map +1 -0
  210. package/dist/storage/session-state-store.js +157 -0
  211. package/dist/storage/session-state-store.js.map +1 -0
  212. package/dist/storage/types.d.ts +50 -0
  213. package/dist/storage/types.d.ts.map +1 -1
  214. package/dist/storage/vector-store.d.ts +17 -2
  215. package/dist/storage/vector-store.d.ts.map +1 -1
  216. package/dist/storage/vector-store.js +104 -36
  217. package/dist/storage/vector-store.js.map +1 -1
  218. package/package.json +4 -2
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Jeopardy vs Summary Index Entry Comparison
3
+ *
4
+ * A/B test comparing two index entry generation strategies:
5
+ * A) Summary-style: "This chunk discusses configuring ESLint..."
6
+ * B) Jeopardy-style: "How to fix ESLint module resolution with TS path aliases?"
7
+ *
8
+ * For a sample of chunks:
9
+ * 1. Gather existing summary entries + embeddings
10
+ * 2. Generate Jeopardy entries + embed them
11
+ * 3. Generate natural language search queries (independent ground truth)
12
+ * 4. For each query, find the ground truth chunk among all sample entries
13
+ * 5. Compare recall: which entry style is found more often?
14
+ *
15
+ * Usage:
16
+ * npx tsx src/eval/experiments/index-vs-chunk/jeopardy-experiment.ts [--sample-size N]
17
+ */
18
+ import { writeFileSync } from 'fs';
19
+ import { getDb } from '../../../storage/db.js';
20
+ import { indexVectorStore } from '../../../storage/vector-store.js';
21
+ import { getChunkById } from '../../../storage/chunk-store.js';
22
+ import { getIndexEntriesForChunk } from '../../../storage/index-entry-store.js';
23
+ import { getAllClusters, getClusterChunkIds } from '../../../storage/cluster-store.js';
24
+ import { Embedder } from '../../../models/embedder.js';
25
+ import { getModel } from '../../../models/model-registry.js';
26
+ import { loadConfig, toRuntimeConfig } from '../../../config/loader.js';
27
+ import { cosineSimilarity } from '../../../utils/angular-distance.js';
28
+ import { generateSearchQueries } from './query-generator.js';
29
+ import { generateJeopardyEntries } from './jeopardy-generator.js';
30
+ /** Seeded PRNG. */
31
+ function createRng(seed) {
32
+ let s = seed;
33
+ return () => {
34
+ s = (s * 1664525 + 1013904223) & 0x7fffffff;
35
+ return s / 0x7fffffff;
36
+ };
37
+ }
38
+ function fmt(n, d = 3) {
39
+ return n.toFixed(d);
40
+ }
41
+ async function run() {
42
+ const args = process.argv.slice(2);
43
+ const sampleSizeArg = args.find((a) => a.startsWith('--sample-size='));
44
+ const sampleSize = sampleSizeArg ? parseInt(sampleSizeArg.split('=')[1], 10) : 100;
45
+ const seed = 42;
46
+ console.log('=== Jeopardy vs Summary Index Entry Comparison ===\n');
47
+ const _db = getDb();
48
+ const externalConfig = loadConfig();
49
+ const config = toRuntimeConfig(externalConfig);
50
+ // 1. Sample chunks across diverse clusters
51
+ console.log(`Sampling ${sampleSize} chunks...`);
52
+ const clusters = getAllClusters();
53
+ const rng = createRng(seed);
54
+ const shuffled = [...clusters].sort(() => rng() - 0.5);
55
+ const sampledChunks = [];
56
+ for (const cluster of shuffled) {
57
+ if (sampledChunks.length >= sampleSize)
58
+ break;
59
+ const chunkIds = getClusterChunkIds(cluster.id);
60
+ if (chunkIds.length < 2)
61
+ continue;
62
+ const shuffledIds = [...chunkIds].sort(() => rng() - 0.5);
63
+ for (let i = 0; i < Math.min(2, shuffledIds.length) && sampledChunks.length < sampleSize; i++) {
64
+ const chunk = getChunkById(shuffledIds[i]);
65
+ if (!chunk || chunk.content.length < 200)
66
+ continue;
67
+ sampledChunks.push({
68
+ id: chunk.id,
69
+ sessionSlug: chunk.sessionSlug,
70
+ content: chunk.content,
71
+ clusterId: cluster.id,
72
+ clusterName: cluster.name,
73
+ });
74
+ }
75
+ }
76
+ console.log(` Sampled ${sampledChunks.length} chunks from ${new Set(sampledChunks.map((c) => c.clusterId)).size} clusters`);
77
+ // 2. Load existing summary embeddings
78
+ console.log('\nLoading existing summary entries...');
79
+ const allIndexVectors = await indexVectorStore.getAllVectors();
80
+ const indexEmbMap = new Map(allIndexVectors.map((v) => [v.id, v.embedding]));
81
+ const sampleEntries = [];
82
+ let skippedNoEntry = 0;
83
+ for (const sc of sampledChunks) {
84
+ const entries = getIndexEntriesForChunk(sc.id);
85
+ if (entries.length === 0) {
86
+ skippedNoEntry++;
87
+ continue;
88
+ }
89
+ const entry = entries[0];
90
+ const emb = indexEmbMap.get(entry.id);
91
+ if (!emb) {
92
+ skippedNoEntry++;
93
+ continue;
94
+ }
95
+ sampleEntries.push({
96
+ chunkId: sc.id,
97
+ sessionSlug: sc.sessionSlug,
98
+ clusterId: sc.clusterId,
99
+ clusterName: sc.clusterName,
100
+ chunkContent: sc.content,
101
+ summaryEmbedding: emb,
102
+ summaryDescription: entry.description,
103
+ jeopardyEmbeddings: [],
104
+ jeopardyQueries: [],
105
+ });
106
+ }
107
+ console.log(` ${sampleEntries.length} chunks with existing summary entries (${skippedNoEntry} skipped)`);
108
+ // 3. Generate Jeopardy entries
109
+ console.log('\nGenerating Jeopardy-style entries via LLM...');
110
+ const jeopardyResults = await generateJeopardyEntries(sampleEntries.map((e) => ({ id: e.chunkId, content: e.chunkContent })), config.clusterRefreshModel, (done, total) => {
111
+ if (done % 20 === 0 || done === total)
112
+ console.log(` ${done}/${total} chunks`);
113
+ });
114
+ const jeopardyMap = new Map(jeopardyResults.map((j) => [j.chunkId, j.queries]));
115
+ let jeopardyCount = 0;
116
+ let totalQueries = 0;
117
+ for (const entry of sampleEntries) {
118
+ const queries = jeopardyMap.get(entry.chunkId);
119
+ if (queries && queries.length > 0) {
120
+ entry.jeopardyQueries = queries;
121
+ jeopardyCount++;
122
+ totalQueries += queries.length;
123
+ }
124
+ }
125
+ console.log(` Generated for ${jeopardyCount}/${sampleEntries.length} chunks (${totalQueries} total queries, avg ${fmt(totalQueries / jeopardyCount, 1)} per chunk)`);
126
+ // Filter to chunks that have both summary and jeopardy entries
127
+ const validEntries = sampleEntries.filter((e) => e.jeopardyQueries.length > 0);
128
+ console.log(` ${validEntries.length} chunks with both entry types`);
129
+ // 4. Embed Jeopardy entries
130
+ console.log('\nEmbedding Jeopardy entries...');
131
+ const embedder = new Embedder();
132
+ await embedder.load(getModel(config.embeddingModel));
133
+ for (let i = 0; i < validEntries.length; i++) {
134
+ const entry = validEntries[i];
135
+ const embeddings = [];
136
+ for (const query of entry.jeopardyQueries) {
137
+ const result = await embedder.embed(query, false);
138
+ embeddings.push(result.embedding);
139
+ }
140
+ entry.jeopardyEmbeddings = embeddings;
141
+ if ((i + 1) % 25 === 0 || i === validEntries.length - 1) {
142
+ console.log(` ${i + 1}/${validEntries.length}`);
143
+ }
144
+ }
145
+ // 5. Generate independent search queries (ground truth)
146
+ console.log('\nGenerating independent search queries (ground truth)...');
147
+ const benchmarkQueries = await generateSearchQueries(validEntries.map((e) => ({
148
+ id: e.chunkId,
149
+ sessionSlug: e.sessionSlug,
150
+ content: e.chunkContent,
151
+ clusterId: e.clusterId,
152
+ clusterName: e.clusterName,
153
+ })), config.clusterRefreshModel);
154
+ console.log(` Generated ${benchmarkQueries.length} benchmark queries`);
155
+ // 6. Embed queries and compare
156
+ console.log('\nRunning A/B comparison...\n');
157
+ // Build flat arrays for ranking
158
+ const summaryIndex = validEntries.map((e) => ({
159
+ chunkId: e.chunkId,
160
+ embedding: e.summaryEmbedding,
161
+ }));
162
+ // For Jeopardy, each chunk may have multiple entries — a query matches if
163
+ // ANY of the chunk's Jeopardy embeddings is the closest
164
+ const jeopardyIndex = [];
165
+ for (const entry of validEntries) {
166
+ for (const emb of entry.jeopardyEmbeddings) {
167
+ jeopardyIndex.push({ chunkId: entry.chunkId, embedding: emb });
168
+ }
169
+ }
170
+ console.log(` Summary index: ${summaryIndex.length} entries (1 per chunk)`);
171
+ console.log(` Jeopardy index: ${jeopardyIndex.length} entries (${fmt(jeopardyIndex.length / validEntries.length, 1)} per chunk)`);
172
+ let summaryHitsAt1 = 0, summaryHitsAt3 = 0, summaryHitsAt5 = 0;
173
+ let jeopardyHitsAt1 = 0, jeopardyHitsAt3 = 0, jeopardyHitsAt5 = 0;
174
+ let summaryMRR = 0, jeopardyMRR = 0;
175
+ let summaryMeanSim = 0, jeopardyMeanSim = 0;
176
+ let queryCount = 0;
177
+ const perQuery = [];
178
+ for (const bq of benchmarkQueries) {
179
+ const queryResult = await embedder.embed(bq.query, true);
180
+ const queryEmb = queryResult.embedding;
181
+ // Rank in summary index
182
+ const summarySims = summaryIndex.map((e) => ({
183
+ chunkId: e.chunkId,
184
+ sim: cosineSimilarity(queryEmb, e.embedding),
185
+ }));
186
+ summarySims.sort((a, b) => b.sim - a.sim);
187
+ const summaryRank = summarySims.findIndex((s) => s.chunkId === bq.groundTruthChunkId) + 1;
188
+ const summarySim = summarySims.find((s) => s.chunkId === bq.groundTruthChunkId)?.sim ?? 0;
189
+ // Rank in Jeopardy index (best rank across all chunk's entries)
190
+ const jeopardySims = jeopardyIndex.map((e) => ({
191
+ chunkId: e.chunkId,
192
+ sim: cosineSimilarity(queryEmb, e.embedding),
193
+ }));
194
+ // Deduplicate by chunkId: keep best sim per chunk
195
+ const bestByChunk = new Map();
196
+ for (const js of jeopardySims) {
197
+ const existing = bestByChunk.get(js.chunkId) ?? -1;
198
+ if (js.sim > existing)
199
+ bestByChunk.set(js.chunkId, js.sim);
200
+ }
201
+ const jeopardyRanked = [...bestByChunk.entries()]
202
+ .map(([chunkId, sim]) => ({ chunkId, sim }))
203
+ .sort((a, b) => b.sim - a.sim);
204
+ const jeopardyRank = jeopardyRanked.findIndex((s) => s.chunkId === bq.groundTruthChunkId) + 1;
205
+ const jeopardySim = jeopardyRanked.find((s) => s.chunkId === bq.groundTruthChunkId)?.sim ?? 0;
206
+ if (summaryRank === 1)
207
+ summaryHitsAt1++;
208
+ if (summaryRank > 0 && summaryRank <= 3)
209
+ summaryHitsAt3++;
210
+ if (summaryRank > 0 && summaryRank <= 5)
211
+ summaryHitsAt5++;
212
+ if (summaryRank > 0)
213
+ summaryMRR += 1 / summaryRank;
214
+ if (jeopardyRank === 1)
215
+ jeopardyHitsAt1++;
216
+ if (jeopardyRank > 0 && jeopardyRank <= 3)
217
+ jeopardyHitsAt3++;
218
+ if (jeopardyRank > 0 && jeopardyRank <= 5)
219
+ jeopardyHitsAt5++;
220
+ if (jeopardyRank > 0)
221
+ jeopardyMRR += 1 / jeopardyRank;
222
+ summaryMeanSim += summarySim;
223
+ jeopardyMeanSim += jeopardySim;
224
+ queryCount++;
225
+ perQuery.push({
226
+ query: bq.query,
227
+ groundTruth: bq.groundTruthChunkId,
228
+ summaryRank,
229
+ summarySim,
230
+ jeopardyRank,
231
+ jeopardySim,
232
+ });
233
+ }
234
+ await embedder.dispose();
235
+ // 7. Display results
236
+ console.log(' Metric Summary Jeopardy Delta');
237
+ console.log(' ' + '─'.repeat(60));
238
+ console.log(` Hit@1 (rank 1) ${fmt((summaryHitsAt1 / queryCount) * 100, 1)}% ${fmt((jeopardyHitsAt1 / queryCount) * 100, 1)}% ${fmt(((jeopardyHitsAt1 - summaryHitsAt1) / queryCount) * 100, 1)}%`);
239
+ console.log(` Hit@3 ${fmt((summaryHitsAt3 / queryCount) * 100, 1)}% ${fmt((jeopardyHitsAt3 / queryCount) * 100, 1)}% ${fmt(((jeopardyHitsAt3 - summaryHitsAt3) / queryCount) * 100, 1)}%`);
240
+ console.log(` Hit@5 ${fmt((summaryHitsAt5 / queryCount) * 100, 1)}% ${fmt((jeopardyHitsAt5 / queryCount) * 100, 1)}% ${fmt(((jeopardyHitsAt5 - summaryHitsAt5) / queryCount) * 100, 1)}%`);
241
+ console.log(` MRR ${fmt(summaryMRR / queryCount)} ${fmt(jeopardyMRR / queryCount)} ${fmt((jeopardyMRR - summaryMRR) / queryCount)}`);
242
+ console.log(` Mean cos sim ${fmt(summaryMeanSim / queryCount)} ${fmt(jeopardyMeanSim / queryCount)} ${fmt((jeopardyMeanSim - summaryMeanSim) / queryCount)}`);
243
+ // Head-to-head
244
+ const jeopardyWins = perQuery.filter((q) => q.jeopardyRank > 0 && (q.summaryRank === 0 || q.jeopardyRank < q.summaryRank));
245
+ const summaryWins = perQuery.filter((q) => q.summaryRank > 0 && (q.jeopardyRank === 0 || q.summaryRank < q.jeopardyRank));
246
+ const ties = perQuery.filter((q) => q.summaryRank > 0 && q.summaryRank === q.jeopardyRank);
247
+ const bothMiss = perQuery.filter((q) => q.summaryRank === 0 && q.jeopardyRank === 0);
248
+ console.log(`\n Head-to-head: Jeopardy wins ${jeopardyWins.length}, Summary wins ${summaryWins.length}, Ties ${ties.length}, Both miss ${bothMiss.length}`);
249
+ if (jeopardyWins.length > 0) {
250
+ console.log('\n Sample queries where JEOPARDY wins:');
251
+ for (const q of jeopardyWins.slice(0, 5)) {
252
+ console.log(` "${q.query.slice(0, 80)}" → jeopardy rank ${q.jeopardyRank}, summary rank ${q.summaryRank || 'miss'}`);
253
+ }
254
+ }
255
+ if (summaryWins.length > 0) {
256
+ console.log('\n Sample queries where SUMMARY wins:');
257
+ for (const q of summaryWins.slice(0, 5)) {
258
+ console.log(` "${q.query.slice(0, 80)}" → summary rank ${q.summaryRank}, jeopardy rank ${q.jeopardyRank || 'miss'}`);
259
+ }
260
+ }
261
+ // Summary
262
+ const summary = [];
263
+ summary.push(`A/B test: ${queryCount} queries, ${validEntries.length} chunks (summary: 1 entry/chunk, jeopardy: ${fmt(jeopardyIndex.length / validEntries.length, 1)} entries/chunk)`);
264
+ const mrrDelta = (jeopardyMRR - summaryMRR) / queryCount;
265
+ if (mrrDelta > 0.02) {
266
+ summary.push(`Jeopardy BETTER: +${fmt(mrrDelta)} MRR, wins ${jeopardyWins.length} vs ${summaryWins.length}`);
267
+ }
268
+ else if (mrrDelta < -0.02) {
269
+ summary.push(`Summary BETTER: ${fmt(mrrDelta)} MRR, wins ${summaryWins.length} vs ${jeopardyWins.length}`);
270
+ }
271
+ else {
272
+ summary.push(`Comparable: ${fmt(mrrDelta)} MRR delta, ${jeopardyWins.length} vs ${summaryWins.length} wins`);
273
+ }
274
+ console.log('\n══ Summary ══\n');
275
+ for (const line of summary) {
276
+ console.log(` • ${line}`);
277
+ }
278
+ // Write report
279
+ const report = {
280
+ timestamp: new Date().toISOString(),
281
+ queryCount,
282
+ validChunks: validEntries.length,
283
+ summaryEntriesPerChunk: 1,
284
+ jeopardyEntriesPerChunk: jeopardyIndex.length / validEntries.length,
285
+ summaryMetrics: {
286
+ hitAt1: summaryHitsAt1 / queryCount,
287
+ hitAt3: summaryHitsAt3 / queryCount,
288
+ hitAt5: summaryHitsAt5 / queryCount,
289
+ mrr: summaryMRR / queryCount,
290
+ meanCosSim: summaryMeanSim / queryCount,
291
+ },
292
+ jeopardyMetrics: {
293
+ hitAt1: jeopardyHitsAt1 / queryCount,
294
+ hitAt3: jeopardyHitsAt3 / queryCount,
295
+ hitAt5: jeopardyHitsAt5 / queryCount,
296
+ mrr: jeopardyMRR / queryCount,
297
+ meanCosSim: jeopardyMeanSim / queryCount,
298
+ },
299
+ headToHead: {
300
+ jeopardyWins: jeopardyWins.length,
301
+ summaryWins: summaryWins.length,
302
+ ties: ties.length,
303
+ bothMiss: bothMiss.length,
304
+ },
305
+ perQuery,
306
+ sampleJeopardyEntries: validEntries.slice(0, 5).map((e) => ({
307
+ chunkId: e.chunkId,
308
+ summaryDescription: e.summaryDescription,
309
+ jeopardyQueries: e.jeopardyQueries,
310
+ })),
311
+ summary,
312
+ };
313
+ return report;
314
+ }
315
+ // ── CLI ──────────────────────────────────────────────────────────────────────
316
+ run()
317
+ .then((report) => {
318
+ const outPath = 'jeopardy-vs-summary-report.json';
319
+ writeFileSync(outPath, JSON.stringify(report, null, 2));
320
+ console.log(`\nReport written to ${outPath}`);
321
+ })
322
+ .catch((err) => {
323
+ console.error('Experiment failed:', err);
324
+ process.exit(1);
325
+ });
326
+ //# sourceMappingURL=jeopardy-experiment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jeopardy-experiment.js","sourceRoot":"","sources":["../../../../src/eval/experiments/index-vs-chunk/jeopardy-experiment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAyB,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE,mBAAmB;AACnB,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,CAAC,GAAG,IAAI,CAAC;IACb,OAAO,GAAG,EAAE;QACV,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;QAC5C,OAAO,CAAC,GAAG,UAAU,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,GAAG,CAAC,CAAS,EAAE,CAAC,GAAG,CAAC;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAgBD,KAAK,UAAU,GAAG;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACnF,MAAM,IAAI,GAAG,EAAE,CAAC;IAEhB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IAEpE,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IACpB,MAAM,cAAc,GAAG,UAAU,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;IAE/C,2CAA2C;IAC3C,OAAO,CAAC,GAAG,CAAC,YAAY,UAAU,YAAY,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;IAEvD,MAAM,aAAa,GAAuB,EAAE,CAAC;IAC7C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,aAAa,CAAC,MAAM,IAAI,UAAU;YAAE,MAAM;QAC9C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAChD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAElC,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;QAC1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9F,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG;gBAAE,SAAS;YACnD,aAAa,CAAC,IAAI,CAAC;gBACjB,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,WAAW,EAAE,OAAO,CAAC,IAAI;aAC1B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CACT,aAAa,aAAa,CAAC,MAAM,gBAAgB,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,WAAW,CAChH,CAAC;IAEF,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACrD,MAAM,eAAe,GAAG,MAAM,gBAAgB,CAAC,aAAa,EAAE,CAAC;IAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAE7E,MAAM,aAAa,GAAkB,EAAE,CAAC;IACxC,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,uBAAuB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,cAAc,EAAE,CAAC;YACjB,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,cAAc,EAAE,CAAC;YACjB,SAAS;QACX,CAAC;QAED,aAAa,CAAC,IAAI,CAAC;YACjB,OAAO,EAAE,EAAE,CAAC,EAAE;YACd,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,YAAY,EAAE,EAAE,CAAC,OAAO;YACxB,gBAAgB,EAAE,GAAG;YACrB,kBAAkB,EAAE,KAAK,CAAC,WAAW;YACrC,kBAAkB,EAAE,EAAE;YACtB,eAAe,EAAE,EAAE;SACpB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,CACT,KAAK,aAAa,CAAC,MAAM,0CAA0C,cAAc,WAAW,CAC7F,CAAC;IAEF,+BAA+B;IAC/B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;IAC9D,MAAM,eAAe,GAAG,MAAM,uBAAuB,CACnD,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,EACtE,MAAM,CAAC,mBAAmB,EAC1B,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACd,IAAI,IAAI,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,KAAK,SAAS,CAAC,CAAC;IAClF,CAAC,CACF,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChF,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,eAAe,GAAG,OAAO,CAAC;YAChC,aAAa,EAAE,CAAC;YAChB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CACT,mBAAmB,aAAa,IAAI,aAAa,CAAC,MAAM,YAAY,YAAY,uBAAuB,GAAG,CAAC,YAAY,GAAG,aAAa,EAAE,CAAC,CAAC,aAAa,CACzJ,CAAC;IAEF,+DAA+D;IAC/D,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,KAAK,YAAY,CAAC,MAAM,+BAA+B,CAAC,CAAC;IAErE,4BAA4B;IAC5B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;IAErD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,UAAU,GAAe,EAAE,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAClD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,KAAK,CAAC,kBAAkB,GAAG,UAAU,CAAC;QAEtC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,wDAAwD;IACxD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IACzE,MAAM,gBAAgB,GAAG,MAAM,qBAAqB,CAClD,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,EAAE,EAAE,CAAC,CAAC,OAAO;QACb,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,OAAO,EAAE,CAAC,CAAC,YAAY;QACvB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC,CAAC,EACH,MAAM,CAAC,mBAAmB,CAC3B,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,eAAe,gBAAgB,CAAC,MAAM,oBAAoB,CAAC,CAAC;IAExE,+BAA+B;IAC/B,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAE7C,gCAAgC;IAChC,MAAM,YAAY,GAAoD,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7F,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,SAAS,EAAE,CAAC,CAAC,gBAAgB;KAC9B,CAAC,CAAC,CAAC;IAEJ,0EAA0E;IAC1E,wDAAwD;IACxD,MAAM,aAAa,GAAoD,EAAE,CAAC;IAC1E,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,YAAY,CAAC,MAAM,wBAAwB,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CACT,qBAAqB,aAAa,CAAC,MAAM,aAAa,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,aAAa,CACtH,CAAC;IAEF,IAAI,cAAc,GAAG,CAAC,EACpB,cAAc,GAAG,CAAC,EAClB,cAAc,GAAG,CAAC,CAAC;IACrB,IAAI,eAAe,GAAG,CAAC,EACrB,eAAe,GAAG,CAAC,EACnB,eAAe,GAAG,CAAC,CAAC;IACtB,IAAI,UAAU,GAAG,CAAC,EAChB,WAAW,GAAG,CAAC,CAAC;IAClB,IAAI,cAAc,GAAG,CAAC,EACpB,eAAe,GAAG,CAAC,CAAC;IACtB,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,MAAM,QAAQ,GAOT,EAAE,CAAC;IAER,KAAK,MAAM,EAAE,IAAI,gBAAgB,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC;QAEvC,wBAAwB;QACxB,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3C,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC;SAC7C,CAAC,CAAC,CAAC;QACJ,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAE1C,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC1F,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,kBAAkB,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAE1F,gEAAgE;QAChE,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,EAAE,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC;SAC7C,CAAC,CAAC,CAAC;QACJ,kDAAkD;QAClD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACnD,IAAI,EAAE,CAAC,GAAG,GAAG,QAAQ;gBAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;aAC9C,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;aAC3C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAEjC,MAAM,YAAY,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC9F,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,kBAAkB,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAE9F,IAAI,WAAW,KAAK,CAAC;YAAE,cAAc,EAAE,CAAC;QACxC,IAAI,WAAW,GAAG,CAAC,IAAI,WAAW,IAAI,CAAC;YAAE,cAAc,EAAE,CAAC;QAC1D,IAAI,WAAW,GAAG,CAAC,IAAI,WAAW,IAAI,CAAC;YAAE,cAAc,EAAE,CAAC;QAC1D,IAAI,WAAW,GAAG,CAAC;YAAE,UAAU,IAAI,CAAC,GAAG,WAAW,CAAC;QAEnD,IAAI,YAAY,KAAK,CAAC;YAAE,eAAe,EAAE,CAAC;QAC1C,IAAI,YAAY,GAAG,CAAC,IAAI,YAAY,IAAI,CAAC;YAAE,eAAe,EAAE,CAAC;QAC7D,IAAI,YAAY,GAAG,CAAC,IAAI,YAAY,IAAI,CAAC;YAAE,eAAe,EAAE,CAAC;QAC7D,IAAI,YAAY,GAAG,CAAC;YAAE,WAAW,IAAI,CAAC,GAAG,YAAY,CAAC;QAEtD,cAAc,IAAI,UAAU,CAAC;QAC7B,eAAe,IAAI,WAAW,CAAC;QAC/B,UAAU,EAAE,CAAC;QAEb,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,WAAW,EAAE,EAAE,CAAC,kBAAkB;YAClC,WAAW;YACX,UAAU;YACV,YAAY;YACZ,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAEzB,qBAAqB;IACrB,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CACT,yBAAyB,GAAG,CAAC,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,eAAe,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAC7M,CAAC;IACF,OAAO,CAAC,GAAG,CACT,yBAAyB,GAAG,CAAC,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,eAAe,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAC7M,CAAC;IACF,OAAO,CAAC,GAAG,CACT,yBAAyB,GAAG,CAAC,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,eAAe,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,CAC7M,CAAC;IACF,OAAO,CAAC,GAAG,CACT,yBAAyB,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC,aAAa,GAAG,CAAC,WAAW,GAAG,UAAU,CAAC,aAAa,GAAG,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC,EAAE,CAC3J,CAAC;IACF,OAAO,CAAC,GAAG,CACT,yBAAyB,GAAG,CAAC,cAAc,GAAG,UAAU,CAAC,aAAa,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC,aAAa,GAAG,CAAC,CAAC,eAAe,GAAG,cAAc,CAAC,GAAG,UAAU,CAAC,EAAE,CAC3K,CAAC;IAEF,eAAe;IACf,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,WAAW,CAAC,CACrF,CAAC;IACF,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,YAAY,CAAC,CACrF,CAAC;IACF,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;IAC3F,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC;IAErF,OAAO,CAAC,GAAG,CACT,mCAAmC,YAAY,CAAC,MAAM,kBAAkB,WAAW,CAAC,MAAM,UAAU,IAAI,CAAC,MAAM,eAAe,QAAQ,CAAC,MAAM,EAAE,CAChJ,CAAC;IAEF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;QACvD,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CACT,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC,YAAY,kBAAkB,CAAC,CAAC,WAAW,IAAI,MAAM,EAAE,CAC3G,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CACT,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,WAAW,mBAAmB,CAAC,CAAC,YAAY,IAAI,MAAM,EAAE,CAC3G,CAAC;QACJ,CAAC;IACH,CAAC;IAED,UAAU;IACV,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,OAAO,CAAC,IAAI,CACV,aAAa,UAAU,aAAa,YAAY,CAAC,MAAM,8CAA8C,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,iBAAiB,CACzK,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;IACzD,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CACV,qBAAqB,GAAG,CAAC,QAAQ,CAAC,cAAc,YAAY,CAAC,MAAM,OAAO,WAAW,CAAC,MAAM,EAAE,CAC/F,CAAC;IACJ,CAAC;SAAM,IAAI,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QAC5B,OAAO,CAAC,IAAI,CACV,mBAAmB,GAAG,CAAC,QAAQ,CAAC,cAAc,WAAW,CAAC,MAAM,OAAO,YAAY,CAAC,MAAM,EAAE,CAC7F,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CACV,eAAe,GAAG,CAAC,QAAQ,CAAC,eAAe,YAAY,CAAC,MAAM,OAAO,WAAW,CAAC,MAAM,OAAO,CAC/F,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,eAAe;IACf,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,UAAU;QACV,WAAW,EAAE,YAAY,CAAC,MAAM;QAChC,sBAAsB,EAAE,CAAC;QACzB,uBAAuB,EAAE,aAAa,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM;QACnE,cAAc,EAAE;YACd,MAAM,EAAE,cAAc,GAAG,UAAU;YACnC,MAAM,EAAE,cAAc,GAAG,UAAU;YACnC,MAAM,EAAE,cAAc,GAAG,UAAU;YACnC,GAAG,EAAE,UAAU,GAAG,UAAU;YAC5B,UAAU,EAAE,cAAc,GAAG,UAAU;SACxC;QACD,eAAe,EAAE;YACf,MAAM,EAAE,eAAe,GAAG,UAAU;YACpC,MAAM,EAAE,eAAe,GAAG,UAAU;YACpC,MAAM,EAAE,eAAe,GAAG,UAAU;YACpC,GAAG,EAAE,WAAW,GAAG,UAAU;YAC7B,UAAU,EAAE,eAAe,GAAG,UAAU;SACzC;QACD,UAAU,EAAE;YACV,YAAY,EAAE,YAAY,CAAC,MAAM;YACjC,WAAW,EAAE,WAAW,CAAC,MAAM;YAC/B,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM;SAC1B;QACD,QAAQ;QACR,qBAAqB,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1D,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,kBAAkB,EAAE,CAAC,CAAC,kBAAkB;YACxC,eAAe,EAAE,CAAC,CAAC,eAAe;SACnC,CAAC,CAAC;QACH,OAAO;KACR,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gFAAgF;AAEhF,GAAG,EAAE;KACF,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;IACf,MAAM,OAAO,GAAG,iCAAiC,CAAC;IAClD,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;AAChD,CAAC,CAAC;KACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACb,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * "Jeopardy-style" index entry generation.
3
+ *
4
+ * Instead of generating summaries of chunk content, generates the
5
+ * natural language queries that would have this chunk as the right answer.
6
+ *
7
+ * The key insight: a search index entry should embed close to the
8
+ * QUERIES that should find the chunk, not close to the chunk content itself.
9
+ * Like Jeopardy — given the answer (chunk), produce the questions.
10
+ */
11
+ /** Generated search targets for a chunk. */
12
+ export interface JeopardyEntry {
13
+ chunkId: string;
14
+ /** 2-3 search target questions per chunk. */
15
+ queries: string[];
16
+ }
17
+ /**
18
+ * Generate Jeopardy-style search targets for a batch of chunks.
19
+ *
20
+ * Returns 2-3 specific search queries per chunk — things a user
21
+ * would type that should find this chunk as the answer.
22
+ */
23
+ export declare function generateJeopardyEntries(chunks: Array<{
24
+ id: string;
25
+ content: string;
26
+ }>, model: string, onProgress?: (done: number, total: number) => void): Promise<JeopardyEntry[]>;
27
+ //# sourceMappingURL=jeopardy-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jeopardy-generator.d.ts","sourceRoot":"","sources":["../../../../src/eval/experiments/index-vs-chunk/jeopardy-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9C,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACjD,OAAO,CAAC,aAAa,EAAE,CAAC,CAiB1B"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * "Jeopardy-style" index entry generation.
3
+ *
4
+ * Instead of generating summaries of chunk content, generates the
5
+ * natural language queries that would have this chunk as the right answer.
6
+ *
7
+ * The key insight: a search index entry should embed close to the
8
+ * QUERIES that should find the chunk, not close to the chunk content itself.
9
+ * Like Jeopardy — given the answer (chunk), produce the questions.
10
+ */
11
+ import Anthropic from '@anthropic-ai/sdk';
12
+ import { createSecretStore } from '../../../utils/secret-store.js';
13
+ /**
14
+ * Generate Jeopardy-style search targets for a batch of chunks.
15
+ *
16
+ * Returns 2-3 specific search queries per chunk — things a user
17
+ * would type that should find this chunk as the answer.
18
+ */
19
+ export async function generateJeopardyEntries(chunks, model, onProgress) {
20
+ const client = await getClient();
21
+ if (!client) {
22
+ throw new Error('No Anthropic API key available');
23
+ }
24
+ const results = [];
25
+ const batchSize = 8; // smaller batches — more output per chunk
26
+ for (let i = 0; i < chunks.length; i += batchSize) {
27
+ const batch = chunks.slice(i, i + batchSize);
28
+ const entries = await generateBatch(client, batch, model);
29
+ results.push(...entries);
30
+ onProgress?.(Math.min(i + batchSize, chunks.length), chunks.length);
31
+ }
32
+ return results;
33
+ }
34
+ async function generateBatch(client, chunks, model) {
35
+ const maxContentChars = 500 * 4;
36
+ const chunkTexts = chunks
37
+ .map((c, i) => {
38
+ const content = c.content.length > maxContentChars
39
+ ? c.content.slice(0, maxContentChars) + '\n...[truncated]'
40
+ : c.content;
41
+ return `--- Chunk ${i} ---\n${content}`;
42
+ })
43
+ .join('\n\n');
44
+ const prompt = `You are building a search index. For each conversation chunk below, write 2-3 specific search queries that a user would type when they need the information in this chunk.
45
+
46
+ Think of it like Jeopardy: the chunk is the "answer" — what are the "questions"?
47
+
48
+ Rules:
49
+ - Each query should be a natural question or search phrase (5-20 words)
50
+ - Queries must be SPECIFIC enough to uniquely target THIS chunk, not the general topic
51
+ - Focus on the concrete outcome, decision, error, or technique — not the topic category
52
+ - Include specific names: file paths, function names, error messages, library names where relevant
53
+ - Do NOT include dates, project names, or agent IDs
54
+ - Do NOT copy text verbatim from the chunk
55
+ - If the chunk is trivial (just greetings, acknowledgements, or boilerplate), write "SKIP"
56
+
57
+ ${chunkTexts}
58
+
59
+ Respond with queries grouped by chunk number:
60
+ 0:
61
+ - [query 1]
62
+ - [query 2]
63
+ - [query 3]
64
+ 1:
65
+ - [query 1]
66
+ - [query 2]
67
+ ...`;
68
+ try {
69
+ const response = await client.messages.create({
70
+ model,
71
+ max_tokens: Math.min(4096, chunks.length * 300),
72
+ messages: [{ role: 'user', content: prompt }],
73
+ });
74
+ const text = response.content[0].type === 'text' ? response.content[0].text : '';
75
+ return parseResponse(text, chunks);
76
+ }
77
+ catch (error) {
78
+ console.warn(` Jeopardy batch failed: ${error.message}`);
79
+ return [];
80
+ }
81
+ }
82
+ function parseResponse(text, chunks) {
83
+ const results = [];
84
+ const lines = text.split('\n');
85
+ let currentIndex = -1;
86
+ let currentQueries = [];
87
+ const flush = () => {
88
+ if (currentIndex >= 0 &&
89
+ currentIndex < chunks.length &&
90
+ currentQueries.length > 0 &&
91
+ !currentQueries.some((q) => q.toUpperCase() === 'SKIP')) {
92
+ results.push({
93
+ chunkId: chunks[currentIndex].id,
94
+ queries: currentQueries,
95
+ });
96
+ }
97
+ currentQueries = [];
98
+ };
99
+ for (const line of lines) {
100
+ // Match "0:", "Chunk 0:", "**Chunk 0:**", "## Chunk 0", etc.
101
+ const indexMatch = line.match(/^(?:\*{0,2})?(?:Chunk\s+)?(\d+)(?:\*{0,2})?:\s*$/i);
102
+ if (indexMatch) {
103
+ flush();
104
+ currentIndex = parseInt(indexMatch[1], 10);
105
+ continue;
106
+ }
107
+ // Handle "0: - query" or "Chunk 0: - query" on same line
108
+ const inlineMatch = line.match(/^(?:\*{0,2})?(?:Chunk\s+)?(\d+)(?:\*{0,2})?:\s*-\s*(.+)/i);
109
+ if (inlineMatch) {
110
+ flush();
111
+ currentIndex = parseInt(inlineMatch[1], 10);
112
+ const query = inlineMatch[2].trim();
113
+ if (query && query.toUpperCase() !== 'SKIP') {
114
+ currentQueries.push(query);
115
+ }
116
+ continue;
117
+ }
118
+ // Handle "0: SKIP" or "Chunk 0: SKIP"
119
+ const skipMatch = line.match(/^(?:\*{0,2})?(?:Chunk\s+)?(\d+)(?:\*{0,2})?:\s*SKIP\s*$/i);
120
+ if (skipMatch) {
121
+ flush();
122
+ currentIndex = parseInt(skipMatch[1], 10);
123
+ currentQueries = ['SKIP'];
124
+ continue;
125
+ }
126
+ const queryMatch = line.match(/^\s*[-•]\s*(.+)/);
127
+ if (queryMatch && currentIndex >= 0) {
128
+ const query = queryMatch[1].trim();
129
+ if (query && query.toUpperCase() !== 'SKIP') {
130
+ currentQueries.push(query);
131
+ }
132
+ }
133
+ }
134
+ flush();
135
+ return results;
136
+ }
137
+ async function getClient() {
138
+ if (!process.env.ANTHROPIC_API_KEY) {
139
+ try {
140
+ const store = createSecretStore();
141
+ const storedKey = await store.get('anthropic-api-key');
142
+ if (storedKey) {
143
+ process.env.ANTHROPIC_API_KEY = storedKey;
144
+ }
145
+ }
146
+ catch {
147
+ // Keychain not available
148
+ }
149
+ }
150
+ if (!process.env.ANTHROPIC_API_KEY)
151
+ return null;
152
+ return new Anthropic();
153
+ }
154
+ //# sourceMappingURL=jeopardy-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jeopardy-generator.js","sourceRoot":"","sources":["../../../../src/eval/experiments/index-vs-chunk/jeopardy-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Generate natural language search queries from chunks using LLM.
3
+ *
4
+ * Each query is something a user might search for that should find
5
+ * the source chunk. The LLM sees a truncated chunk and generates
6
+ * a plausible search query.
7
+ */
8
+ import type { BenchmarkQuery } from './types.js';
9
+ /** Chunk data for query generation. */
10
+ export interface ChunkForQueryGen {
11
+ id: string;
12
+ sessionSlug: string;
13
+ content: string;
14
+ clusterId: string;
15
+ clusterName: string | null;
16
+ }
17
+ /**
18
+ * Generate search queries for a batch of chunks.
19
+ *
20
+ * Batches up to 10 chunks per API call to keep cost low.
21
+ */
22
+ export declare function generateSearchQueries(chunks: ChunkForQueryGen[], model: string): Promise<BenchmarkQuery[]>;
23
+ //# sourceMappingURL=query-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-generator.d.ts","sourceRoot":"","sources":["../../../../src/eval/experiments/index-vs-chunk/query-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,gBAAgB,EAAE,EAC1B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,EAAE,CAAC,CAgB3B"}