oh-my-knowledge 0.0.1 → 0.19.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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +600 -322
  3. package/README.zh.md +724 -0
  4. package/dist/src/analysis/coverage-analyzer.d.ts +57 -0
  5. package/dist/src/analysis/coverage-analyzer.d.ts.map +1 -0
  6. package/dist/src/analysis/coverage-analyzer.js +262 -0
  7. package/dist/src/analysis/coverage-analyzer.js.map +1 -0
  8. package/dist/src/analysis/gap-analyzer.d.ts +114 -0
  9. package/dist/src/analysis/gap-analyzer.d.ts.map +1 -0
  10. package/dist/src/analysis/gap-analyzer.js +439 -0
  11. package/dist/src/analysis/gap-analyzer.js.map +1 -0
  12. package/dist/src/analysis/hedging-classifier.d.ts +34 -0
  13. package/dist/src/analysis/hedging-classifier.d.ts.map +1 -0
  14. package/dist/src/analysis/hedging-classifier.js +144 -0
  15. package/dist/src/analysis/hedging-classifier.js.map +1 -0
  16. package/dist/src/analysis/report-diagnostics.d.ts +9 -0
  17. package/dist/src/analysis/report-diagnostics.d.ts.map +1 -0
  18. package/dist/src/analysis/report-diagnostics.js +631 -0
  19. package/dist/src/analysis/report-diagnostics.js.map +1 -0
  20. package/dist/src/authoring/evolver.d.ts +64 -0
  21. package/dist/src/authoring/evolver.d.ts.map +1 -0
  22. package/dist/src/authoring/evolver.js +275 -0
  23. package/dist/src/authoring/evolver.js.map +1 -0
  24. package/dist/src/authoring/generator.d.ts +13 -0
  25. package/dist/src/authoring/generator.d.ts.map +1 -0
  26. package/dist/src/authoring/generator.js +60 -0
  27. package/dist/src/authoring/generator.js.map +1 -0
  28. package/dist/src/cli.d.ts +3 -0
  29. package/dist/src/cli.d.ts.map +1 -0
  30. package/dist/src/cli.js +1012 -0
  31. package/dist/src/cli.js.map +1 -0
  32. package/dist/src/eval-core/cache.d.ts +11 -0
  33. package/dist/src/eval-core/cache.d.ts.map +1 -0
  34. package/dist/src/eval-core/cache.js +53 -0
  35. package/dist/src/eval-core/cache.js.map +1 -0
  36. package/dist/src/eval-core/ci-gates.d.ts +17 -0
  37. package/dist/src/eval-core/ci-gates.d.ts.map +1 -0
  38. package/dist/src/eval-core/ci-gates.js +42 -0
  39. package/dist/src/eval-core/ci-gates.js.map +1 -0
  40. package/dist/src/eval-core/dependency-checker.d.ts +37 -0
  41. package/dist/src/eval-core/dependency-checker.d.ts.map +1 -0
  42. package/dist/src/eval-core/dependency-checker.js +280 -0
  43. package/dist/src/eval-core/dependency-checker.js.map +1 -0
  44. package/dist/src/eval-core/evaluation-execution.d.ts +26 -0
  45. package/dist/src/eval-core/evaluation-execution.d.ts.map +1 -0
  46. package/dist/src/eval-core/evaluation-execution.js +196 -0
  47. package/dist/src/eval-core/evaluation-execution.js.map +1 -0
  48. package/dist/src/eval-core/evaluation-job.d.ts +50 -0
  49. package/dist/src/eval-core/evaluation-job.d.ts.map +1 -0
  50. package/dist/src/eval-core/evaluation-job.js +114 -0
  51. package/dist/src/eval-core/evaluation-job.js.map +1 -0
  52. package/dist/src/eval-core/evaluation-reporting.d.ts +28 -0
  53. package/dist/src/eval-core/evaluation-reporting.d.ts.map +1 -0
  54. package/dist/src/eval-core/evaluation-reporting.js +123 -0
  55. package/dist/src/eval-core/evaluation-reporting.js.map +1 -0
  56. package/dist/src/eval-core/execution-strategy.d.ts +11 -0
  57. package/dist/src/eval-core/execution-strategy.d.ts.map +1 -0
  58. package/dist/src/eval-core/execution-strategy.js +121 -0
  59. package/dist/src/eval-core/execution-strategy.js.map +1 -0
  60. package/dist/src/eval-core/fact-checker.d.ts +25 -0
  61. package/dist/src/eval-core/fact-checker.d.ts.map +1 -0
  62. package/dist/src/eval-core/fact-checker.js +66 -0
  63. package/dist/src/eval-core/fact-checker.js.map +1 -0
  64. package/dist/src/eval-core/schema.d.ts +30 -0
  65. package/dist/src/eval-core/schema.d.ts.map +1 -0
  66. package/dist/src/eval-core/schema.js +195 -0
  67. package/dist/src/eval-core/schema.js.map +1 -0
  68. package/dist/src/eval-core/statistics.d.ts +86 -0
  69. package/dist/src/eval-core/statistics.d.ts.map +1 -0
  70. package/dist/src/eval-core/statistics.js +210 -0
  71. package/dist/src/eval-core/statistics.js.map +1 -0
  72. package/dist/src/eval-core/task-planner.d.ts +4 -0
  73. package/dist/src/eval-core/task-planner.d.ts.map +1 -0
  74. package/dist/src/eval-core/task-planner.js +33 -0
  75. package/dist/src/eval-core/task-planner.js.map +1 -0
  76. package/dist/src/eval-workflows/each-evaluation-workflow.d.ts +137 -0
  77. package/dist/src/eval-workflows/each-evaluation-workflow.d.ts.map +1 -0
  78. package/dist/src/eval-workflows/each-evaluation-workflow.js +174 -0
  79. package/dist/src/eval-workflows/each-evaluation-workflow.js.map +1 -0
  80. package/dist/src/eval-workflows/evaluation-pipeline.d.ts +42 -0
  81. package/dist/src/eval-workflows/evaluation-pipeline.d.ts.map +1 -0
  82. package/dist/src/eval-workflows/evaluation-pipeline.js +218 -0
  83. package/dist/src/eval-workflows/evaluation-pipeline.js.map +1 -0
  84. package/dist/src/eval-workflows/evaluation-preparation.d.ts +64 -0
  85. package/dist/src/eval-workflows/evaluation-preparation.d.ts.map +1 -0
  86. package/dist/src/eval-workflows/evaluation-preparation.js +90 -0
  87. package/dist/src/eval-workflows/evaluation-preparation.js.map +1 -0
  88. package/dist/src/eval-workflows/run-evaluation.d.ts +111 -0
  89. package/dist/src/eval-workflows/run-evaluation.d.ts.map +1 -0
  90. package/dist/src/eval-workflows/run-evaluation.js +272 -0
  91. package/dist/src/eval-workflows/run-evaluation.js.map +1 -0
  92. package/dist/src/executors/anthropic-api.d.ts +3 -0
  93. package/dist/src/executors/anthropic-api.d.ts.map +1 -0
  94. package/dist/src/executors/anthropic-api.js +43 -0
  95. package/dist/src/executors/anthropic-api.js.map +1 -0
  96. package/dist/src/executors/claude-cli.d.ts +3 -0
  97. package/dist/src/executors/claude-cli.d.ts.map +1 -0
  98. package/dist/src/executors/claude-cli.js +103 -0
  99. package/dist/src/executors/claude-cli.js.map +1 -0
  100. package/dist/src/executors/claude-sdk-trace.d.ts +10 -0
  101. package/dist/src/executors/claude-sdk-trace.d.ts.map +1 -0
  102. package/dist/src/executors/claude-sdk-trace.js +100 -0
  103. package/dist/src/executors/claude-sdk-trace.js.map +1 -0
  104. package/dist/src/executors/claude-sdk.d.ts +3 -0
  105. package/dist/src/executors/claude-sdk.d.ts.map +1 -0
  106. package/dist/src/executors/claude-sdk.js +160 -0
  107. package/dist/src/executors/claude-sdk.js.map +1 -0
  108. package/dist/src/executors/gemini.d.ts +3 -0
  109. package/dist/src/executors/gemini.d.ts.map +1 -0
  110. package/dist/src/executors/gemini.js +78 -0
  111. package/dist/src/executors/gemini.js.map +1 -0
  112. package/dist/src/executors/index.d.ts +7 -0
  113. package/dist/src/executors/index.d.ts.map +1 -0
  114. package/dist/src/executors/index.js +22 -0
  115. package/dist/src/executors/index.js.map +1 -0
  116. package/dist/src/executors/openai-api.d.ts +3 -0
  117. package/dist/src/executors/openai-api.d.ts.map +1 -0
  118. package/dist/src/executors/openai-api.js +40 -0
  119. package/dist/src/executors/openai-api.js.map +1 -0
  120. package/dist/src/executors/openai-cli.d.ts +3 -0
  121. package/dist/src/executors/openai-cli.d.ts.map +1 -0
  122. package/dist/src/executors/openai-cli.js +60 -0
  123. package/dist/src/executors/openai-cli.js.map +1 -0
  124. package/dist/src/executors/script.d.ts +3 -0
  125. package/dist/src/executors/script.d.ts.map +1 -0
  126. package/dist/src/executors/script.js +63 -0
  127. package/dist/src/executors/script.js.map +1 -0
  128. package/dist/src/executors/shared.d.ts +117 -0
  129. package/dist/src/executors/shared.d.ts.map +1 -0
  130. package/dist/src/executors/shared.js +49 -0
  131. package/dist/src/executors/shared.js.map +1 -0
  132. package/dist/src/grading/assertions.d.ts +18 -0
  133. package/dist/src/grading/assertions.d.ts.map +1 -0
  134. package/dist/src/grading/assertions.js +239 -0
  135. package/dist/src/grading/assertions.js.map +1 -0
  136. package/dist/src/grading/index.d.ts +26 -0
  137. package/dist/src/grading/index.d.ts.map +1 -0
  138. package/dist/src/grading/index.js +98 -0
  139. package/dist/src/grading/index.js.map +1 -0
  140. package/dist/src/grading/judge.d.ts +13 -0
  141. package/dist/src/grading/judge.d.ts.map +1 -0
  142. package/dist/src/grading/judge.js +98 -0
  143. package/dist/src/grading/judge.js.map +1 -0
  144. package/dist/src/grading/layered-scores.d.ts +13 -0
  145. package/dist/src/grading/layered-scores.d.ts.map +1 -0
  146. package/dist/src/grading/layered-scores.js +62 -0
  147. package/dist/src/grading/layered-scores.js.map +1 -0
  148. package/dist/src/inputs/eval-config.d.ts +13 -0
  149. package/dist/src/inputs/eval-config.d.ts.map +1 -0
  150. package/dist/src/inputs/eval-config.js +136 -0
  151. package/dist/src/inputs/eval-config.js.map +1 -0
  152. package/dist/src/inputs/load-samples.d.ts +16 -0
  153. package/dist/src/inputs/load-samples.d.ts.map +1 -0
  154. package/dist/src/inputs/load-samples.js +51 -0
  155. package/dist/src/inputs/load-samples.js.map +1 -0
  156. package/dist/src/inputs/mcp-resolver.d.ts +50 -0
  157. package/dist/src/inputs/mcp-resolver.d.ts.map +1 -0
  158. package/dist/src/inputs/mcp-resolver.js +307 -0
  159. package/dist/src/inputs/mcp-resolver.js.map +1 -0
  160. package/dist/src/inputs/skill-loader.d.ts +18 -0
  161. package/dist/src/inputs/skill-loader.d.ts.map +1 -0
  162. package/dist/src/inputs/skill-loader.js +222 -0
  163. package/dist/src/inputs/skill-loader.js.map +1 -0
  164. package/dist/src/inputs/url-fetcher.d.ts +19 -0
  165. package/dist/src/inputs/url-fetcher.d.ts.map +1 -0
  166. package/dist/src/inputs/url-fetcher.js +241 -0
  167. package/dist/src/inputs/url-fetcher.js.map +1 -0
  168. package/dist/src/observability/skill-health-analyzer.d.ts +83 -0
  169. package/dist/src/observability/skill-health-analyzer.d.ts.map +1 -0
  170. package/dist/src/observability/skill-health-analyzer.js +238 -0
  171. package/dist/src/observability/skill-health-analyzer.js.map +1 -0
  172. package/dist/src/observability/trace-adapter.d.ts +75 -0
  173. package/dist/src/observability/trace-adapter.d.ts.map +1 -0
  174. package/dist/src/observability/trace-adapter.js +367 -0
  175. package/dist/src/observability/trace-adapter.js.map +1 -0
  176. package/dist/src/renderer/html-renderer.d.ts +9 -0
  177. package/dist/src/renderer/html-renderer.d.ts.map +1 -0
  178. package/dist/src/renderer/html-renderer.js +360 -0
  179. package/dist/src/renderer/html-renderer.js.map +1 -0
  180. package/dist/src/renderer/layout.d.ts +13 -0
  181. package/dist/src/renderer/layout.d.ts.map +1 -0
  182. package/dist/src/renderer/layout.js +582 -0
  183. package/dist/src/renderer/layout.js.map +1 -0
  184. package/dist/src/renderer/skill-health-renderer.d.ts +20 -0
  185. package/dist/src/renderer/skill-health-renderer.d.ts.map +1 -0
  186. package/dist/src/renderer/skill-health-renderer.js +253 -0
  187. package/dist/src/renderer/skill-health-renderer.js.map +1 -0
  188. package/dist/src/renderer/summary.d.ts +21 -0
  189. package/dist/src/renderer/summary.d.ts.map +1 -0
  190. package/dist/src/renderer/summary.js +1072 -0
  191. package/dist/src/renderer/summary.js.map +1 -0
  192. package/dist/src/renderer/table.d.ts +3 -0
  193. package/dist/src/renderer/table.d.ts.map +1 -0
  194. package/dist/src/renderer/table.js +134 -0
  195. package/dist/src/renderer/table.js.map +1 -0
  196. package/dist/src/renderer/trends.d.ts +6 -0
  197. package/dist/src/renderer/trends.d.ts.map +1 -0
  198. package/dist/src/renderer/trends.js +127 -0
  199. package/dist/src/renderer/trends.js.map +1 -0
  200. package/dist/src/server/job-store.d.ts +4 -0
  201. package/dist/src/server/job-store.d.ts.map +1 -0
  202. package/dist/src/server/job-store.js +68 -0
  203. package/dist/src/server/job-store.js.map +1 -0
  204. package/dist/src/server/report-server.d.ts +17 -0
  205. package/dist/src/server/report-server.d.ts.map +1 -0
  206. package/dist/src/server/report-server.js +591 -0
  207. package/dist/src/server/report-server.js.map +1 -0
  208. package/dist/src/server/report-store.d.ts +44 -0
  209. package/dist/src/server/report-store.d.ts.map +1 -0
  210. package/dist/src/server/report-store.js +190 -0
  211. package/dist/src/server/report-store.js.map +1 -0
  212. package/dist/src/types.d.ts +559 -0
  213. package/dist/src/types.d.ts.map +1 -0
  214. package/dist/src/types.js +2 -0
  215. package/dist/src/types.js.map +1 -0
  216. package/package.json +53 -5
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Knowledge gap signal analyzer.
3
+ *
4
+ * Implements the v0.1 detection pipeline defined in
5
+ * docs/knowledge-gap-signal-spec.md:
6
+ *
7
+ * gap_rate = (samples with ≥1 gap signal) / (successfully-executed samples)
8
+ *
9
+ * Four signal types are extracted per sample:
10
+ * 1. failed_search — Grep/Read/Bash search that returned empty or failed
11
+ * 2. explicit_marker — 【推断】【知识缺口】【未知】 markers in agent output
12
+ * 3. hedging — hedging language in agent output (accepts FP in v0.1)
13
+ * 4. repeated_failure — ≥3 consecutive failed searches of the same tool type
14
+ *
15
+ * Intentionally does NOT touch report rendering, trends, or CI — those are
16
+ * step-3 work. This module only computes the structured GapReport.
17
+ */
18
+ import { classifyHedgingCandidates } from './hedging-classifier.js';
19
+ // ---------- Pattern tables ----------
20
+ const EXPLICIT_MARKER_PATTERNS = [
21
+ /【推断】/g,
22
+ /【知识缺口】/g,
23
+ /【未知】/g,
24
+ /\[inferred\]/gi,
25
+ /\[unknown\]/gi,
26
+ /\[knowledge\s*gap\]/gi,
27
+ ];
28
+ // v0.1 hedging patterns. Known to have false positives (e.g. "可能是" in normal
29
+ // speech). Spec Section 4.3 accepts this in v0.1 and plans LLM-assisted
30
+ // classification for v0.2.
31
+ const HEDGING_PATTERNS = [
32
+ /我不确定/g,
33
+ /没有足够信息/g,
34
+ /需要查证/g,
35
+ /无法确认/g,
36
+ /\bI['\s]?m not sure\b/gi,
37
+ /\binsufficient information\b/gi,
38
+ /\bneed to verify\b/gi,
39
+ /\bpresumably\b/gi,
40
+ ];
41
+ /** Minimum consecutive failed-search count to trigger a repeated_failure signal. */
42
+ const REPEATED_FAILURE_THRESHOLD = 3;
43
+ /**
44
+ * v0.2 severity weights (spec §6).
45
+ *
46
+ * Strong (1.0): 硬证据类——agent 工具层真的撞墙了
47
+ * - failed_search: Grep/Read 返回空或失败,确定性 miss
48
+ * - repeated_failure: 同一类查询连续 ≥3 次失败,已不是偶然
49
+ *
50
+ * Weak (0.5): 自我陈述类——依赖模型配合,可能假阳
51
+ * - explicit_marker: 依赖 agent 按约定打【推断】等标记,可能漏标
52
+ * - hedging: 字符串匹配 "我不确定/可能是"等,假阳率已知较高(spec §2.8)
53
+ *
54
+ * Aggregation: 每个样本取其信号的最高权重作"样本严重度",平均到 weightedGapRate。
55
+ * weightedGapRate ≤ gapRate,差值反映"软信号占比"——读者据此判断结果可信度。
56
+ */
57
+ export const SIGNAL_WEIGHTS = {
58
+ failed_search: 1.0,
59
+ repeated_failure: 1.0,
60
+ explicit_marker: 0.5,
61
+ hedging: 0.5,
62
+ };
63
+ // ---------- Signal 1: failed searches ----------
64
+ /**
65
+ * Decide whether a tool call counts as a "failed search" signal.
66
+ *
67
+ * Covers:
68
+ * - Read with success: false
69
+ * - Grep with success: false
70
+ * - Grep with success but empty/"No matches found" output (still a miss)
71
+ * - Bash with grep/rg/find in the command and either failure or empty output
72
+ */
73
+ export function isFailedSearchTool(tc) {
74
+ const output = typeof tc.output === 'string' ? tc.output : String(tc.output ?? '');
75
+ const emptyOutput = output.trim() === '' || /No matches found/i.test(output);
76
+ if (tc.tool === 'Read') {
77
+ return tc.success === false;
78
+ }
79
+ if (tc.tool === 'Grep') {
80
+ if (tc.success === false)
81
+ return true;
82
+ return emptyOutput;
83
+ }
84
+ if (tc.tool === 'Bash') {
85
+ const cmd = (tc.input?.command) || '';
86
+ if (!/\b(grep|rg|find)\b/.test(cmd))
87
+ return false;
88
+ if (tc.success === false)
89
+ return true;
90
+ return emptyOutput;
91
+ }
92
+ return false;
93
+ }
94
+ function formatToolEvidence(tc) {
95
+ const input = tc.input || {};
96
+ let pattern = '';
97
+ let path = '';
98
+ if (tc.tool === 'Grep') {
99
+ pattern = String(input.pattern ?? '');
100
+ path = String(input.path ?? '');
101
+ }
102
+ else if (tc.tool === 'Read') {
103
+ path = String(input.file_path ?? '');
104
+ }
105
+ else if (tc.tool === 'Bash') {
106
+ pattern = String(input.command ?? '').slice(0, 120);
107
+ }
108
+ const context = `${tc.tool}: ${pattern || path}`.slice(0, 160);
109
+ return { pattern, path, context };
110
+ }
111
+ /**
112
+ * Extract failed-search signals from a flat tool call sequence.
113
+ * Deduplicates consecutive duplicates (same tool + same pattern) so an agent
114
+ * that retries the exact same Grep 5 times counts as one signal, not five.
115
+ */
116
+ export function extractFailedSearchSignals(toolCalls) {
117
+ const raw = [];
118
+ for (const tc of toolCalls) {
119
+ if (!isFailedSearchTool(tc))
120
+ continue;
121
+ const { pattern, path, context } = formatToolEvidence(tc);
122
+ raw.push({
123
+ sampleId: '',
124
+ type: 'failed_search',
125
+ context,
126
+ evidence: { tool: tc.tool, pattern, path, success: tc.success },
127
+ weight: SIGNAL_WEIGHTS.failed_search,
128
+ });
129
+ }
130
+ // Dedup consecutive identical signals
131
+ const deduped = [];
132
+ for (const s of raw) {
133
+ const prev = deduped[deduped.length - 1];
134
+ if (prev && prev.type === s.type && prev.context === s.context)
135
+ continue;
136
+ deduped.push(s);
137
+ }
138
+ return deduped;
139
+ }
140
+ // ---------- Signals 2 & 3: text-based (markers + hedging) ----------
141
+ function collectAssistantText(vr) {
142
+ const parts = [];
143
+ if (vr.turns) {
144
+ for (const turn of vr.turns) {
145
+ if (turn.role === 'assistant' && turn.content)
146
+ parts.push(turn.content);
147
+ }
148
+ }
149
+ // Fallback: fullOutput if turns are missing (some executors only emit final text)
150
+ if (parts.length === 0 && vr.fullOutput)
151
+ parts.push(vr.fullOutput);
152
+ return parts.join('\n');
153
+ }
154
+ /**
155
+ * Find explicit "I'm inferring / I don't know" markers in agent output text.
156
+ * Each marker occurrence produces one signal; dedupe is at the sample level
157
+ * (handled by the aggregator, not here).
158
+ */
159
+ export function extractMarkerSignals(text) {
160
+ const signals = [];
161
+ if (!text)
162
+ return signals;
163
+ for (const pat of EXPLICIT_MARKER_PATTERNS) {
164
+ let match;
165
+ // Reset lastIndex for the global regex to be safe on reuse
166
+ pat.lastIndex = 0;
167
+ while ((match = pat.exec(text)) !== null) {
168
+ const idx = match.index;
169
+ const snippet = text.slice(Math.max(0, idx - 20), Math.min(text.length, idx + match[0].length + 60));
170
+ signals.push({
171
+ sampleId: '',
172
+ type: 'explicit_marker',
173
+ context: snippet.replace(/\s+/g, ' ').trim().slice(0, 160),
174
+ evidence: { marker: match[0] },
175
+ weight: SIGNAL_WEIGHTS.explicit_marker,
176
+ });
177
+ }
178
+ }
179
+ return signals;
180
+ }
181
+ /**
182
+ * Match hedging-language phrases in agent output text.
183
+ * v0.1 emits at most one hedging signal per sample — the aggregator upgrades
184
+ * this from "per pattern" to "per sample", since multiple hedges in the same
185
+ * turn are usually coming from the same epistemic state.
186
+ */
187
+ export function extractHedgingSignals(text) {
188
+ if (!text)
189
+ return [];
190
+ for (const pat of HEDGING_PATTERNS) {
191
+ pat.lastIndex = 0;
192
+ const match = pat.exec(text);
193
+ if (!match)
194
+ continue;
195
+ const idx = match.index;
196
+ const snippet = text.slice(Math.max(0, idx - 15), Math.min(text.length, idx + match[0].length + 50));
197
+ return [{
198
+ sampleId: '',
199
+ type: 'hedging',
200
+ context: snippet.replace(/\s+/g, ' ').trim().slice(0, 160),
201
+ evidence: { matched: match[0] },
202
+ weight: SIGNAL_WEIGHTS.hedging,
203
+ }];
204
+ }
205
+ return [];
206
+ }
207
+ // ---------- Signal 4: repeated failure pattern ----------
208
+ /**
209
+ * Detect ≥N consecutive failed searches of the same tool type within a turn
210
+ * sequence. Each qualifying run emits exactly one signal anchored at the
211
+ * first failure in the run.
212
+ */
213
+ export function extractRepeatedFailureSignals(turns) {
214
+ if (!turns || turns.length === 0)
215
+ return [];
216
+ const signals = [];
217
+ let run = null;
218
+ let emittedForThisRun = false;
219
+ for (let ti = 0; ti < turns.length; ti++) {
220
+ const turn = turns[ti];
221
+ if (!turn.toolCalls || turn.toolCalls.length === 0)
222
+ continue;
223
+ for (const tc of turn.toolCalls) {
224
+ if (isFailedSearchTool(tc)) {
225
+ if (run && run.tool === tc.tool) {
226
+ run.count += 1;
227
+ }
228
+ else {
229
+ run = { tool: tc.tool, count: 1, startTurn: ti };
230
+ emittedForThisRun = false;
231
+ }
232
+ if (!emittedForThisRun && run.count >= REPEATED_FAILURE_THRESHOLD) {
233
+ signals.push({
234
+ sampleId: '',
235
+ type: 'repeated_failure',
236
+ turn: run.startTurn,
237
+ context: `${run.tool}: 连续失败 ≥${REPEATED_FAILURE_THRESHOLD} 次`,
238
+ evidence: { tool: run.tool, count: run.count, startTurn: run.startTurn },
239
+ weight: SIGNAL_WEIGHTS.repeated_failure,
240
+ });
241
+ emittedForThisRun = true;
242
+ }
243
+ }
244
+ else {
245
+ run = null;
246
+ emittedForThisRun = false;
247
+ }
248
+ }
249
+ }
250
+ return signals;
251
+ }
252
+ // ---------- Per-sample aggregation ----------
253
+ /**
254
+ * Run all four signal extractors on a single variant's result for one sample.
255
+ * Output signals carry the provided sampleId.
256
+ */
257
+ export function extractGapSignalsFromSample(variantResult, sampleId) {
258
+ // 1. Failed searches — flatten all tool calls across turns + top-level fallback
259
+ const toolCalls = [];
260
+ if (variantResult.turns) {
261
+ for (const turn of variantResult.turns) {
262
+ if (turn.toolCalls)
263
+ toolCalls.push(...turn.toolCalls);
264
+ }
265
+ }
266
+ if (toolCalls.length === 0 && variantResult.toolCalls) {
267
+ toolCalls.push(...variantResult.toolCalls);
268
+ }
269
+ const failedSearchSignals = extractFailedSearchSignals(toolCalls);
270
+ // 2 & 3. Text-based signals
271
+ const assistantText = collectAssistantText(variantResult);
272
+ const markerSignals = extractMarkerSignals(assistantText);
273
+ const hedgingSignals = extractHedgingSignals(assistantText);
274
+ // 4. Repeated failure (turn-ordered, so we need turns not flat toolCalls)
275
+ const repeatedFailureSignals = extractRepeatedFailureSignals(variantResult.turns);
276
+ const all = [...failedSearchSignals, ...markerSignals, ...hedgingSignals, ...repeatedFailureSignals];
277
+ return all.map((s) => ({ ...s, sampleId }));
278
+ }
279
+ // ---------- Report-level aggregation ----------
280
+ /**
281
+ * Compute the gap report for one variant across all samples in a report.
282
+ *
283
+ * Denominator rule (spec §5): samples with `ok: false` (the variant completely
284
+ * failed to execute) are EXCLUDED from both numerator and denominator.
285
+ * gap_rate is computed only on samples that actually produced a trace.
286
+ */
287
+ export function computeGapReport(results, variant) {
288
+ const signals = [];
289
+ const sampleIdsWithGap = new Set();
290
+ // 每样本取信号中的最强权重,用于 weightedGapRate(v0.2 §6)。
291
+ // 无信号样本 sampleWeight 隐含为 0,自然不计入 weighted 和。
292
+ const sampleMaxWeight = new Map();
293
+ let sampleCount = 0;
294
+ for (const entry of results) {
295
+ const vr = entry.variants?.[variant];
296
+ if (!vr || vr.ok === false)
297
+ continue;
298
+ sampleCount += 1;
299
+ const sampleSignals = extractGapSignalsFromSample(vr, entry.sample_id);
300
+ if (sampleSignals.length > 0) {
301
+ sampleIdsWithGap.add(entry.sample_id);
302
+ signals.push(...sampleSignals);
303
+ const maxW = sampleSignals.reduce((m, s) => (s.weight > m ? s.weight : m), 0);
304
+ sampleMaxWeight.set(entry.sample_id, maxW);
305
+ }
306
+ }
307
+ const samplesWithGap = sampleIdsWithGap.size;
308
+ const gapRate = sampleCount > 0 ? Number((samplesWithGap / sampleCount).toFixed(4)) : 0;
309
+ const weightSum = Array.from(sampleMaxWeight.values()).reduce((a, b) => a + b, 0);
310
+ const weightedGapRate = sampleCount > 0 ? Number((weightSum / sampleCount).toFixed(4)) : 0;
311
+ const byType = {
312
+ failed_search: 0,
313
+ explicit_marker: 0,
314
+ hedging: 0,
315
+ repeated_failure: 0,
316
+ };
317
+ for (const s of signals)
318
+ byType[s.type] += 1;
319
+ return {
320
+ variant,
321
+ sampleCount,
322
+ samplesWithGap,
323
+ gapRate,
324
+ weightedGapRate,
325
+ testSetPath: null,
326
+ testSetHash: null,
327
+ signals,
328
+ byType,
329
+ };
330
+ }
331
+ /**
332
+ * Compute gap reports for every variant in a Report. Convenience wrapper.
333
+ */
334
+ export function computeReportGapRates(results, variants) {
335
+ const out = {};
336
+ for (const v of variants) {
337
+ out[v] = computeGapReport(results, v);
338
+ }
339
+ return out;
340
+ }
341
+ // ---------- v0.2 hedging classifier integration ----------
342
+ /**
343
+ * 重新计算 GapReport 的衍生字段(samplesWithGap / gapRate / weightedGapRate /
344
+ * byType),用于 hedging signal 被 classifier 过滤后的二次聚合。
345
+ * sampleCount 不变(分母:成功执行的样本数,与是否有信号无关)。
346
+ */
347
+ function recomputeAggregates(report) {
348
+ const sampleIdsWithGap = new Set();
349
+ const sampleMaxWeight = new Map();
350
+ const byType = {
351
+ failed_search: 0,
352
+ explicit_marker: 0,
353
+ hedging: 0,
354
+ repeated_failure: 0,
355
+ };
356
+ for (const s of report.signals) {
357
+ sampleIdsWithGap.add(s.sampleId);
358
+ const cur = sampleMaxWeight.get(s.sampleId) ?? 0;
359
+ if (s.weight > cur)
360
+ sampleMaxWeight.set(s.sampleId, s.weight);
361
+ byType[s.type] += 1;
362
+ }
363
+ const samplesWithGap = sampleIdsWithGap.size;
364
+ const gapRate = report.sampleCount > 0
365
+ ? Number((samplesWithGap / report.sampleCount).toFixed(4))
366
+ : 0;
367
+ const weightSum = Array.from(sampleMaxWeight.values()).reduce((a, b) => a + b, 0);
368
+ const weightedGapRate = report.sampleCount > 0
369
+ ? Number((weightSum / report.sampleCount).toFixed(4))
370
+ : 0;
371
+ return { ...report, samplesWithGap, gapRate, weightedGapRate, byType };
372
+ }
373
+ /**
374
+ * 对一份 GapReport 做 hedging classifier 二次过滤(spec §四.3, v0.2)。
375
+ * 流程:
376
+ * 1) 收集 signals 中所有 type='hedging' 的 candidate
377
+ * 2) 调 classifyHedgingCandidates 拿 verdict
378
+ * 3) verdict.isUncertainty=false 的 signal 丢弃
379
+ * 4) verdict.isUncertainty=true 的保留并挂 classifierVerdict
380
+ * 5) recompute samplesWithGap / gapRate / weightedGapRate / byType
381
+ *
382
+ * 失败降级在 classifier 层:单批失败 → 该 batch 全部 isUncertainty=true (保守保留)。
383
+ * 调用方拿到的 report 永远是合法的,不会因 classifier 失败而崩。
384
+ */
385
+ export async function applyHedgingClassifier(report, executor, opts) {
386
+ const hedgingIndices = [];
387
+ const candidates = [];
388
+ for (let i = 0; i < report.signals.length; i++) {
389
+ const s = report.signals[i];
390
+ if (s.type !== 'hedging')
391
+ continue;
392
+ hedgingIndices.push(i);
393
+ const matched = s.evidence?.matched ?? s.context;
394
+ candidates.push({
395
+ sampleId: s.sampleId,
396
+ sentence: matched,
397
+ context: s.context,
398
+ });
399
+ }
400
+ if (candidates.length === 0) {
401
+ return { report, costUSD: 0, truncated: false };
402
+ }
403
+ const { verdicts, costUSD, truncated } = await classifyHedgingCandidates(candidates, executor, opts);
404
+ // 按 verdict 重组 signals:非 hedging 原样保留,hedging 按 verdict.isUncertainty 过滤 + 挂 verdict
405
+ const keptHedging = new Set();
406
+ hedgingIndices.forEach((idx, i) => {
407
+ if (verdicts[i].isUncertainty)
408
+ keptHedging.add(idx);
409
+ });
410
+ const newSignals = [];
411
+ for (let i = 0; i < report.signals.length; i++) {
412
+ const s = report.signals[i];
413
+ if (s.type !== 'hedging') {
414
+ newSignals.push(s);
415
+ continue;
416
+ }
417
+ if (!keptHedging.has(i))
418
+ continue; // dropped by classifier
419
+ const verdictIdx = hedgingIndices.indexOf(i);
420
+ newSignals.push({ ...s, classifierVerdict: verdicts[verdictIdx] });
421
+ }
422
+ const next = recomputeAggregates({ ...report, signals: newSignals });
423
+ return { report: next, costUSD, truncated };
424
+ }
425
+ /**
426
+ * 批量为一组 variant 的 gap reports 跑 classifier。
427
+ * 串行(不并行)避免 rate limit + 让 cache hit 在第一批后被后续 batch 复用。
428
+ */
429
+ export async function applyHedgingClassifierToReports(reports, executor, opts) {
430
+ const out = {};
431
+ let totalCost = 0;
432
+ for (const [variant, report] of Object.entries(reports)) {
433
+ const result = await applyHedgingClassifier(report, executor, opts);
434
+ out[variant] = result.report;
435
+ totalCost += result.costUSD;
436
+ }
437
+ return { reports: out, costUSD: totalCost };
438
+ }
439
+ //# sourceMappingURL=gap-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gap-analyzer.js","sourceRoot":"","sources":["../../../src/analysis/gap-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Hedging classifier (spec §四.3, v0.2).
3
+ *
4
+ * regex 召回 → LLM 二次判定。把 extractHedgingSignals 的 candidate 句子送给小模型,
5
+ * 让模型判断"这一句是知识层面的不确定,还是业务推理 / 假设 / 礼貌表达"。
6
+ *
7
+ * 关键约束:
8
+ * - cost 上限: 默认 maxCandidates=50, 超出截断 + warn
9
+ * - cache: in-memory Map<sha256(sentence), HedgingVerdict>, 同句子不重复调用
10
+ * - 失败降级: 调用 / 解析失败 → 该 candidate 默认 isUncertainty=true (保守保留)
11
+ */
12
+ import type { ExecutorFn, HedgingVerdict } from '../types.js';
13
+ export interface HedgingCandidate {
14
+ sampleId: string;
15
+ sentence: string;
16
+ context: string;
17
+ }
18
+ export interface ClassifyOptions {
19
+ maxCandidates?: number;
20
+ model?: string;
21
+ batchSize?: number;
22
+ }
23
+ export interface ClassifyResult {
24
+ verdicts: HedgingVerdict[];
25
+ costUSD: number;
26
+ truncated: boolean;
27
+ }
28
+ export declare function clearHedgingCache(): void;
29
+ /**
30
+ * 对一批 candidate 做分类判定。返回与 input 等长的 verdicts。
31
+ * 失败降级:单批 LLM 调用 / 解析失败 → 该 batch 全部 isUncertainty=true (保守保留)。
32
+ */
33
+ export declare function classifyHedgingCandidates(candidates: HedgingCandidate[], executor: ExecutorFn, opts?: ClassifyOptions): Promise<ClassifyResult>;
34
+ //# sourceMappingURL=hedging-classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hedging-classifier.d.ts","sourceRoot":"","sources":["../../../src/analysis/hedging-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AASD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AA+DD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,gBAAgB,EAAE,EAC9B,QAAQ,EAAE,UAAU,EACpB,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,cAAc,CAAC,CAmEzB"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Hedging classifier (spec §四.3, v0.2).
3
+ *
4
+ * regex 召回 → LLM 二次判定。把 extractHedgingSignals 的 candidate 句子送给小模型,
5
+ * 让模型判断"这一句是知识层面的不确定,还是业务推理 / 假设 / 礼貌表达"。
6
+ *
7
+ * 关键约束:
8
+ * - cost 上限: 默认 maxCandidates=50, 超出截断 + warn
9
+ * - cache: in-memory Map<sha256(sentence), HedgingVerdict>, 同句子不重复调用
10
+ * - 失败降级: 调用 / 解析失败 → 该 candidate 默认 isUncertainty=true (保守保留)
11
+ */
12
+ import { createHash } from 'node:crypto';
13
+ const DEFAULT_MAX_CANDIDATES = 50;
14
+ const DEFAULT_BATCH_SIZE = 10;
15
+ const DEFAULT_MODEL = 'claude-haiku-4-5-20251001';
16
+ // in-memory cache,进程内复用。key = sha256(sentence)。
17
+ const verdictCache = new Map();
18
+ export function clearHedgingCache() {
19
+ verdictCache.clear();
20
+ }
21
+ function hashSentence(sentence) {
22
+ return createHash('sha256').update(sentence).digest('hex').slice(0, 16);
23
+ }
24
+ function buildBatchPrompt(batch) {
25
+ const items = batch
26
+ .map((c, i) => `### ${i + 1}\n命中句: ${c.sentence}\n上下文: ${c.context}`)
27
+ .join('\n\n');
28
+ return [
29
+ '判断以下每段话是否表达了"知识 / 事实层面的不确定"。',
30
+ '',
31
+ '满足以下任一条算"不确定"(isUncertainty=true):',
32
+ ' - 表示自己不知道答案 / 缺少信息 / 需要查证',
33
+ ' - 给出答案但显著降级措辞("可能是 X 但不确定")',
34
+ '',
35
+ '以下情况 **不算** "不确定" (isUncertainty=false):',
36
+ ' - 业务可能性分析(讨论多种业务场景的可能性)',
37
+ ' - 礼貌 / 假设性措辞("如果你需要,可能可以...")',
38
+ ' - 对未来不确定("未来可能会..."),不属于知识不确定',
39
+ '',
40
+ items,
41
+ '',
42
+ '返回 JSON 数组(不要 markdown 代码块标记),按上面编号顺序,每项格式:',
43
+ '{"id": <编号>, "isUncertainty": <bool>, "confidence": <0-1 的小数>, "reason": "<10 字以内简短理由>"}',
44
+ ].join('\n');
45
+ }
46
+ function parseBatchResponse(text, batchSize) {
47
+ const trimmed = text.trim();
48
+ const jsonMatch = trimmed.match(/\[[\s\S]*\]/);
49
+ if (!jsonMatch)
50
+ throw new Error(`classifier returned non-JSON: ${trimmed.slice(0, 100)}`);
51
+ const parsed = JSON.parse(jsonMatch[0]);
52
+ if (!Array.isArray(parsed))
53
+ throw new Error('classifier response is not an array');
54
+ // 按 id 排序后填充,缺失的 id 走降级
55
+ const verdicts = [];
56
+ for (let i = 1; i <= batchSize; i++) {
57
+ const item = parsed.find((p) => Number(p.id) === i);
58
+ if (!item) {
59
+ verdicts.push({ isUncertainty: true, confidence: 0, reason: `classifier missing id ${i}` });
60
+ continue;
61
+ }
62
+ verdicts.push({
63
+ isUncertainty: Boolean(item.isUncertainty),
64
+ confidence: Math.max(0, Math.min(1, Number(item.confidence) || 0)),
65
+ reason: String(item.reason || '').slice(0, 60),
66
+ });
67
+ }
68
+ return verdicts;
69
+ }
70
+ function fallbackVerdict(reason) {
71
+ return { isUncertainty: true, confidence: 0, reason: `classifier failed: ${reason}` };
72
+ }
73
+ /**
74
+ * 对一批 candidate 做分类判定。返回与 input 等长的 verdicts。
75
+ * 失败降级:单批 LLM 调用 / 解析失败 → 该 batch 全部 isUncertainty=true (保守保留)。
76
+ */
77
+ export async function classifyHedgingCandidates(candidates, executor, opts) {
78
+ const max = opts?.maxCandidates ?? DEFAULT_MAX_CANDIDATES;
79
+ const batchSize = opts?.batchSize ?? DEFAULT_BATCH_SIZE;
80
+ const model = opts?.model ?? DEFAULT_MODEL;
81
+ const truncated = candidates.length > max;
82
+ const work = candidates.slice(0, max);
83
+ const verdicts = new Array(candidates.length);
84
+ let costUSD = 0;
85
+ if (truncated) {
86
+ process.stderr.write(`[omk] hedging classifier: ${candidates.length} candidates exceeds maxCandidates=${max}, truncated\n`);
87
+ // 被截断的部分走降级保守保留
88
+ for (let i = max; i < candidates.length; i++) {
89
+ verdicts[i] = fallbackVerdict('truncated by maxCandidates');
90
+ }
91
+ }
92
+ // 先查 cache
93
+ const uncached = [];
94
+ for (let i = 0; i < work.length; i++) {
95
+ const key = hashSentence(work[i].sentence);
96
+ const hit = verdictCache.get(key);
97
+ if (hit) {
98
+ verdicts[i] = hit;
99
+ }
100
+ else {
101
+ uncached.push({ idx: i, cand: work[i] });
102
+ }
103
+ }
104
+ // 按 batch 调用
105
+ for (let b = 0; b < uncached.length; b += batchSize) {
106
+ const slice = uncached.slice(b, b + batchSize);
107
+ const batchCands = slice.map((s) => s.cand);
108
+ const prompt = buildBatchPrompt(batchCands);
109
+ let result;
110
+ try {
111
+ result = await executor({
112
+ model,
113
+ system: '你是一个判定 LLM 输出是否表达"知识层面不确定"的分类器。只返回 JSON 数组。',
114
+ prompt,
115
+ });
116
+ }
117
+ catch (err) {
118
+ const msg = err instanceof Error ? err.message : String(err);
119
+ slice.forEach((s) => { verdicts[s.idx] = fallbackVerdict(`exec ${msg}`); });
120
+ continue;
121
+ }
122
+ if (!result.ok || !result.output) {
123
+ slice.forEach((s) => { verdicts[s.idx] = fallbackVerdict(`exec ${result.error ?? 'no output'}`); });
124
+ costUSD += result.costUSD ?? 0;
125
+ continue;
126
+ }
127
+ costUSD += result.costUSD ?? 0;
128
+ let parsed;
129
+ try {
130
+ parsed = parseBatchResponse(result.output, slice.length);
131
+ }
132
+ catch (err) {
133
+ const msg = err instanceof Error ? err.message : String(err);
134
+ slice.forEach((s) => { verdicts[s.idx] = fallbackVerdict(`parse ${msg}`); });
135
+ continue;
136
+ }
137
+ slice.forEach((s, i) => {
138
+ verdicts[s.idx] = parsed[i];
139
+ verdictCache.set(hashSentence(s.cand.sentence), parsed[i]);
140
+ });
141
+ }
142
+ return { verdicts, costUSD, truncated };
143
+ }
144
+ //# sourceMappingURL=hedging-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hedging-classifier.js","sourceRoot":"","sources":["../../../src/analysis/hedging-classifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Auto-analysis: detect patterns and generate insights from evaluation results.
3
+ */
4
+ import type { Report, AnalysisResult } from '../types.js';
5
+ /**
6
+ * Analyze an evaluation report and produce insights + suggestions.
7
+ */
8
+ export declare function analyzeResults(report: Report): AnalysisResult;
9
+ //# sourceMappingURL=report-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-diagnostics.d.ts","sourceRoot":"","sources":["../../../src/analysis/report-diagnostics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAwB,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhF;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CA2C7D"}