bare-agent 0.10.0 → 0.10.1
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/index.js +4 -1
- package/package.json +4 -2
- package/src/bareguard-adapter.js +26 -3
- package/src/loop.js +8 -0
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.
|
|
3
|
+
"version": "0.10.1",
|
|
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"
|
package/src/bareguard-adapter.js
CHANGED
|
@@ -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(
|
|
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 =
|
|
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
|
-
|
|
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;
|