@iris-eval/mcp-server 0.6.0 → 0.8.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 (38) hide show
  1. package/README.md +7 -3
  2. package/dist/config/defaults.js +17 -1
  3. package/dist/config/index.js +8 -0
  4. package/dist/dashboard/assets/{index-CshLgDRB.js → index-DTA8DzF_.js} +1 -1
  5. package/dist/dashboard/index.html +1 -1
  6. package/dist/dashboard/routes/rules.d.ts +8 -11
  7. package/dist/dashboard/routes/rules.js +9 -16
  8. package/dist/dashboard/routes/traces.js +14 -2
  9. package/dist/dashboard/validation.d.ts +4 -4
  10. package/dist/dashboard/validation.js +6 -2
  11. package/dist/eval/criticality.d.ts +67 -0
  12. package/dist/eval/criticality.js +154 -0
  13. package/dist/eval/engine.d.ts +33 -2
  14. package/dist/eval/engine.js +64 -8
  15. package/dist/eval/rules/cost.d.ts +9 -0
  16. package/dist/eval/rules/cost.js +97 -1
  17. package/dist/eval/rules/relevance.d.ts +13 -0
  18. package/dist/eval/rules/relevance.js +185 -21
  19. package/dist/eval/rules/safety.d.ts +13 -1
  20. package/dist/eval/rules/safety.js +273 -21
  21. package/dist/eval/rules/trajectory.d.ts +91 -0
  22. package/dist/eval/rules/trajectory.js +297 -0
  23. package/dist/index.js +1 -1
  24. package/dist/self-test.js +1 -1
  25. package/dist/server.js +1 -1
  26. package/dist/tools/evaluate-output.js +38 -23
  27. package/dist/tools/index.js +1 -1
  28. package/dist/tools/list-rules.d.ts +2 -1
  29. package/dist/tools/list-rules.js +22 -4
  30. package/dist/tools/log-trace.d.ts +8 -1
  31. package/dist/tools/log-trace.js +19 -4
  32. package/dist/tools/strict-input.js +2 -2
  33. package/dist/tools/trace-link.d.ts +10 -0
  34. package/dist/tools/trace-link.js +13 -1
  35. package/dist/types/config.d.ts +14 -0
  36. package/dist/types/eval.d.ts +39 -7
  37. package/package.json +8 -1
  38. package/server.json +2 -2
@@ -1,7 +1,17 @@
1
1
  import type { IStorageAdapter } from '../types/query.js';
2
2
  import type { EvalResult } from '../types/eval.js';
3
+ import type { Trace } from '../types/trace.js';
3
4
  import type { TenantId } from '../types/tenant.js';
4
5
  export declare function unknownTraceMessage(traceId: string): string;
6
+ /**
7
+ * The same refuse-before-any-work check, returning the row it already read.
8
+ *
9
+ * evaluate_output needs the trace itself (its `tool_calls`, so a caller who
10
+ * has already logged the trajectory does not have to resend it), and the
11
+ * existence check had to load the row anyway. Fetching it twice would be
12
+ * two reads for one fact — and two chances for them to disagree.
13
+ */
14
+ export declare function getTraceOrThrow(storage: IStorageAdapter, tenantId: TenantId, traceId: string): Promise<Trace>;
5
15
  export declare function assertTraceExists(storage: IStorageAdapter, tenantId: TenantId, traceId: string): Promise<void>;
6
16
  /** insertEvalResult with the foreign-key race translated into the same clear message. */
7
17
  export declare function insertLinkedEvalResult(storage: IStorageAdapter, tenantId: TenantId, result: EvalResult): Promise<void>;
@@ -18,10 +18,22 @@ export function unknownTraceMessage(traceId) {
18
18
  'Nothing was evaluated or written. Pass the trace_id returned by log_trace (or listed by get_traces), ' +
19
19
  'or omit trace_id to store an unlinked evaluation.');
20
20
  }
21
- export async function assertTraceExists(storage, tenantId, traceId) {
21
+ /**
22
+ * The same refuse-before-any-work check, returning the row it already read.
23
+ *
24
+ * evaluate_output needs the trace itself (its `tool_calls`, so a caller who
25
+ * has already logged the trajectory does not have to resend it), and the
26
+ * existence check had to load the row anyway. Fetching it twice would be
27
+ * two reads for one fact — and two chances for them to disagree.
28
+ */
29
+ export async function getTraceOrThrow(storage, tenantId, traceId) {
22
30
  const trace = await storage.getTrace(tenantId, traceId);
23
31
  if (!trace)
24
32
  throw new Error(unknownTraceMessage(traceId));
33
+ return trace;
34
+ }
35
+ export async function assertTraceExists(storage, tenantId, traceId) {
36
+ await getTraceOrThrow(storage, tenantId, traceId);
25
37
  }
26
38
  /** insertEvalResult with the foreign-key race translated into the same clear message. */
27
39
  export async function insertLinkedEvalResult(storage, tenantId, result) {
@@ -32,7 +32,21 @@ export interface IrisConfig {
32
32
  topic_consistency?: number;
33
33
  cost_threshold?: number;
34
34
  max_token_ratio?: number;
35
+ max_tool_repeats?: number;
35
36
  };
37
+ /**
38
+ * Built-in rule names promoted to CRITICAL — a failure vetoes `passed`
39
+ * regardless of the weighted score. Validated against the rule registry
40
+ * when the config loads; an unknown name is a startup error naming the
41
+ * valid list, never a silent no-op.
42
+ */
43
+ criticalRules?: string[];
44
+ /**
45
+ * Built-in rule names demoted from critical — they still score and still
46
+ * report a failure, but they stop vetoing `passed`. Same validation. A
47
+ * name in both lists is a config error: it does not say what you want.
48
+ */
49
+ nonCriticalRules?: string[];
36
50
  };
37
51
  logging: {
38
52
  level: 'debug' | 'info' | 'warn' | 'error';
@@ -1,3 +1,4 @@
1
+ import type { ToolCallRecord } from './trace.js';
1
2
  export type EvalType = 'completeness' | 'relevance' | 'safety' | 'cost' | 'custom';
2
3
  /**
3
4
  * What an EvalResult can be tagged as: a single bundle (EvalType), or
@@ -30,11 +31,19 @@ export interface EvalContext {
30
31
  output: string;
31
32
  expected?: string;
32
33
  input?: string;
33
- toolCalls?: Array<{
34
- tool_name: string;
35
- input?: unknown;
36
- output?: unknown;
37
- }>;
34
+ /**
35
+ * The agent's trajectory — what it actually DID, in call order.
36
+ *
37
+ * Deliberately the SAME record the capture path stores (ToolCallRecord =
38
+ * log_trace's `tool_calls[]`), not a narrower local shape. It used to be
39
+ * a three-field inline type without `error`, so a rule could see that a
40
+ * tool was called but never that it FAILED: the acceptance pass found
41
+ * three real transcripts that answered confidently after a grep exited 1,
42
+ * an ls hit a missing directory and a node -e threw, and no rule could
43
+ * reach the fact. Re-declaring a subset here would reintroduce exactly
44
+ * that gap the next time a field is added to the capture shape.
45
+ */
46
+ toolCalls?: ToolCallRecord[];
38
47
  tokenUsage?: {
39
48
  prompt_tokens?: number;
40
49
  completion_tokens?: number;
@@ -71,6 +80,22 @@ export interface EvalRuleResult {
71
80
  * regroup them.
72
81
  */
73
82
  category?: EvalType;
83
+ /**
84
+ * Whether this rule VETOES the verdict — its EFFECTIVE criticality, after
85
+ * `eval.criticalRules` / `eval.nonCriticalRules` are applied, not the
86
+ * value on the rule's definition. A reader holding a failed evaluation
87
+ * could otherwise not tell a hard violation from a low score without
88
+ * knowing the rule library by heart.
89
+ */
90
+ critical?: boolean;
91
+ /**
92
+ * Who decided that: 'default' is the rule's own declaration (for a
93
+ * deployed custom rule, the severity it was deployed with); 'config' means
94
+ * one of the two override lists named it. The distinction is the point of
95
+ * making criticality configurable — an operator reading a verdict must be
96
+ * able to see that their own promotion caused it.
97
+ */
98
+ criticalSource?: 'default' | 'config';
74
99
  passed: boolean;
75
100
  score: number;
76
101
  message: string;
@@ -83,10 +108,17 @@ export interface EvalRuleResult {
83
108
  * Per-bundle verdict inside an eval_type="all" result. Same semantics as a
84
109
  * single-bundle EvalResult (threshold + critical veto), computed over that
85
110
  * bundle's rules only.
111
+ *
112
+ * `score` and `passed` are null when the bundle evaluated no rule (every
113
+ * rule skipped for missing context — cost without cost_usd, relevance
114
+ * without input). Such a bundle was not judged: it is neither passing nor
115
+ * failing, `insufficient_data` is true, and it never counted toward the
116
+ * overall verdict (#406). The top-level EvalResult keeps a boolean
117
+ * `passed` on purpose — a gate keyed on it must fail closed.
86
118
  */
87
119
  export interface EvalCategoryResult {
88
- score: number;
89
- passed: boolean;
120
+ score: number | null;
121
+ passed: boolean | null;
90
122
  rules_evaluated: number;
91
123
  rules_skipped: number;
92
124
  insufficient_data: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iris-eval/mcp-server",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Stop shipping agents on vibes. Score every agent output for quality, safety, and cost.",
5
5
  "mcpName": "io.github.iris-eval/mcp-server",
6
6
  "type": "module",
@@ -28,8 +28,15 @@
28
28
  "version:sync": "node scripts/sync-versions.mjs",
29
29
  "claims:capture-tests": "node scripts/claims/capture-tests.mjs",
30
30
  "claims:generate": "node scripts/claims/generate.mjs",
31
+ "claims:generate:live": "node scripts/claims/generate.mjs --live",
31
32
  "claims:check": "node scripts/claims/generate.mjs --check",
32
33
  "claims:check-hardcoded": "node scripts/claims/check-no-hardcoded.mjs",
34
+ "proof": "tsx proof/run.ts",
35
+ "proof:typecheck": "tsc -p proof/tsconfig.json",
36
+ "llms:render": "node scripts/claims/render-llms.mjs",
37
+ "llms:check": "node scripts/claims/render-llms.mjs --check",
38
+ "proof:judge": "tsx proof/judge/run.ts",
39
+ "proof:judge:typecheck": "tsc -p proof/judge/tsconfig.json",
33
40
  "clean": "rm -rf dist coverage",
34
41
  "seed:demo": "tsx scripts/seed-demo-data.ts",
35
42
  "demo": "tsx scripts/demo.ts"
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/iris-eval/mcp-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.6.0",
9
+ "version": "0.8.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@iris-eval/mcp-server",
14
- "version": "0.6.0",
14
+ "version": "0.8.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },