open-agents-ai 0.184.5 → 0.184.7
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 +65 -10
- package/dist/index.js +115 -57
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,16 +26,6 @@ An autonomous multi-turn tool-calling agent that reads your code, makes changes,
|
|
|
26
26
|
|
|
27
27
|
An LLM is a high-bandwidth associative generative core — closer to a cortex-like prior than to a complete agent. Its weights contain broad latent structure, but they do not by themselves give you situated continuity, durable task state, calibrated action policies, or grounded memory management. Open Agents treats the model as one organ inside a larger organism. The framework provides the rest: sensors, effectors, memory stores, routing, gating, evaluation, and persistence.
|
|
28
28
|
|
|
29
|
-
**Empirical proof** — 65 IQ-grade reasoning tasks (LSAT Logic Games, Bayesian probability, cryptarithmetic, constraint satisfaction, formal logic):
|
|
30
|
-
|
|
31
|
-
| | With Framework (Full Organism) | Pure Reasoning (Cortex Only) |
|
|
32
|
-
|---|---|---|
|
|
33
|
-
| **4B model** | 65/65 (100%) | 15/15 (100%) |
|
|
34
|
-
| **9B model** | 50/50 (100%) | 12/15 (80%) |
|
|
35
|
-
| **30B model** | 20/20 (100%) | 11/15 (73%) |
|
|
36
|
-
|
|
37
|
-
When the framework provides externalized computation (shell), persistent state (files), and verification loops (validators) — model size becomes irrelevant. A 4B model with the full agentic framework outperforms a 30B model reasoning alone.
|
|
38
|
-
|
|
39
29
|
**What the framework provides:**
|
|
40
30
|
|
|
41
31
|
| Layer | Biological Analog | Implementation |
|
|
@@ -109,6 +99,7 @@ The agent uses tools autonomously in a loop — reading errors, fixing code, and
|
|
|
109
99
|
- **Task templates** — specialized system prompts and tool recommendations for code, document, analysis, plan tasks
|
|
110
100
|
- **Inference capability scoring** — canirun.ai-style hardware assessment at first launch: memory/compute/speed scores, per-model compatibility matrix, recommended model selection
|
|
111
101
|
- **Auto-install everything** — first-run wizard auto-installs Ollama, curl, Python3, python3-venv with platform-aware package managers (apt, dnf, yum, pacman, apk, zypper, brew)
|
|
102
|
+
- **Sponsored inference** — `/sponsor` walks through a 5-step wizard to share your GPU with the world: select endpoints, choose banner animation (8 presets + AI-generated custom), set header message/links, configure transport (cloudflared/libp2p) + rate limits, and go live. Consumers discover sponsors via `/endpoint sponsor`. Secure proxy relay with per-IP rate limiting, daily token budgets, model allowlist, and concurrent request caps. Sponsor's raw API URL is never exposed. See [Sponsored Inference](#sponsored-inference--share-your-gpu-with-the-world) below
|
|
112
103
|
- **P2P inference network** — `/expose` local models or forward any `/endpoint` (Chutes, Groq, OpenRouter, etc.) through the libp2p P2P mesh. Passthrough mode (`/expose passthrough`) relays upstream API requests; `--loadbalance` distributes rate-limited token budgets across peers. `/expose config` provides an arrow-key menu for all settings. Gateway stats show budget remaining from `x-ratelimit-*` headers. Background daemon persists across OA restarts
|
|
113
104
|
- **P2P mesh networking** — `/p2p` with secret-safe variable placeholders (`{{OA_VAR_*}}`), trust tiers (LOCAL/TEE/VERIFIED/PUBLIC), WebSocket peer mesh, and inference routing with automatic secret redaction/injection
|
|
114
105
|
- **Secret vault** — `/secrets` manages API keys and credentials with AES-256-GCM encrypted persistence; secrets are automatically redacted before sending to untrusted inference peers and re-injected on response
|
|
@@ -1446,6 +1437,70 @@ nexus(action='budget_set', auto_approve_below='0.01') # Auto-approve micropayme
|
|
|
1446
1437
|
- All outbound messages scanned for key material before sending
|
|
1447
1438
|
- Keys NEVER appear in tool output, logs, or LLM context
|
|
1448
1439
|
|
|
1440
|
+
## Sponsored Inference — Share Your GPU With the World
|
|
1441
|
+
|
|
1442
|
+
Anyone running Open Agents can become an inference sponsor — sharing their local models (or forwarded cloud endpoints) with users worldwide through a secure, branded relay.
|
|
1443
|
+
|
|
1444
|
+
### For Sponsors: `/sponsor`
|
|
1445
|
+
|
|
1446
|
+
Run `/sponsor` to walk through the 5-step onboarding wizard:
|
|
1447
|
+
|
|
1448
|
+
```
|
|
1449
|
+
Step 1 → Select endpoints (auto-discovers local Ollama models + configured /endpoints)
|
|
1450
|
+
Step 2 → Choose banner animation (8 presets: wave, pulse, matrix, sparkle, radar, circuit, fire)
|
|
1451
|
+
or generate a custom animation with your local LLM
|
|
1452
|
+
Step 3 → Set header message + clickable link (displayed to consumers during inference)
|
|
1453
|
+
Step 4 → Configure transport (cloudflared tunnel and/or libp2p P2P mesh)
|
|
1454
|
+
+ rate limits (req/min, tokens/day, max concurrent, model allowlist)
|
|
1455
|
+
Step 5 → Review and Go Live
|
|
1456
|
+
```
|
|
1457
|
+
|
|
1458
|
+
**What happens under the hood:**
|
|
1459
|
+
- A secure reverse proxy starts on localhost, forwarding to your backend
|
|
1460
|
+
- Bearer token auth gate — unauthenticated requests rejected
|
|
1461
|
+
- Per-IP sliding window rate limiting + global daily token budget
|
|
1462
|
+
- Model allowlist enforcement (block models you don't want to share)
|
|
1463
|
+
- Token usage tracked from both Ollama and OpenAI response formats
|
|
1464
|
+
- Cloudflared tunnel creates a public HTTPS URL (or libp2p for decentralized relay)
|
|
1465
|
+
- Your raw API endpoint URL is **never exposed** — consumers only see the tunnel URL
|
|
1466
|
+
- Config persists to `.oa/sponsor/config.json` — survives restarts
|
|
1467
|
+
|
|
1468
|
+
**Management:**
|
|
1469
|
+
```bash
|
|
1470
|
+
/sponsor # Dashboard (when active) or wizard (when inactive)
|
|
1471
|
+
/sponsor status # Usage metrics: requests, tokens, active connections, unique users
|
|
1472
|
+
/sponsor pause # Stop serving, keep config
|
|
1473
|
+
/sponsor remove # Retire sponsorship entirely
|
|
1474
|
+
```
|
|
1475
|
+
|
|
1476
|
+
### For Consumers: `/endpoint sponsor`
|
|
1477
|
+
|
|
1478
|
+
Users who need inference can discover and connect to sponsors:
|
|
1479
|
+
|
|
1480
|
+
```bash
|
|
1481
|
+
/endpoint sponsor # Browse available sponsored endpoints
|
|
1482
|
+
# Arrow-key select → auto-configures as active endpoint
|
|
1483
|
+
/endpoint <url> --auth <key> # Direct connection with shared credentials
|
|
1484
|
+
```
|
|
1485
|
+
|
|
1486
|
+
When using sponsored inference, the sponsor's banner animation and message appear in your header area.
|
|
1487
|
+
|
|
1488
|
+
### Architecture
|
|
1489
|
+
|
|
1490
|
+
```
|
|
1491
|
+
Consumer OA ──→ Cloudflared Tunnel ──→ Sponsor Proxy ──→ Ollama/vLLM
|
|
1492
|
+
(HTTPS) (auth + rate limit) (local)
|
|
1493
|
+
│
|
|
1494
|
+
├─ Bearer token gate
|
|
1495
|
+
├─ Per-IP sliding window (N req/min)
|
|
1496
|
+
├─ Daily token budget tracking
|
|
1497
|
+
├─ Model allowlist enforcement
|
|
1498
|
+
├─ Concurrent request cap
|
|
1499
|
+
└─ Response header sanitization
|
|
1500
|
+
```
|
|
1501
|
+
|
|
1502
|
+
The tunnel fix uses debounced restarts with exponential cooldown (10s → 20s → 40s), stopping auto-restart after 3 consecutive failures to prevent Cloudflare rate limiting. Progress indicators emit every 5 seconds during startup, and specific error messages are shown for common failure modes (ENOENT, port conflict, 429, DNS).
|
|
1503
|
+
|
|
1449
1504
|
## Dream Mode — Creative Idle Exploration
|
|
1450
1505
|
|
|
1451
1506
|
When you're not actively tasking the agent, Dream Mode lets it creatively explore your codebase and generate improvement proposals autonomously. The system models real human sleep architecture with four stages per cycle:
|
package/dist/index.js
CHANGED
|
@@ -42644,21 +42644,29 @@ async function stepBanner(config, rl, availableRows) {
|
|
|
42644
42644
|
return false;
|
|
42645
42645
|
}
|
|
42646
42646
|
async function stepHeader(config, rl, availableRows) {
|
|
42647
|
+
function msgDetail() {
|
|
42648
|
+
return config.header.message || "(none set \u2014 press Enter to edit)";
|
|
42649
|
+
}
|
|
42650
|
+
function linkDetail() {
|
|
42651
|
+
return config.header.linkUrl ? `${config.header.linkUrl} [${config.header.linkText || "link"}]` : "(none set \u2014 press Enter to edit)";
|
|
42652
|
+
}
|
|
42647
42653
|
const items = [
|
|
42648
42654
|
{ key: "hdr", label: "Header Content" },
|
|
42649
42655
|
{
|
|
42650
42656
|
key: "message_toggle",
|
|
42651
42657
|
label: `${config.header.messageEnabled ? "[x]" : "[ ]"} Header Message`,
|
|
42652
|
-
detail:
|
|
42658
|
+
detail: msgDetail()
|
|
42653
42659
|
},
|
|
42654
42660
|
{
|
|
42655
42661
|
key: "link_toggle",
|
|
42656
42662
|
label: `${config.header.linkEnabled ? "[x]" : "[ ]"} Link`,
|
|
42657
|
-
detail:
|
|
42663
|
+
detail: linkDetail()
|
|
42658
42664
|
},
|
|
42659
42665
|
{ key: "sep", label: "" },
|
|
42660
42666
|
{ key: "next", label: selectColors.green(" Next Step \u2192") }
|
|
42661
42667
|
];
|
|
42668
|
+
const msgIdx = 1;
|
|
42669
|
+
const linkIdx = 2;
|
|
42662
42670
|
const result = await tuiSelect({
|
|
42663
42671
|
items,
|
|
42664
42672
|
title: "Step 3/5 \u2014 Header Text & Links",
|
|
@@ -42679,31 +42687,52 @@ async function stepHeader(config, rl, availableRows) {
|
|
|
42679
42687
|
}
|
|
42680
42688
|
}
|
|
42681
42689
|
return false;
|
|
42690
|
+
},
|
|
42691
|
+
// Use onCustomKey + helpers.getInput() for proper inline text capture
|
|
42692
|
+
// (same pattern as TTS clone rename in voice list)
|
|
42693
|
+
customKeyHint: " e edit space toggle",
|
|
42694
|
+
onCustomKey: (item, key, helpers) => {
|
|
42695
|
+
if ((key === "e" || key === "E") && item.key === "message_toggle") {
|
|
42696
|
+
config.header.messageEnabled = true;
|
|
42697
|
+
helpers.getInput("Header message:", config.header.message).then((text) => {
|
|
42698
|
+
if (text !== null && text.trim()) {
|
|
42699
|
+
config.header.message = text.trim().slice(0, 80);
|
|
42700
|
+
helpers.updateItem(msgIdx, {
|
|
42701
|
+
label: `[x] Header Message`,
|
|
42702
|
+
detail: msgDetail()
|
|
42703
|
+
});
|
|
42704
|
+
}
|
|
42705
|
+
helpers.render();
|
|
42706
|
+
});
|
|
42707
|
+
return true;
|
|
42708
|
+
}
|
|
42709
|
+
if ((key === "e" || key === "E") && item.key === "link_toggle") {
|
|
42710
|
+
config.header.linkEnabled = true;
|
|
42711
|
+
helpers.getInput("Link URL:", config.header.linkUrl).then((url) => {
|
|
42712
|
+
if (url !== null && url.trim()) {
|
|
42713
|
+
config.header.linkUrl = url.trim();
|
|
42714
|
+
helpers.getInput("Link text:", config.header.linkText).then((text) => {
|
|
42715
|
+
if (text !== null && text.trim()) {
|
|
42716
|
+
config.header.linkText = text.trim();
|
|
42717
|
+
}
|
|
42718
|
+
helpers.updateItem(linkIdx, {
|
|
42719
|
+
label: `[x] Link`,
|
|
42720
|
+
detail: linkDetail()
|
|
42721
|
+
});
|
|
42722
|
+
helpers.render();
|
|
42723
|
+
});
|
|
42724
|
+
} else {
|
|
42725
|
+
helpers.render();
|
|
42726
|
+
}
|
|
42727
|
+
});
|
|
42728
|
+
return true;
|
|
42729
|
+
}
|
|
42730
|
+
return false;
|
|
42682
42731
|
}
|
|
42683
42732
|
});
|
|
42684
42733
|
if (!result.confirmed)
|
|
42685
42734
|
return false;
|
|
42686
|
-
|
|
42687
|
-
return true;
|
|
42688
|
-
if (result.key === "message_toggle") {
|
|
42689
|
-
config.header.messageEnabled = true;
|
|
42690
|
-
const msg = await promptLine(rl, "Header message: ");
|
|
42691
|
-
if (msg)
|
|
42692
|
-
config.header.message = msg.slice(0, 80);
|
|
42693
|
-
return stepHeader(config, rl, availableRows);
|
|
42694
|
-
}
|
|
42695
|
-
if (result.key === "link_toggle") {
|
|
42696
|
-
config.header.linkEnabled = true;
|
|
42697
|
-
const url = await promptLine(rl, "Link URL: ");
|
|
42698
|
-
if (url) {
|
|
42699
|
-
config.header.linkUrl = url;
|
|
42700
|
-
const text = await promptLine(rl, "Link text: ");
|
|
42701
|
-
if (text)
|
|
42702
|
-
config.header.linkText = text;
|
|
42703
|
-
}
|
|
42704
|
-
return stepHeader(config, rl, availableRows);
|
|
42705
|
-
}
|
|
42706
|
-
return false;
|
|
42735
|
+
return result.key === "next";
|
|
42707
42736
|
}
|
|
42708
42737
|
async function stepTransport(config, rl, availableRows) {
|
|
42709
42738
|
const items = [
|
|
@@ -42734,12 +42763,16 @@ async function stepTransport(config, rl, availableRows) {
|
|
|
42734
42763
|
{ key: "sep", label: "" },
|
|
42735
42764
|
{ key: "next", label: selectColors.green(" Next Step \u2192") }
|
|
42736
42765
|
];
|
|
42766
|
+
const rpmIdx = items.findIndex((i) => i.key === "rpm");
|
|
42767
|
+
const tpdIdx = items.findIndex((i) => i.key === "tpd");
|
|
42768
|
+
const concIdx = items.findIndex((i) => i.key === "conc");
|
|
42737
42769
|
const result = await tuiSelect({
|
|
42738
42770
|
items,
|
|
42739
42771
|
title: "Step 4/5 \u2014 Transport & Rate Limits",
|
|
42740
42772
|
rl,
|
|
42741
42773
|
skipKeys: ["hdr_transport", "hdr_limits", "sep"],
|
|
42742
42774
|
availableRows,
|
|
42775
|
+
customKeyHint: " e edit space toggle",
|
|
42743
42776
|
onAction: (item, action) => {
|
|
42744
42777
|
if (action === "space") {
|
|
42745
42778
|
if (item.key === "cf_toggle") {
|
|
@@ -42754,6 +42787,42 @@ async function stepTransport(config, rl, availableRows) {
|
|
|
42754
42787
|
}
|
|
42755
42788
|
}
|
|
42756
42789
|
return false;
|
|
42790
|
+
},
|
|
42791
|
+
onCustomKey: (item, key, helpers) => {
|
|
42792
|
+
if ((key === "e" || key === "E") && item.key === "rpm") {
|
|
42793
|
+
helpers.getInput("Max req/min:", String(config.rateLimits.maxRequestsPerMinute)).then((val) => {
|
|
42794
|
+
if (val !== null) {
|
|
42795
|
+
const n = parseInt(val, 10);
|
|
42796
|
+
if (!isNaN(n) && n > 0)
|
|
42797
|
+
config.rateLimits.maxRequestsPerMinute = n;
|
|
42798
|
+
}
|
|
42799
|
+
helpers.updateItem(rpmIdx, { label: ` Max requests/min: ${config.rateLimits.maxRequestsPerMinute}` });
|
|
42800
|
+
});
|
|
42801
|
+
return true;
|
|
42802
|
+
}
|
|
42803
|
+
if ((key === "e" || key === "E") && item.key === "tpd") {
|
|
42804
|
+
helpers.getInput("Max tokens/day:", String(config.rateLimits.maxTokensPerDay)).then((val) => {
|
|
42805
|
+
if (val !== null) {
|
|
42806
|
+
const n = parseInt(val, 10);
|
|
42807
|
+
if (!isNaN(n) && n > 0)
|
|
42808
|
+
config.rateLimits.maxTokensPerDay = n;
|
|
42809
|
+
}
|
|
42810
|
+
helpers.updateItem(tpdIdx, { label: ` Max tokens/day: ${config.rateLimits.maxTokensPerDay.toLocaleString()}` });
|
|
42811
|
+
});
|
|
42812
|
+
return true;
|
|
42813
|
+
}
|
|
42814
|
+
if ((key === "e" || key === "E") && item.key === "conc") {
|
|
42815
|
+
helpers.getInput("Max concurrent:", String(config.rateLimits.maxConcurrent)).then((val) => {
|
|
42816
|
+
if (val !== null) {
|
|
42817
|
+
const n = parseInt(val, 10);
|
|
42818
|
+
if (!isNaN(n) && n > 0)
|
|
42819
|
+
config.rateLimits.maxConcurrent = n;
|
|
42820
|
+
}
|
|
42821
|
+
helpers.updateItem(concIdx, { label: ` Max concurrent: ${config.rateLimits.maxConcurrent}` });
|
|
42822
|
+
});
|
|
42823
|
+
return true;
|
|
42824
|
+
}
|
|
42825
|
+
return false;
|
|
42757
42826
|
}
|
|
42758
42827
|
});
|
|
42759
42828
|
if (!result.confirmed)
|
|
@@ -42765,27 +42834,6 @@ async function stepTransport(config, rl, availableRows) {
|
|
|
42765
42834
|
}
|
|
42766
42835
|
return true;
|
|
42767
42836
|
}
|
|
42768
|
-
if (result.key === "rpm") {
|
|
42769
|
-
const val = await promptLine(rl, "Max requests per minute: ");
|
|
42770
|
-
const n = parseInt(val, 10);
|
|
42771
|
-
if (!isNaN(n) && n > 0)
|
|
42772
|
-
config.rateLimits.maxRequestsPerMinute = n;
|
|
42773
|
-
return stepTransport(config, rl, availableRows);
|
|
42774
|
-
}
|
|
42775
|
-
if (result.key === "tpd") {
|
|
42776
|
-
const val = await promptLine(rl, "Max tokens per day: ");
|
|
42777
|
-
const n = parseInt(val, 10);
|
|
42778
|
-
if (!isNaN(n) && n > 0)
|
|
42779
|
-
config.rateLimits.maxTokensPerDay = n;
|
|
42780
|
-
return stepTransport(config, rl, availableRows);
|
|
42781
|
-
}
|
|
42782
|
-
if (result.key === "conc") {
|
|
42783
|
-
const val = await promptLine(rl, "Max concurrent requests: ");
|
|
42784
|
-
const n = parseInt(val, 10);
|
|
42785
|
-
if (!isNaN(n) && n > 0)
|
|
42786
|
-
config.rateLimits.maxConcurrent = n;
|
|
42787
|
-
return stepTransport(config, rl, availableRows);
|
|
42788
|
-
}
|
|
42789
42837
|
return false;
|
|
42790
42838
|
}
|
|
42791
42839
|
async function stepReview(config, rl, availableRows) {
|
|
@@ -42880,16 +42928,6 @@ async function runSponsorWizard(ctx) {
|
|
|
42880
42928
|
renderInfo("Toggle: /sponsor status | Pause: /sponsor pause | Remove: /sponsor remove");
|
|
42881
42929
|
return config;
|
|
42882
42930
|
}
|
|
42883
|
-
function promptLine(rl, prompt) {
|
|
42884
|
-
return new Promise((resolve35) => {
|
|
42885
|
-
process.stdout.write(prompt);
|
|
42886
|
-
const handler = (line) => {
|
|
42887
|
-
rl.removeListener("line", handler);
|
|
42888
|
-
resolve35(line.trim());
|
|
42889
|
-
};
|
|
42890
|
-
rl.on("line", handler);
|
|
42891
|
-
});
|
|
42892
|
-
}
|
|
42893
42931
|
var ANIM_PRESETS;
|
|
42894
42932
|
var init_sponsor_wizard = __esm({
|
|
42895
42933
|
"packages/cli/dist/tui/sponsor-wizard.js"() {
|
|
@@ -48972,17 +49010,37 @@ async function handleSponsoredEndpoint(ctx, local) {
|
|
|
48972
49010
|
`);
|
|
48973
49011
|
const sponsors = [];
|
|
48974
49012
|
const gateway = ctx.getExposeGateway?.();
|
|
48975
|
-
if (gateway && gateway.isActive
|
|
49013
|
+
if (gateway && gateway.isActive) {
|
|
49014
|
+
const gwUrl = gateway.tunnelUrl || `http://127.0.0.1:${gateway._proxyPort || 11434}`;
|
|
48976
49015
|
sponsors.push({
|
|
48977
49016
|
name: "Local Gateway",
|
|
48978
|
-
url:
|
|
49017
|
+
url: gwUrl,
|
|
48979
49018
|
authKey: gateway.authKey,
|
|
48980
49019
|
models: [],
|
|
48981
|
-
// would need to probe
|
|
48982
49020
|
limits: { rpm: 60, tpd: 1e5 },
|
|
48983
49021
|
source: "local"
|
|
48984
49022
|
});
|
|
48985
49023
|
}
|
|
49024
|
+
const { loadSponsorConfig: loadSpCfg } = await Promise.resolve().then(() => (init_sponsor_wizard(), sponsor_wizard_exports));
|
|
49025
|
+
const spCfg = loadSpCfg(ctx.repoRoot ?? process.cwd());
|
|
49026
|
+
if (spCfg && spCfg.status === "active") {
|
|
49027
|
+
const epUrls = new Set(sponsors.map((s) => s.url));
|
|
49028
|
+
for (const ep of spCfg.endpoints.filter((e) => e.enabled)) {
|
|
49029
|
+
if (!epUrls.has(ep.url)) {
|
|
49030
|
+
sponsors.push({
|
|
49031
|
+
name: ep.label,
|
|
49032
|
+
url: ep.url,
|
|
49033
|
+
authKey: "",
|
|
49034
|
+
models: ep.models,
|
|
49035
|
+
limits: {
|
|
49036
|
+
rpm: spCfg.rateLimits.maxRequestsPerMinute,
|
|
49037
|
+
tpd: spCfg.rateLimits.maxTokensPerDay
|
|
49038
|
+
},
|
|
49039
|
+
source: "local"
|
|
49040
|
+
});
|
|
49041
|
+
}
|
|
49042
|
+
}
|
|
49043
|
+
}
|
|
48986
49044
|
const sponsorDir2 = join58(ctx.repoRoot ?? process.cwd(), ".oa", "sponsor");
|
|
48987
49045
|
const knownFile = join58(sponsorDir2, "known-sponsors.json");
|
|
48988
49046
|
try {
|
package/package.json
CHANGED