bare-agent 0.12.0 → 0.12.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 +1 -0
- package/bareagent.context.md +1149 -0
- package/examples/README.md +14 -0
- package/examples/mcp-bridge-concurrent.js +106 -0
- package/examples/mcp-bridge-poc.js +77 -0
- package/examples/orchestrator/README.md +53 -0
- package/examples/orchestrator/orchestrator.json +14 -0
- package/examples/orchestrator/specialists/researcher.json +12 -0
- package/examples/orchestrator/specialists/summarizer.json +11 -0
- package/examples/replay-job.js +213 -0
- package/examples/wake.md +99 -0
- package/examples/wake.sh +84 -0
- package/examples/with-bareguard.mjs +65 -0
- package/package.json +4 -1
- package/src/providers.d.ts +1 -1
- package/src/providers.js +8 -0
package/examples/wake.sh
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# examples/wake.sh — reference scheduler for bareagent's defer queue.
|
|
3
|
+
#
|
|
4
|
+
# This is a *reference*, not a primitive. Copy into your project and modify.
|
|
5
|
+
# See examples/wake.md for the cron entry and customization points.
|
|
6
|
+
#
|
|
7
|
+
# What this script does:
|
|
8
|
+
# 1. Reads the JSONL defer queue file.
|
|
9
|
+
# 2. Folds status-update lines per id (latest wins) using jq.
|
|
10
|
+
# 3. For each pending record whose `when` <= now: appends a "fired" status
|
|
11
|
+
# line to the queue (atomic JSONL append), then invokes
|
|
12
|
+
# `bareagent --config <orchestrator>` with the inner action as stdin.
|
|
13
|
+
# 4. Uses flock(1) to prevent overlapping wake invocations.
|
|
14
|
+
#
|
|
15
|
+
# The fired action goes through bareguard's gate AGAIN at fire time — full
|
|
16
|
+
# pipeline against the inner action, separate from the emit-time check.
|
|
17
|
+
# (Two gate.check calls, two distinct audit lines, reconstructable via
|
|
18
|
+
# parent_run_id.)
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
QUEUE="${BAREAGENT_DEFER_QUEUE:-./bareagent-defers.jsonl}"
|
|
23
|
+
ORCHESTRATOR_CONFIG="${ORCHESTRATOR_CONFIG:-./orchestrator.json}"
|
|
24
|
+
LOCKFILE="${LOCKFILE:-/tmp/bareagent-wake.lock}"
|
|
25
|
+
LOG_DIR="${BAREAGENT_WAKE_LOG_DIR:-/tmp/bareagent-wake}"
|
|
26
|
+
|
|
27
|
+
mkdir -p "$LOG_DIR"
|
|
28
|
+
|
|
29
|
+
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
30
|
+
|
|
31
|
+
# Single-instance: bail if another wake is running.
|
|
32
|
+
exec 9>"$LOCKFILE"
|
|
33
|
+
if ! flock -n 9; then
|
|
34
|
+
echo "[wake $NOW] another instance running, exiting" >&2
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# No queue file = nothing to do.
|
|
39
|
+
if [ ! -f "$QUEUE" ]; then
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Reconstruct status by folding all lines per id (latest wins) and filter
|
|
44
|
+
# to records whose `when` <= now AND status == "pending". One JSON object
|
|
45
|
+
# per output line.
|
|
46
|
+
PENDING=$(jq -n -c '
|
|
47
|
+
reduce inputs as $r ({};
|
|
48
|
+
.[$r.id] |= (. // {}) + $r
|
|
49
|
+
)
|
|
50
|
+
| to_entries
|
|
51
|
+
| map(.value)
|
|
52
|
+
| map(select(.status == "pending" and .when <= "'"$NOW"'"))
|
|
53
|
+
| .[]
|
|
54
|
+
' < "$QUEUE")
|
|
55
|
+
|
|
56
|
+
if [ -z "$PENDING" ]; then
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo "$PENDING" | while IFS= read -r record; do
|
|
61
|
+
[ -z "$record" ] && continue
|
|
62
|
+
|
|
63
|
+
ID=$(echo "$record" | jq -r '.id')
|
|
64
|
+
ACTION=$(echo "$record" | jq -c '.action')
|
|
65
|
+
|
|
66
|
+
# Append "fired" status line first (defer queue is append-only).
|
|
67
|
+
printf '{"id":"%s","status":"fired","ts":"%s"}\n' "$ID" "$NOW" >> "$QUEUE"
|
|
68
|
+
|
|
69
|
+
# Invoke bareagent with the deferred action as stdin input.
|
|
70
|
+
# Run in background — wake script doesn't wait for completion.
|
|
71
|
+
( echo "$ACTION" | bare-agent --config "$ORCHESTRATOR_CONFIG" \
|
|
72
|
+
>> "$LOG_DIR/fired-$ID.log" 2>&1
|
|
73
|
+
rc=$?
|
|
74
|
+
if [ $rc -ne 0 ]; then
|
|
75
|
+
printf '{"id":"%s","status":"failed","ts":"%s","exit_code":%d}\n' \
|
|
76
|
+
"$ID" "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$rc" >> "$QUEUE"
|
|
77
|
+
else
|
|
78
|
+
printf '{"id":"%s","status":"done","ts":"%s"}\n' \
|
|
79
|
+
"$ID" "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> "$QUEUE"
|
|
80
|
+
fi
|
|
81
|
+
) &
|
|
82
|
+
done
|
|
83
|
+
|
|
84
|
+
wait
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// examples/with-bareguard.mjs
|
|
2
|
+
//
|
|
3
|
+
// End-to-end: bareagent Loop + bareguard Gate.
|
|
4
|
+
// Runs a small LLM loop with budget cap, fs scope, audit log, and humanChannel.
|
|
5
|
+
//
|
|
6
|
+
// Run: OPENAI_API_KEY=... node examples/with-bareguard.mjs
|
|
7
|
+
//
|
|
8
|
+
// What this demonstrates:
|
|
9
|
+
// - Single-gate governance: every tool call traverses gate.check; every
|
|
10
|
+
// result reaches gate.record (via wrapTools).
|
|
11
|
+
// - Budget halt: if accumulated cost exceeds maxCostUsd, gate halts the loop.
|
|
12
|
+
// - Audit log: one JSONL line per gated event at ./bareagent-audit.jsonl.
|
|
13
|
+
// - humanChannel: required by bareguard. Here we auto-deny asks; in real use
|
|
14
|
+
// wire it to a chat platform, terminal prompt, etc.
|
|
15
|
+
|
|
16
|
+
import { Gate } from 'bareguard';
|
|
17
|
+
import { createRequire } from 'node:module';
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const { Loop, wireGate } = require('bare-agent');
|
|
20
|
+
const { OpenAI } = require('bare-agent/providers');
|
|
21
|
+
const { createShellTools } = require('bare-agent/tools');
|
|
22
|
+
|
|
23
|
+
// 1. Build the gate. Every primitive is optional with sensible defaults.
|
|
24
|
+
const gate = new Gate({
|
|
25
|
+
budget: { maxCostUsd: 0.10 }, // hard USD cap
|
|
26
|
+
limits: { maxTurns: 20 }, // safety net on think/act cycles
|
|
27
|
+
fs: { readScope: ['/tmp', '~/'] }, // shell_read / shell_grep allowed roots
|
|
28
|
+
bash: { allow: ['ls', 'cat', 'echo', 'pwd'] }, // argv[0] allowlist for shell_run
|
|
29
|
+
audit: { path: './bareagent-audit.jsonl' },
|
|
30
|
+
// Required by bareguard: any ask/halt event flows through here.
|
|
31
|
+
// Auto-deny is the safest default for headless use; in real apps, wire to
|
|
32
|
+
// a Telegram/Slack/terminal prompt and return { decision: 'allow' | 'deny' }.
|
|
33
|
+
humanChannel: async (event) => {
|
|
34
|
+
console.warn(`[humanChannel] ${event.kind}: ${event.rule} — auto-denying`);
|
|
35
|
+
return { decision: 'deny' };
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
await gate.init();
|
|
39
|
+
|
|
40
|
+
// 2. Wire the gate into Loop's policy slot and wrap tools so gate.record fires.
|
|
41
|
+
const { policy, wrapTools } = wireGate(gate);
|
|
42
|
+
|
|
43
|
+
// 3. Standard bareagent setup.
|
|
44
|
+
const provider = new OpenAI({
|
|
45
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
46
|
+
model: 'gpt-4o-mini',
|
|
47
|
+
});
|
|
48
|
+
const { tools } = createShellTools();
|
|
49
|
+
|
|
50
|
+
const loop = new Loop({
|
|
51
|
+
provider,
|
|
52
|
+
policy,
|
|
53
|
+
onError: (err, meta) => console.error(`[onError ${meta.source}]`, err.message),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// 4. Run.
|
|
57
|
+
const result = await loop.run(
|
|
58
|
+
[{ role: 'user', content: 'List the contents of /tmp using shell_run with argv ["ls", "/tmp"].' }],
|
|
59
|
+
wrapTools(tools),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
console.log('---');
|
|
63
|
+
console.log('text:', result.text);
|
|
64
|
+
console.log('cost:', result.cost?.toFixed(6) ?? 'n/a');
|
|
65
|
+
console.log('audit log → ./bareagent-audit.jsonl');
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-agent",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"files": [
|
|
5
5
|
"index.js",
|
|
6
6
|
"index.d.ts",
|
|
7
|
+
"bareagent.context.md",
|
|
7
8
|
"src/",
|
|
8
9
|
"bin/",
|
|
9
10
|
"tools/",
|
|
10
11
|
"types/",
|
|
12
|
+
"examples/",
|
|
11
13
|
"LICENSE",
|
|
12
14
|
"NOTICE"
|
|
13
15
|
],
|
|
@@ -91,6 +93,7 @@
|
|
|
91
93
|
"scripts": {
|
|
92
94
|
"test": "node --test --test-force-exit test/**/*.test.js",
|
|
93
95
|
"typecheck": "tsc --noEmit",
|
|
96
|
+
"prebuild:types": "node scripts/clean-types.js",
|
|
94
97
|
"build:types": "tsc",
|
|
95
98
|
"prepublishOnly": "npm run build:types"
|
|
96
99
|
},
|
package/src/providers.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ import { AnthropicProvider } from "./provider-anthropic";
|
|
|
3
3
|
import { OllamaProvider } from "./provider-ollama";
|
|
4
4
|
import { CLIPipeProvider } from "./provider-clipipe";
|
|
5
5
|
import { FallbackProvider } from "./provider-fallback";
|
|
6
|
-
export { OpenAIProvider as OpenAI, AnthropicProvider as Anthropic, OllamaProvider as Ollama, CLIPipeProvider as CLIPipe, FallbackProvider as Fallback };
|
|
6
|
+
export { OpenAIProvider as OpenAI, AnthropicProvider as Anthropic, OllamaProvider as Ollama, CLIPipeProvider as CLIPipe, FallbackProvider as Fallback, OpenAIProvider, AnthropicProvider, OllamaProvider, CLIPipeProvider, FallbackProvider };
|
package/src/providers.js
CHANGED
|
@@ -7,9 +7,17 @@ const { CLIPipeProvider } = require('./provider-clipipe');
|
|
|
7
7
|
const { FallbackProvider } = require('./provider-fallback');
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
10
|
+
// Short names (canonical — used throughout docs and the integration guide)
|
|
10
11
|
OpenAI: OpenAIProvider,
|
|
11
12
|
Anthropic: AnthropicProvider,
|
|
12
13
|
Ollama: OllamaProvider,
|
|
13
14
|
CLIPipe: CLIPipeProvider,
|
|
14
15
|
Fallback: FallbackProvider,
|
|
16
|
+
// *Provider aliases match the class names in source/stack traces, so
|
|
17
|
+
// `const { OpenAIProvider } = require('bare-agent/providers')` also works.
|
|
18
|
+
OpenAIProvider,
|
|
19
|
+
AnthropicProvider,
|
|
20
|
+
OllamaProvider,
|
|
21
|
+
CLIPipeProvider,
|
|
22
|
+
FallbackProvider,
|
|
15
23
|
};
|