jev-layer 0.1.0 → 0.3.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 (88) hide show
  1. package/CHANGELOG.md +73 -34
  2. package/CONTRIBUTING.md +146 -146
  3. package/LICENSE +21 -21
  4. package/README.md +125 -126
  5. package/README.ru.md +140 -117
  6. package/README.zh-CN.md +139 -117
  7. package/RELEASE.md +53 -53
  8. package/SECURITY.md +64 -56
  9. package/bin/jev.mjs +215 -213
  10. package/config/codex.mcp.toml +8 -8
  11. package/config/generic-mcp.json +13 -13
  12. package/config/hermes.mcp.yaml +9 -9
  13. package/config/jev.example.json +23 -22
  14. package/config/omp.mcp.json +14 -14
  15. package/config/providers.env.example +13 -13
  16. package/docs/AGENT-IMPLEMENTATION.md +306 -0
  17. package/docs/COMPATIBILITY.md +24 -15
  18. package/docs/HERMES-LOCAL-AGENT-HANDOFF.ru.md +187 -0
  19. package/docs/PROVIDERS.md +109 -0
  20. package/docs/SCHEMA-VERSIONING.md +101 -94
  21. package/docs/architecture.svg +77 -0
  22. package/docs/jev-layer-banner.svg +38 -0
  23. package/examples/capabilities.json +39 -39
  24. package/examples/route-request.json +28 -28
  25. package/integrations/codex/.codex-plugin/plugin.json +19 -19
  26. package/integrations/codex/.mcp.json +11 -11
  27. package/integrations/codex/AGENTS.md +1 -1
  28. package/integrations/codex/run-mcp.mjs +9 -9
  29. package/integrations/codex/skills/jev-route/SKILL.md +17 -17
  30. package/integrations/hermes/__init__.py +156 -51
  31. package/integrations/hermes/plugin.yaml +11 -5
  32. package/integrations/hermes/schemas.py +120 -12
  33. package/integrations/omp/extension.js +106 -105
  34. package/integrations/template/README.md +10 -10
  35. package/integrations/template/adapter.mjs +87 -87
  36. package/package.json +60 -59
  37. package/scripts/benchmark.mjs +35 -35
  38. package/scripts/browser-benchmark.mjs +92 -92
  39. package/scripts/browser-e2e.mjs +117 -117
  40. package/scripts/capability-e2e.mjs +31 -31
  41. package/scripts/clean-install-smoke.mjs +176 -162
  42. package/scripts/codex-mcp-smoke.mjs +119 -119
  43. package/scripts/context-filter-e2e.mjs +45 -45
  44. package/scripts/fail-open-smoke.mjs +120 -120
  45. package/scripts/feature-flags-smoke.mjs +46 -46
  46. package/scripts/mcp-receipt-smoke.mjs +115 -98
  47. package/scripts/model-route-report.mjs +15 -0
  48. package/scripts/openrouter-choice.mjs +59 -59
  49. package/scripts/replay-eval.mjs +124 -124
  50. package/scripts/smoke.mjs +34 -34
  51. package/scripts/supervision-e2e.mjs +138 -109
  52. package/src/browser.mjs +583 -569
  53. package/src/cli.mjs +33 -33
  54. package/src/computer.mjs +196 -0
  55. package/src/config.mjs +86 -75
  56. package/src/context-filter.mjs +56 -56
  57. package/src/contract.mjs +74 -72
  58. package/src/discovery.mjs +65 -65
  59. package/src/hermes-adapter.mjs +134 -0
  60. package/src/images.mjs +98 -0
  61. package/src/mcp-server.mjs +313 -210
  62. package/src/model-route-metrics.mjs +89 -0
  63. package/src/model-routing.mjs +87 -0
  64. package/src/providers/demo.mjs +52 -52
  65. package/src/providers/index.mjs +12 -0
  66. package/src/providers/typesafe.mjs +206 -126
  67. package/src/receipts.mjs +228 -226
  68. package/src/registry.mjs +109 -109
  69. package/src/relevance-filter.mjs +99 -99
  70. package/src/route.mjs +228 -221
  71. package/src/shadow-compaction.mjs +170 -0
  72. package/src/supervision.mjs +268 -244
  73. package/test/browser.test.mjs +222 -199
  74. package/test/capability.test.mjs +54 -54
  75. package/test/computer.test.mjs +195 -0
  76. package/test/context-filter.test.mjs +65 -65
  77. package/test/hermes-adapter.test.mjs +63 -0
  78. package/test/image-fixture.mjs +2 -0
  79. package/test/images.test.mjs +85 -0
  80. package/test/model-route-metrics.test.mjs +61 -0
  81. package/test/model-routing.test.mjs +59 -0
  82. package/test/openrouter-provider.test.mjs +55 -55
  83. package/test/provider-transports.test.mjs +205 -0
  84. package/test/providers.test.mjs +125 -0
  85. package/test/receipts.test.mjs +71 -71
  86. package/test/route.test.mjs +86 -74
  87. package/test/shadow-compaction.test.mjs +67 -0
  88. package/test/supervision.test.mjs +117 -99
@@ -1,109 +1,138 @@
1
- import assert from "node:assert/strict";
2
- import { mkdtemp, readFile } from "node:fs/promises";
3
- import { spawn } from "node:child_process";
4
- import { createInterface } from "node:readline";
5
- import { fileURLToPath } from "node:url";
6
- import { dirname, join, resolve } from "node:path";
7
- import { tmpdir } from "node:os";
8
- import { deterministicSupervisionPolicy } from "../src/supervision.mjs";
9
-
10
- const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
11
- const casesPath = join(await mkdtemp(join(tmpdir(), "jev-supervision-e2e-")), "cases.jsonl");
12
- const child = spawn(process.env.JEV_NODE ?? "node", [resolve(root, "src/mcp-server.mjs")], {
13
- cwd: root,
14
- env: { ...process.env, JEV_REPLAY_CASES: casesPath },
15
- stdio: ["pipe", "pipe", "pipe"],
16
- });
17
- const lines = createInterface({ input: child.stdout });
18
- const pending = new Map();
19
- lines.on("line", (line) => {
20
- if (!line.trim()) return;
21
- const message = JSON.parse(line);
22
- const waiter = pending.get(message.id);
23
- if (waiter) {
24
- pending.delete(message.id);
25
- waiter(message);
26
- }
27
- });
28
-
29
- try {
30
- const initialized = await request(1, "initialize", {});
31
- assert.equal(initialized.result.serverInfo.name, "jev-layer");
32
- await notification("notifications/initialized", {});
33
- const listed = await request(2, "tools/list", {});
34
- assert.ok(listed.result.tools.some((tool) => tool.name === "jev_supervise"));
35
-
36
- const disabled = await request(3, "tools/call", {
37
- name: "jev_supervise",
38
- arguments: { enabled: false, provider: "demo", job: {}, observation: {} },
39
- });
40
- assert.equal(disabled.result.structuredContent.fallback.type, "disabled");
41
-
42
- const judged = await request(4, "tools/call", {
43
- name: "jev_supervise",
44
- arguments: {
45
- enabled: true,
46
- provider: process.env.JEV_SUPERVISION_PROVIDER ?? "demo",
47
- harness: "supervision-e2e",
48
- job: { requirements: ["run tests", "inspect receipts"] },
49
- observation: { status: "ready", progress: "complete" },
50
- evidence: {
51
- tests_passed: true,
52
- judgments: {
53
- requirements_addressed: 0.9,
54
- verification_needed: 0.1,
55
- meaningful_progress: 0.9,
56
- worker_stuck: 0.05,
57
- work_off_track: 0.05,
58
- completion: 0.9,
59
- },
60
- },
61
- },
62
- });
63
- const result = judged.result.structuredContent;
64
- assert.equal(result.status, "judged");
65
- assert.equal(result.action, "finish");
66
- assert.equal(result.metrics.jev_calls, 1);
67
- assert.ok(result.receipt.correlation_id);
68
-
69
- const records = (await readFile(casesPath, "utf8")).trim().split(/\r?\n/).map(JSON.parse);
70
- assert.deepEqual(records.map((record) => record.record_type), ["supervision_case"]);
71
- assert.equal(records[0].supervision.action, "finish");
72
- const replayed = deterministicSupervisionPolicy({
73
- assessment: records[0].supervision.assessment,
74
- evidence: records[0].request.context.evidence,
75
- });
76
- assert.equal(replayed.action, records[0].supervision.action);
77
- console.log(JSON.stringify({
78
- ok: true,
79
- cases_path: casesPath,
80
- action: result.action,
81
- status: result.status,
82
- dimensions: Object.keys(result.assessment).length,
83
- latency_ms: result.receipt.latency_ms,
84
- cost_usd: result.receipt.cost_usd,
85
- receipts: records.length,
86
- }, null, 2));
87
- } finally {
88
- child.kill();
89
- await new Promise((resolveExit) => child.once("close", resolveExit));
90
- }
91
-
92
- function request(id, method, params) {
93
- return new Promise((resolveResponse, reject) => {
94
- const timer = setTimeout(() => {
95
- pending.delete(id);
96
- reject(new Error(`MCP request timed out: ${method}`));
97
- }, 15_000);
98
- pending.set(id, (message) => {
99
- clearTimeout(timer);
100
- resolveResponse(message);
101
- });
102
- child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`);
103
- });
104
- }
105
-
106
- function notification(method, params) {
107
- child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}\n`);
108
- return new Promise((resolveNotification) => setImmediate(resolveNotification));
109
- }
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, readFile } from "node:fs/promises";
3
+ import { spawn } from "node:child_process";
4
+ import { createInterface } from "node:readline";
5
+ import { fileURLToPath } from "node:url";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { tmpdir } from "node:os";
8
+ import { deterministicSupervisionPolicy } from "../src/supervision.mjs";
9
+
10
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
11
+ const casesPath = join(await mkdtemp(join(tmpdir(), "jev-supervision-e2e-")), "cases.jsonl");
12
+ const child = spawn(process.env.JEV_NODE ?? "node", [resolve(root, "src/mcp-server.mjs")], {
13
+ cwd: root,
14
+ env: { ...process.env, JEV_REPLAY_CASES: casesPath },
15
+ stdio: ["pipe", "pipe", "pipe"],
16
+ });
17
+ const lines = createInterface({ input: child.stdout });
18
+ const pending = new Map();
19
+ lines.on("line", (line) => {
20
+ if (!line.trim()) return;
21
+ const message = JSON.parse(line);
22
+ const waiter = pending.get(message.id);
23
+ if (waiter) {
24
+ pending.delete(message.id);
25
+ waiter(message);
26
+ }
27
+ });
28
+
29
+ try {
30
+ const initialized = await request(1, "initialize", {});
31
+ assert.equal(initialized.result.serverInfo.name, "jev-layer");
32
+ await notification("notifications/initialized", {});
33
+ const listed = await request(2, "tools/list", {});
34
+ assert.ok(listed.result.tools.some((tool) => tool.name === "jev_supervise"));
35
+
36
+ const disabled = await request(3, "tools/call", {
37
+ name: "jev_supervise",
38
+ arguments: { enabled: false, provider: "demo", job: {}, observation: {} },
39
+ });
40
+ assert.equal(disabled.result.structuredContent.fallback.type, "disabled");
41
+
42
+ const judged = await request(4, "tools/call", {
43
+ name: "jev_supervise",
44
+ arguments: {
45
+ enabled: true,
46
+ provider: process.env.JEV_SUPERVISION_PROVIDER ?? "demo",
47
+ harness: "supervision-e2e",
48
+ job: { requirements: ["run tests", "inspect receipts"] },
49
+ observation: { status: "ready", progress: "complete" },
50
+ evidence: {
51
+ tests_passed: true,
52
+ judgments: {
53
+ requirements_addressed: 0.9,
54
+ verification_needed: 0.1,
55
+ meaningful_progress: 0.9,
56
+ worker_stuck: 0.05,
57
+ work_off_track: 0.05,
58
+ completion: 0.9,
59
+ },
60
+ },
61
+ },
62
+ });
63
+ const result = judged.result.structuredContent;
64
+ assert.equal(result.status, "judged");
65
+ assert.equal(result.action, "finish");
66
+ assert.equal(result.metrics.jev_calls, 1);
67
+ assert.ok(result.receipt.correlation_id);
68
+
69
+ const contradictory = await request(5, "tools/call", {
70
+ name: "jev_supervise",
71
+ arguments: {
72
+ enabled: true,
73
+ provider: process.env.JEV_SUPERVISION_PROVIDER ?? "demo",
74
+ harness: "supervision-e2e",
75
+ job: { requirements: ["run tests"] },
76
+ observation: { status: "claimed-complete" },
77
+ evidence: {
78
+ tests_passed: true,
79
+ tests_failed: true,
80
+ judgments: {
81
+ requirements_addressed: 0.9,
82
+ verification_needed: 0.1,
83
+ meaningful_progress: 0.9,
84
+ worker_stuck: 0.05,
85
+ work_off_track: 0.05,
86
+ completion: 0.9,
87
+ },
88
+ },
89
+ },
90
+ });
91
+ const contradictoryResult = contradictory.result.structuredContent;
92
+ assert.equal(contradictoryResult.status, "judged");
93
+ assert.equal(contradictoryResult.action, "verify");
94
+ assert.equal(contradictoryResult.evidence_state.state, "contradictory");
95
+
96
+ const records = (await readFile(casesPath, "utf8")).trim().split(/\r?\n/).map(JSON.parse);
97
+ assert.deepEqual(records.map((record) => record.record_type), ["supervision_case", "supervision_case"]);
98
+ assert.equal(records[0].supervision.action, "finish");
99
+ assert.equal(records[1].supervision.action, "verify");
100
+ assert.equal(records[1].supervision.evidence_state.state, "contradictory");
101
+ const replayed = deterministicSupervisionPolicy({
102
+ assessment: records[0].supervision.assessment,
103
+ evidence: records[0].request.context.evidence,
104
+ });
105
+ assert.equal(replayed.action, records[0].supervision.action);
106
+ console.log(JSON.stringify({
107
+ ok: true,
108
+ cases_path: casesPath,
109
+ action: result.action,
110
+ status: result.status,
111
+ dimensions: Object.keys(result.assessment).length,
112
+ latency_ms: result.receipt.latency_ms,
113
+ cost_usd: result.receipt.cost_usd,
114
+ receipts: records.length,
115
+ }, null, 2));
116
+ } finally {
117
+ child.kill();
118
+ await new Promise((resolveExit) => child.once("close", resolveExit));
119
+ }
120
+
121
+ function request(id, method, params) {
122
+ return new Promise((resolveResponse, reject) => {
123
+ const timer = setTimeout(() => {
124
+ pending.delete(id);
125
+ reject(new Error(`MCP request timed out: ${method}`));
126
+ }, 15_000);
127
+ pending.set(id, (message) => {
128
+ clearTimeout(timer);
129
+ resolveResponse(message);
130
+ });
131
+ child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`);
132
+ });
133
+ }
134
+
135
+ function notification(method, params) {
136
+ child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}\n`);
137
+ return new Promise((resolveNotification) => setImmediate(resolveNotification));
138
+ }