bare-agent 0.4.2 → 0.4.3
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 +4 -4
- package/package.json +2 -2
- package/src/loop.js +36 -5
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
**Agent orchestration in ~
|
|
14
|
+
**Agent orchestration in ~1800 lines. Zero required deps. MIT license.**
|
|
15
15
|
|
|
16
16
|
Lightweight enough to understand completely. Complete enough to not reinvent wheels. Not a framework, not 50,000 lines of opinions — just composable building blocks for agents.
|
|
17
17
|
|
|
@@ -60,7 +60,7 @@ Every piece works alone — take what you need, ignore the rest.
|
|
|
60
60
|
|
|
61
61
|
| Component | What it does |
|
|
62
62
|
|---|---|
|
|
63
|
-
| **Loop** | Think → act → observe → repeat. Calls any LLM, executes your tools, loops until done. Throws on error by default |
|
|
63
|
+
| **Loop** | Think → act → observe → repeat. Calls any LLM, executes your tools, loops until done. Throws on error by default. Returns estimated USD cost per run |
|
|
64
64
|
| **Planner** | Break a goal into a step DAG via LLM. Built-in caching (`cacheTTL`) |
|
|
65
65
|
| **runPlan** | Execute steps in parallel waves. Dependency-aware, failure propagation, per-step retry |
|
|
66
66
|
| **Retry** | Exponential/linear backoff with jitter. Respects `err.retryable` |
|
|
@@ -72,7 +72,7 @@ Every piece works alone — take what you need, ignore the rest.
|
|
|
72
72
|
| **Scheduler** | Cron (`0 9 * * 1-5`) or relative (`2h`, `30m`). Persisted jobs survive restarts |
|
|
73
73
|
| **Stream** | Structured event emitter. Pipe as JSONL, subscribe in-process, or custom transport |
|
|
74
74
|
| **Errors** | Typed hierarchy — `ProviderError`, `ToolError`, `TimeoutError`, `MaxRoundsError`, `CircuitOpenError` |
|
|
75
|
-
| **Browsing** | Web navigation, clicking, typing, reading via `barebrowse
|
|
75
|
+
| **Browsing** | Web navigation, clicking, typing, reading via `barebrowse` (17 tools). Two modes: library tools (inline snapshots, pass to Loop) or CLI session (disk-based snapshots, token-efficient for multi-step flows). Optional `assess` tool (privacy scan) when `wearehere` is installed |
|
|
76
76
|
| **Mobile** | Android + iOS device control via `baremobile`. Same two modes: library tools (`createMobileTools` — action tools auto-return snapshots) or CLI session (`baremobile` CLI — disk-based snapshots) |
|
|
77
77
|
|
|
78
78
|
**Providers:** OpenAI-compatible (OpenAI, OpenRouter, Groq, vLLM, LM Studio), Anthropic, Ollama, CLIPipe (any CLI tool via stdin/stdout with real-time streaming), Fallback, or bring your own (one method: `generate`). All return the same shape — swap freely.
|
|
@@ -81,7 +81,7 @@ Every piece works alone — take what you need, ignore the rest.
|
|
|
81
81
|
|
|
82
82
|
**Cross-language:** Runs as a subprocess. Communicate via JSONL on stdin/stdout from Python, Go, Rust, Ruby, Java, or anything that can spawn a process. Ready-made wrappers in [`contrib/`](contrib/README.md).
|
|
83
83
|
|
|
84
|
-
**Deps:** 0 required. Optional: `cron-parser` (cron expressions), `better-sqlite3` (SQLite store), `barebrowse` (web browsing), `baremobile` (Android + iOS device control).
|
|
84
|
+
**Deps:** 0 required. Optional: `cron-parser` (cron expressions), `better-sqlite3` (SQLite store), `barebrowse` (web browsing), `baremobile` (Android + iOS device control), `wearehere` (privacy assessment via barebrowse).
|
|
85
85
|
|
|
86
86
|
---
|
|
87
87
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-agent",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"files": [
|
|
5
5
|
"index.js",
|
|
6
6
|
"src/",
|
|
7
7
|
"bin/",
|
|
8
8
|
"tools/"
|
|
9
9
|
],
|
|
10
|
-
"description": "Lightweight, composable agent orchestration. ~
|
|
10
|
+
"description": "Lightweight, composable agent orchestration. ~1800 lines, 0 required deps.",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"author": "hamr0",
|
|
13
13
|
"repository": {
|
package/src/loop.js
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
const { ToolError, MaxRoundsError } = require('./errors');
|
|
4
4
|
|
|
5
|
+
// Average pricing per 1K tokens (USD). Adjust these to match your provider's rates.
|
|
6
|
+
// Last updated: 2026-03-18. Source: public provider pricing pages.
|
|
7
|
+
const COST_PER_1K = {
|
|
8
|
+
// OpenAI
|
|
9
|
+
'gpt-4o': { in: 0.0025, out: 0.01 },
|
|
10
|
+
'gpt-4o-mini': { in: 0.00015, out: 0.0006 },
|
|
11
|
+
'gpt-4.1': { in: 0.002, out: 0.008 },
|
|
12
|
+
'gpt-4.1-mini': { in: 0.0004, out: 0.0016 },
|
|
13
|
+
'gpt-4.1-nano': { in: 0.0001, out: 0.0004 },
|
|
14
|
+
'o3-mini': { in: 0.0011, out: 0.0044 },
|
|
15
|
+
// Anthropic
|
|
16
|
+
'claude-sonnet-4-20250514': { in: 0.003, out: 0.015 },
|
|
17
|
+
'claude-haiku-4-5-20251001': { in: 0.0008, out: 0.004 },
|
|
18
|
+
'claude-opus-4-20250514': { in: 0.015, out: 0.075 },
|
|
19
|
+
// Fallback average across popular models (~$0.002 in, ~$0.008 out per 1K)
|
|
20
|
+
'_default': { in: 0.002, out: 0.008 },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function estimateCost(model, usage) {
|
|
24
|
+
if (!usage || !model) return null;
|
|
25
|
+
const rates = COST_PER_1K[model] || COST_PER_1K['_default'];
|
|
26
|
+
return (
|
|
27
|
+
((usage.inputTokens || 0) * rates.in +
|
|
28
|
+
(usage.outputTokens || 0) * rates.out) / 1000
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
5
32
|
class Loop {
|
|
6
33
|
/**
|
|
7
34
|
* @param {object} options
|
|
@@ -68,6 +95,7 @@ class Loop {
|
|
|
68
95
|
this.stream?.emit({ type: 'loop:start', data: { messageCount: msgs.length } });
|
|
69
96
|
|
|
70
97
|
let lastUsage = { inputTokens: 0, outputTokens: 0 };
|
|
98
|
+
let totalCost = 0;
|
|
71
99
|
|
|
72
100
|
for (let round = 0; round < this.maxRounds; round++) {
|
|
73
101
|
if (this._stopped) break;
|
|
@@ -80,17 +108,20 @@ class Loop {
|
|
|
80
108
|
this.stream?.emit({ type: 'loop:error', data: { error: err.message, round } });
|
|
81
109
|
this.onError?.(err);
|
|
82
110
|
if (this.throwOnError) throw err;
|
|
83
|
-
return { text: '', toolCalls: [], usage: lastUsage, error: err.message };
|
|
111
|
+
return { text: '', toolCalls: [], usage: lastUsage, cost: totalCost, error: err.message };
|
|
84
112
|
}
|
|
85
113
|
|
|
86
114
|
lastUsage = result.usage || lastUsage;
|
|
115
|
+
const model = this.provider.model || null;
|
|
116
|
+
const roundCost = estimateCost(model, lastUsage);
|
|
117
|
+
if (roundCost !== null) totalCost += roundCost;
|
|
87
118
|
|
|
88
119
|
// No tool calls — LLM gave a final text response
|
|
89
120
|
if (!result.toolCalls || result.toolCalls.length === 0) {
|
|
90
121
|
this.stream?.emit({ type: 'loop:text', data: { text: result.text } });
|
|
91
122
|
this.onText?.(result.text);
|
|
92
|
-
this.stream?.emit({ type: 'loop:done', data: { text: result.text, usage: lastUsage } });
|
|
93
|
-
return { text: result.text, toolCalls: [], usage: lastUsage, error: null };
|
|
123
|
+
this.stream?.emit({ type: 'loop:done', data: { text: result.text, usage: lastUsage, cost: totalCost } });
|
|
124
|
+
return { text: result.text, toolCalls: [], usage: lastUsage, cost: totalCost, error: null };
|
|
94
125
|
}
|
|
95
126
|
|
|
96
127
|
// Execute tool calls
|
|
@@ -149,9 +180,9 @@ class Loop {
|
|
|
149
180
|
|
|
150
181
|
// maxRounds exceeded
|
|
151
182
|
const warning = `[Loop] ended after ${this.maxRounds} rounds without final response`;
|
|
152
|
-
this.stream?.emit({ type: 'loop:done', data: { text: '', warning } });
|
|
183
|
+
this.stream?.emit({ type: 'loop:done', data: { text: '', warning, cost: totalCost } });
|
|
153
184
|
if (this.throwOnError) throw new MaxRoundsError(warning);
|
|
154
|
-
return { text: '', toolCalls: [], usage: lastUsage, error: warning };
|
|
185
|
+
return { text: '', toolCalls: [], usage: lastUsage, cost: totalCost, error: warning };
|
|
155
186
|
}
|
|
156
187
|
|
|
157
188
|
/**
|