jev-layer 0.1.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 (66) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/CONTRIBUTING.md +146 -0
  3. package/LICENSE +21 -0
  4. package/README.md +126 -0
  5. package/README.ru.md +117 -0
  6. package/README.zh-CN.md +117 -0
  7. package/RELEASE.md +53 -0
  8. package/SECURITY.md +56 -0
  9. package/bin/jev.mjs +214 -0
  10. package/config/codex.mcp.toml +8 -0
  11. package/config/generic-mcp.json +13 -0
  12. package/config/hermes.mcp.yaml +9 -0
  13. package/config/jev.example.json +22 -0
  14. package/config/omp.mcp.json +14 -0
  15. package/config/providers.env.example +13 -0
  16. package/docs/COMPATIBILITY.md +15 -0
  17. package/docs/SCHEMA-VERSIONING.md +94 -0
  18. package/examples/capabilities.json +39 -0
  19. package/examples/route-request.json +28 -0
  20. package/integrations/codex/.codex-plugin/plugin.json +19 -0
  21. package/integrations/codex/.mcp.json +11 -0
  22. package/integrations/codex/AGENTS.md +1 -0
  23. package/integrations/codex/run-mcp.mjs +9 -0
  24. package/integrations/codex/skills/jev-route/SKILL.md +17 -0
  25. package/integrations/hermes/__init__.py +51 -0
  26. package/integrations/hermes/plugin.yaml +5 -0
  27. package/integrations/hermes/schemas.py +12 -0
  28. package/integrations/omp/extension.js +105 -0
  29. package/integrations/template/README.md +10 -0
  30. package/integrations/template/adapter.mjs +87 -0
  31. package/package.json +59 -0
  32. package/scripts/benchmark.mjs +35 -0
  33. package/scripts/browser-benchmark.mjs +92 -0
  34. package/scripts/browser-e2e.mjs +117 -0
  35. package/scripts/capability-e2e.mjs +31 -0
  36. package/scripts/clean-install-smoke.mjs +162 -0
  37. package/scripts/codex-mcp-smoke.mjs +119 -0
  38. package/scripts/context-filter-e2e.mjs +45 -0
  39. package/scripts/fail-open-smoke.mjs +120 -0
  40. package/scripts/feature-flags-smoke.mjs +46 -0
  41. package/scripts/mcp-receipt-smoke.mjs +98 -0
  42. package/scripts/openrouter-choice.mjs +59 -0
  43. package/scripts/replay-eval.mjs +124 -0
  44. package/scripts/smoke.mjs +34 -0
  45. package/scripts/supervision-e2e.mjs +109 -0
  46. package/src/browser.mjs +569 -0
  47. package/src/cli.mjs +33 -0
  48. package/src/config.mjs +75 -0
  49. package/src/context-filter.mjs +56 -0
  50. package/src/contract.mjs +72 -0
  51. package/src/discovery.mjs +65 -0
  52. package/src/mcp-server.mjs +210 -0
  53. package/src/providers/demo.mjs +52 -0
  54. package/src/providers/typesafe.mjs +126 -0
  55. package/src/receipts.mjs +226 -0
  56. package/src/registry.mjs +109 -0
  57. package/src/relevance-filter.mjs +99 -0
  58. package/src/route.mjs +221 -0
  59. package/src/supervision.mjs +244 -0
  60. package/test/browser.test.mjs +199 -0
  61. package/test/capability.test.mjs +54 -0
  62. package/test/context-filter.test.mjs +65 -0
  63. package/test/openrouter-provider.test.mjs +55 -0
  64. package/test/receipts.test.mjs +71 -0
  65. package/test/route.test.mjs +74 -0
  66. package/test/supervision.test.mjs +99 -0
@@ -0,0 +1,71 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, readFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { test } from "node:test";
6
+ import { appendExecutionReceipt, appendRoutingCase, readRoutingCases } from "../src/receipts.mjs";
7
+ import { routeRequest } from "../src/route.mjs";
8
+
9
+ const request = {
10
+ harness: "receipt-test",
11
+ intent: "inspect the repository",
12
+ context: { workspace: "test" },
13
+ actor_permissions: ["read"],
14
+ capabilities: [{
15
+ id: "read_repo",
16
+ kind: "tool",
17
+ name: "Read repository",
18
+ description: "Read repository metadata without modifying files",
19
+ permissions: ["read"],
20
+ risk: "low",
21
+ }],
22
+ };
23
+
24
+ test("execution receipt carries one correlation id through host completion", async () => {
25
+ const provider = {
26
+ name: "receipt-test-provider",
27
+ async decide() {
28
+ return {
29
+ answers: {
30
+ tool: {
31
+ type: "choice",
32
+ choice: "read_repo",
33
+ probabilities: { read_repo: 1 },
34
+ confidence: 1,
35
+ },
36
+ },
37
+ usage: { cost: 0.000123 },
38
+ };
39
+ },
40
+ };
41
+ const decision = await routeRequest(request, { provider });
42
+ const path = join(await mkdtemp(join(tmpdir(), "jev-receipts-")), "cases.jsonl");
43
+ await appendRoutingCase({ path, request, decision });
44
+ const completed = await appendExecutionReceipt({
45
+ path,
46
+ request,
47
+ decision,
48
+ host: {
49
+ harness: "receipt-test",
50
+ capability_id: "read_repo",
51
+ status: "completed",
52
+ result: { bytes: 42 },
53
+ exit_status: 0,
54
+ duration_ms: 12.5,
55
+ },
56
+ });
57
+
58
+ assert.equal(decision.correlation_id, decision.receipt.correlation_id);
59
+ assert.equal(decision.receipt.cost_usd, 0.000123);
60
+ assert.equal(completed.record.correlation_id, decision.correlation_id);
61
+ assert.equal(completed.record.jev.cost_usd, 0.000123);
62
+ assert.equal(completed.record.host.exit_status, 0);
63
+ assert.equal(completed.record.host.duration_ms, 12.5);
64
+ assert.deepEqual(completed.record.host.result, { bytes: 42 });
65
+
66
+ const routingCases = await readRoutingCases(path);
67
+ assert.equal(routingCases.length, 1);
68
+ assert.equal(routingCases[0].case_id, decision.correlation_id);
69
+ const firstRecord = JSON.parse((await readFile(path, "utf8")).split(/\r?\n/)[0]);
70
+ assert.equal(firstRecord.record_type, "routing_case");
71
+ });
@@ -0,0 +1,74 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { projectState } from "../src/context-filter.mjs";
4
+ import { routeRequest } from "../src/route.mjs";
5
+
6
+ const candidates = [
7
+ { id: "search", kind: "mcp", name: "Repository search", description: "Search repository files and symbols", permissions: ["read"], risk: "low" },
8
+ { id: "write", kind: "tool", name: "File writer", description: "Modify repository files", permissions: ["write"], risk: "high" },
9
+ ];
10
+
11
+ function request(overrides = {}) {
12
+ return {
13
+ harness: "test",
14
+ intent: "Search repository files",
15
+ context: { workspace: "test", api_key: "hidden" },
16
+ actor_permissions: ["read"],
17
+ capabilities: candidates,
18
+ ...overrides,
19
+ };
20
+ }
21
+
22
+ test("routes to an eligible capability without executing it", async () => {
23
+ const decision = await routeRequest(request(), { provider: "demo" });
24
+ assert.equal(decision.status, "selected");
25
+ assert.equal(decision.selected, "search");
26
+ assert.deepEqual(decision.execution, { enabled: false, status: "not_started" });
27
+ assert.equal(decision.candidates.find((candidate) => candidate.id === "write").filtered, true);
28
+ });
29
+
30
+ test("returns no_decision when every candidate is unavailable or forbidden", async () => {
31
+ const decision = await routeRequest(request({ capabilities: [
32
+ { ...candidates[0], availability: { available: false, reason: "offline" } },
33
+ candidates[1],
34
+ ] }), { provider: "demo" });
35
+ assert.equal(decision.status, "no_decision");
36
+ assert.equal(decision.execution.enabled, false);
37
+ });
38
+
39
+ test("fails open on provider errors and malformed responses", async () => {
40
+ const providerError = await routeRequest(request(), { provider: { name: "test-error", async decide() { throw new Error("down"); } } });
41
+ assert.equal(providerError.status, "fallback");
42
+ assert.equal(providerError.fallback.type, "provider_error");
43
+
44
+ const malformed = await routeRequest(request(), { provider: { name: "test-malformed", async decide() { return { answers: { tool: { type: "score" } } }; } } });
45
+ assert.equal(malformed.status, "fallback");
46
+ assert.equal(malformed.fallback.type, "malformed_response");
47
+ });
48
+
49
+ test("falls back when confidence is below the code threshold", async () => {
50
+ const decision = await routeRequest(request({ intent: "Do something unrelated", actor_permissions: ["read", "write"] }), { provider: "demo", policy: { min_confidence: 0.99 } });
51
+ assert.equal(decision.status, "fallback");
52
+ assert.equal(decision.fallback.type, "low_confidence");
53
+ });
54
+
55
+ test("filters secrets and bounds provider state", () => {
56
+ const projection = projectState(request({ context: { api_key: "hidden", nested: { password: "hidden-too" }, note: "safe" } }), candidates, 1_000);
57
+ const serialized = JSON.stringify(projection.state);
58
+ assert.equal(serialized.includes("hidden"), false);
59
+ assert.equal(serialized.includes("safe"), true);
60
+ assert.ok(projection.context_bytes <= 1_000);
61
+ });
62
+
63
+ test("honors explicit disablement with fail-open fallback", async () => {
64
+ const previous = process.env.JEV_LAYER_ENABLED;
65
+ process.env.JEV_LAYER_ENABLED = "0";
66
+ try {
67
+ const decision = await routeRequest(request(), { provider: "demo" });
68
+ assert.equal(decision.status, "fallback");
69
+ assert.equal(decision.fallback.type, "disabled");
70
+ } finally {
71
+ if (previous === undefined) delete process.env.JEV_LAYER_ENABLED;
72
+ else process.env.JEV_LAYER_ENABLED = previous;
73
+ }
74
+ });
@@ -0,0 +1,99 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, readFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { test } from "node:test";
6
+ import {
7
+ deterministicSupervisionPolicy,
8
+ normalizeAssessment,
9
+ superviseWork,
10
+ supervisionQuestions,
11
+ } from "../src/supervision.mjs";
12
+ import { readSupervisionCases } from "../src/receipts.mjs";
13
+
14
+ function assessment(overrides = {}) {
15
+ return {
16
+ requirements_addressed: 0.8,
17
+ verification_needed: 0.1,
18
+ meaningful_progress: 0.8,
19
+ worker_stuck: 0.1,
20
+ work_off_track: 0.1,
21
+ completion: 0.8,
22
+ ...overrides,
23
+ };
24
+ }
25
+
26
+ test("supervision contract exposes bounded dimensions and parses Noul answers", () => {
27
+ assert.deepEqual(Object.keys(supervisionQuestions()), [
28
+ "requirements_addressed",
29
+ "verification_needed",
30
+ "meaningful_progress",
31
+ "worker_stuck",
32
+ "work_off_track",
33
+ "completion",
34
+ ]);
35
+ const parsed = normalizeAssessment({
36
+ answers: {
37
+ requirements_addressed: { type: "noul", probability: 0.8 },
38
+ verification_needed: { type: "noul", p_true: 0.2 },
39
+ meaningful_progress: { type: "noul", score: 0.7 },
40
+ worker_stuck: true,
41
+ work_off_track: 0.1,
42
+ completion: { type: "noul", noul: 0.9 },
43
+ },
44
+ });
45
+ assert.deepEqual(parsed, {
46
+ requirements_addressed: 0.8,
47
+ verification_needed: 0.2,
48
+ meaningful_progress: 0.7,
49
+ worker_stuck: 1,
50
+ work_off_track: 0.1,
51
+ completion: 0.9,
52
+ });
53
+ });
54
+
55
+ test("deterministic host policy owns the supervision action", () => {
56
+ assert.equal(deterministicSupervisionPolicy({ assessment: assessment({ verification_needed: 0.9 }) }).action, "verify");
57
+ assert.equal(deterministicSupervisionPolicy({ assessment: assessment({ worker_stuck: 0.9 }), attempts: 0 }).action, "retry");
58
+ assert.equal(deterministicSupervisionPolicy({ assessment: assessment({ worker_stuck: 0.9 }), attempts: 2 }).action, "escalate");
59
+ assert.equal(deterministicSupervisionPolicy({ assessment: assessment(), evidence: { tests_passed: true } }).action, "finish");
60
+ });
61
+
62
+ test("supervision is opt-in, fail-open, and records replayable judgments", async () => {
63
+ const disabled = await superviseWork({ enabled: false, provider: { async evaluate() { throw new Error("must not call"); } } });
64
+ assert.equal(disabled.status, "fallback");
65
+ assert.equal(disabled.action, "continue");
66
+ assert.equal(disabled.fallback.type, "disabled");
67
+
68
+ const directory = await mkdtemp(join(tmpdir(), "jev-supervision-test-"));
69
+ const path = join(directory, "cases.jsonl");
70
+ let calls = 0;
71
+ const result = await superviseWork({
72
+ enabled: true,
73
+ harness: "supervision-test",
74
+ job: { requirements: ["run tests"] },
75
+ observation: { status: "ready" },
76
+ evidence: { tests_passed: true },
77
+ provider: {
78
+ name: "injected-supervision",
79
+ async evaluate({ questions }) {
80
+ calls += 1;
81
+ return {
82
+ answers: Object.fromEntries(Object.keys(questions).map((key) => [key, { type: "noul", probability: assessment()[key] }])),
83
+ usage: { cost: 0.0003 },
84
+ };
85
+ },
86
+ },
87
+ receiptPath: path,
88
+ });
89
+ assert.equal(calls, 1);
90
+ assert.equal(result.status, "judged");
91
+ assert.equal(result.action, "finish");
92
+ assert.equal(result.metrics.jev_calls, 1);
93
+ assert.equal(result.metrics.cost_usd, 0.0003);
94
+ const cases = await readSupervisionCases(path);
95
+ assert.equal(cases.length, 1);
96
+ assert.equal(cases[0].record_type, "supervision_case");
97
+ assert.equal(cases[0].supervision.action, "finish");
98
+ assert.equal(JSON.parse(await readFile(path, "utf8")).record_type, "supervision_case");
99
+ });