@verax-ai/body 0.1.0 → 0.1.2

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/wiring.js CHANGED
@@ -2,11 +2,11 @@ import { createProxy, FileLedger, loadPolicy, tenantKey, } from "@verax-ai/proxy
2
2
  import { readFileSync } from "node:fs";
3
3
  import { persistPolicySnapshot } from "./policy-store.js";
4
4
  import { inputsPrincipal } from "./inputs-read.js";
5
- import { memoryBelongsToOtherTenant, memoryGet, memoryPut, readMemoryMeta } from "./tools/memory.js";
5
+ import { memoryBelongsToOtherTenant, memoryExistsForTenant, memoryGet, memoryPut, readMemoryMeta, } from "./tools/memory.js";
6
6
  import { auditExplain } from "./tools/audit.js";
7
7
  import { messageRead, messageSend } from "./tools/message.js";
8
8
  import { spendAuthorize } from "./tools/spend.js";
9
- import { requestWitnessSign } from "./witness.js";
9
+ import { requestWitnessCheckpoint, requestWitnessSign } from "./witness.js";
10
10
  export const TOOL_NAMES = [
11
11
  "memory.get",
12
12
  "memory.put",
@@ -17,11 +17,32 @@ export const TOOL_NAMES = [
17
17
  ];
18
18
  /**
19
19
  * Tool functions live in a Map that is not exported. The only way to
20
- * reach them at runtime is `proxy.call` -> `inner`.
20
+ * reach them at runtime is `proxy.call` -> `inner`. Extra tools (a
21
+ * downstream prefix) enter that Map at construction; they still pass
22
+ * the gate.
21
23
  */
22
24
  export function createBodyServices(opts) {
25
+ const extraNames = [];
26
+ const reserved = new Set(TOOL_NAMES);
27
+ for (const tool of opts.extraTools ?? []) {
28
+ if (reserved.has(tool.name) || extraNames.includes(tool.name)) {
29
+ throw new Error(`downstream-name-collision:${tool.name}`);
30
+ }
31
+ // Same shape as extraToolNameOk in downstream.ts (prefix.childName).
32
+ if (!/^[A-Za-z][A-Za-z0-9_-]{0,31}\.[A-Za-z][A-Za-z0-9._-]{0,63}$/.test(tool.name)) {
33
+ throw new Error(`downstream-name-invalid:${tool.name}`);
34
+ }
35
+ extraNames.push(tool.name);
36
+ }
23
37
  const ledger = new FileLedger(opts.stateDir);
24
38
  ledger.remoteWitness = (row, resultHash) => requestWitnessSign(opts.stateDir, row, resultHash);
39
+ ledger.onPieceClose = async (window) => {
40
+ await requestWitnessCheckpoint(opts.stateDir, {
41
+ epoch: 0,
42
+ startMs: window.startMs,
43
+ endMs: window.endMs,
44
+ });
45
+ };
25
46
  const policyText = readFileSync(opts.policyFile, "utf8");
26
47
  const policyDocument = JSON.parse(policyText);
27
48
  const policy = loadPolicy(policyText);
@@ -49,6 +70,9 @@ export function createBodyServices(opts) {
49
70
  registry.set("message.read", (call, principal) => messageRead(call, opts.stateDir, principal));
50
71
  registry.set("message.send", (call, principal, ref) => messageSend(call, opts.stateDir, ref ?? "", principal));
51
72
  registry.set("spend", (call, _principal, ref) => spendAuthorize(call, ref ?? ""));
73
+ for (const tool of opts.extraTools ?? []) {
74
+ registry.set(tool.name, tool.fn);
75
+ }
52
76
  const inner = async (call, principal, ref) => {
53
77
  const fn = registry.get(call.name);
54
78
  if (!fn) {
@@ -73,6 +97,8 @@ export function createBodyServices(opts) {
73
97
  const id = call.arguments.id;
74
98
  if (typeof id !== "string")
75
99
  return false;
100
+ if (memoryExistsForTenant(opts.stateDir, id, principal))
101
+ return false;
76
102
  return memoryBelongsToOtherTenant(opts.stateDir, id, tenantKey(principal));
77
103
  }
78
104
  if (call.name === "audit.explain") {
@@ -93,9 +119,10 @@ export function createBodyServices(opts) {
93
119
  return {
94
120
  proxy,
95
121
  ledger,
122
+ policy,
96
123
  policyHash: policy.hash,
97
124
  policyDocument,
98
- listTools: () => TOOL_NAMES,
125
+ listTools: () => (extraNames.length === 0 ? TOOL_NAMES : [...TOOL_NAMES, ...extraNames]),
99
126
  explainOpts,
100
127
  };
101
128
  }
package/dist/witness.js CHANGED
@@ -5,7 +5,7 @@ import { join } from "node:path";
5
5
  import { writeFileAtomic } from "./atomic-write.js";
6
6
  import { buildCheckpointClaims, checkpointHash, signCheckpoint, totalsFromDecisionRecords, } from "@cedulon/checkpoint";
7
7
  import { decisionRecordHash } from "@cedulon/core";
8
- import { checkpointsPath, signEffectAttestation } from "@verax-ai/proxy";
8
+ import { checkpointsPath, listPieceFiles, signEffectAttestation } from "@verax-ai/proxy";
9
9
  import { pidAlive } from "./unlock.js";
10
10
  const WITNESS_CLASS = "same-org";
11
11
  function listenPath(stateDir) {
@@ -104,21 +104,23 @@ function send(res, status, body) {
104
104
  res.end(text);
105
105
  }
106
106
  function loadDecisions(stateDir) {
107
- try {
108
- const text = readFileSync(join(stateDir, "decisions.jsonl"), "utf8");
109
- const out = [];
110
- for (const line of text.split("\n")) {
111
- if (line === "")
107
+ const out = [];
108
+ for (const piece of listPieceFiles(stateDir)) {
109
+ try {
110
+ const text = readFileSync(piece.decisions, "utf8");
111
+ for (const line of text.split("\n")) {
112
+ if (line === "")
113
+ continue;
114
+ out.push(JSON.parse(line));
115
+ }
116
+ }
117
+ catch (err) {
118
+ if (err.code === "ENOENT")
112
119
  continue;
113
- out.push(JSON.parse(line));
120
+ throw err;
114
121
  }
115
- return out;
116
- }
117
- catch (err) {
118
- if (err.code === "ENOENT")
119
- return [];
120
- throw err;
121
122
  }
123
+ return out;
122
124
  }
123
125
  function lastCheckpointHash(stateDir) {
124
126
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verax-ai/body",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "engines": {
@@ -27,6 +27,17 @@
27
27
  "jose": "^6.2.11"
28
28
  },
29
29
  "description": "VERAX body: an MCP server that decides, records and proves what an agent did.",
30
+ "homepage": "https://verax-ai.com",
31
+ "keywords": [
32
+ "verax",
33
+ "mcp",
34
+ "mcp-server",
35
+ "agent",
36
+ "policy",
37
+ "audit",
38
+ "ledger",
39
+ "approval"
40
+ ],
30
41
  "mcpName": "io.github.verax-ai/verax",
31
42
  "scripts": {
32
43
  "build": "tsc -p tsconfig.build.json",