Files
nanobot-runtime/plans/ollama-usage-poller.md

84 lines
4.0 KiB
Markdown

# Ollama Usage Poller — Continuous Collection
## Context
The `/usage` skill shows Ollama Cloud credit usage on demand. The user wants
continuous collection: poll `GET https://ollama.com/api/usage` every minute,
store a sample whenever anything changed since the last one. Goal: later
analysis of how much each nanobot session cost, and when.
Constraints found in exploration:
- The API (`ollama.com/api/usage`, Bearer key from `workspace/.env`) returns:
`limits.session.usage` (fraction of plan limit, rolling 1-hour window),
`limits.weekly.usage` (weekly window), per-model `request_count` for both
windows, `activity.cost` (broken, always $0.00000 on Pro).
- No reset timestamps, no per-model cost split, no token counts in the API.
- Existing pattern: per-minute system crontab entries running `uv run <script>`
with output to `workspace/log/<name>_cron.log` (remind, wiki-compile,
wiki-sync). Reuse this pattern.
- Session attribution later needs `memory/history.jsonl` (per-request
timestamps, token counts, session ids) — out of scope for this plan, this
plan only builds the collector + a delta report.
## Steps
1. **Collector**`scripts/ollama_usage_poll.py` (English, stdlib only,
reuse `load_api_key` from `skills/usage/scripts/ollama_usage.py`):
- GET the API, on network/HTTP error log to stderr and exit 0
(never noisy, never blocks cron).
- SQLite `db/ollama_usage.sqlite`, table `samples`:
```sql
CREATE TABLE IF NOT EXISTS samples (
ts TEXT PRIMARY KEY, -- UTC ISO 8601
session REAL NOT NULL, -- limits.session.usage fraction
weekly REAL NOT NULL, -- limits.weekly.usage fraction
models TEXT NOT NULL -- JSON: weekly {"model": count}
);
```
- Write-on-change: compare against the latest row; insert only when
session, weekly, or models JSON differ. Unchanged minutes are noise.
- Session-window reset detection (usage drops instead of rising) is
implicit — we store raw values; deltas are computed at report time.
2. **Crontab** — add system crontab entry (user's crontab, alongside the
existing ones):
```
# ollama-usage: continuous usage sampling into db/ollama_usage.sqlite
* * * * * uv run /home/nanobot/.nanobot/workspace/scripts/ollama_usage_poll.py >> /home/nanobot/.nanobot/workspace/log/ollama_usage_cron.log 2>&1
```
3. **Report** — `scripts/ollama_usage_report.py` (English, stdlib only):
- No args: last 24 h delta summary (session/weekly spend per hour, model
request deltas).
- `--since ISO` / `--until ISO`: arbitrary window.
- Output: plain text table — for each consecutive sample pair:
`ts, Δsession %, Δweekly %, Δrequests per model`. Detect hourly reset
(session drops) and mark it as a new window boundary.
- Extend the `/usage` skill SKILL.md with a "Reports" section pointing
at this script (does not change the on-demand output format).
4. **Skill update** — `skills/usage/SKILL.md`: add a short note that
continuous sampling runs via crontab into `db/ollama_usage.sqlite` and
reports are available via `scripts/ollama_usage_report.py`.
5. **Git commit** — workspace repo, timestamped message.
## Out of scope (later)
- Session-level attribution (join with `memory/history.jsonl` token counts
per session) — separate plan once we have a few days of samples.
- Notification thresholds (e.g. Telegram alert at 80 % weekly).
- Retention/compaction of the samples table (1 row per change, negligible
size for months).
## Verification
1. Run `uv run scripts/ollama_usage_poll.py` twice back to back → second run
writes nothing (no change), DB has 1 row.
2. Wait for a real request (or make one via nanobot) → next poll writes a
new row with changed session fraction / model counts.
3. Run the report script → delta table renders, hourly reset detected as
boundary when a session window rolls over.
4. `crontab -l` shows the new entry; after ~5 minutes `log/ollama_usage_cron.log`
is empty or minimal, DB grew.