bare-agent 0.10.0 → 0.10.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/README.md CHANGED
@@ -101,17 +101,24 @@ Every piece works alone — take what you need, ignore the rest.
101
101
 
102
102
  ```js
103
103
  const { Gate } = require('bareguard');
104
- const { Loop } = require('bare-agent');
105
- const { wireGate } = require('bare-agent/bareguard');
104
+ const { Loop, wireGate, defaultActionTranslator } = require('bare-agent');
106
105
 
107
106
  const gate = new Gate({
108
107
  budget: { maxCostUsd: 0.50 },
109
- limits: { maxTurns: 20 },
108
+ limits: { maxToolRounds: 20 }, // bareguard 0.4.2+ — N tool rounds, LLM rounds bypass
110
109
  audit: { path: './audit.jsonl' },
111
110
  });
112
111
  await gate.init();
113
112
 
114
- const { policy, onLlmResult, onToolResult, filterTools } = wireGate(gate);
113
+ const { policy, onLlmResult, onToolResult, filterTools } = wireGate(gate, {
114
+ // Optional: translate tool names → bareguard primitive types for bash/fs/net rules.
115
+ // bareguard 0.4.1+ reads args.command / args.path verbatim, so args passes through.
116
+ actionTranslator: (toolName, args, ctx) => {
117
+ if (toolName === 'shell_exec') return { type: 'bash', args, _ctx: ctx };
118
+ if (toolName === 'shell_read') return { type: 'read', args, _ctx: ctx };
119
+ return defaultActionTranslator(toolName, args, ctx);
120
+ },
121
+ });
115
122
  const tools = await filterTools(myTools); // drop tools denied by static policy
116
123
 
117
124
  const loop = new Loop({ provider, policy, onLlmResult, onToolResult });
package/index.js CHANGED
@@ -10,7 +10,7 @@ const { Stream } = require('./src/stream');
10
10
  const { Retry } = require('./src/retry');
11
11
  const { runPlan } = require('./src/run-plan');
12
12
  const { CircuitBreaker } = require('./src/circuit-breaker');
13
- const { wireGate } = require('./src/bareguard-adapter');
13
+ const { wireGate, defaultActionTranslator } = require('./src/bareguard-adapter');
14
14
  const {
15
15
  BareAgentError,
16
16
  ProviderError,
@@ -18,6 +18,7 @@ const {
18
18
  TimeoutError,
19
19
  ValidationError,
20
20
  CircuitOpenError,
21
+ HaltError,
21
22
  } = require('./src/errors');
22
23
 
23
24
  module.exports = {
@@ -32,10 +33,12 @@ module.exports = {
32
33
  runPlan,
33
34
  CircuitBreaker,
34
35
  wireGate,
36
+ defaultActionTranslator,
35
37
  BareAgentError,
36
38
  ProviderError,
37
39
  ToolError,
38
40
  TimeoutError,
39
41
  ValidationError,
40
42
  CircuitOpenError,
43
+ HaltError,
41
44
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-agent",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "files": [
5
5
  "index.js",
6
6
  "src/",
@@ -22,12 +22,14 @@
22
22
  },
23
23
  "exports": {
24
24
  ".": "./index.js",
25
+ "./errors": "./src/errors.js",
25
26
  "./providers": "./src/providers.js",
26
27
  "./stores": "./src/stores.js",
27
28
  "./transports": "./src/transports.js",
28
29
  "./tools": "./src/tools.js",
29
30
  "./mcp": "./src/mcp.js",
30
- "./bareguard": "./src/bareguard-adapter.js"
31
+ "./bareguard": "./src/bareguard-adapter.js",
32
+ "./package.json": "./package.json"
31
33
  },
32
34
  "engines": {
33
35
  "node": ">=18"
@@ -44,7 +46,7 @@
44
46
  "governance"
45
47
  ],
46
48
  "dependencies": {
47
- "bareguard": "^0.2.0"
49
+ "bareguard": "^0.4.2"
48
50
  },
49
51
  "optionalDependencies": {
50
52
  "barebrowse": "^0.5.0",
@@ -28,6 +28,14 @@ const { HaltError } = require('./errors');
28
28
  * @param {Function} [options.formatDeny] - (decision) => string. Transforms the deny
29
29
  * string fed to the LLM. Default: "[deny: <rule>] <reason>". Halt bypasses this
30
30
  * (HaltError doesn't reach the LLM).
31
+ * @param {Function} [options.actionTranslator] - (toolName, args, ctx) => action.
32
+ * Builds the action object passed to `gate.check` and `gate.record`. Default:
33
+ * `{ type: toolName, args, _ctx: ctx }`. Override when bareguard's primitives
34
+ * need a specific shape — e.g. `bashCheck` requires `{type:'bash', cmd:...}`,
35
+ * `fsCheck` requires `{type:'read'|'write'|'edit', path:...}`. The default shape
36
+ * matches `tools.denylist` / `tools.allowlist` (which read `action.type`) but
37
+ * does NOT activate `bash`/`fs`/`net` primitives — those need their own
38
+ * `action.type` value. Adopters using those primitives must translate.
31
39
  * @returns {{policy: Function, onLlmResult: Function, onToolResult: Function, filterTools: Function, wrapTool: Function, wrapTools: Function}}
32
40
  *
33
41
  * @example
@@ -54,10 +62,14 @@ function wireGate(gate, options = {}) {
54
62
  if (options.formatDeny != null && typeof options.formatDeny !== 'function') {
55
63
  throw new Error('[wireGate] options.formatDeny must be a function (decision) => string');
56
64
  }
65
+ if (options.actionTranslator != null && typeof options.actionTranslator !== 'function') {
66
+ throw new Error('[wireGate] options.actionTranslator must be a function (toolName, args, ctx) => action');
67
+ }
57
68
  const formatDeny = options.formatDeny || defaultFormatDeny;
69
+ const translate = options.actionTranslator || defaultActionTranslator;
58
70
 
59
71
  const policy = async (toolName, args, ctx) => {
60
- const decision = await gate.check({ type: toolName, args, _ctx: ctx });
72
+ const decision = await gate.check(translate(toolName, args, ctx));
61
73
  if (decision.outcome === 'allow') return true;
62
74
  if (decision.severity === 'halt') {
63
75
  throw new HaltError(decision.reason || `${toolName} halted by ${decision.rule}`, {
@@ -69,6 +81,8 @@ function wireGate(gate, options = {}) {
69
81
  };
70
82
 
71
83
  const onLlmResult = async ({ model, provider, usage, costUsd, durationMs, ctx }) => {
84
+ // LLM rounds bypass actionTranslator — they always use the canonical
85
+ // {type:'llm'} action so budget rules can match without translator collusion.
72
86
  await gate.record(
73
87
  { type: 'llm', args: { model: model || null, provider: provider || null }, _ctx: ctx ?? null },
74
88
  {
@@ -80,7 +94,7 @@ function wireGate(gate, options = {}) {
80
94
  };
81
95
 
82
96
  const onToolResult = async ({ name, args, result, error, durationMs, ctx }) => {
83
- const action = { type: name, args, _ctx: ctx ?? null };
97
+ const action = translate(name, args, ctx);
84
98
  if (error) {
85
99
  await gate.record(action, {
86
100
  error: error?.message || String(error),
@@ -159,4 +173,13 @@ function defaultFormatDeny(decision, toolName) {
159
173
  return decision.reason ? `${tag} ${decision.reason}` : `${tag} ${toolName} denied`;
160
174
  }
161
175
 
162
- module.exports = { wireGate };
176
+ // Canonical action shape: tool name as type, args nested, ctx tagged. Matches
177
+ // bareguard's `tools.denylist`/`tools.allowlist` (which read `action.type`) but
178
+ // does NOT activate `bash`/`fs`/`net` primitives — those require `action.type`
179
+ // to be `bash`/`read`/`write`/etc. and read fields like `action.cmd` /
180
+ // `action.path` at the top level. Override via `wireGate(gate, { actionTranslator })`.
181
+ function defaultActionTranslator(toolName, args, ctx) {
182
+ return { type: toolName, args, _ctx: ctx ?? null };
183
+ }
184
+
185
+ module.exports = { wireGate, defaultActionTranslator };
package/src/loop.js CHANGED
@@ -50,6 +50,14 @@ class Loop {
50
50
  */
51
51
  constructor(options = {}) {
52
52
  if (!options.provider) throw new Error('[Loop] requires a provider');
53
+ if (options.maxRounds !== undefined) {
54
+ throw new Error(
55
+ '[Loop] options.maxRounds was removed in v0.8 when single-gate governance landed. ' +
56
+ 'Bound iteration via bareguard `new Gate({ limits: { maxTurns: N } })` and wire it with ' +
57
+ '`new Loop({ policy: wireGate(gate).policy })`. Loop\'s internal HARD_ROUND_LIMIT (100) is ' +
58
+ 'a safety net only and not configurable.',
59
+ );
60
+ }
53
61
  this.provider = options.provider;
54
62
  this.system = options.system || null;
55
63
  this.checkpoint = options.checkpoint || null;