@hmharness/evaluation 0.8.3 → 0.8.4

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/dist/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export * from './evaluators.ts';
3
3
  export * from './runner.ts';
4
4
  export * from './harmonybench.ts';
5
5
  export * from './score.ts';
6
+ export * from './sdk.ts';
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export * from "./evaluators.js";
3
3
  export * from "./runner.js";
4
4
  export * from "./harmonybench.js";
5
5
  export * from "./score.js";
6
+ export * from "./sdk.js";
package/dist/sdk.d.ts ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @hmharness/evaluation - Evaluator SDK (P1-02)
3
+ *
4
+ * The audit called for: "统一 evaluator plugin、evidence references、metric registry"
5
+ *
6
+ * This module provides the plugin interface that ALL evaluators implement,
7
+ * evidence references that link scores to concrete proof, and a metric
8
+ * registry for named, versioned scoring functions.
9
+ */
10
+ /** Evidence tier per the existing evidence ladder (M2) */
11
+ export type EvidenceTier = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
12
+ /** Reference to concrete evidence backing an evaluation */
13
+ export interface EvidenceRef {
14
+ /** what kind of evidence */
15
+ kind: 'build-log' | 'test-result' | 'command-output' | 'file-content' | 'judge-score' | 'device-log' | 'metric';
16
+ /** where to find it (path, URL, or inline) */
17
+ source: string;
18
+ /** relevant excerpt (for audit trail) */
19
+ excerpt?: string;
20
+ /** evidence tier (1=build, 7=llm-judge, 8=self-report) */
21
+ tier: EvidenceTier;
22
+ }
23
+ /** The result of running an evaluator */
24
+ export interface SdkEvaluationResult {
25
+ /** evaluator that produced this result */
26
+ evaluatorId: string;
27
+ /** pass/fail/indeterminate */
28
+ outcome: 'pass' | 'fail' | 'indeterminate';
29
+ /** numeric score [0,1] if applicable */
30
+ score?: number;
31
+ /** human-readable detail */
32
+ detail: string;
33
+ /** evidence backing this result */
34
+ evidence: EvidenceRef[];
35
+ /** when this evaluation ran */
36
+ evaluatedAt: string;
37
+ /** duration in ms */
38
+ durationMs: number;
39
+ }
40
+ /** The evaluator plugin interface - ALL evaluators implement this */
41
+ export interface SdkEvaluator {
42
+ /** unique evaluator id */
43
+ readonly id: string;
44
+ /** what this evaluator checks */
45
+ readonly description: string;
46
+ /** evidence tier this evaluator operates at */
47
+ readonly tier: EvidenceTier;
48
+ /** evaluate and return a result */
49
+ evaluate(input: unknown): Promise<SdkEvaluationResult>;
50
+ }
51
+ /** A named metric in the registry */
52
+ export interface MetricDef {
53
+ name: string;
54
+ description: string;
55
+ /** units (e.g. 'percent', 'count', 'ms') */
56
+ unit: string;
57
+ /** higher is better? (for display) */
58
+ higherIsBetter: boolean;
59
+ /** compute from evaluation results */
60
+ compute: (results: SdkEvaluationResult[]) => number;
61
+ }
62
+ /**
63
+ * The metric registry - named, versioned scoring functions.
64
+ * Metrics are registered once and referenced by name everywhere.
65
+ */
66
+ export declare class MetricRegistry {
67
+ private metrics;
68
+ register(def: MetricDef): {
69
+ ok: boolean;
70
+ reason?: string;
71
+ };
72
+ get(name: string): MetricDef | undefined;
73
+ list(): MetricDef[];
74
+ /** Compute a metric from evaluation results */
75
+ compute(name: string, results: SdkEvaluationResult[]): number | undefined;
76
+ }
77
+ /** Create a standard metric registry with common metrics pre-registered */
78
+ export declare function createDefaultRegistry(): MetricRegistry;
79
+ /**
80
+ * Create a simple pass/fail evaluator from a predicate function.
81
+ * Convenience factory for the most common evaluator pattern.
82
+ */
83
+ export declare function createPredicateEvaluator(id: string, description: string, tier: EvidenceTier, predicate: (input: unknown) => boolean, evidenceKind?: EvidenceRef['kind']): SdkEvaluator;
package/dist/sdk.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @hmharness/evaluation - Evaluator SDK (P1-02)
3
+ *
4
+ * The audit called for: "统一 evaluator plugin、evidence references、metric registry"
5
+ *
6
+ * This module provides the plugin interface that ALL evaluators implement,
7
+ * evidence references that link scores to concrete proof, and a metric
8
+ * registry for named, versioned scoring functions.
9
+ */
10
+ /**
11
+ * The metric registry - named, versioned scoring functions.
12
+ * Metrics are registered once and referenced by name everywhere.
13
+ */
14
+ export class MetricRegistry {
15
+ metrics = new Map();
16
+ register(def) {
17
+ if (this.metrics.has(def.name)) {
18
+ return { ok: false, reason: `metric ${def.name} already registered` };
19
+ }
20
+ this.metrics.set(def.name, def);
21
+ return { ok: true };
22
+ }
23
+ get(name) {
24
+ return this.metrics.get(name);
25
+ }
26
+ list() {
27
+ return [...this.metrics.values()];
28
+ }
29
+ /** Compute a metric from evaluation results */
30
+ compute(name, results) {
31
+ const m = this.metrics.get(name);
32
+ if (!m)
33
+ return undefined;
34
+ return m.compute(results);
35
+ }
36
+ }
37
+ /** Create a standard metric registry with common metrics pre-registered */
38
+ export function createDefaultRegistry() {
39
+ const reg = new MetricRegistry();
40
+ reg.register({
41
+ name: 'pass_rate', description: 'fraction of evaluations that passed',
42
+ unit: 'fraction', higherIsBetter: true,
43
+ compute: (rs) => rs.length > 0 ? rs.filter(r => r.outcome === 'pass').length / rs.length : 0,
44
+ });
45
+ reg.register({
46
+ name: 'avg_score', description: 'average numeric score',
47
+ unit: 'fraction', higherIsBetter: true,
48
+ compute: (rs) => {
49
+ const scored = rs.filter(r => r.score !== undefined);
50
+ return scored.length > 0 ? scored.reduce((a, b) => a + (b.score ?? 0), 0) / scored.length : 0;
51
+ },
52
+ });
53
+ reg.register({
54
+ name: 'avg_duration', description: 'average evaluation duration',
55
+ unit: 'ms', higherIsBetter: false,
56
+ compute: (rs) => rs.length > 0 ? rs.reduce((a, b) => a + b.durationMs, 0) / rs.length : 0,
57
+ });
58
+ reg.register({
59
+ name: 'evidence_coverage', description: 'fraction of results with evidence',
60
+ unit: 'fraction', higherIsBetter: true,
61
+ compute: (rs) => rs.length > 0 ? rs.filter(r => r.evidence.length > 0).length / rs.length : 0,
62
+ });
63
+ return reg;
64
+ }
65
+ /**
66
+ * Create a simple pass/fail evaluator from a predicate function.
67
+ * Convenience factory for the most common evaluator pattern.
68
+ */
69
+ export function createPredicateEvaluator(id, description, tier, predicate, evidenceKind = 'command-output') {
70
+ return {
71
+ id, description, tier,
72
+ async evaluate(input) {
73
+ const start = Date.now();
74
+ const pass = predicate(input);
75
+ return {
76
+ evaluatorId: id,
77
+ outcome: pass ? 'pass' : 'fail',
78
+ detail: pass ? 'predicate satisfied' : 'predicate not satisfied',
79
+ evidence: [{ kind: evidenceKind, source: 'inline', tier, excerpt: String(input).slice(0, 200) }],
80
+ evaluatedAt: new Date().toISOString(),
81
+ durationMs: Date.now() - start,
82
+ };
83
+ },
84
+ };
85
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hmharness/evaluation",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "hmharness evaluation: the Evaluator/Judge contract (V2 blueprint M2). Hard evidence outranks LLM judgment - build results, exit codes, exact/regex assertions first; the LLM judge is a last resort and is labeled as such. Evaluations attach to trajectories (judge.completed events).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",