oh-my-knowledge 0.48.0 → 0.49.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.
- package/README.md +50 -18
- package/README.zh.md +55 -23
- package/dist/analysis/coverage-analyzer.d.ts +1 -0
- package/dist/analysis/coverage-analyzer.js +125 -62
- package/dist/analysis/failure-clusterer.js +2 -1
- package/dist/analysis/gap-analyzer.d.ts +2 -2
- package/dist/analysis/gap-analyzer.js +13 -3
- package/dist/analysis/hedging-classifier.d.ts +2 -2
- package/dist/analysis/hedging-classifier.js +3 -4
- package/dist/analysis/report-diagnostics.js +9 -7
- package/dist/analysis/sample-diagnostics.js +6 -6
- package/dist/artifact-graph/doctor.js +15 -7
- package/dist/assets/agent-skills/omk/SKILL.md +27 -7
- package/dist/assets/agent-skills/omk/references/commands.md +18 -17
- package/dist/authoring/evolver.d.ts +10 -6
- package/dist/authoring/evolver.js +496 -83
- package/dist/authoring/generator.d.ts +3 -3
- package/dist/authoring/generator.js +5 -10
- package/dist/authoring/sample-fixer.d.ts +8 -6
- package/dist/authoring/sample-fixer.js +76 -5
- package/dist/cli/commands/doctor.js +31 -14
- package/dist/cli/commands/eval/index.d.ts +3 -0
- package/dist/cli/commands/eval/index.js +163 -17
- package/dist/cli/commands/evolve.d.ts +4 -4
- package/dist/cli/commands/evolve.js +27 -13
- package/dist/cli/commands/init.js +16 -3
- package/dist/cli/commands/observe/inbox.js +28 -21
- package/dist/cli/commands/observe/index.js +20 -11
- package/dist/cli/commands/observe/ingest.d.ts +3 -0
- package/dist/cli/commands/observe/ingest.js +30 -2
- package/dist/cli/commands/sample.d.ts +6 -3
- package/dist/cli/commands/sample.js +72 -68
- package/dist/cli/lib/codex-model-hint.d.ts +9 -0
- package/dist/cli/lib/codex-model-hint.js +45 -0
- package/dist/cli/lib/generation-failure-hint.d.ts +2 -0
- package/dist/cli/lib/generation-failure-hint.js +61 -0
- package/dist/cli/lib/i18n-dict/common.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/common.js +4 -0
- package/dist/cli/lib/i18n-dict/gen.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/gen.js +38 -6
- package/dist/cli/lib/i18n-dict/help.js +6 -6
- package/dist/cli/lib/i18n-dict/init.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/init.js +13 -9
- package/dist/cli/lib/i18n-dict/run.d.ts +1 -1
- package/dist/cli/lib/i18n-dict/run.js +34 -2
- package/dist/cli/lib/llm-failure-classifier.d.ts +2 -0
- package/dist/cli/lib/llm-failure-classifier.js +8 -0
- package/dist/cli/lib/parse-run-config.d.ts +6 -5
- package/dist/cli/lib/parse-run-config.js +16 -9
- package/dist/cli/lib/runtime-defaults.d.ts +21 -0
- package/dist/cli/lib/runtime-defaults.js +79 -0
- package/dist/diagnosis/observe-mapper.js +14 -15
- package/dist/diagnosis/observe-producer.js +3 -1
- package/dist/diagnosis/studio-projection.js +14 -7
- package/dist/diagnosis/types.d.ts +2 -0
- package/dist/diagnosis/types.js +12 -0
- package/dist/doctor/endpoint-rule.js +2 -1
- package/dist/eval-core/artifact-file-names.js +18 -1
- package/dist/eval-core/artifact-index.d.ts +7 -11
- package/dist/eval-core/artifact-index.js +139 -80
- package/dist/eval-core/cache.d.ts +12 -3
- package/dist/eval-core/cache.js +89 -29
- package/dist/eval-core/comparability.js +10 -6
- package/dist/eval-core/evaluation-execution.d.ts +2 -1
- package/dist/eval-core/evaluation-execution.js +122 -37
- package/dist/eval-core/evaluation-job.d.ts +4 -1
- package/dist/eval-core/evaluation-job.js +4 -1
- package/dist/eval-core/evaluation-reporting.d.ts +15 -13
- package/dist/eval-core/evaluation-reporting.js +54 -52
- package/dist/eval-core/execution-strategy.d.ts +2 -0
- package/dist/eval-core/execution-strategy.js +11 -9
- package/dist/eval-core/fact-checker.js +15 -7
- package/dist/eval-core/holdout.js +3 -2
- package/dist/eval-core/judge-independence.d.ts +2 -2
- package/dist/eval-core/mock-hook.cjs +23 -6
- package/dist/eval-core/mocks-runtime.js +30 -8
- package/dist/eval-core/report-document.d.ts +12 -0
- package/dist/eval-core/report-document.js +1151 -0
- package/dist/eval-core/report-extensions.d.ts +4 -0
- package/dist/eval-core/report-extensions.js +500 -0
- package/dist/eval-core/report-file-migration.js +7 -2
- package/dist/eval-core/resume-compatibility.d.ts +31 -0
- package/dist/eval-core/resume-compatibility.js +141 -0
- package/dist/eval-core/sample-fingerprint.d.ts +12 -0
- package/dist/eval-core/sample-fingerprint.js +193 -0
- package/dist/eval-core/schema.js +86 -31
- package/dist/eval-core/verdict.d.ts +8 -4
- package/dist/eval-core/verdict.js +24 -10
- package/dist/eval-workflows/batch-evaluation-workflow.d.ts +2 -1
- package/dist/eval-workflows/batch-evaluation-workflow.js +25 -12
- package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.d.ts +10 -5
- package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.js +58 -21
- package/dist/eval-workflows/evaluation-pipeline/report-finalize.js +3 -1
- package/dist/eval-workflows/evaluation-pipeline/run-state.d.ts +4 -1
- package/dist/eval-workflows/evaluation-pipeline/run-state.js +4 -1
- package/dist/eval-workflows/evaluation-pipeline/test-set-hash.d.ts +6 -5
- package/dist/eval-workflows/evaluation-pipeline/test-set-hash.js +17 -10
- package/dist/eval-workflows/evaluation-pipeline.js +12 -7
- package/dist/eval-workflows/run-evaluation.d.ts +9 -7
- package/dist/eval-workflows/run-evaluation.js +79 -51
- package/dist/executors/anthropic-api.js +65 -9
- package/dist/executors/claude-cli.js +16 -79
- package/dist/executors/claude-protocol.d.ts +28 -0
- package/dist/executors/claude-protocol.js +180 -0
- package/dist/executors/claude-sdk-trace.js +56 -28
- package/dist/executors/claude-sdk.d.ts +1 -0
- package/dist/executors/claude-sdk.js +39 -93
- package/dist/executors/codex-cli-trace.js +166 -31
- package/dist/executors/codex-cli.d.ts +6 -8
- package/dist/executors/codex-cli.js +49 -151
- package/dist/executors/codex-protocol.d.ts +24 -0
- package/dist/executors/codex-protocol.js +234 -0
- package/dist/executors/codex-sdk.js +68 -120
- package/dist/executors/gemini.js +88 -13
- package/dist/executors/index.d.ts +2 -3
- package/dist/executors/index.js +5 -3
- package/dist/executors/openai-api.js +70 -9
- package/dist/executors/runtime-fingerprint.js +88 -11
- package/dist/executors/script-command.d.ts +8 -0
- package/dist/executors/script-command.js +87 -0
- package/dist/executors/script.js +202 -29
- package/dist/executors/shared.d.ts +35 -3
- package/dist/executors/shared.js +113 -15
- package/dist/grading/assertions.d.ts +1 -1
- package/dist/grading/assertions.js +19 -9
- package/dist/grading/diagnostic.d.ts +9 -2
- package/dist/grading/diagnostic.js +25 -2
- package/dist/grading/index.js +10 -4
- package/dist/grading/judge.js +19 -6
- package/dist/grading/layered-scores.d.ts +2 -3
- package/dist/grading/layered-scores.js +2 -3
- package/dist/inputs/load-samples.d.ts +1 -2
- package/dist/inputs/load-samples.js +23 -1
- package/dist/inputs/mcp-resolver.js +6 -3
- package/dist/inputs/sample-document.d.ts +11 -0
- package/dist/inputs/sample-document.js +96 -0
- package/dist/managed/evidence.d.ts +1 -0
- package/dist/managed/evidence.js +1 -1
- package/dist/managed/store.js +200 -91
- package/dist/observability/codex-trace-adapter.d.ts +5 -0
- package/dist/observability/codex-trace-adapter.js +850 -0
- package/dist/observability/experience.d.ts +32 -6
- package/dist/observability/experience.js +2695 -459
- package/dist/observability/feedback-matchers.js +16 -1
- package/dist/observability/inbox-view-model.d.ts +1 -1
- package/dist/observability/inbox-view-model.js +19 -14
- package/dist/observability/inbox.d.ts +7 -1
- package/dist/observability/inbox.js +632 -124
- package/dist/observability/problem-patterns.js +2 -0
- package/dist/observability/review-state.d.ts +6 -0
- package/dist/observability/review-state.js +235 -63
- package/dist/observability/skill-chain-advisories.js +1 -1
- package/dist/observability/skill-chain.js +17 -4
- package/dist/observability/skill-health-analyzer.d.ts +32 -7
- package/dist/observability/skill-health-analyzer.js +194 -121
- package/dist/observability/skill-health-report.d.ts +10 -0
- package/dist/observability/skill-health-report.js +620 -0
- package/dist/observability/soft-standards/constants.d.ts +0 -1
- package/dist/observability/soft-standards/constants.js +0 -1
- package/dist/observability/soft-standards/index.d.ts +1 -1
- package/dist/observability/soft-standards/index.js +1 -1
- package/dist/observability/soft-standards/llm-extractor.js +8 -10
- package/dist/observability/soft-standards/skill-standards-store.d.ts +2 -1
- package/dist/observability/soft-standards/skill-standards-store.js +59 -18
- package/dist/observability/soft-standards/types.d.ts +2 -2
- package/dist/observability/trace-adapter.d.ts +12 -7
- package/dist/observability/trace-adapter.js +11 -9
- package/dist/observability/trace-attribution.d.ts +13 -5
- package/dist/observability/trace-attribution.js +315 -21
- package/dist/observability/trace-ingestion.d.ts +9 -0
- package/dist/observability/trace-ingestion.js +80 -0
- package/dist/observability/trace-ir.d.ts +113 -0
- package/dist/observability/trace-ir.js +87 -0
- package/dist/observability/trace-segmenter.d.ts +19 -6
- package/dist/observability/trace-segmenter.js +377 -196
- package/dist/observability/trace-session-index.d.ts +19 -0
- package/dist/observability/trace-session-index.js +68 -0
- package/dist/observability/trace-source.d.ts +12 -4
- package/dist/observability/trace-source.js +939 -215
- package/dist/renderer/html-renderer.js +37 -6
- package/dist/renderer/icons.js +3 -0
- package/dist/renderer/observation-inbox-renderer.js +208 -90
- package/dist/renderer/skill-detail-renderer.js +452 -109
- package/dist/renderer/skill-health-renderer.js +69 -12
- package/dist/renderer/summary.js +28 -7
- package/dist/renderer/table.js +21 -4
- package/dist/renderer/test-view.d.ts +1 -0
- package/dist/renderer/test-view.js +44 -9
- package/dist/server/indexed-report-store.js +14 -18
- package/dist/server/job-store.js +64 -26
- package/dist/server/report-server.js +190 -78
- package/dist/server/report-store.js +57 -80
- package/dist/server/skill-index.js +143 -49
- package/dist/server/skill-insights.js +44 -5
- package/dist/shared/artifact-graph.d.ts +3 -0
- package/dist/shared/artifact-graph.js +224 -0
- package/dist/shared/assertion-types.d.ts +8 -0
- package/dist/shared/assertion-types.js +46 -0
- package/dist/shared/atomic-json.d.ts +8 -0
- package/dist/shared/atomic-json.js +33 -0
- package/dist/shared/diagnosis-schema.d.ts +9 -0
- package/dist/shared/diagnosis-schema.js +181 -0
- package/dist/shared/doctor-report.d.ts +3 -0
- package/dist/shared/doctor-report.js +103 -0
- package/dist/shared/evaluation-job.d.ts +6 -0
- package/dist/shared/evaluation-job.js +217 -0
- package/dist/shared/executor-result.d.ts +17 -0
- package/dist/shared/executor-result.js +221 -0
- package/dist/shared/file-lock.d.ts +12 -0
- package/dist/shared/file-lock.js +129 -0
- package/dist/shared/json-value.d.ts +5 -0
- package/dist/shared/json-value.js +36 -0
- package/dist/shared/keyed-mutex.d.ts +7 -0
- package/dist/shared/keyed-mutex.js +24 -0
- package/dist/shared/record-count.d.ts +8 -0
- package/dist/shared/record-count.js +43 -0
- package/dist/shared/sample-contract.d.ts +3 -0
- package/dist/shared/sample-contract.js +332 -0
- package/dist/shared/timestamp.d.ts +6 -0
- package/dist/shared/timestamp.js +64 -0
- package/dist/shared/token-usage.d.ts +19 -0
- package/dist/shared/token-usage.js +50 -0
- package/dist/shared/tool-call-status.d.ts +8 -0
- package/dist/shared/tool-call-status.js +28 -0
- package/dist/shared/tool-identity.d.ts +21 -0
- package/dist/shared/tool-identity.js +84 -0
- package/dist/shared/tool-search.js +73 -16
- package/dist/shared/trace-projection.d.ts +5 -0
- package/dist/shared/trace-projection.js +20 -0
- package/dist/shared/trace-source-kind.d.ts +3 -0
- package/dist/shared/trace-source-kind.js +12 -0
- package/dist/types/diagnosis.d.ts +2 -0
- package/dist/types/eval.d.ts +4 -0
- package/dist/types/executor.d.ts +32 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/judge.d.ts +2 -0
- package/dist/types/observability.d.ts +116 -9
- package/dist/types/report.d.ts +58 -6
- package/dist/types/skill-index.d.ts +7 -0
- package/dist/types/trace.d.ts +2 -0
- package/dist/types/trace.js +1 -0
- package/package.json +9 -5
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
import { SIGNAL_WEIGHTS } from '../analysis/gap-analyzer.js';
|
|
2
|
+
import { confidenceOf, healthBandOf, toolStabilityOf } from './skill-health-analyzer.js';
|
|
3
|
+
import { parseTraceIngestionSummary } from './trace-ingestion.js';
|
|
4
|
+
import { sumRecordCounts } from '../shared/record-count.js';
|
|
5
|
+
import { normalizeRfc3339Timestamp } from '../shared/timestamp.js';
|
|
6
|
+
const TOOL_STABILITIES = new Set([
|
|
7
|
+
'stable',
|
|
8
|
+
'unstable',
|
|
9
|
+
'very-unstable',
|
|
10
|
+
'unknown',
|
|
11
|
+
]);
|
|
12
|
+
const HEALTH_BANDS = new Set([
|
|
13
|
+
'green',
|
|
14
|
+
'yellow',
|
|
15
|
+
'red',
|
|
16
|
+
]);
|
|
17
|
+
const CONFIDENCE_LEVELS = new Set([
|
|
18
|
+
'high',
|
|
19
|
+
'low',
|
|
20
|
+
'underpowered',
|
|
21
|
+
]);
|
|
22
|
+
const GAP_TYPES = new Set([
|
|
23
|
+
'failed_search',
|
|
24
|
+
'explicit_marker',
|
|
25
|
+
'hedging',
|
|
26
|
+
'repeated_failure',
|
|
27
|
+
]);
|
|
28
|
+
const COVERAGE_ENTRY_TYPES = new Set([
|
|
29
|
+
'principle',
|
|
30
|
+
'semantic',
|
|
31
|
+
'design',
|
|
32
|
+
'script',
|
|
33
|
+
'code',
|
|
34
|
+
'other',
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Parse persisted observe-health data at the storage boundary.
|
|
38
|
+
*
|
|
39
|
+
* Legacy reports may omit additive fields such as usage, confidence and
|
|
40
|
+
* tool-outcome coverage. Those fields are reconstructed from authoritative
|
|
41
|
+
* counts. Contradictory counts/rates are rejected; derived labels are
|
|
42
|
+
* recomputed because their threshold formula can evolve between releases.
|
|
43
|
+
*/
|
|
44
|
+
export function parseSkillHealthReport(value) {
|
|
45
|
+
if (!isRecord(value))
|
|
46
|
+
return null;
|
|
47
|
+
if (value.kind !== undefined && value.kind !== 'observe-health')
|
|
48
|
+
return null;
|
|
49
|
+
const meta = normalizeMeta(value.meta);
|
|
50
|
+
const overall = normalizeOverall(value.overall, meta?.segmentCount);
|
|
51
|
+
if (!meta || !overall || !isRecord(value.bySkill))
|
|
52
|
+
return null;
|
|
53
|
+
const skillEntries = [];
|
|
54
|
+
for (const [key, rawHealth] of Object.entries(value.bySkill)) {
|
|
55
|
+
const health = normalizeSkillHealth(rawHealth, key);
|
|
56
|
+
if (!health)
|
|
57
|
+
return null;
|
|
58
|
+
skillEntries.push([key, health]);
|
|
59
|
+
}
|
|
60
|
+
const bySkill = Object.fromEntries(skillEntries);
|
|
61
|
+
if (!reportAggregatesAreConsistent(meta, overall, bySkill))
|
|
62
|
+
return null;
|
|
63
|
+
return {
|
|
64
|
+
...(value.kind === 'observe-health' ? { kind: value.kind } : {}),
|
|
65
|
+
meta,
|
|
66
|
+
overall,
|
|
67
|
+
bySkill,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function normalizeMeta(value) {
|
|
71
|
+
if (!isRecord(value))
|
|
72
|
+
return null;
|
|
73
|
+
const generatedAt = timestamp(value.generatedAt);
|
|
74
|
+
const sessionCount = nonNegativeInteger(value.sessionCount);
|
|
75
|
+
const segmentCount = nonNegativeInteger(value.segmentCount);
|
|
76
|
+
const messageCount = nonNegativeInteger(value.messageCount);
|
|
77
|
+
const toolCallCount = nonNegativeInteger(value.toolCallCount);
|
|
78
|
+
const toolFailureRate = rate(value.toolFailureRate);
|
|
79
|
+
const rawTimeRange = isRecord(value.timeRange) ? value.timeRange : null;
|
|
80
|
+
const timeRange = rawTimeRange
|
|
81
|
+
? {
|
|
82
|
+
from: rawTimeRange.from === '' ? '' : timestamp(rawTimeRange.from),
|
|
83
|
+
to: rawTimeRange.to === '' ? '' : timestamp(rawTimeRange.to),
|
|
84
|
+
}
|
|
85
|
+
: null;
|
|
86
|
+
if (!generatedAt
|
|
87
|
+
|| timeRange?.from === undefined
|
|
88
|
+
|| timeRange.to === undefined
|
|
89
|
+
|| (timeRange.from === '') !== (timeRange.to === '')
|
|
90
|
+
|| (timeRange.from !== ''
|
|
91
|
+
&& timeRange.to !== ''
|
|
92
|
+
&& Date.parse(timeRange.from) > Date.parse(timeRange.to))
|
|
93
|
+
|| sessionCount == null
|
|
94
|
+
|| segmentCount == null
|
|
95
|
+
|| messageCount == null
|
|
96
|
+
|| toolCallCount == null
|
|
97
|
+
|| toolFailureRate == null
|
|
98
|
+
|| typeof value.tracePath !== 'string'
|
|
99
|
+
|| !(value.kbPath === null || typeof value.kbPath === 'string'))
|
|
100
|
+
return null;
|
|
101
|
+
const inferredTimestampedSegmentCount = timeRange.from === '' ? 0 : segmentCount;
|
|
102
|
+
const timestampedSegmentCount = value.timestampedSegmentCount === undefined
|
|
103
|
+
? inferredTimestampedSegmentCount
|
|
104
|
+
: nonNegativeInteger(value.timestampedSegmentCount);
|
|
105
|
+
const excludedUntimestampedSegmentCount = value.excludedUntimestampedSegmentCount === undefined
|
|
106
|
+
? 0
|
|
107
|
+
: nonNegativeInteger(value.excludedUntimestampedSegmentCount);
|
|
108
|
+
if (timestampedSegmentCount == null
|
|
109
|
+
|| timestampedSegmentCount > segmentCount
|
|
110
|
+
|| excludedUntimestampedSegmentCount == null
|
|
111
|
+
|| (timeRange.from === '') !== (timestampedSegmentCount === 0))
|
|
112
|
+
return null;
|
|
113
|
+
const expectedTimestampCoverage = segmentCount > 0
|
|
114
|
+
? Number((timestampedSegmentCount / segmentCount).toFixed(4))
|
|
115
|
+
: 1;
|
|
116
|
+
const timestampCoverage = value.timestampCoverage === undefined
|
|
117
|
+
? expectedTimestampCoverage
|
|
118
|
+
: rate(value.timestampCoverage);
|
|
119
|
+
if (timestampCoverage == null
|
|
120
|
+
|| !approximatelyEqual(timestampCoverage, expectedTimestampCoverage))
|
|
121
|
+
return null;
|
|
122
|
+
const outcomes = normalizeToolOutcomeCounts(toolCallCount, value.toolResolvedCount, value.toolCancelledCount, value.toolUnknownCount, value.toolOutcomeCoverage);
|
|
123
|
+
if (!outcomes)
|
|
124
|
+
return null;
|
|
125
|
+
if (outcomes.comparable === 0 && toolFailureRate !== 0)
|
|
126
|
+
return null;
|
|
127
|
+
const ingestion = value.ingestion === undefined
|
|
128
|
+
? undefined
|
|
129
|
+
: parseTraceIngestionSummary(value.ingestion);
|
|
130
|
+
if (value.ingestion !== undefined && !ingestion)
|
|
131
|
+
return null;
|
|
132
|
+
return {
|
|
133
|
+
tracePath: value.tracePath,
|
|
134
|
+
kbPath: value.kbPath,
|
|
135
|
+
sessionCount,
|
|
136
|
+
segmentCount,
|
|
137
|
+
messageCount,
|
|
138
|
+
timestampedSegmentCount,
|
|
139
|
+
timestampCoverage,
|
|
140
|
+
excludedUntimestampedSegmentCount,
|
|
141
|
+
toolCallCount,
|
|
142
|
+
toolResolvedCount: outcomes.resolved,
|
|
143
|
+
toolCancelledCount: outcomes.cancelled,
|
|
144
|
+
toolUnknownCount: outcomes.unknown,
|
|
145
|
+
toolOutcomeCoverage: outcomes.coverage,
|
|
146
|
+
toolFailureRate,
|
|
147
|
+
timeRange: { from: timeRange.from, to: timeRange.to },
|
|
148
|
+
generatedAt,
|
|
149
|
+
...(ingestion ? { ingestion } : {}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function normalizeOverall(value, segmentCount) {
|
|
153
|
+
if (!isRecord(value) || segmentCount == null)
|
|
154
|
+
return null;
|
|
155
|
+
const gapRate = rate(value.gapRate);
|
|
156
|
+
const weightedGapRate = rate(value.weightedGapRate);
|
|
157
|
+
const healthBand = stringEnum(value.healthBand, HEALTH_BANDS);
|
|
158
|
+
const suppliedConfidence = value.confidence === undefined
|
|
159
|
+
? undefined
|
|
160
|
+
: stringEnum(value.confidence, CONFIDENCE_LEVELS);
|
|
161
|
+
if (gapRate == null
|
|
162
|
+
|| weightedGapRate == null
|
|
163
|
+
|| weightedGapRate > gapRate
|
|
164
|
+
|| !healthBand
|
|
165
|
+
|| (value.confidence !== undefined && !suppliedConfidence)) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
gapRate,
|
|
170
|
+
weightedGapRate,
|
|
171
|
+
healthBand: healthBandOf(weightedGapRate),
|
|
172
|
+
confidence: confidenceOf(segmentCount),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function normalizeSkillHealth(value, key) {
|
|
176
|
+
if (!isRecord(value) || typeof value.skillName !== 'string' || value.skillName !== key)
|
|
177
|
+
return null;
|
|
178
|
+
const segmentCount = nonNegativeInteger(value.segmentCount);
|
|
179
|
+
const toolCallCount = nonNegativeInteger(value.toolCallCount);
|
|
180
|
+
const toolFailureCount = nonNegativeInteger(value.toolFailureCount);
|
|
181
|
+
const toolFailureRate = rate(value.toolFailureRate);
|
|
182
|
+
if (segmentCount == null
|
|
183
|
+
|| toolCallCount == null
|
|
184
|
+
|| toolFailureCount == null
|
|
185
|
+
|| toolFailureRate == null)
|
|
186
|
+
return null;
|
|
187
|
+
const outcomes = normalizeToolOutcomeCounts(toolCallCount, value.toolResolvedCount, value.toolCancelledCount, value.toolUnknownCount, value.toolOutcomeCoverage);
|
|
188
|
+
if (!outcomes || toolFailureCount > outcomes.comparable)
|
|
189
|
+
return null;
|
|
190
|
+
const expectedFailureRate = outcomes.comparable > 0
|
|
191
|
+
? Number((toolFailureCount / outcomes.comparable).toFixed(4))
|
|
192
|
+
: 0;
|
|
193
|
+
if (!approximatelyEqual(toolFailureRate, expectedFailureRate))
|
|
194
|
+
return null;
|
|
195
|
+
const gap = normalizeGap(value.gap, key, segmentCount);
|
|
196
|
+
const coverage = value.coverage === null || value.coverage === undefined
|
|
197
|
+
? null
|
|
198
|
+
: normalizeCoverage(value.coverage);
|
|
199
|
+
const usage = value.usage === undefined ? emptyUsage() : normalizeUsage(value.usage, segmentCount);
|
|
200
|
+
const suppliedConfidence = value.confidence === undefined
|
|
201
|
+
? undefined
|
|
202
|
+
: stringEnum(value.confidence, CONFIDENCE_LEVELS);
|
|
203
|
+
const suppliedStability = value.stability === undefined
|
|
204
|
+
? undefined
|
|
205
|
+
: stringEnum(value.stability, TOOL_STABILITIES);
|
|
206
|
+
if (!gap
|
|
207
|
+
|| coverage === undefined
|
|
208
|
+
|| !usage
|
|
209
|
+
|| (value.confidence !== undefined && !suppliedConfidence)
|
|
210
|
+
|| (value.stability !== undefined && !suppliedStability))
|
|
211
|
+
return null;
|
|
212
|
+
const confidence = confidenceOf(segmentCount);
|
|
213
|
+
const stability = toolStabilityOf(toolFailureRate, outcomes.comparable, toolCallCount);
|
|
214
|
+
if (value.testSetPath !== undefined
|
|
215
|
+
&& value.testSetPath !== null
|
|
216
|
+
&& typeof value.testSetPath !== 'string')
|
|
217
|
+
return null;
|
|
218
|
+
if (value.testSetHash !== undefined
|
|
219
|
+
&& value.testSetHash !== null
|
|
220
|
+
&& typeof value.testSetHash !== 'string')
|
|
221
|
+
return null;
|
|
222
|
+
return {
|
|
223
|
+
skillName: key,
|
|
224
|
+
segmentCount,
|
|
225
|
+
toolCallCount,
|
|
226
|
+
toolFailureCount,
|
|
227
|
+
toolResolvedCount: outcomes.resolved,
|
|
228
|
+
toolCancelledCount: outcomes.cancelled,
|
|
229
|
+
toolUnknownCount: outcomes.unknown,
|
|
230
|
+
toolOutcomeCoverage: outcomes.coverage,
|
|
231
|
+
toolFailureRate,
|
|
232
|
+
stability,
|
|
233
|
+
confidence,
|
|
234
|
+
usage,
|
|
235
|
+
coverage,
|
|
236
|
+
gap,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function normalizeToolOutcomeCounts(total, rawResolved, rawCancelled, rawUnknown, rawCoverage) {
|
|
240
|
+
const suppliedResolved = rawResolved === undefined ? undefined : nonNegativeInteger(rawResolved);
|
|
241
|
+
const suppliedCancelled = rawCancelled === undefined ? undefined : nonNegativeInteger(rawCancelled);
|
|
242
|
+
const suppliedUnknown = rawUnknown === undefined ? undefined : nonNegativeInteger(rawUnknown);
|
|
243
|
+
if ((rawResolved !== undefined && suppliedResolved == null)
|
|
244
|
+
|| (rawCancelled !== undefined && suppliedCancelled == null)
|
|
245
|
+
|| (rawUnknown !== undefined && suppliedUnknown == null))
|
|
246
|
+
return null;
|
|
247
|
+
const resolved = suppliedResolved ?? (suppliedUnknown === undefined ? total : total - suppliedUnknown);
|
|
248
|
+
const cancelled = suppliedCancelled ?? 0;
|
|
249
|
+
const unknown = suppliedUnknown ?? total - resolved;
|
|
250
|
+
const comparable = resolved - cancelled;
|
|
251
|
+
if (resolved < 0
|
|
252
|
+
|| cancelled < 0
|
|
253
|
+
|| unknown < 0
|
|
254
|
+
|| comparable < 0
|
|
255
|
+
|| resolved + unknown !== total)
|
|
256
|
+
return null;
|
|
257
|
+
const coverage = total > 0 ? Number((resolved / total).toFixed(4)) : 1;
|
|
258
|
+
if (rawCoverage !== undefined) {
|
|
259
|
+
const suppliedCoverage = rate(rawCoverage);
|
|
260
|
+
if (suppliedCoverage == null || !approximatelyEqual(suppliedCoverage, coverage))
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
return { resolved, comparable, cancelled, unknown, coverage };
|
|
264
|
+
}
|
|
265
|
+
function normalizeGap(value, skillName, segmentCount) {
|
|
266
|
+
if (!isRecord(value))
|
|
267
|
+
return null;
|
|
268
|
+
const gapRate = rate(value.gapRate);
|
|
269
|
+
const weightedGapRate = rate(value.weightedGapRate);
|
|
270
|
+
if (gapRate == null || weightedGapRate == null || weightedGapRate > gapRate)
|
|
271
|
+
return null;
|
|
272
|
+
if (!Array.isArray(value.signals))
|
|
273
|
+
return null;
|
|
274
|
+
const signals = value.signals.map(normalizeGapSignal);
|
|
275
|
+
if (signals.some((signal) => signal === null))
|
|
276
|
+
return null;
|
|
277
|
+
const typedSignals = signals;
|
|
278
|
+
const sampleCount = value.sampleCount === undefined
|
|
279
|
+
? segmentCount
|
|
280
|
+
: nonNegativeInteger(value.sampleCount);
|
|
281
|
+
const signalSampleIds = new Set(typedSignals.map((signal) => signal.sampleId));
|
|
282
|
+
const derivedSamplesWithGap = signalSampleIds.size;
|
|
283
|
+
const samplesWithGap = value.samplesWithGap === undefined
|
|
284
|
+
? derivedSamplesWithGap
|
|
285
|
+
: nonNegativeInteger(value.samplesWithGap);
|
|
286
|
+
if (sampleCount == null
|
|
287
|
+
|| sampleCount !== segmentCount
|
|
288
|
+
|| samplesWithGap == null
|
|
289
|
+
|| samplesWithGap > sampleCount
|
|
290
|
+
|| samplesWithGap !== derivedSamplesWithGap)
|
|
291
|
+
return null;
|
|
292
|
+
const expectedGapRate = sampleCount > 0
|
|
293
|
+
? Number((samplesWithGap / sampleCount).toFixed(4))
|
|
294
|
+
: 0;
|
|
295
|
+
const maxWeightBySample = new Map();
|
|
296
|
+
for (const signal of typedSignals) {
|
|
297
|
+
maxWeightBySample.set(signal.sampleId, Math.max(maxWeightBySample.get(signal.sampleId) ?? 0, signal.weight));
|
|
298
|
+
}
|
|
299
|
+
const expectedWeightedGapRate = sampleCount > 0
|
|
300
|
+
? Number(([...maxWeightBySample.values()].reduce((sum, weight) => sum + weight, 0)
|
|
301
|
+
/ sampleCount).toFixed(4))
|
|
302
|
+
: 0;
|
|
303
|
+
if (!approximatelyEqual(gapRate, expectedGapRate)
|
|
304
|
+
|| !approximatelyEqual(weightedGapRate, expectedWeightedGapRate))
|
|
305
|
+
return null;
|
|
306
|
+
const byType = normalizeGapCounts(value.byType, typedSignals);
|
|
307
|
+
if (!byType)
|
|
308
|
+
return null;
|
|
309
|
+
if ((value.variant !== undefined && value.variant !== skillName)
|
|
310
|
+
|| (value.testSetPath !== undefined
|
|
311
|
+
&& value.testSetPath !== null
|
|
312
|
+
&& typeof value.testSetPath !== 'string')
|
|
313
|
+
|| (value.testSetHash !== undefined
|
|
314
|
+
&& value.testSetHash !== null
|
|
315
|
+
&& typeof value.testSetHash !== 'string'))
|
|
316
|
+
return null;
|
|
317
|
+
return {
|
|
318
|
+
variant: skillName,
|
|
319
|
+
sampleCount,
|
|
320
|
+
samplesWithGap,
|
|
321
|
+
gapRate,
|
|
322
|
+
weightedGapRate,
|
|
323
|
+
...(value.testSetPath === null || typeof value.testSetPath === 'string'
|
|
324
|
+
? { testSetPath: value.testSetPath }
|
|
325
|
+
: {}),
|
|
326
|
+
...(value.testSetHash === null || typeof value.testSetHash === 'string'
|
|
327
|
+
? { testSetHash: value.testSetHash }
|
|
328
|
+
: {}),
|
|
329
|
+
signals: typedSignals,
|
|
330
|
+
byType,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function normalizeGapSignal(value) {
|
|
334
|
+
if (!isRecord(value))
|
|
335
|
+
return null;
|
|
336
|
+
const type = stringEnum(value.type, GAP_TYPES);
|
|
337
|
+
const weight = rate(value.weight);
|
|
338
|
+
if (typeof value.sampleId !== 'string'
|
|
339
|
+
|| !type
|
|
340
|
+
|| typeof value.context !== 'string'
|
|
341
|
+
|| weight == null
|
|
342
|
+
|| !approximatelyEqual(weight, SIGNAL_WEIGHTS[type])
|
|
343
|
+
|| (value.turn !== undefined && nonNegativeInteger(value.turn) == null)
|
|
344
|
+
|| (value.evidence !== undefined && !isRecord(value.evidence)))
|
|
345
|
+
return null;
|
|
346
|
+
if (value.classifierVerdict !== undefined) {
|
|
347
|
+
if (!isRecord(value.classifierVerdict)
|
|
348
|
+
|| typeof value.classifierVerdict.isUncertainty !== 'boolean'
|
|
349
|
+
|| rate(value.classifierVerdict.confidence) == null
|
|
350
|
+
|| typeof value.classifierVerdict.reason !== 'string')
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
sampleId: value.sampleId,
|
|
355
|
+
type,
|
|
356
|
+
context: value.context,
|
|
357
|
+
weight,
|
|
358
|
+
...(value.turn !== undefined ? { turn: value.turn } : {}),
|
|
359
|
+
...(value.evidence !== undefined
|
|
360
|
+
? { evidence: value.evidence }
|
|
361
|
+
: {}),
|
|
362
|
+
...(value.classifierVerdict !== undefined
|
|
363
|
+
? {
|
|
364
|
+
classifierVerdict: {
|
|
365
|
+
isUncertainty: value.classifierVerdict.isUncertainty,
|
|
366
|
+
confidence: value.classifierVerdict.confidence,
|
|
367
|
+
reason: value.classifierVerdict.reason,
|
|
368
|
+
},
|
|
369
|
+
}
|
|
370
|
+
: {}),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function normalizeGapCounts(value, signals) {
|
|
374
|
+
if (value === undefined) {
|
|
375
|
+
return {
|
|
376
|
+
failed_search: signals.filter((signal) => signal.type === 'failed_search').length,
|
|
377
|
+
explicit_marker: signals.filter((signal) => signal.type === 'explicit_marker').length,
|
|
378
|
+
hedging: signals.filter((signal) => signal.type === 'hedging').length,
|
|
379
|
+
repeated_failure: signals.filter((signal) => signal.type === 'repeated_failure').length,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
if (!isRecord(value))
|
|
383
|
+
return null;
|
|
384
|
+
const failedSearch = nonNegativeInteger(value.failed_search);
|
|
385
|
+
const explicitMarker = nonNegativeInteger(value.explicit_marker);
|
|
386
|
+
const hedging = nonNegativeInteger(value.hedging);
|
|
387
|
+
const repeatedFailure = nonNegativeInteger(value.repeated_failure);
|
|
388
|
+
if (failedSearch == null || explicitMarker == null || hedging == null || repeatedFailure == null)
|
|
389
|
+
return null;
|
|
390
|
+
const normalized = {
|
|
391
|
+
failed_search: failedSearch,
|
|
392
|
+
explicit_marker: explicitMarker,
|
|
393
|
+
hedging,
|
|
394
|
+
repeated_failure: repeatedFailure,
|
|
395
|
+
};
|
|
396
|
+
const expected = normalizeGapCounts(undefined, signals);
|
|
397
|
+
return expected
|
|
398
|
+
&& Object.keys(normalized).every((key) => normalized[key] === expected[key])
|
|
399
|
+
? normalized
|
|
400
|
+
: null;
|
|
401
|
+
}
|
|
402
|
+
function normalizeCoverage(value) {
|
|
403
|
+
if (!isRecord(value) || !Array.isArray(value.entries) || !Array.isArray(value.uncoveredFiles))
|
|
404
|
+
return undefined;
|
|
405
|
+
const entries = value.entries.map((entry) => {
|
|
406
|
+
const type = isRecord(entry) ? stringEnum(entry.type, COVERAGE_ENTRY_TYPES) : undefined;
|
|
407
|
+
if (!isRecord(entry)
|
|
408
|
+
|| typeof entry.path !== 'string'
|
|
409
|
+
|| !type
|
|
410
|
+
|| typeof entry.accessed !== 'boolean'
|
|
411
|
+
|| nonNegativeInteger(entry.accessCount) == null
|
|
412
|
+
|| (entry.lineCount !== undefined && nonNegativeInteger(entry.lineCount) == null)
|
|
413
|
+
|| (entry.accessed && entry.accessCount === 0)
|
|
414
|
+
|| (!entry.accessed && entry.accessCount !== 0))
|
|
415
|
+
return null;
|
|
416
|
+
return {
|
|
417
|
+
path: entry.path,
|
|
418
|
+
type,
|
|
419
|
+
accessed: entry.accessed,
|
|
420
|
+
accessCount: entry.accessCount,
|
|
421
|
+
...(entry.lineCount !== undefined ? { lineCount: entry.lineCount } : {}),
|
|
422
|
+
};
|
|
423
|
+
});
|
|
424
|
+
const filesCovered = nonNegativeInteger(value.filesCovered);
|
|
425
|
+
const filesTotal = nonNegativeInteger(value.filesTotal);
|
|
426
|
+
const fileCoverageRate = rate(value.fileCoverageRate);
|
|
427
|
+
const grepPatternsUsed = nonNegativeInteger(value.grepPatternsUsed);
|
|
428
|
+
const overallRate = rate(value.overallRate);
|
|
429
|
+
if (entries.some((entry) => entry === null)
|
|
430
|
+
|| value.uncoveredFiles.some((path) => typeof path !== 'string')
|
|
431
|
+
|| filesCovered == null
|
|
432
|
+
|| filesTotal == null
|
|
433
|
+
|| filesCovered > filesTotal
|
|
434
|
+
|| fileCoverageRate == null
|
|
435
|
+
|| grepPatternsUsed == null
|
|
436
|
+
|| overallRate == null)
|
|
437
|
+
return undefined;
|
|
438
|
+
const typedEntries = entries;
|
|
439
|
+
if (new Set(typedEntries.map((entry) => entry.path)).size !== typedEntries.length
|
|
440
|
+
|| new Set(value.uncoveredFiles).size !== value.uncoveredFiles.length)
|
|
441
|
+
return undefined;
|
|
442
|
+
const derivedCovered = typedEntries.filter((entry) => entry.accessed).length;
|
|
443
|
+
const derivedUncovered = typedEntries.filter((entry) => !entry.accessed).map((entry) => entry.path);
|
|
444
|
+
const expectedFileCoverageRate = filesTotal > 0
|
|
445
|
+
? Number((filesCovered / filesTotal).toFixed(2))
|
|
446
|
+
: 0;
|
|
447
|
+
const grepBonus = grepPatternsUsed > 0
|
|
448
|
+
? Math.min(1, grepPatternsUsed / Math.max(5, filesTotal))
|
|
449
|
+
: 0;
|
|
450
|
+
const expectedOverallRate = Number((fileCoverageRate * 0.6 + grepBonus * 0.4).toFixed(2));
|
|
451
|
+
if (filesTotal !== typedEntries.length
|
|
452
|
+
|| filesCovered !== derivedCovered
|
|
453
|
+
|| !approximatelyEqual(fileCoverageRate, expectedFileCoverageRate)
|
|
454
|
+
|| !sameStringSet(value.uncoveredFiles, derivedUncovered)
|
|
455
|
+
|| !approximatelyEqual(overallRate, expectedOverallRate))
|
|
456
|
+
return undefined;
|
|
457
|
+
return {
|
|
458
|
+
entries: typedEntries,
|
|
459
|
+
filesCovered,
|
|
460
|
+
filesTotal,
|
|
461
|
+
fileCoverageRate,
|
|
462
|
+
uncoveredFiles: derivedUncovered,
|
|
463
|
+
grepPatternsUsed,
|
|
464
|
+
overallRate,
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
function normalizeUsage(value, segmentCount) {
|
|
468
|
+
if (!isRecord(value))
|
|
469
|
+
return null;
|
|
470
|
+
const integerFields = [
|
|
471
|
+
'inputTokens',
|
|
472
|
+
'outputTokens',
|
|
473
|
+
'cacheReadTokens',
|
|
474
|
+
'cacheCreationTokens',
|
|
475
|
+
'totalTokens',
|
|
476
|
+
'numTurns',
|
|
477
|
+
'avgTokensPerSegment',
|
|
478
|
+
'avgDurationMsPerSegment',
|
|
479
|
+
];
|
|
480
|
+
const normalized = Object.fromEntries(integerFields.map((field) => [field, nonNegativeInteger(value[field])]));
|
|
481
|
+
const durationMs = nonNegativeNumber(value.durationMs);
|
|
482
|
+
if (Object.values(normalized).some((entry) => entry == null) || durationMs == null)
|
|
483
|
+
return null;
|
|
484
|
+
const hasTokenCoverage = value.tokenObservedSegmentCount !== undefined
|
|
485
|
+
|| value.tokenCoverage !== undefined;
|
|
486
|
+
const tokenObservedSegmentCount = hasTokenCoverage
|
|
487
|
+
? nonNegativeInteger(value.tokenObservedSegmentCount)
|
|
488
|
+
: 0;
|
|
489
|
+
const tokenCoverage = hasTokenCoverage
|
|
490
|
+
? rate(value.tokenCoverage)
|
|
491
|
+
: 0;
|
|
492
|
+
if (tokenObservedSegmentCount == null
|
|
493
|
+
|| tokenCoverage == null
|
|
494
|
+
|| tokenObservedSegmentCount > segmentCount)
|
|
495
|
+
return null;
|
|
496
|
+
const usage = {
|
|
497
|
+
...normalized,
|
|
498
|
+
durationMs,
|
|
499
|
+
tokenObservedSegmentCount,
|
|
500
|
+
tokenCoverage,
|
|
501
|
+
};
|
|
502
|
+
const expectedTotal = usage.inputTokens
|
|
503
|
+
+ usage.outputTokens
|
|
504
|
+
+ usage.cacheReadTokens
|
|
505
|
+
+ usage.cacheCreationTokens;
|
|
506
|
+
const tokenDivisor = usage.tokenObservedSegmentCount || 1;
|
|
507
|
+
const durationDivisor = segmentCount || 1;
|
|
508
|
+
if (!Number.isSafeInteger(expectedTotal)
|
|
509
|
+
|| usage.totalTokens !== expectedTotal
|
|
510
|
+
|| (hasTokenCoverage
|
|
511
|
+
&& usage.avgTokensPerSegment !== Math.round(expectedTotal / tokenDivisor))
|
|
512
|
+
|| usage.avgDurationMsPerSegment !== Math.round(usage.durationMs / durationDivisor)
|
|
513
|
+
|| (hasTokenCoverage
|
|
514
|
+
&& !approximatelyEqual(usage.tokenCoverage, segmentCount > 0 ? usage.tokenObservedSegmentCount / segmentCount : 1)))
|
|
515
|
+
return null;
|
|
516
|
+
return usage;
|
|
517
|
+
}
|
|
518
|
+
function reportAggregatesAreConsistent(meta, overall, bySkill) {
|
|
519
|
+
const skills = Object.values(bySkill);
|
|
520
|
+
const segmentCount = safeCountSum(skills.map((health) => health.segmentCount));
|
|
521
|
+
const toolCallCount = safeCountSum(skills.map((health) => health.toolCallCount));
|
|
522
|
+
const toolResolvedCount = safeCountSum(skills.map((health) => health.toolResolvedCount ?? health.toolCallCount));
|
|
523
|
+
const toolCancelledCount = safeCountSum(skills.map((health) => health.toolCancelledCount ?? 0));
|
|
524
|
+
const toolUnknownCount = safeCountSum(skills.map((health) => health.toolUnknownCount ?? 0));
|
|
525
|
+
const toolFailureCount = safeCountSum(skills.map((health) => health.toolFailureCount));
|
|
526
|
+
const gapSampleCount = safeCountSum(skills.map((health) => health.gap.sampleCount));
|
|
527
|
+
const samplesWithGap = safeCountSum(skills.map((health) => health.gap.samplesWithGap));
|
|
528
|
+
const weightedGapTotal = safeFiniteSum(skills.map((health) => health.gap.weightedGapRate * health.gap.sampleCount));
|
|
529
|
+
if (segmentCount === undefined
|
|
530
|
+
|| toolCallCount === undefined
|
|
531
|
+
|| toolResolvedCount === undefined
|
|
532
|
+
|| toolCancelledCount === undefined
|
|
533
|
+
|| toolUnknownCount === undefined
|
|
534
|
+
|| toolFailureCount === undefined
|
|
535
|
+
|| gapSampleCount === undefined
|
|
536
|
+
|| samplesWithGap === undefined
|
|
537
|
+
|| weightedGapTotal === undefined)
|
|
538
|
+
return false;
|
|
539
|
+
const comparable = toolResolvedCount - toolCancelledCount;
|
|
540
|
+
const expectedFailureRate = comparable > 0
|
|
541
|
+
? Number((toolFailureCount / comparable).toFixed(4))
|
|
542
|
+
: 0;
|
|
543
|
+
const expectedGapRate = segmentCount > 0
|
|
544
|
+
? Number((samplesWithGap / segmentCount).toFixed(4))
|
|
545
|
+
: 0;
|
|
546
|
+
const expectedWeightedGapRate = segmentCount > 0
|
|
547
|
+
? Number((weightedGapTotal / segmentCount).toFixed(4))
|
|
548
|
+
: 0;
|
|
549
|
+
return segmentCount === meta.segmentCount
|
|
550
|
+
&& gapSampleCount === meta.segmentCount
|
|
551
|
+
&& toolCallCount === meta.toolCallCount
|
|
552
|
+
&& toolResolvedCount === meta.toolResolvedCount
|
|
553
|
+
&& toolCancelledCount === meta.toolCancelledCount
|
|
554
|
+
&& toolUnknownCount === meta.toolUnknownCount
|
|
555
|
+
&& approximatelyEqual(meta.toolFailureRate, expectedFailureRate)
|
|
556
|
+
&& approximatelyEqual(overall.gapRate, expectedGapRate)
|
|
557
|
+
&& approximatelyEqual(overall.weightedGapRate, expectedWeightedGapRate);
|
|
558
|
+
}
|
|
559
|
+
function safeCountSum(values) {
|
|
560
|
+
try {
|
|
561
|
+
return sumRecordCounts(...values);
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
return undefined;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
function safeFiniteSum(values) {
|
|
568
|
+
let total = 0;
|
|
569
|
+
for (const value of values) {
|
|
570
|
+
if (!Number.isFinite(value) || value < 0)
|
|
571
|
+
return undefined;
|
|
572
|
+
total += value;
|
|
573
|
+
if (!Number.isFinite(total) || total > Number.MAX_SAFE_INTEGER)
|
|
574
|
+
return undefined;
|
|
575
|
+
}
|
|
576
|
+
return total;
|
|
577
|
+
}
|
|
578
|
+
function sameStringSet(left, right) {
|
|
579
|
+
return left.length === right.length
|
|
580
|
+
&& left.every((entry) => right.includes(entry))
|
|
581
|
+
&& right.every((entry) => left.includes(entry));
|
|
582
|
+
}
|
|
583
|
+
function emptyUsage() {
|
|
584
|
+
return {
|
|
585
|
+
inputTokens: 0,
|
|
586
|
+
outputTokens: 0,
|
|
587
|
+
cacheReadTokens: 0,
|
|
588
|
+
cacheCreationTokens: 0,
|
|
589
|
+
totalTokens: 0,
|
|
590
|
+
tokenObservedSegmentCount: 0,
|
|
591
|
+
tokenCoverage: 0,
|
|
592
|
+
durationMs: 0,
|
|
593
|
+
numTurns: 0,
|
|
594
|
+
avgTokensPerSegment: 0,
|
|
595
|
+
avgDurationMsPerSegment: 0,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function timestamp(value) {
|
|
599
|
+
return normalizeRfc3339Timestamp(value);
|
|
600
|
+
}
|
|
601
|
+
function nonNegativeInteger(value) {
|
|
602
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
603
|
+
}
|
|
604
|
+
function nonNegativeNumber(value) {
|
|
605
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
606
|
+
}
|
|
607
|
+
function rate(value) {
|
|
608
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1
|
|
609
|
+
? value
|
|
610
|
+
: undefined;
|
|
611
|
+
}
|
|
612
|
+
function approximatelyEqual(left, right) {
|
|
613
|
+
return Math.abs(left - right) <= 0.0001;
|
|
614
|
+
}
|
|
615
|
+
function stringEnum(value, values) {
|
|
616
|
+
return typeof value === 'string' && values.has(value) ? value : undefined;
|
|
617
|
+
}
|
|
618
|
+
function isRecord(value) {
|
|
619
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
620
|
+
}
|
|
@@ -6,4 +6,3 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
export const PROMPTS_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'prompts');
|
|
7
7
|
export const SOFT_STANDARD_PROMPT_ID = 'llm-enhanced-review';
|
|
8
8
|
export const SOFT_STANDARD_PROMPT_VERSION = '2026-05-22.v7';
|
|
9
|
-
export const DEFAULT_LLM_ENHANCED_REVIEW_MODEL = 'sonnet';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PROMPTS_DIR, SOFT_STANDARD_PROMPT_ID, SOFT_STANDARD_PROMPT_VERSION, } from './constants.js';
|
|
2
2
|
export type { ExtractSkillSoftStandardsOptions, LlmEnhancedChecklistStatus, LlmEnhancedSkillType, LlmEnhancedUserFeeling, LlmEnhancedVerdict, ResolveSkillStandardsOptions, ResolvedSkillStandard, ResolvedSkillStandardKind, ResolvedSkillStandardSource, ResolvedSkillStandards, RuntimeMatchedSignal, RuntimeNodeResult, RuntimeNodeVerdict, RuntimeSignal, RuntimeSignalOp, RuntimeSignalRef, RuntimeSignalType, RuntimeStandardNode, RuntimeStandardNodeKind, RuntimeStandardNodeSourceHint, RuntimeTrigger, RuntimeTriggerWindowScope, SkillDerivedStandard, SkillDerivedStandardKind, SkillDerivedStandardStatus, SkillDerivedStandards, SkillLlmEnhancedReviewSections, SkillLlmEnhancedRuntimeEvidence, SkillLlmRuntimeNodeAssessment, SkillLlmTypeSpecificChecklistItem, } from './types.js';
|
|
3
3
|
export { loadSkillDerivedStandards, resolveSkillStandards, skillDerivedStandardsDir, skillDerivedStandardsPath, updateSkillDerivedStandardStatus, } from './skill-standards-store.js';
|
|
4
4
|
export { extractSkillSoftStandards } from './llm-extractor.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PROMPTS_DIR, SOFT_STANDARD_PROMPT_ID, SOFT_STANDARD_PROMPT_VERSION, } from './constants.js';
|
|
2
2
|
export { loadSkillDerivedStandards, resolveSkillStandards, skillDerivedStandardsDir, skillDerivedStandardsPath, updateSkillDerivedStandardStatus, } from './skill-standards-store.js';
|
|
3
3
|
export { extractSkillSoftStandards } from './llm-extractor.js';
|
|
4
4
|
import { normalizeRuntimeSignals, normalizeRuntimeTriggers, normalizeSignalOpForType, } from './llm-extractor.js';
|