mslxdff 0.1.43 → 0.1.54

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 CHANGED
@@ -1,162 +1,162 @@
1
- # mslxdff
2
-
3
- 测试项目,请勿使用。
4
-
5
- Zero runtime dependencies: Node ≥ 20, built-in `node:http`, `node:crypto`, `node:test`.
6
-
7
- ## What it does
8
-
9
- - `POST /v1/chat/completions` — forwards your OpenAI-format request to the upstream (with reasoning-content injection for thinking-mode DeepSeek/Kimi models), streams SSE back chunk-by-chunk, or passes through JSON for non-streaming calls.
10
- - `GET /v1/models` — the ~7 free models (`*-free` plus `big-pickle`), filtered from the full upstream list, cached and refreshed in the background every 2 hours.
11
- - `GET /health` — public liveness check.
12
-
13
- ### `auto` model
14
-
15
- Omitting `model` (or passing `"auto"`) picks a free model automatically, DeepSeek first. On an upstream error the next candidate is tried in the same request; each model's last-error timestamp is recorded (persisted in the state file) so the most reliably-available model is preferred next time.
16
-
17
- ### Fallback for a specific model
18
-
19
- Pointing at a specific model (e.g. `deepseek-v4-flash-free`) still gets failover: if that model errors, the request automatically falls through to the next free model so your task isn't interrupted, and the error is recorded. The model enters a cooldown window (default 60s, `MSLXDFF_MODEL_COOLDOWN_MS`); during cooldown the backup models are used directly, and afterwards your model is tried again — once it succeeds it keeps being used until it errors again.
20
-
21
- ## Install & run
22
-
23
- ```
24
- npm install # no deps actually fetched; just links the bin
25
- mslxdff # or: node bin/mslxdff.js
26
- ```
27
-
28
- First run generates a bearer token, writes it to the state file, and prints it:
29
-
30
- ```
31
- mslxdff listening on http://localhost:8989
32
- auth token: 9b5de021e914...
33
- endpoint: http://localhost:8989/v1
34
- ```
35
-
36
- ### Port
37
-
38
- Default port is **8989**. Persist a different port (and hot-restart the daemon onto it if one is running):
39
-
40
- ```
41
- mslxdff -port 8000 # set port to 8000; restarts the daemon on 8000
42
- mslxdff -d # next starts reuse the persisted port (8000)
43
- ```
44
-
45
- Priority: `-port` arg > persisted port > `PORT` env > default `8989`.
46
-
47
- ### Daemon (background, stays resident)
48
-
49
- Just run `mslxdff` (no args): if no daemon is running yet, it **starts a background
50
- daemon and exits** — the command never holds your terminal, so `npx mslxdff` works
51
- the same way. If a daemon is already up, the bare command shows status + help.
52
-
53
- ```
54
- mslxdff # starts the background daemon (if none running); exits immediately
55
- mslxdff -d # same, explicit
56
- mslxdff -stop # stop it
57
- ```
58
-
59
- Logs go to `~/.config/mslxdff/daemon.log`, the daemon pid to `daemon.pid` (both overridable via `MSLXDFF_DAEMON_DIR`). The daemon keeps running after your shell exits.
60
-
61
- ### Status
62
-
63
- Running `mslxdff` with no args shows a status panel when a daemon is already up: joined groups with their members, failover targets, the free model list, the last 5 calls (model/status/latency), and the most recent error (`mslxdff -status` for status only, `mslxdff -help` for the full command reference). Call and error history are stored as JSON-lines at `calls.log` / `errors.log` in the state dir.
64
-
65
- ```
66
- $ mslxdff -status
67
- mslxdff v0.1.2
68
- daemon: running (pid 12345)
69
- endpoint: http://localhost:8989/v1
70
- log dir: C:/Users/you/.config/mslxdff
71
-
72
- models (7 free):
73
- big-pickle
74
- deepseek-v4-flash-free
75
- ...
76
-
77
- recent calls:
78
- 08-03 12:00:03 deepseek-v4-flash-free 200 812ms
79
- ...
80
-
81
- last error:
82
- 08-03 11:59:58 deepseek-v4-flash-free 429 upstream 429
83
- ```
84
-
85
- ### Update
86
-
87
- ```
88
- mslxdff -update # install the latest published version; restarts a running daemon
89
- ```
90
-
91
- ### Groups (join several machines by name)
92
-
93
- Run mslxdff on several machines (e.g. locally + a VPS) and join them into a named group — **the group name is the password**. When the local upstream fails for a model, the request is forwarded to a group member running the **same model** — your task keeps the model it asked for, just served from another machine with its own upstream quota.
94
-
95
- ```
96
- # on the leader machine B (must be reachable from the others):
97
- mslxdff -creategroup mygroup # group name IS the password, no address needed
98
-
99
- # on machine A (and C, D, …) — give the leader's host; your own address is auto-registered:
100
- mslxdff -addtogroup <B-ip> mygroup
101
- ```
102
-
103
- - Anyone who knows the group name can join — pick something unguessable, like `mygroup@mslxd-7f3k`. The leader's first joiner seeds the leader's own entry from the address it connects from, so `-creategroup` takes no address argument (default port 8989; `-addtogroup` also accepts `host:port`).
104
- - Joining registers your node with the leader (membership is keyed by your bearer token) and immediately pulls the member list into local failover targets.
105
- - Membership is persisted and re-synced on every start + every `MSLXDFF_GROUP_SYNC_MS` (default 60s), so a newly joined machine becomes a failover target on all nodes automatically.
106
- - Local-first: every request tries the local upstream before any group member. On local failure, members are tried round-robin for the same model; a member that just failed is skipped for `MSLXDFF_PEER_COOLDOWN_MS` (default 30s).
107
- - Forwarded requests carry a hop limit (`MSLXDFF_MAX_HOPS`, default 3) to prevent forwarding loops, and a model-lock so the member doesn't switch models. A→B→C chaining works as long as each member knows the others.
108
- - Wrong group names (or wrong tokens) are counted per source IP: `MSLXDFF_BAN_THRESHOLD` (default 5) failures ban the IP for `MSLXDFF_BAN_WINDOW_MS` (default 48h). `mslxdff -resetban [ip]` clears bans (all, or one IP).
109
- - `mslxdff -group sync` pulls once manually; `mslxdff -group leave <name>` detaches from a group and clears its members; `mslxdff -group list` shows groups. See `docs/adr/0005-peer-mesh.md`.
110
-
111
- ```
112
- mslxdff -showtoken # print the current token (creates one on first use)
113
- mslxdff -refresh-token # rotate it (prints the new token, does not start the server)
114
- ```
115
-
116
- ## Client configuration
117
-
118
- Point any OpenAI-compatible client at the endpoint with the token:
119
-
120
- ```
121
- Endpoint: http://localhost:8989/v1
122
- API Key: <the bearer token> (sent as Authorization: Bearer <token>)
123
- Model: oc/deepseek-v4-flash-free (the oc/ prefix is optional)
124
- ```
125
-
126
- <x-model list>
127
-
128
- ```
129
- $ curl -H "Authorization: Bearer <token>" http://localhost:8989/v1/models
130
- {"object":"list","data":[{"id":"big-pickle",...},{"id":"deepseek-v4-flash-free",...}, ...]}
131
- </x-model list>
132
-
133
- ## Environment variables
134
-
135
- | Variable | Default | Purpose |
136
- |---|---|---|
137
- | `PORT` | `8989` | listen port (used when no `-port` arg and no persisted port) |
138
- | `MSLXDFF_STATE_FILE` | `~/.config/mslxdff/state.json` | token/port state file (mode 0600) |
139
- | `MSLXDFF_DAEMON_DIR` | `~/.config/mslxdff` | daemon pid + log directory |
140
- | `UPSTREAM_BASE_URL` | `https://opencode.ai` | upstream base |
141
- | `UPSTREAM_AUTH_TOKEN` | `public` | upstream `Authorization: Bearer <…>` value |
142
- | `UPSTREAM_CONNECT_TIMEOUT_MS` | `30000` | upstream connect timeout |
143
- | `LOG_LEVEL` | `info` | (reserved) |
144
- | `MODELS_REFRESH_MS` | `7200000` | background model-list refresh interval (2h) |
145
- | `MSLXDFF_MODEL_COOLDOWN_MS` | `60000` | fallback cooldown after a model error |
146
- | `MSLXDFF_PEER_COOLDOWN_MS` | `30000` | peer failover cooldown |
147
- | `MSLXDFF_GROUP_SYNC_MS` | `60000` | group membership sync interval |
148
- | `MSLXDFF_MAX_HOPS` | `3` | max peer-forwarding depth |
149
- | `MSLXDFF_BAN_THRESHOLD` | `5` | failed joins before an IP is banned |
150
- | `MSLXDFF_BAN_WINDOW_MS` | `172800000` | ban duration after too many join failures (48h) |
151
-
152
- ## Clients
153
-
154
- Point your OpenAI client at `http://<host>:8989/v1` (or the equivalent config seen above). Works for streaming and non-streaming chat completions.
155
-
156
- ## Development
157
-
158
- ```
159
- npm test # node --test, no network access
160
- ```
161
-
162
- The reference implementation is 9Router v0.5.45 (`/root/9router`); see `CLAUDE.md`, `CONTEXT.md`, and `docs/adr/` for the contract and the decisions behind it.
1
+ # mslxdff
2
+
3
+ 测试项目,请勿使用。
4
+
5
+ Zero runtime dependencies: Node ≥ 20, built-in `node:http`, `node:crypto`, `node:test`.
6
+
7
+ ## What it does
8
+
9
+ - `POST /v1/chat/completions` — forwards your OpenAI-format request to the upstream (with reasoning-content injection for thinking-mode DeepSeek/Kimi models), streams SSE back chunk-by-chunk, or passes through JSON for non-streaming calls.
10
+ - `GET /v1/models` — the ~7 free models (`*-free` plus `big-pickle`), filtered from the full upstream list, cached and refreshed in the background every 2 hours.
11
+ - `GET /health` — public liveness check.
12
+
13
+ ### `auto` model
14
+
15
+ Omitting `model` (or passing `"auto"`) picks a free model automatically, DeepSeek first. On an upstream error the next candidate is tried in the same request; each model's last-error timestamp is recorded (persisted in the state file) so the most reliably-available model is preferred next time.
16
+
17
+ ### Fallback for a specific model
18
+
19
+ Pointing at a specific model (e.g. `deepseek-v4-flash-free`) still gets failover: if that model errors, the request automatically falls through to the next free model so your task isn't interrupted, and the error is recorded. The model enters a cooldown window (default 60s, `MSLXDFF_MODEL_COOLDOWN_MS`); during cooldown the backup models are used directly, and afterwards your model is tried again — once it succeeds it keeps being used until it errors again.
20
+
21
+ ## Install & run
22
+
23
+ ```
24
+ npm install # no deps actually fetched; just links the bin
25
+ mslxdff # or: node bin/mslxdff.js
26
+ ```
27
+
28
+ First run generates a bearer token, writes it to the state file, and prints it:
29
+
30
+ ```
31
+ mslxdff listening on http://localhost:8989
32
+ auth token: 9b5de021e914...
33
+ endpoint: http://localhost:8989/v1
34
+ ```
35
+
36
+ ### Port
37
+
38
+ Default port is **8989**. Persist a different port (and hot-restart the daemon onto it if one is running):
39
+
40
+ ```
41
+ mslxdff -port 8000 # set port to 8000; restarts the daemon on 8000
42
+ mslxdff -d # next starts reuse the persisted port (8000)
43
+ ```
44
+
45
+ Priority: `-port` arg > persisted port > `PORT` env > default `8989`.
46
+
47
+ ### Daemon (background, stays resident)
48
+
49
+ Just run `mslxdff` (no args): if no daemon is running yet, it **starts a background
50
+ daemon and exits** — the command never holds your terminal, so `npx mslxdff` works
51
+ the same way. If a daemon is already up, the bare command shows status + help.
52
+
53
+ ```
54
+ mslxdff # starts the background daemon (if none running); exits immediately
55
+ mslxdff -d # same, explicit
56
+ mslxdff -stop # stop it
57
+ ```
58
+
59
+ Logs go to `~/.config/mslxdff/daemon.log`, the daemon pid to `daemon.pid` (both overridable via `MSLXDFF_DAEMON_DIR`). The daemon keeps running after your shell exits.
60
+
61
+ ### Status
62
+
63
+ Running `mslxdff` with no args shows a status panel when a daemon is already up: joined groups with their members, failover targets, the free model list, the last 5 calls (model/status/latency), and the most recent error (`mslxdff -status` for status only, `mslxdff -help` for the full command reference). Call and error history are stored as JSON-lines at `calls.log` / `errors.log` in the state dir.
64
+
65
+ ```
66
+ $ mslxdff -status
67
+ mslxdff v0.1.2
68
+ daemon: running (pid 12345)
69
+ endpoint: http://localhost:8989/v1
70
+ log dir: C:/Users/you/.config/mslxdff
71
+
72
+ models (7 free):
73
+ big-pickle
74
+ deepseek-v4-flash-free
75
+ ...
76
+
77
+ recent calls:
78
+ 08-03 12:00:03 deepseek-v4-flash-free 200 812ms
79
+ ...
80
+
81
+ last error:
82
+ 08-03 11:59:58 deepseek-v4-flash-free 429 upstream 429
83
+ ```
84
+
85
+ ### Update
86
+
87
+ ```
88
+ mslxdff -update # install the latest published version; restarts a running daemon
89
+ ```
90
+
91
+ ### Groups (join several machines by name)
92
+
93
+ Run mslxdff on several machines (e.g. locally + a VPS) and join them into a named group — **the group name is the password**. When the local upstream fails for a model, the request is forwarded to a group member running the **same model** — your task keeps the model it asked for, just served from another machine with its own upstream quota.
94
+
95
+ ```
96
+ # on the leader machine B (must be reachable from the others):
97
+ mslxdff -creategroup mygroup # group name IS the password, no address needed
98
+
99
+ # on machine A (and C, D, …) — give the leader's host; your own address is auto-registered:
100
+ mslxdff -addtogroup <B-ip> mygroup
101
+ ```
102
+
103
+ - Anyone who knows the group name can join — pick something unguessable, like `mygroup@mslxd-7f3k`. The leader's first joiner seeds the leader's own entry from the address it connects from, so `-creategroup` takes no address argument (default port 8989; `-addtogroup` also accepts `host:port`).
104
+ - Joining registers your node with the leader (membership is keyed by your bearer token) and immediately pulls the member list into local failover targets.
105
+ - Membership is persisted and re-synced on every start + every `MSLXDFF_GROUP_SYNC_MS` (default 60s), so a newly joined machine becomes a failover target on all nodes automatically.
106
+ - Local-first: every request tries the local upstream before any group member. On local failure, members are tried round-robin for the same model; a member that just failed is skipped for `MSLXDFF_PEER_COOLDOWN_MS` (default 30s).
107
+ - Forwarded requests carry a hop limit (`MSLXDFF_MAX_HOPS`, default 3) to prevent forwarding loops, and a model-lock so the member doesn't switch models. A→B→C chaining works as long as each member knows the others.
108
+ - Wrong group names (or wrong tokens) are counted per source IP: `MSLXDFF_BAN_THRESHOLD` (default 5) failures ban the IP for `MSLXDFF_BAN_WINDOW_MS` (default 48h). `mslxdff -resetban [ip]` clears bans (all, or one IP).
109
+ - `mslxdff -group sync` pulls once manually; `mslxdff -group leave <name>` detaches from a group and clears its members; `mslxdff -group list` shows groups. See `docs/adr/0005-peer-mesh.md`.
110
+
111
+ ```
112
+ mslxdff -showtoken # print the current token (creates one on first use)
113
+ mslxdff -refresh-token # rotate it (prints the new token, does not start the server)
114
+ ```
115
+
116
+ ## Client configuration
117
+
118
+ Point any OpenAI-compatible client at the endpoint with the token:
119
+
120
+ ```
121
+ Endpoint: http://localhost:8989/v1
122
+ API Key: <the bearer token> (sent as Authorization: Bearer <token>)
123
+ Model: oc/deepseek-v4-flash-free (the oc/ prefix is optional)
124
+ ```
125
+
126
+ <x-model list>
127
+
128
+ ```
129
+ $ curl -H "Authorization: Bearer <token>" http://localhost:8989/v1/models
130
+ {"object":"list","data":[{"id":"big-pickle",...},{"id":"deepseek-v4-flash-free",...}, ...]}
131
+ </x-model list>
132
+
133
+ ## Environment variables
134
+
135
+ | Variable | Default | Purpose |
136
+ |---|---|---|
137
+ | `PORT` | `8989` | listen port (used when no `-port` arg and no persisted port) |
138
+ | `MSLXDFF_STATE_FILE` | `~/.config/mslxdff/state.json` | token/port state file (mode 0600) |
139
+ | `MSLXDFF_DAEMON_DIR` | `~/.config/mslxdff` | daemon pid + log directory |
140
+ | `UPSTREAM_BASE_URL` | `https://opencode.ai` | upstream base |
141
+ | `UPSTREAM_AUTH_TOKEN` | `public` | upstream `Authorization: Bearer <…>` value |
142
+ | `UPSTREAM_CONNECT_TIMEOUT_MS` | `30000` | upstream connect timeout |
143
+ | `LOG_LEVEL` | `info` | (reserved) |
144
+ | `MODELS_REFRESH_MS` | `7200000` | background model-list refresh interval (2h) |
145
+ | `MSLXDFF_MODEL_COOLDOWN_MS` | `60000` | fallback cooldown after a model error |
146
+ | `MSLXDFF_PEER_COOLDOWN_MS` | `30000` | peer failover cooldown |
147
+ | `MSLXDFF_GROUP_SYNC_MS` | `60000` | group membership sync interval |
148
+ | `MSLXDFF_MAX_HOPS` | `3` | max peer-forwarding depth |
149
+ | `MSLXDFF_BAN_THRESHOLD` | `5` | failed joins before an IP is banned |
150
+ | `MSLXDFF_BAN_WINDOW_MS` | `172800000` | ban duration after too many join failures (48h) |
151
+
152
+ ## Clients
153
+
154
+ Point your OpenAI client at `http://<host>:8989/v1` (or the equivalent config seen above). Works for streaming and non-streaming chat completions.
155
+
156
+ ## Development
157
+
158
+ ```
159
+ npm test # node --test, no network access
160
+ ```
161
+
162
+ The reference implementation is 9Router v0.5.45 (`/root/9router`); see `CLAUDE.md`, `CONTEXT.md`, and `docs/adr/` for the contract and the decisions behind it.