Skip to content

Commit 3d4a8e0

Browse files
authored
Merge pull request #169 from Routstr/dev
## Routstr v0.1.3 — 2025-09-15 ### Highlights - **DB-backed settings with live updates**: Env vars seed on first run; DB is the source of truth (except `DATABASE_URL`). Manage via Admin UI or `PATCH /admin/api/settings`. - **Models moved to database** with background sats-pricing computation and optional periodic refresh. - **Smarter max-cost reservation**: Discount based on prompt tokens and `max_tokens` using `TOLERANCE_PERCENTAGE`, with a `MIN_REQUEST_MSAT` floor. - **Faster startup and provider discovery**; `.onion` endpoints use Tor proxy by default. ### Breaking changes - **Configuration is DB-first** after bootstrap. Env changes won’t auto-apply (besides `DATABASE_URL`). - **Models endpoint**: Use `/v1/models` for canonical model info; `/v1/info` keeps an empty `models` field for back-compat. - **Legacy pricing envs** are auto-mapped but deprecated: - `MODEL_BASED_PRICING` → `!FIXED_PRICING` - `COST_PER_REQUEST` → `FIXED_COST_PER_REQUEST` - `COST_PER_1K_*` → `FIXED_PER_1K_*` ### Added - **SettingsService** with env→computed→DB merge; runtime edits; app metadata (name/description) applied to OpenAPI. - **Automatic migrations** on startup; new tables: `settings`, `models`. - **Per-model sats pricing** and per-request maximums computed in the background. - **Pricing controls**: `FIXED_PRICING`, `FIXED_COST_PER_REQUEST`, optional per-1k token overrides, `MIN_REQUEST_MSAT`. - **Azure chat support**: Optional `CHAT_COMPLETIONS_API_VERSION` adds `api-version` to `/chat/completions`. - **Derive `NPUB` from `NSEC`** during bootstrap if not provided. ### Changed / Improvements - **Proxy header hardening**: Strip sensitive headers; replace Authorization with upstream key when configured. - **Discovery**: Read `RELAYS` from settings; Tor proxy defaults for `.onion` via `TOR_PROXY_URL`; faster announcement fetching. - **Admin**: Improved auth/log UX; fixed log search; show mint balances in dashboard. - **Performance**: Optimized startup; lazy DB info loading. ### Fixed - **Refunds**: Correct msat→sat conversion; configurable refund cache TTL via `REFUND_CACHE_TTL_SECONDS`; better error mapping for mint outages. - **Balances**: Reserved balance reporting and negative-reserved edge cases. - **Tests**: Updated to patch settings and use fixed-pricing flags. ### Upgrade notes (from v0.1.2) 1. Ensure `DATABASE_URL`, `UPSTREAM_BASE_URL`, and `ADMIN_PASSWORD` are set. Optionally set `UPSTREAM_API_KEY`, `RELAYS`, `CASHU_MINTS`, `TOR_PROXY_URL`. 2. Start the service; automatic Alembic migrations will run (`settings`, `models` tables). 3. Configure settings via Admin UI (`/admin`) or `PATCH /admin/api/settings`. Env changes after first run won’t apply automatically. 4. Prefer new pricing envs or a `models.json` at `MODELS_PATH`. Legacy envs are mapped but will be removed in a future release. 5. Optional tuning: `TOLERANCE_PERCENTAGE`, `MIN_REQUEST_MSAT`, `PRICING_REFRESH_INTERVAL_SECONDS`, `MODELS_REFRESH_INTERVAL_SECONDS`, `ENABLE_*_REFRESH`. 6. For Azure, set `CHAT_COMPLETIONS_API_VERSION`. ### References - Configuration: `docs/getting-started/configuration.md` - API: `docs/api/endpoints.md` - Custom pricing: `docs/advanced/custom-pricing.md` ### Stats and credits - 42 files changed, +1819/−832 lines. - Merges: #170 token-discount-max-cost, #171 move-models-to-db. - Contributors: Shroominic.
2 parents 54fe4e2 + 8b9d53b commit 3d4a8e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1820
-829
lines changed

.env.example

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,39 @@
11
# Core Configuration
22
UPSTREAM_BASE_URL=https://api.openai.com/v1
33
UPSTREAM_API_KEY=your-upstream-api-key
4-
ADMIN_PASSWORD=secure-admin-password
4+
5+
# ADMIN_PASSWORD=secure-admin-password
56

67
# Database
7-
DATABASE_URL=sqlite+aiosqlite:///keys.db
8+
# DATABASE_URL=sqlite+aiosqlite:///keys.db
89

910
# Node Information
10-
NAME=My Routstr Node
11-
DESCRIPTION=Fast AI API access with Bitcoin payments
12-
NPUB=npub1...
13-
HTTP_URL=https://api.mynode.com
14-
ONION_URL=http://mynode.onion
15-
16-
# Cashu Configuration
17-
CASHU_MINTS=https://mint.minibits.cash/Bitcoin
18-
RECEIVE_LN_ADDRESS=
19-
20-
# Pricing Configuration
21-
MODEL_BASED_PRICING=true
22-
COST_PER_REQUEST=1
23-
COST_PER_1K_INPUT_TOKENS=0
24-
COST_PER_1K_OUTPUT_TOKENS=0
25-
EXCHANGE_FEE=1.005
26-
UPSTREAM_PROVIDER_FEE=1.05
11+
# NAME=My Routstr Node
12+
# DESCRIPTION=Fast AI API access with Bitcoin payments
13+
# NSEC=nsec1...
14+
# HTTP_URL=https://api.mynode.com
15+
# ONION_URL=http://mynode.onion (auto fetched from compose)
16+
# RELAYS="wss://relay.damus.io,wss://relay.nostr.band,wss://eden.nostr.land,wss://relay.routstr.com"
17+
# CASHU_MINTS="https://mint.minibits.cash/Bitcoin,https://mint.cubabitcoin.org,https://ecashmint.otrta.me"
18+
# RECEIVE_LN_ADDRESS=
19+
20+
# Custom Pricing Configuration
21+
# MODEL_BASED_PRICING=true
22+
# COST_PER_REQUEST=1
23+
# COST_PER_1K_INPUT_TOKENS=0
24+
# COST_PER_1K_OUTPUT_TOKENS=0
25+
# EXCHANGE_FEE=1.005
26+
# UPSTREAM_PROVIDER_FEE=1.05
2727

2828
# Network Configuration
29-
CORS_ORIGINS=*
30-
TOR_PROXY_URL=socks5://127.0.0.1:9050
29+
# CORS_ORIGINS=*
30+
# TOR_PROXY_URL=socks5://127.0.0.1:9050
3131

3232
# Logging
33-
LOG_LEVEL=INFO
34-
ENABLE_CONSOLE_LOGGING=true
35-
36-
# Model Management
37-
MODELS_PATH=models.json
38-
BASE_URL=https://openrouter.ai/api/v1
39-
SOURCE=
33+
# LOG_LEVEL=INFO
34+
# ENABLE_CONSOLE_LOGGING=true
4035

41-
# Optional Features
42-
PREPAID_API_KEY=
43-
PREPAID_BALANCE=0
36+
# Custom Model Management
37+
# BASE_URL=https://openrouter.ai/api/v1
38+
# MODELS_PATH=models.json
39+
# SOURCE=

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ The most common settings are shown below. See `.env.example` for the full list.
9191

9292
- `UPSTREAM_BASE_URL` – URL of the OpenAI-compatible service
9393
- `UPSTREAM_API_KEY` – API key for the upstream service (optional)
94-
- `MODEL_BASED_PRICING` – Set to `true` to use pricing from `models.json`
94+
- `FIXED_PRICING` – Set to `true` to use a fixed per-request price; `false` (default) uses model pricing from `models.json`
9595
- `ADMIN_PASSWORD` – Password for the `/admin/` dashboard
9696
- `CASHU_MINTS` – Comma-separated list of Cashu mint URLs
9797
- `NAME` – Name of the proxy

compose.testing.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ services:
1919
- "ONION_URL=http://test.onion"
2020
- "CORS_ORIGINS=*"
2121
22-
- "COST_PER_REQUEST=10"
23-
- "COST_PER_1K_INPUT_TOKENS=0"
24-
- "COST_PER_1K_OUTPUT_TOKENS=0"
25-
- "MODEL_BASED_PRICING=true"
22+
- "FIXED_COST_PER_REQUEST=10"
23+
- "FIXED_PER_1K_INPUT_TOKENS=0"
24+
- "FIXED_PER_1K_OUTPUT_TOKENS=0"
25+
- "FIXED_PRICING=false"
2626
- "NSEC=nsec1testkey1234567890abcdef"
2727
- "REFUND_PROCESSING_INTERVAL=3600"
2828
- "MINIMUM_PAYOUT=1000"

compose.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: '3.8'
2-
31
services:
42
routstr:
53
build: .
@@ -26,12 +24,5 @@ services:
2624
depends_on:
2725
- routstr
2826

29-
# Legacy service definition to ensure cleanup of old container
30-
router:
31-
image: alpine:latest
32-
command: /bin/true
33-
profiles:
34-
- cleanup
35-
3627
volumes:
3728
tor-data:

docs/advanced/custom-pricing.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ Routstr supports three pricing models:
1414

1515
### Configuration
1616

17-
Enable model-based pricing:
17+
Enable model-based pricing (default behavior):
1818

1919
```bash
2020
# .env
21-
MODEL_BASED_PRICING=true
21+
FIXED_PRICING=false
2222
MODELS_PATH=/app/config/models.json
2323
EXCHANGE_FEE=1.005 # 0.5% exchange fee
2424
UPSTREAM_PROVIDER_FEE=1.05 # 5% provider margin
@@ -118,14 +118,14 @@ if __name__ == "__main__":
118118

119119
### Configuration
120120

121-
Set up token-based pricing:
121+
Set up token-based pricing overrides:
122122

123123
```bash
124124
# .env
125-
MODEL_BASED_PRICING=false
126-
COST_PER_REQUEST=1 # 1 sat base fee
127-
COST_PER_1K_INPUT_TOKENS=5 # 5 sats per 1K input
128-
COST_PER_1K_OUTPUT_TOKENS=15 # 15 sats per 1K output
125+
FIXED_PRICING=false # use model pricing
126+
FIXED_COST_PER_REQUEST=1 # optional base fee
127+
FIXED_PER_1K_INPUT_TOKENS=5 # optional override
128+
FIXED_PER_1K_OUTPUT_TOKENS=15 # optional override
129129
```
130130

131131
### Custom Token Counting

docs/advanced/nostr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Configure which relays to publish to:
102102
DEFAULT_RELAYS = [
103103
"wss://relay.damus.io",
104104
"wss://relay.nostr.band",
105-
"wss://nostr.mom",
105+
"wss://relay.routstr.com",
106106
"wss://nos.lol"
107107
]
108108

docs/api/endpoints.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,27 @@ Authorization: Bearer sk-...
436436

437437
## Provider Discovery
438438

439+
## Admin Settings
440+
441+
These endpoints are protected by the Admin cookie (`admin_password` set to your configured admin password).
442+
443+
### Get Settings
444+
445+
```http
446+
GET /admin/api/settings
447+
```
448+
449+
Returns the current application settings (sensitive values may be redacted).
450+
451+
### Update Settings
452+
453+
```http
454+
PATCH /admin/api/settings
455+
Content-Type: application/json
456+
```
457+
458+
Body is a partial JSON of settings fields to update. Validated and persisted to the database.
459+
439460
### List Providers
440461

441462
Get available upstream providers.

docs/api/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ GET /health
347347
Response:
348348
{
349349
"status": "healthy",
350-
"version": "0.1.2",
350+
"version": "0.1.3",
351351
"timestamp": "2024-01-01T00:00:00Z",
352352
"checks": {
353353
"database": "ok",

docs/contributing/code-structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ Project metadata and dependencies:
348348
```toml
349349
[project]
350350
name = "routstr"
351-
version = "0.1.2"
351+
version = "0.1.3"
352352
dependencies = [
353353
"fastapi[standard]>=0.115",
354354
"sqlmodel>=0.0.24",

docs/getting-started/configuration.md

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Configuration
22

3-
Routstr Core is configured through environment variables. This guide covers all available options.
3+
Routstr Core is configured via a single settings row in the database. Environment variables are only used on first run to seed that row (with a few computed defaults like `ONION_URL`). After that, the database is the source of truth. You can update settings at runtime via the admin API. `DATABASE_URL` is always env-only.
44

55
## Environment Variables
66

@@ -33,19 +33,21 @@ Routstr Core is configured through environment variables. This guide covers all
3333

3434
| Variable | Description | Default | Required |
3535
|----------|-------------|---------|----------|
36-
| `MODEL_BASED_PRICING` | Enable model-specific pricing from models.json | `false` ||
37-
| `COST_PER_REQUEST` | Fixed cost per API request in sats | `1` ||
38-
| `COST_PER_1K_INPUT_TOKENS` | Cost per 1000 input tokens in sats | `0` ||
39-
| `COST_PER_1K_OUTPUT_TOKENS` | Cost per 1000 output tokens in sats | `0` ||
36+
| `FIXED_PRICING` | Force fixed per-request pricing (ignore model token pricing) | `false` ||
37+
| `FIXED_COST_PER_REQUEST` | Fixed cost per API request in sats | `1` ||
38+
| `FIXED_PER_1K_INPUT_TOKENS` | Optional override: sats per 1000 input tokens | `0` ||
39+
| `FIXED_PER_1K_OUTPUT_TOKENS` | Optional override: sats per 1000 output tokens | `0` ||
4040
| `EXCHANGE_FEE` | Exchange rate markup (1.005 = 0.5% fee) | `1.005` ||
4141
| `UPSTREAM_PROVIDER_FEE` | Provider fee markup (1.05 = 5% fee) | `1.05` ||
4242

43-
### Network Configuration
43+
### Network & Discovery
4444

4545
| Variable | Description | Default | Required |
4646
|----------|-------------|---------|----------|
4747
| `CORS_ORIGINS` | Comma-separated list of allowed CORS origins | `*` ||
4848
| `TOR_PROXY_URL` | SOCKS5 proxy URL for Tor connections | `socks5://127.0.0.1:9050` ||
49+
| `RELAYS` | Comma-separated nostr relays used for provider discovery | sane defaults ||
50+
| `PROVIDERS_REFRESH_INTERVAL_SECONDS` | Provider cache refresh interval | `300` ||
4951

5052
### Logging Configuration
5153

@@ -60,6 +62,7 @@ Routstr Core is configured through environment variables. This guide covers all
6062
|----------|-------------|---------|----------|
6163
| `CHAT_COMPLETIONS_API_VERSION` | Append `api-version` to `/chat/completions` (Azure OpenAI) | - ||
6264
| `DATABASE_URL` | SQLite database connection string | `sqlite+aiosqlite:///keys.db` ||
65+
| `REFUND_CACHE_TTL_SECONDS` | Cache TTL for refund responses (seconds) | `3600` ||
6366

6467
## Configuration Examples
6568

@@ -78,7 +81,6 @@ ADMIN_PASSWORD=my-secure-password
7881
# .env
7982
UPSTREAM_BASE_URL=https://api.anthropic.com/v1
8083
UPSTREAM_API_KEY=your-anthropic-key
81-
MODEL_BASED_PRICING=true
8284
MODELS_PATH=/app/config/anthropic-models.json
8385
```
8486

@@ -115,36 +117,21 @@ ONION_URL=http://lightningai.onion
115117
CASHU_MINTS=https://mint1.com,https://mint2.com
116118
```
117119

118-
## Pricing Models
120+
## Pricing
119121

120-
### Fixed Pricing
122+
- Default: pricing comes from your `models.json`.
123+
- Force fixed per-request pricing: set `FIXED_PRICING=true` and `FIXED_COST_PER_REQUEST`.
124+
- Optional token overrides when using model pricing: set
125+
`FIXED_PER_1K_INPUT_TOKENS` and/or `FIXED_PER_1K_OUTPUT_TOKENS`.
126+
- Legacy envs are still accepted and mapped automatically:
127+
`MODEL_BASED_PRICING``!FIXED_PRICING`, `COST_PER_REQUEST``FIXED_COST_PER_REQUEST`,
128+
`COST_PER_1K_*``FIXED_PER_1K_*`.
121129

122-
Simple per-request pricing:
130+
Example fixed pricing:
123131

124132
```bash
125-
MODEL_BASED_PRICING=false
126-
COST_PER_REQUEST=10 # 10 sats per request
127-
```
128-
129-
### Token-Based Pricing
130-
131-
Charge based on token usage:
132-
133-
```bash
134-
MODEL_BASED_PRICING=false
135-
COST_PER_REQUEST=1 # 1 sat base fee
136-
COST_PER_1K_INPUT_TOKENS=5 # 5 sats per 1k input
137-
COST_PER_1K_OUTPUT_TOKENS=15 # 15 sats per 1k output
138-
```
139-
140-
### Model-Based Pricing
141-
142-
Use dynamic pricing from models.json:
143-
144-
```bash
145-
MODEL_BASED_PRICING=true
146-
EXCHANGE_FEE=1.01 # 1% exchange fee
147-
UPSTREAM_PROVIDER_FEE=1.00 # No additional markup
133+
FIXED_PRICING=true
134+
FIXED_COST_PER_REQUEST=10
148135
```
149136

150137
## Custom Models Configuration

0 commit comments

Comments
 (0)