@flame0510/project-aether 1.10.0 → 1.11.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/README.md +6 -2
- package/app/agents/CostSection.tsx +12 -10
- package/app/agents/PageClient.tsx +7 -0
- package/app/agents/PanelRow.tsx +9 -0
- package/app/agents/ResourceSection.tsx +105 -0
- package/app/api/assistant/route.ts +2 -2
- package/app/api/containers/route.ts +18 -2
- package/app/api/costs/agent/route.ts +20 -3
- package/app/api/gateway/provider/route.ts +20 -2
- package/app/api/metrics/alerts/route.ts +47 -0
- package/app/api/metrics/containers/route.ts +54 -0
- package/app/api/metrics/route.ts +4 -6
- package/app/api/update-check/route.ts +20 -11
- package/app/components/ui/Accordion.tsx +45 -0
- package/app/components/ui/TimeSeriesChart.tsx +20 -2
- package/app/components/ui/index.ts +1 -0
- package/app/containers/ContainersClient.tsx +48 -6
- package/app/gateway/ModelDetailsModal.tsx +4 -2
- package/app/gateway/PageClient.tsx +86 -36
- package/app/globals.css +36 -0
- package/app/system/AgentCharts.tsx +138 -0
- package/app/system/AgentsSection.tsx +281 -0
- package/app/system/PageClient.tsx +11 -9
- package/app/system/RecentAlerts.tsx +72 -0
- package/app/system/SystemSkeleton.tsx +53 -1
- package/app/system/loading.tsx +5 -1
- package/bin/postinstall.js +7 -4
- package/bin/rev4a.js +6 -7
- package/daemon.js +195 -4
- package/docs/ARCHITECTURE.md +36 -5
- package/docs/FRONTEND-ARCHITECTURE.md +13 -4
- package/docs/REV4A.md +9 -6
- package/docs/dev/API-REFERENCE.md +116 -30
- package/docs/dev/DATABASE.md +58 -2
- package/docs/dev/GATEWAY.md +13 -4
- package/docs/rag/DATA-FRESHNESS.md +16 -1
- package/docs/rag/GLOSSARY.md +3 -3
- package/docs/rag/REV4A-OVERVIEW.md +9 -5
- package/docs/rag/WHAT-I-CAN-ANSWER.md +4 -1
- package/lib/container-metrics.ts +340 -0
- package/lib/docker-socket-path.d.ts +9 -0
- package/lib/docker-socket-path.js +133 -0
- package/lib/docker-socket.ts +10 -99
- package/lib/docker-stats.d.ts +88 -0
- package/lib/docker-stats.js +284 -0
- package/lib/metrics-db.ts +15 -6
- package/lib/model-details.ts +3 -3
- package/lib/model-pricing.ts +6 -4
- package/lib/utils/format.ts +29 -3
- package/model-details.json +2799 -2274
- package/model-pricing.json +63 -48
- package/models.config.json +41 -10
- package/npm-shrinkwrap.json +1979 -0
- package/package.json +11 -9
- package/scripts/check-language.mjs +1 -1
- package/scripts/check-package-types.mjs +74 -0
- package/scripts/test-docker-stats.mjs +270 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Rev4a API Reference
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-02
|
|
4
4
|
|
|
5
5
|
All routes are under `/api/`. Authentication is required on every endpoint
|
|
6
6
|
unless otherwise noted.
|
|
@@ -251,10 +251,15 @@ Returns current provider configuration state.
|
|
|
251
251
|
|
|
252
252
|
**Response:** each provider carries its models, and a model carries `params` (the total
|
|
253
253
|
parameter count) when its Hugging Face card publishes one — the Gateway row shows it next
|
|
254
|
-
to the price, and a model without a card simply omits it.
|
|
254
|
+
to the price, and a model without a card simply omits it. A model priced by time of day
|
|
255
|
+
carries `band` (`"peak"` or `"off-peak"`, what the vendor bills right now — the Gateway row
|
|
256
|
+
shows it as a chip) and its `pricing` is the rate in force at answer time, not the peak
|
|
257
|
+
list price: it flips with the band, like the agents' synced prices. The top level carries
|
|
258
|
+
`nextPriceChangeMs`, when the band flips next, so an open page can refresh the chips.
|
|
255
259
|
|
|
256
260
|
```json
|
|
257
261
|
{
|
|
262
|
+
"nextPriceChangeMs": 1790532000000,
|
|
258
263
|
"providers": [
|
|
259
264
|
{
|
|
260
265
|
"provider": "deepseek",
|
|
@@ -263,8 +268,8 @@ to the price, and a model without a card simply omits it.
|
|
|
263
268
|
"baseUrl": "https://api.deepseek.com",
|
|
264
269
|
"docsUrl": "https://platform.deepseek.com/api_keys",
|
|
265
270
|
"models": [
|
|
266
|
-
{ "id": "deepseek/deepseek-flash", "name": "DeepSeek Flash", "enabled": true },
|
|
267
|
-
{ "id": "deepseek/deepseek-v4-pro", "name": "DeepSeek V4 Pro", "enabled": true }
|
|
271
|
+
{ "id": "deepseek/deepseek-flash", "name": "DeepSeek Flash", "enabled": true, "band": "off-peak", "pricing": { "input": 0.15, "output": 0.6, "cacheRead": 0.003, "cacheWrite": 0.15 } },
|
|
272
|
+
{ "id": "deepseek/deepseek-v4-pro", "name": "DeepSeek V4 Pro", "enabled": true, "band": "off-peak", "pricing": { "input": 0.66, "output": 1.98, "cacheRead": 0.022, "cacheWrite": 0.66 } }
|
|
268
273
|
]
|
|
269
274
|
}
|
|
270
275
|
]
|
|
@@ -320,8 +325,8 @@ Rev4a Provider Gateway — proxy chat completions to the correct upstream.
|
|
|
320
325
|
---
|
|
321
326
|
|
|
322
327
|
### `GET /api/models/details?id=<model id>`
|
|
323
|
-
Everything the details modal shows for one model, and nothing more:
|
|
324
|
-
|
|
328
|
+
Everything the details modal shows for one model, and nothing more: unknown optional
|
|
329
|
+
facts are omitted; `price` and `info` can be `null` when absent.
|
|
325
330
|
|
|
326
331
|
**Auth:** browser cookie or bearer token
|
|
327
332
|
|
|
@@ -330,7 +335,7 @@ not have are **absent**, never `null` and never a guess.
|
|
|
330
335
|
{
|
|
331
336
|
"id": "glm/glm-5.3-flash", "name": "GLM-5.3 Flash", "provider": "glm",
|
|
332
337
|
"modality": "text+image+video->text", "enabled": false, "deprecated": false,
|
|
333
|
-
"price": { "input": 0.15, "output": 0.5, "source": "vendor" },
|
|
338
|
+
"price": { "input": 0.15, "output": 0.5, "source": "vendor", "scheduled": false },
|
|
334
339
|
"details": { "description": "…", "created": "2026-08-26", "context": 1310720,
|
|
335
340
|
"providerContext": 1048576, "maxOutput": 943718,
|
|
336
341
|
"reasoning": { "mandatory": true, "default_effort": "max", "supported_efforts": ["max","high","low"] },
|
|
@@ -338,13 +343,15 @@ not have are **absent**, never `null` and never a guess.
|
|
|
338
343
|
"benchmarks": { "design_arena": [ … ], "artificial_analysis": { … } },
|
|
339
344
|
"huggingFaceId": "zai-org/GLM-5.3-Flash", "url": "https://openrouter.ai/…" },
|
|
340
345
|
"info": null,
|
|
341
|
-
"asOf": "2026-
|
|
346
|
+
"asOf": "2026-10-02T10:46:53.452Z",
|
|
342
347
|
"detailsSource": "openrouter"
|
|
343
348
|
}
|
|
344
349
|
```
|
|
345
350
|
|
|
346
351
|
`price.source` is `openrouter` for an `openrouter/*` entry and `vendor` for a direct one,
|
|
347
|
-
which keeps prices honest: the refresh script never writes a vendor price. `
|
|
352
|
+
which keeps prices honest: the refresh script never writes a vendor price. `price.scheduled`
|
|
353
|
+
identifies a time-of-day list price; the Gateway row separately shows the rate in force.
|
|
354
|
+
`details` comes
|
|
348
355
|
from the generated `model-details.json` (`npm run refresh:pricing`, see
|
|
349
356
|
`docs/dev/GATEWAY.md`), `info` from the catalogue's hand-written block, and `asOf` is when
|
|
350
357
|
the generated part was produced. An id the catalogue does not carry answers `404`.
|
|
@@ -652,11 +659,14 @@ One agent's spend for its panel, from `costs.db`.
|
|
|
652
659
|
|
|
653
660
|
**Auth:** browser cookie or Bearer
|
|
654
661
|
|
|
655
|
-
**Response:** `{ "available": true, "intervalS": 300, "today": 0.011, "week": 0.019,
|
|
662
|
+
**Response:** `{ "available": true, "intervalS": 300, "pricing": { "vendor": "DeepSeek", "band": "off-peak", "nextChange": 1790532000000, "source": "https://api-docs.deepseek.com/quick_start/pricing" }, "today": 0.011, "week": 0.019,
|
|
656
663
|
"month": 0.022, "tokensMonth": 2409574, "topModel": { "model": "deepseek/deepseek-flash",
|
|
657
664
|
"cost": 0.022 }, "unpricedMonth": 81, "collectedAt": 1790529516737, "error": null }` —
|
|
658
|
-
UTC days (today, last 7, last 30); `
|
|
659
|
-
|
|
665
|
+
UTC days (today, last 7, last 30); `pricing` is the band billed right now, the same object
|
|
666
|
+
the Costs page header shows (`null` when no scheduled model is on offer); `collectedAt`/`error`
|
|
667
|
+
from the agent's last read. Before `costs.db` exists, the response is
|
|
668
|
+
`{ "available": false, "intervalS": 300, "pricing": null }` (or the current pricing
|
|
669
|
+
object when a scheduled model is on offer).
|
|
660
670
|
|
|
661
671
|
**Errors:** `400` for an invalid container name; `500` when `costs.db` cannot be read.
|
|
662
672
|
|
|
@@ -2045,6 +2055,81 @@ average and peak: 60 s for `1h`, 720 s for `24h`, 5040 s for `7d`, 21 600 s for
|
|
|
2045
2055
|
means the daemon is not sampling; the page says so.
|
|
2046
2056
|
- `host` is read live by the API process, which runs on the same host.
|
|
2047
2057
|
|
|
2058
|
+
### `GET /api/metrics/containers?range=1h|24h|7d|30d`
|
|
2059
|
+
What every container consumes — now, and as an average and peak over the range — plus what is
|
|
2060
|
+
not a container and the disk Docker holds. From `metrics.db` (the daemon samples every 60 s,
|
|
2061
|
+
see `docs/dev/DATABASE.md`). Default range `1h`.
|
|
2062
|
+
|
|
2063
|
+
**Auth:** browser cookie or Bearer
|
|
2064
|
+
|
|
2065
|
+
**Response:**
|
|
2066
|
+
```json
|
|
2067
|
+
{
|
|
2068
|
+
"available": true, "range": "1h", "interval_s": 60,
|
|
2069
|
+
"host": { "ncpu": 10, "mem_total_mb": 7837 },
|
|
2070
|
+
"sampled_at": 1790789760, "age_s": 10,
|
|
2071
|
+
"containers": [
|
|
2072
|
+
{ "container": "agent_9253eee3", "name": "test", "agent_id": "agent_9253eee3", "is_agent": true,
|
|
2073
|
+
"running": true, "last_seen": 1790789760,
|
|
2074
|
+
"now": { "cpu_cores": 0.022, "cpu_percent": 0.22, "mem_mb": 668, "mem_percent": 8.5, "pids": 12,
|
|
2075
|
+
"net_rx_bps": 0, "net_tx_bps": 0, "blk_read_bps": 0, "blk_write_bps": 0 },
|
|
2076
|
+
"range": { "cpu_avg_percent": 1.02, "cpu_max_percent": 2.17, "mem_avg_mb": 679, "mem_max_mb": 701 },
|
|
2077
|
+
"storage": { "volume_mb": 1544, "layer_mb": 10, "total_mb": 1554, "ts": 1790789645 } }
|
|
2078
|
+
],
|
|
2079
|
+
"rest": { "cpu_percent": 42.26, "mem_mb": 11864 },
|
|
2080
|
+
"docker_storage": { "ts": 1790789645, "images_mb": 4734, "images_reclaimable_mb": 3518,
|
|
2081
|
+
"build_cache_mb": 1597, "build_cache_reclaimable_mb": 1597,
|
|
2082
|
+
"volumes_mb": 10120, "unused_volumes_mb": 7337, "layers_mb": 30,
|
|
2083
|
+
"unused_volumes": [ { "name": "rev4a-backups", "size_mb": 7337 } ] }
|
|
2084
|
+
}
|
|
2085
|
+
```
|
|
2086
|
+
|
|
2087
|
+
- `cpu_percent` is a share of Docker's cores (`host.ncpu`), `mem_percent` of Docker's memory —
|
|
2088
|
+
on Docker Desktop that is its VM, on the VPS the machine. `cpu_cores` is the raw figure.
|
|
2089
|
+
- `now` is `null` for a container that is not running (no sample within 3 intervals of the
|
|
2090
|
+
newest sample — running is judged against the newest sample, not the wall clock, so a
|
|
2091
|
+
stopped daemon does not make every container look stopped);
|
|
2092
|
+
`running: false` ones stay listed while they were seen in the range. A rate that is null in
|
|
2093
|
+
the newest sample (the first after a start) is replaced by the previous reading.
|
|
2094
|
+
- The list is sorted running first, then by CPU now. `storage` is the named volumes plus the
|
|
2095
|
+
writable layer, from the last Docker disk reading (every 10 min).
|
|
2096
|
+
- `rest` is the machine's newest sample minus the running containers (the containers' CPU
|
|
2097
|
+
re-scaled to the machine's cores first, so on Docker Desktop the two shares still compare):
|
|
2098
|
+
the host, Rev4a and other software (`null` without a machine sample or Docker's figures).
|
|
2099
|
+
- `docker_storage.*_reclaimable_mb` and `unused_volumes` (the 5 largest): what **no container
|
|
2100
|
+
uses** — images of older agent versions you may still roll back to count as such; a volume
|
|
2101
|
+
like the cold backups' is listed, not advised for removal. `volumes_mb` sums all volumes;
|
|
2102
|
+
`unused_volumes_mb` is the total of what no container uses, `unused_volumes` only names the
|
|
2103
|
+
five largest.
|
|
2104
|
+
- `available: false` until the daemon has created the tables; with the tables present and no
|
|
2105
|
+
rows yet it answers `available: true` with an empty list.
|
|
2106
|
+
|
|
2107
|
+
**With `&container=<name>`** — that container's history, bucketed like `GET /api/metrics`:
|
|
2108
|
+
```json
|
|
2109
|
+
{ "available": true, "range": "1h", "interval_s": 60, "host": { "ncpu": 10, "mem_total_mb": 7837 },
|
|
2110
|
+
"container": "agent_9253eee3", "name": "test", "bucket_s": 120,
|
|
2111
|
+
"history": [ { "ts": 1790789640, "cpu_avg": 1.41, "cpu_max": 2.17, "mem_avg": 685, "mem_max": 701 } ],
|
|
2112
|
+
"storage_bucket_s": 1200, "storage_history": [ { "ts": 1790788800, "total_mb": 1554 } ] }
|
|
2113
|
+
```
|
|
2114
|
+
`cpu_*` are shares of Docker's cores, `mem_*` MB. A container that was not running has no
|
|
2115
|
+
points for that stretch (a gap). A name that matches the rules but was never sampled answers
|
|
2116
|
+
`available: true` with an empty history.
|
|
2117
|
+
|
|
2118
|
+
**Errors:** `400` for another `range` or an invalid container name. A `metrics.db` that
|
|
2119
|
+
cannot be opened (missing, corrupt) answers `available: false`, not an error.
|
|
2120
|
+
|
|
2121
|
+
### `GET /api/metrics/alerts?limit=10`
|
|
2122
|
+
The machine's latest `system_anomaly` events (CPU above 85 % or memory above 90 % on two
|
|
2123
|
+
samples in a row, a disk at 90 %), newest first, from `events.db`. `limit` 1–50, default 10.
|
|
2124
|
+
|
|
2125
|
+
**Auth:** browser cookie or Bearer
|
|
2126
|
+
|
|
2127
|
+
**Response:**
|
|
2128
|
+
```json
|
|
2129
|
+
{ "alerts": [ { "ts": 1790789625355, "metric": "disk", "message": "Disk high: / 94% used", "threshold": 90, "values": [94] } ] }
|
|
2130
|
+
```
|
|
2131
|
+
`ts` is in **milliseconds** (the `events` table's unit); `metric` is `cpu`, `ram`, `disk` or `null`.
|
|
2132
|
+
|
|
2048
2133
|
---
|
|
2049
2134
|
|
|
2050
2135
|
## System Health
|
|
@@ -2302,27 +2387,26 @@ Full key management documentation at [PROVIDERS.md](PROVIDERS.md).
|
|
|
2302
2387
|
## Containers
|
|
2303
2388
|
|
|
2304
2389
|
### `GET /api/containers`
|
|
2305
|
-
|
|
2390
|
+
Every Docker container, running or stopped, with its identity and network details. What a
|
|
2391
|
+
running container consumes lives in `GET /api/metrics/containers`.
|
|
2306
2392
|
|
|
2307
|
-
**Auth:** browser cookie
|
|
2393
|
+
**Auth:** browser cookie or Bearer
|
|
2308
2394
|
|
|
2309
|
-
**Response:**
|
|
2395
|
+
**Response:** a bare array —
|
|
2310
2396
|
```json
|
|
2311
|
-
|
|
2312
|
-
"
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
"status": "running",
|
|
2317
|
-
"ports": ["0.0.0.0:3731->3000/tcp"],
|
|
2318
|
-
"created": "2026-06-20T10:00:00Z",
|
|
2319
|
-
"cpu_percent": 2.1,
|
|
2320
|
-
"mem_usage_mb": 340
|
|
2321
|
-
}
|
|
2322
|
-
]
|
|
2323
|
-
}
|
|
2397
|
+
[
|
|
2398
|
+
{ "id": "a1b2c3d4e5f6", "name": "openclaw-atlas", "image": "openclaw-agent-base:2026.9.3",
|
|
2399
|
+
"status": "Up 3 hours", "state": "running", "ports": "0.0.0.0:3731->3000/tcp",
|
|
2400
|
+
"ip": "172.18.0.2", "agentId": "agent_atlas", "displayName": "Atlas", "created": null }
|
|
2401
|
+
]
|
|
2324
2402
|
```
|
|
2325
2403
|
|
|
2404
|
+
- `name` is the daemon's `primaryName` (the name with one leading slash) — the same key the
|
|
2405
|
+
metrics store and the `/system?agent=` link use.
|
|
2406
|
+
- `displayName` is the agent's `AGENT_NAME`, read from the inspect. If an inspect fails, the
|
|
2407
|
+
row still comes from Docker's list (`ip` and `displayName` then `null`): a container is
|
|
2408
|
+
never dropped, and never renamed, because one call failed.
|
|
2409
|
+
|
|
2326
2410
|
The container list is the only container route. There is no logs endpoint and no
|
|
2327
2411
|
action endpoint: logs are read through the terminal WebSocket, and lifecycle
|
|
2328
2412
|
operations on agent containers go through `/api/agents/[id]/lifecycle`.
|
|
@@ -2807,8 +2891,10 @@ the update kills this process on its way in (`fuser -k <port>/tcp`) and `rev4a s
|
|
|
2807
2891
|
brings the child back on the new binary via its `.restart-flag`, so the connection
|
|
2808
2892
|
drops and the page has to wait for the server to answer again.
|
|
2809
2893
|
|
|
2810
|
-
The child's output goes to `update.log`
|
|
2811
|
-
|
|
2894
|
+
The child's output goes to `update.log` under `<REV4A_DATA_DIR>/data` (or
|
|
2895
|
+
`~/.config/rev4a/data` by default) — the update restarts the process that spawned
|
|
2896
|
+
it, so that file is the only record of what happened. The endpoint creates the
|
|
2897
|
+
directory if needed and reports a failure if it cannot start the updater.
|
|
2812
2898
|
|
|
2813
2899
|
**Auth:** browser cookie or bearer token
|
|
2814
2900
|
|
package/docs/dev/DATABASE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Rev4a — Database Reference
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-01
|
|
4
4
|
|
|
5
5
|
Rev4a keeps four SQLite files in WAL mode, by default all in the data directory's `data/`:
|
|
6
|
-
`events.db` (sessions and events, below), `metrics.db` (machine metrics, see
|
|
6
|
+
`events.db` (sessions and events, below), `metrics.db` (machine and container metrics, see
|
|
7
7
|
[Metrics Database](#metrics-database-metricsdb)), `costs.db` (what the agents spent, see
|
|
8
8
|
[Costs Database](#costs-database-costsdb)) and `credentials.db` (see
|
|
9
9
|
[Credentials Database](#credentials-database-credentialsdb)).
|
|
@@ -318,6 +318,62 @@ has dropped back under, or once after each daemon start: the state is kept in me
|
|
|
318
318
|
Installs from before this database may still have a `system_metrics` table in
|
|
319
319
|
`events.db`: nothing reads or writes it any more, and it can be dropped.
|
|
320
320
|
|
|
321
|
+
### Container consumption (also in `metrics.db`)
|
|
322
|
+
|
|
323
|
+
What each running container uses, and the disk Docker holds, so the System page can say
|
|
324
|
+
*who* is using the machine. The daemon writes it from the Docker Engine API
|
|
325
|
+
(`lib/docker-stats.js`; where the socket is comes from `lib/docker-socket-path.js`, shared
|
|
326
|
+
with the dashboard's `lib/docker-socket.ts`); `lib/container-metrics.ts` reads it for
|
|
327
|
+
`GET /api/metrics/containers`, the agent panel and the Containers page. The tables are
|
|
328
|
+
created with `CREATE TABLE IF NOT EXISTS` when the daemon starts, so an update adds them;
|
|
329
|
+
until then the API answers `available: false`.
|
|
330
|
+
|
|
331
|
+
**Sampling:** containers every 60 s, on a timer of its own — a priming pass 6 s after the
|
|
332
|
+
daemon starts (it only records the gauges: a CPU figure needs two readings), the first
|
|
333
|
+
complete one 15 s later — and Docker's disk (`/system/df`) every 10 min, the first reading
|
|
334
|
+
25 s after start. **Retention:** 30 days, pruned at every sample. A stopped container has no
|
|
335
|
+
rows: a gap, not zeros. Size, estimated: 60 s × 10 containers × 30 days ≈ 430 000 rows ≈ 35 MB
|
|
336
|
+
(to be measured on the VPS; rollups to 5 min may be added if it grows).
|
|
337
|
+
|
|
338
|
+
```sql
|
|
339
|
+
-- One row per running container per sample. CPU in cores (CPU-seconds per second), rates in
|
|
340
|
+
-- bytes per second; each is NULL on the first sample after a start and when its counter went
|
|
341
|
+
-- backwards (the container restarted) — never a negative rate or a spike. Memory is the
|
|
342
|
+
-- working set: usage − inactive page cache, what `docker stats` shows.
|
|
343
|
+
CREATE TABLE container_metrics (
|
|
344
|
+
ts INTEGER NOT NULL, -- Unix seconds
|
|
345
|
+
container TEXT NOT NULL,
|
|
346
|
+
cpu_cores REAL,
|
|
347
|
+
mem_mb INTEGER,
|
|
348
|
+
pids INTEGER,
|
|
349
|
+
net_rx_bps INTEGER, net_tx_bps INTEGER,
|
|
350
|
+
blk_read_bps INTEGER, blk_write_bps INTEGER
|
|
351
|
+
);
|
|
352
|
+
CREATE INDEX idx_container_metrics_ts ON container_metrics(ts);
|
|
353
|
+
CREATE INDEX idx_container_metrics_c_ts ON container_metrics(container, ts);
|
|
354
|
+
|
|
355
|
+
-- Who each container is: an agent's name (AGENT_NAME), whether it is an agent, and its named
|
|
356
|
+
-- volumes (the link to docker_storage). Forgotten after the retention.
|
|
357
|
+
CREATE TABLE container_sources (
|
|
358
|
+
container TEXT PRIMARY KEY,
|
|
359
|
+
agent_id TEXT, name TEXT, is_agent INTEGER NOT NULL DEFAULT 0,
|
|
360
|
+
volumes TEXT, -- comma-separated volume names
|
|
361
|
+
last_seen INTEGER NOT NULL
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
-- Docker's own cores and memory: the denominators for a container's share (on Docker Desktop
|
|
365
|
+
-- that is its VM — 8 GB of a 16 GB Mac — not the machine). One row.
|
|
366
|
+
CREATE TABLE docker_host (id INTEGER PRIMARY KEY CHECK (id = 1), ncpu INTEGER, mem_total_mb INTEGER, updated_at INTEGER);
|
|
367
|
+
|
|
368
|
+
-- Disk Docker holds, one set of rows per reading: kind 'volume' (name = the volume;
|
|
369
|
+
-- reclaimable_mb = its size when no container uses it), 'layer' (name = a container, its
|
|
370
|
+
-- writable layer), 'images' and 'build_cache' (totals; reclaimable_mb = what no container /
|
|
371
|
+
-- no build uses). A size Docker could not compute is NULL.
|
|
372
|
+
CREATE TABLE docker_storage (ts INTEGER NOT NULL, kind TEXT NOT NULL, name TEXT NOT NULL DEFAULT '', size_mb INTEGER, reclaimable_mb INTEGER);
|
|
373
|
+
CREATE INDEX idx_docker_storage_ts ON docker_storage(ts);
|
|
374
|
+
CREATE INDEX idx_docker_storage_kind_ts ON docker_storage(kind, name, ts);
|
|
375
|
+
```
|
|
376
|
+
|
|
321
377
|
## Costs Database (`costs.db`)
|
|
322
378
|
|
|
323
379
|
What each agent spent, **as its own OpenClaw priced it** — Rev4a computes no cost here.
|
package/docs/dev/GATEWAY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Gateway Page
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-02
|
|
4
4
|
|
|
5
5
|
The Gateway page (`/gateway`) is the control panel for provider configuration:
|
|
6
6
|
API keys and the model catalogue offered to every agent container. It does not
|
|
@@ -113,9 +113,10 @@ its own Control UI too. Rev4a computes no cost: the daemon reads OpenClaw's figu
|
|
|
113
113
|
(cached tokens priced as if the cache gave no discount); one without `cacheWrite` to
|
|
114
114
|
1.25 × the input rate — vendors that bill cache writes apart charge more than input
|
|
115
115
|
(Anthropic's five-minute cache: 1.25×), and the ones that report no cache writes never
|
|
116
|
-
use it.
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
use it. These fallbacks avoid treating an unknown cache rate as free, but can differ
|
|
117
|
+
from what a vendor bills. `refresh:pricing` writes published OpenRouter cache rates;
|
|
118
|
+
the file currently has cache-read rates for 107 models and cache-write rates for 44 of
|
|
119
|
+
184 entries. Direct vendors are filled by hand from their pricing page.
|
|
119
120
|
- **Time-of-day prices.** DeepSeek bills half its rates off-peak (peak 01:00–04:00 and
|
|
120
121
|
06:00–10:00 UTC, Monday–Friday). `PRICE_SCHEDULES` in `lib/model-pricing.ts` holds
|
|
121
122
|
that schedule; `priceAt()` writes the rate of the moment, and
|
|
@@ -131,6 +132,11 @@ its own Control UI too. Rev4a computes no cost: the daemon reads OpenClaw's figu
|
|
|
131
132
|
time, so a later change of rate does not reprice a call (verified with a real call,
|
|
132
133
|
priced off-peak and read again after the switch to peak). Chinese public holidays,
|
|
133
134
|
which DeepSeek bills off-peak all day, are priced as peak — a small overestimate.
|
|
135
|
+
Where the band is visible: the Costs page header (a pill with the time of the next
|
|
136
|
+
change), the agent panel's COSTS section (Rates now), and the Gateway page — a
|
|
137
|
+
band-priced model's row carries a PEAK / OFF-PEAK chip next to its price, and that price
|
|
138
|
+
is the rate in force now (off-peak it shows half the list price), refreshed just after
|
|
139
|
+
each change while the page stays open (`nextPriceChangeMs`).
|
|
134
140
|
- **Calls made before a model had a price** are priced by OpenClaw when read, at the
|
|
135
141
|
rate in force then; OpenClaw reindexes its transcripts after a price change, which is
|
|
136
142
|
why a read can briefly answer `cacheStatus: refreshing`.
|
|
@@ -206,6 +212,9 @@ sources, each one labelled in the modal:
|
|
|
206
212
|
| Price | `model-pricing.json` | refreshed for `openrouter/*`, hand for direct vendors |
|
|
207
213
|
| Description, specs, benchmarks | `model-details.json` | **generated**, never hand-edited |
|
|
208
214
|
|
|
215
|
+
For a scheduled vendor, the modal labels the static rate as a list price; the Gateway
|
|
216
|
+
row shows the rate in force and its peak/off-peak band.
|
|
217
|
+
|
|
209
218
|
`npm run refresh:pricing` (script `scripts/refresh-model-pricing.mjs`) fetches the
|
|
210
219
|
OpenRouter catalogue once and writes both the prices and `model-details.json`:
|
|
211
220
|
description, release date (`created`), context and the provider's own limit, max output,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Data Freshness in Rev4a
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-01
|
|
4
4
|
|
|
5
5
|
Understanding how current the data in Rev4a is — and what is truly real-time vs. periodically updated.
|
|
6
6
|
|
|
@@ -56,6 +56,21 @@ the collector is not running instead of showing stale numbers as current.
|
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
+
## Container consumption (System page, Containers page, agent panel)
|
|
60
|
+
|
|
61
|
+
**Update frequency:** every 60 seconds for CPU, memory, processes, network and block I/O of
|
|
62
|
+
each running container; every 10 minutes for the disk Docker holds (volumes, writable layers,
|
|
63
|
+
images, build cache). Both are sampled by the Rev4a daemon on timers of their own and kept 30
|
|
64
|
+
days in `metrics.db`. The first figures after the daemon starts take about 20 seconds (a CPU
|
|
65
|
+
figure needs two readings). A stopped container leaves a gap in its charts, not zeros.
|
|
66
|
+
|
|
67
|
+
CPU is a share of Docker's cores and memory a share of Docker's memory: on Docker Desktop that
|
|
68
|
+
is its virtual machine (for example 8 GB of a 16 GB Mac), on a server it is the machine. If the
|
|
69
|
+
newest sample is older than three minutes the System page says it is not collecting — the
|
|
70
|
+
figures still on show are the last known ones, not live. The agent panel stands its "now" rows
|
|
71
|
+
down, and the Containers page clears its usage row rather than leave stale figures. A container
|
|
72
|
+
still seen in Docker's list but without fresh statistics says "no data", not "stopped".
|
|
73
|
+
|
|
59
74
|
## Agent costs (Costs page)
|
|
60
75
|
|
|
61
76
|
**Update frequency:** every 5 minutes. The Rev4a daemon asks each running agent
|
package/docs/rag/GLOSSARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Rev4a Glossary
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-01
|
|
4
4
|
|
|
5
5
|
Terms you'll encounter while using the Rev4a dashboard.
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ A compressed archive (`.tar.gz`) of an agent's persistent volume (`/root/`). Bac
|
|
|
22
22
|
Which browsers may open an agent's Control UI. On OpenClaw 9.x every new browser must be approved once; the approval is remembered per browser. Managed in the "BROWSER ACCESS" section of the agent detail panel: approve or reject waiting browsers, rename or revoke approved ones. The Open button uses a one-time link that skips the approval. The Invite link button gives a link for someone else: their browser still waits for approval.
|
|
23
23
|
|
|
24
24
|
## Container
|
|
25
|
-
A Docker container running on the server. Each agent runs in its own container. The Containers page shows all containers, including infrastructure ones such as databases and reverse proxies, with a web terminal link (a real shell in the browser; a dropped connection is resumed for 2 minutes).
|
|
25
|
+
A Docker container running on the server. Each agent runs in its own container. The Containers page shows all containers (a running one also with its CPU, memory and processes now), including infrastructure ones such as databases and reverse proxies, with a web terminal link (a real shell in the browser; a dropped connection is resumed for 2 minutes).
|
|
26
26
|
|
|
27
27
|
## Channel
|
|
28
28
|
A communication channel (Telegram) configured on an agent. Channels allow users to send DMs to the agent via messaging apps. The Channel Manager modal lets you connect/disconnect Telegram and manage pairings (approve/reject senders).
|
|
@@ -34,7 +34,7 @@ Modal in the agent detail panel for configuring Telegram channels. Connect with
|
|
|
34
34
|
What an agent spent in USD. Each agent's OpenClaw prices every model call itself, with the prices Rev4a writes into it (input, output, cached input), and Rev4a reads those figures every 5 minutes. The Costs page (`/costs`) shows them for today, 7 or 30 days — by day, by agent, by model, and the most expensive sessions. The dashboard's "Spent today" card shows the same figures for today, and each agent's panel on the Agents page has a COSTS section with its own. The Costs page also compares the agents' figures with what DeepSeek and OpenRouter actually billed (their balance or usage, read every hour).
|
|
35
35
|
|
|
36
36
|
## Off-peak
|
|
37
|
-
DeepSeek bills half price outside its peak hours (peak: 01:00–04:00 and 06:00–10:00 UTC, Monday–Friday). Rev4a writes the lower prices into the agents when off-peak starts and the full ones when it ends, so each call is priced at the rate in force when it ran. The Costs page header
|
|
37
|
+
DeepSeek bills half price outside its peak hours (peak: 01:00–04:00 and 06:00–10:00 UTC, Monday–Friday). Rev4a writes the lower prices into the agents when off-peak starts and the full ones when it ends, so each call is priced at the rate in force when it ran. The Costs page header and the agent panel's COSTS section (Rates now) show the current band.
|
|
38
38
|
|
|
39
39
|
## Cost Override
|
|
40
40
|
A manual correction for a month's total cost, stored through `/api/cost-override`. There is currently no screen for it: no page in the dashboard reads or writes an override, so it can only be set by calling the API directly.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# What is Rev4a?
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-01
|
|
4
4
|
|
|
5
5
|
Rev4a is the control panel for your AI agent infrastructure. It shows you everything your agents are doing, how much they cost, and whether the system is healthy — all in one dashboard.
|
|
6
6
|
|
|
@@ -74,19 +74,23 @@ Wizard to spin up a new agent. Steps: choose a template (Prometheus, Argus, Atla
|
|
|
74
74
|
Interactive graph showing session family trees — which agent spawned which child agent, across configurable time periods: 1d, 3d, 7d, 15d, 30d, and all. Click any node to inspect. Includes a live feed side panel.
|
|
75
75
|
|
|
76
76
|
### Gateway (`/gateway`)
|
|
77
|
-
Connects agents to AI providers. Add and remove provider API keys, enable or disable individual models in the catalogue read from `models.config.json`, and push the resulting model list to every agent container. It does not assign models to agents: choosing which model an agent runs is done per agent, in the Model section of the agent's detail panel on the Agents page. Every model row has a **Details** button: the modal shows the model's description, price and provider, its architecture and parameter count when the weights are public, reasoning modes, capabilities, benchmarks with sources, licence and how much disk the weights take — the numbers come from the model card on Hugging Face and from curated entries that cite a source, never from estimates.
|
|
77
|
+
Connects agents to AI providers. Add and remove provider API keys, enable or disable individual models in the catalogue read from `models.config.json`, and push the resulting model list to every agent container. It does not assign models to agents: choosing which model an agent runs is done per agent, in the Model section of the agent's detail panel on the Agents page. A DeepSeek model row shows its current rate and a peak/off-peak chip; the rate updates after the next band change. Every model row has a **Details** button: the modal shows the model's description, list price and provider, its architecture and parameter count when the weights are public, reasoning modes, capabilities, benchmarks with sources, licence and how much disk the weights take — the numbers come from the model card on Hugging Face and from curated entries that cite a source, never from estimates.
|
|
78
78
|
|
|
79
79
|
### Containers (`/containers`)
|
|
80
|
-
Full list of all Docker containers on the server, including stopped ones. Each row shows name, status, image, IP, ports, and an agent pill where applicable. Click "Terminal" to open an interactive shell into that container.
|
|
80
|
+
Full list of all Docker containers on the server, including stopped ones. Each row shows name, status, image, IP, ports, and an agent pill where applicable. Click "Terminal" to open an interactive shell into that container. A running container also shows what it consumes now — CPU share, memory and processes — with a "Charts" link to its history on the System page.
|
|
81
81
|
|
|
82
|
-
The page
|
|
82
|
+
The page has no start, stop, or restart buttons: it is read-only apart from the terminal link. Container lifecycle is managed from the Agents page.
|
|
83
83
|
|
|
84
84
|
### Costs (`/costs`)
|
|
85
|
-
What each agent spent, as its own OpenClaw priced it with the prices Rev4a syncs. Pick today, 7 days or 30 days (UTC days): the total, where the money went (input, output, cache), the tokens and how much input came from cache, a chart of the spend per day, the spend by agent and by model, and the most expensive sessions. Calls that could not be priced are listed by model, and agents whose figures are not current are flagged. When a DeepSeek model is on offer, the header shows whether DeepSeek is billing peak or off-peak (half price) and until when. Figures are read from the agents every 5 minutes. *Against the bill* compares them with what DeepSeek and OpenRouter actually charged (their balance or usage, read every hour); a small gap is normal, since the same key may pay for the assistant too. Each agent's own spend is also in its panel on the Agents page (COSTS).
|
|
85
|
+
What each agent spent, as its own OpenClaw priced it with the prices Rev4a syncs. Pick today, 7 days or 30 days (UTC days): the total, where the money went (input, output, cache), the tokens and how much input came from cache, a chart of the spend per day, the spend by agent and by model, and the most expensive sessions. Calls that could not be priced are listed by model, and agents whose figures are not current are flagged. When a DeepSeek model is on offer, the header shows whether DeepSeek is billing peak or off-peak (half price) and until when. Figures are read from the agents every 5 minutes. *Against the bill* compares them with what DeepSeek and OpenRouter actually charged (their balance or usage, read every hour); a small gap is normal, since the same key may pay for the assistant too. Each agent's own spend is also in its panel on the Agents page (COSTS), with the current DeepSeek band (Rates now).
|
|
86
86
|
|
|
87
87
|
### System (`/system`)
|
|
88
88
|
The machine Rev4a runs on. Three cards — CPU (percent, cores, load average), memory (used, available, swap) and storage (each disk with its used and free space, and whether it is the system disk, where Docker keeps agents, or where Rev4a keeps its data) — then charts of CPU, memory and each disk over 1 hour, 24 hours, 7 days or 30 days (for CPU and memory the average line with the peak shaded). Hover a chart (or focus it and use the arrow keys) to read a point; each chart has a Table view. Bars turn yellow and red when they reach their thresholds. Figures refresh every 30 seconds; history is kept 30 days.
|
|
89
89
|
|
|
90
|
+
### Agents and containers (on the System page)
|
|
91
|
+
Under the machine's charts: what Docker holds on disk (images, volumes, writable layers, build cache, and how much of each no container uses), then one row per container sorted by CPU. A closed row shows its name, whether it is an agent, and its CPU share, memory, storage and processes now, with the average and peak over the chosen range (1 hour to 30 days); open it for the same three charts as the machine — CPU, Memory, Storage — for that container. "Everything else" is what is not a container (the host, Rev4a, other software). Each agent's panel on the Agents page has the same numbers in its RESOURCES section, with a link to its charts. Below, the machine's recent alerts: CPU, memory or a disk that crossed its limit, and when.
|
|
92
|
+
When Docker still sees a container but it has no current statistics, its row says "no data". If collection stops, the current figures are hidden and old rows say "not current" instead of implying a live reading.
|
|
93
|
+
|
|
90
94
|
### Container Terminal (`/containers/terminal/[id]`)
|
|
91
95
|
Live web terminal into a running Docker container — like SSH in the browser: Tab completion, command history, `top`, `vi`, resizing with the window. If the connection drops (network, laptop sleep) the shell keeps running for 2 minutes and reconnecting picks it up; reloading the page resumes it too. **Close** ends the shell. If the container is stopped or missing, the page says so and offers **Reconnect**. Only a logged-in user can open it.
|
|
92
96
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# What PULSE Can Answer
|
|
2
2
|
|
|
3
|
-
> **Last updated:** 2026-
|
|
3
|
+
> **Last updated:** 2026-10-01
|
|
4
4
|
|
|
5
5
|
PULSE is the in-dashboard AI concierge for Rev4a. This document defines what she can and cannot answer.
|
|
6
6
|
|
|
@@ -11,6 +11,9 @@ PULSE is the in-dashboard AI concierge for Rev4a. This document defines what she
|
|
|
11
11
|
- "Where do I find the agents page?"
|
|
12
12
|
- "How do I get to the container list?"
|
|
13
13
|
- "Where do I see CPU, RAM or disk usage of the server?" — The System page (`/system`), and the Machine card on the Dashboard.
|
|
14
|
+
- "Which agent is using the most CPU or memory?" — The "Agents and containers" section of the System page: one row per container, sorted by CPU, with memory, storage and processes; open a row for its charts. An agent's own panel has the same numbers under RESOURCES.
|
|
15
|
+
- "What is filling the disk?" — The "Docker storage" block on the System page: images, volumes (an unused volume is named), writable layers and build cache.
|
|
16
|
+
- "Why is there a red bar or an alert on the System page?" — "Recent alerts" at the bottom of the System page lists what crossed its limit and when.
|
|
14
17
|
- "Where can I see the first-run wizard?"
|
|
15
18
|
- "Is there a page for cron jobs?"
|
|
16
19
|
- "Where can I see my AI providers?" — The Gateway page (`/gateway`) shows providers and the model catalogue. Which model an agent runs is on the Agents page, in that agent's detail panel.
|