@mlx-node/server 0.0.7 → 0.0.9
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/dist/auth.d.ts +56 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +106 -0
- package/dist/chat-session-warm-reuse.d.ts +51 -0
- package/dist/chat-session-warm-reuse.d.ts.map +1 -0
- package/dist/chat-session-warm-reuse.js +72 -0
- package/dist/endpoints/messages-count-tokens.d.ts +8 -0
- package/dist/endpoints/messages-count-tokens.d.ts.map +1 -0
- package/dist/endpoints/messages-count-tokens.js +121 -0
- package/dist/endpoints/messages.d.ts +57 -5
- package/dist/endpoints/messages.d.ts.map +1 -1
- package/dist/endpoints/messages.js +1043 -147
- package/dist/endpoints/models.d.ts +2 -1
- package/dist/endpoints/models.d.ts.map +1 -1
- package/dist/endpoints/models.js +2 -2
- package/dist/endpoints/responses.d.ts +22 -7
- package/dist/endpoints/responses.d.ts.map +1 -1
- package/dist/endpoints/responses.js +608 -85
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/handler.d.ts +69 -1
- package/dist/handler.d.ts.map +1 -1
- package/dist/handler.js +70 -16
- package/dist/health.d.ts +146 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +107 -0
- package/dist/host/discover.d.ts +19 -0
- package/dist/host/discover.d.ts.map +1 -0
- package/dist/host/discover.js +50 -0
- package/dist/host/env-policy.d.ts +62 -0
- package/dist/host/env-policy.d.ts.map +1 -0
- package/dist/host/env-policy.js +69 -0
- package/dist/host/index.d.ts +202 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +325 -0
- package/dist/host/logger.d.ts +36 -0
- package/dist/host/logger.d.ts.map +1 -0
- package/dist/host/logger.js +376 -0
- package/dist/host/net.d.ts +65 -0
- package/dist/host/net.d.ts.map +1 -0
- package/dist/host/net.js +97 -0
- package/dist/host/paths.d.ts +28 -0
- package/dist/host/paths.d.ts.map +1 -0
- package/dist/host/paths.js +71 -0
- package/dist/host/swap.d.ts +27 -0
- package/dist/host/swap.d.ts.map +1 -0
- package/dist/host/swap.js +178 -0
- package/dist/host/temp-root.d.ts +57 -0
- package/dist/host/temp-root.d.ts.map +1 -0
- package/dist/host/temp-root.js +99 -0
- package/dist/idle-sweeper.d.ts +245 -0
- package/dist/idle-sweeper.d.ts.map +1 -0
- package/dist/idle-sweeper.js +408 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/load-model.d.ts +69 -0
- package/dist/load-model.d.ts.map +1 -0
- package/dist/load-model.js +63 -0
- package/dist/mappers/anthropic-request.d.ts +24 -2
- package/dist/mappers/anthropic-request.d.ts.map +1 -1
- package/dist/mappers/anthropic-request.js +222 -24
- package/dist/mappers/anthropic-response.d.ts +29 -4
- package/dist/mappers/anthropic-response.d.ts.map +1 -1
- package/dist/mappers/anthropic-response.js +143 -21
- package/dist/mappers/request.d.ts +48 -0
- package/dist/mappers/request.d.ts.map +1 -1
- package/dist/mappers/request.js +211 -35
- package/dist/mappers/response.d.ts.map +1 -1
- package/dist/mappers/response.js +13 -1
- package/dist/model-work-coordinator.d.ts +95 -0
- package/dist/model-work-coordinator.d.ts.map +1 -0
- package/dist/model-work-coordinator.js +201 -0
- package/dist/pending-writes.d.ts.map +1 -1
- package/dist/presets.d.ts +82 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +98 -0
- package/dist/registry.d.ts +31 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +33 -5
- package/dist/router.d.ts +37 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +79 -7
- package/dist/server.d.ts +193 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +173 -10
- package/dist/session-registry.d.ts +279 -18
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +518 -37
- package/dist/stop-sequence-buffer.d.ts +58 -0
- package/dist/stop-sequence-buffer.d.ts.map +1 -0
- package/dist/stop-sequence-buffer.js +148 -0
- package/dist/streaming.d.ts +14 -0
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +45 -0
- package/dist/text-recovery.d.ts +35 -0
- package/dist/text-recovery.d.ts.map +1 -0
- package/dist/text-recovery.js +41 -0
- package/dist/timing.d.ts +80 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +121 -0
- package/dist/tool-call-buffer.d.ts +5 -5
- package/dist/tool-call-buffer.d.ts.map +1 -1
- package/dist/tool-call-buffer.js +28 -8
- package/dist/types-anthropic.d.ts +161 -1
- package/dist/types-anthropic.d.ts.map +1 -1
- package/dist/types.d.ts +172 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -3
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a thrown value for {@link ModelLoadRecord.error}.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately avoids `String(unknown)`: a rejection carrying a plain object
|
|
5
|
+
* would render as the useless `[object Object]` in the one field a supervisor
|
|
6
|
+
* reads to find out why the model would not load.
|
|
7
|
+
*/
|
|
8
|
+
function describeLoadFailure(error) {
|
|
9
|
+
if (error instanceof Error)
|
|
10
|
+
return error.message;
|
|
11
|
+
if (typeof error === 'string')
|
|
12
|
+
return error;
|
|
13
|
+
if (error == null)
|
|
14
|
+
return 'unknown error';
|
|
15
|
+
try {
|
|
16
|
+
return JSON.stringify(error) ?? 'unknown error';
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Circular structure, or a `toJSON` that throws.
|
|
20
|
+
return 'unknown error';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Process-local gate for native MLX work.
|
|
25
|
+
*
|
|
26
|
+
* Individual model instances already have a per-model execution mutex, but a
|
|
27
|
+
* lazy `loadModel()` can still run load-time materialization / warmup Metal
|
|
28
|
+
* work while another model is decoding. MLX's allocator and command queues are
|
|
29
|
+
* process-wide, so model load/swap takes an exclusive writer slot; inference
|
|
30
|
+
* takes shared reader slots.
|
|
31
|
+
*/
|
|
32
|
+
export class ModelWorkCoordinator {
|
|
33
|
+
activeReaders = 0;
|
|
34
|
+
writerHeld = false;
|
|
35
|
+
queuedWriters = 0;
|
|
36
|
+
readerWaiters = [];
|
|
37
|
+
writerWaiters = [];
|
|
38
|
+
/**
|
|
39
|
+
* Most recent settled load bracket. Retained here because the coordinator
|
|
40
|
+
* is the ONE place that brackets every load: a `resolveModel` failure in
|
|
41
|
+
* `/v1/messages` becomes a 500 and is otherwise dropped on the floor, so a
|
|
42
|
+
* supervisor polling `/health` afterwards had no way to learn what went
|
|
43
|
+
* wrong. See {@link ModelLoadRecord} for the "successful no-op overwrites
|
|
44
|
+
* an earlier failure" caveat.
|
|
45
|
+
*/
|
|
46
|
+
lastLoadRecord = null;
|
|
47
|
+
/** Read-only: `true` while a load holds the exclusive writer slot. */
|
|
48
|
+
get writerActive() {
|
|
49
|
+
return this.writerHeld;
|
|
50
|
+
}
|
|
51
|
+
/** Read-only: loads parked in `acquireWrite()` waiting for the slot. */
|
|
52
|
+
get waitingWriters() {
|
|
53
|
+
return this.queuedWriters;
|
|
54
|
+
}
|
|
55
|
+
/** Read-only: outcome of the most recent settled load bracket, or `null`. */
|
|
56
|
+
get lastLoad() {
|
|
57
|
+
return this.lastLoadRecord;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Record a settled bracket. Called from the `finally` of both load
|
|
61
|
+
* wrappers so a throw is captured just as reliably as a success.
|
|
62
|
+
*/
|
|
63
|
+
recordLoad(label, startedAt, error, ok) {
|
|
64
|
+
this.lastLoadRecord = {
|
|
65
|
+
label: label ?? null,
|
|
66
|
+
startedAt,
|
|
67
|
+
finishedAt: Date.now(),
|
|
68
|
+
ok,
|
|
69
|
+
error: ok ? null : describeLoadFailure(error),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* @param label Optional identifier (normally the model name) stamped into
|
|
74
|
+
* {@link lastLoad} so `/health` can name what was being loaded.
|
|
75
|
+
*/
|
|
76
|
+
async withModelLoad(fn, label) {
|
|
77
|
+
await this.acquireWrite();
|
|
78
|
+
// Measured from lock acquisition, not from arrival: `startedAt` is meant
|
|
79
|
+
// to answer "how long has the actual materialization been running",
|
|
80
|
+
// which is what a supervisor deciding whether to wait needs.
|
|
81
|
+
const startedAt = Date.now();
|
|
82
|
+
let ok = false;
|
|
83
|
+
let failure;
|
|
84
|
+
try {
|
|
85
|
+
const result = await fn();
|
|
86
|
+
ok = true;
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
failure = err;
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
this.recordLoad(label, startedAt, failure, ok);
|
|
95
|
+
this.releaseWrite();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Like {@link withModelLoad} but reports whether THIS caller owned the
|
|
100
|
+
* load (acquired the writer lock with no contention) or merely waited
|
|
101
|
+
* behind a load that was already in flight when it arrived.
|
|
102
|
+
*
|
|
103
|
+
* Decided at sync-time before any await: if neither a writer is active
|
|
104
|
+
* nor any writer is queued ahead, this caller is the owner; otherwise
|
|
105
|
+
* it is parked behind someone else's load and `owner` is `false`. The
|
|
106
|
+
* distinction is used by `/v1/messages` to split `resolve_ms` (own
|
|
107
|
+
* load + lookup) from `load_wait_ms` (waiting on a peer's load) so a
|
|
108
|
+
* 60-second cold-load does not look like 60 seconds of own work for
|
|
109
|
+
* every concurrent request.
|
|
110
|
+
*/
|
|
111
|
+
async withModelLoadInstrumented(fn, label) {
|
|
112
|
+
// `owner` MUST be decided synchronously, before any await, so the
|
|
113
|
+
// signal reflects coordinator state at arrival rather than after
|
|
114
|
+
// any peer transition. The wait/own split is measured around the
|
|
115
|
+
// actual phase boundaries (lock acquisition, fn completion) so the
|
|
116
|
+
// two intervals partition cleanly instead of both reporting total
|
|
117
|
+
// elapsed time — see `ModelLoadOutcome` for the contract.
|
|
118
|
+
const owner = !this.writerHeld && this.queuedWriters === 0;
|
|
119
|
+
const arrivedAt = Date.now();
|
|
120
|
+
await this.acquireWrite();
|
|
121
|
+
const lockAcquiredAt = Date.now();
|
|
122
|
+
let ok = false;
|
|
123
|
+
let failure;
|
|
124
|
+
try {
|
|
125
|
+
const result = await fn();
|
|
126
|
+
ok = true;
|
|
127
|
+
const fnDoneAt = Date.now();
|
|
128
|
+
const waitMs = Math.max(0, lockAcquiredAt - arrivedAt);
|
|
129
|
+
const ownMs = Math.max(0, fnDoneAt - lockAcquiredAt);
|
|
130
|
+
return { result, owner, waitMs, ownMs };
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
failure = err;
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
this.recordLoad(label, lockAcquiredAt, failure, ok);
|
|
138
|
+
this.releaseWrite();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async withInference(fn) {
|
|
142
|
+
await this.acquireRead();
|
|
143
|
+
try {
|
|
144
|
+
return await fn();
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
this.releaseRead();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
acquireRead() {
|
|
151
|
+
if (!this.writerHeld && this.queuedWriters === 0) {
|
|
152
|
+
this.activeReaders += 1;
|
|
153
|
+
return Promise.resolve();
|
|
154
|
+
}
|
|
155
|
+
return new Promise((resolve) => {
|
|
156
|
+
this.readerWaiters.push(() => {
|
|
157
|
+
this.activeReaders += 1;
|
|
158
|
+
resolve();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
acquireWrite() {
|
|
163
|
+
this.queuedWriters += 1;
|
|
164
|
+
if (!this.writerHeld && this.activeReaders === 0) {
|
|
165
|
+
this.queuedWriters -= 1;
|
|
166
|
+
this.writerHeld = true;
|
|
167
|
+
return Promise.resolve();
|
|
168
|
+
}
|
|
169
|
+
return new Promise((resolve) => {
|
|
170
|
+
this.writerWaiters.push(() => {
|
|
171
|
+
this.queuedWriters -= 1;
|
|
172
|
+
this.writerHeld = true;
|
|
173
|
+
resolve();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
releaseRead() {
|
|
178
|
+
this.activeReaders -= 1;
|
|
179
|
+
if (this.activeReaders < 0)
|
|
180
|
+
this.activeReaders = 0;
|
|
181
|
+
if (this.activeReaders === 0)
|
|
182
|
+
this.drain();
|
|
183
|
+
}
|
|
184
|
+
releaseWrite() {
|
|
185
|
+
this.writerHeld = false;
|
|
186
|
+
this.drain();
|
|
187
|
+
}
|
|
188
|
+
drain() {
|
|
189
|
+
if (this.writerHeld)
|
|
190
|
+
return;
|
|
191
|
+
if (this.activeReaders === 0 && this.writerWaiters.length > 0) {
|
|
192
|
+
this.writerWaiters.shift()?.();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (this.queuedWriters === 0 && this.readerWaiters.length > 0) {
|
|
196
|
+
const readers = this.readerWaiters.splice(0);
|
|
197
|
+
for (const resolve of readers)
|
|
198
|
+
resolve();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pending-writes.d.ts","sourceRoot":"","sources":["../src/pending-writes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwGG;AAEH;;;;;;;GAOG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAkC;IAE3E;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CACjB;IAEZ;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAElD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"pending-writes.d.ts","sourceRoot":"","sources":["../src/pending-writes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwGG;AAEH;;;;;;;GAOG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAkC;IAE3E;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CACjB;IAEZ;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAElD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAwCjF;IAED;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAElD;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASrD;IAED;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAI3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAuB9E;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IAYpB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAmBlC;IAED,iEAAiE;IACjE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;;;;;;;OAYG;IACH,IAAI,gBAAgB,IAAI,MAAM,CAG7B;IAED;;;;;;OAMG;IACH,IAAI,4BAA4B,IAAI,MAAM,CAEzC;CACF;AAYD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB,CAOxE"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sampling presets recommended by third-party model authors, exposed
|
|
3
|
+
* here as `ChatConfig`-shaped objects so an operator can pin them at
|
|
4
|
+
* `ModelRegistry.register(name, model, { samplingDefaults: ... })`
|
|
5
|
+
* time with a single import.
|
|
6
|
+
*
|
|
7
|
+
* Per-request client values (OpenAI `temperature`/`top_p`, Anthropic
|
|
8
|
+
* equivalents) still override these defaults where the client sends
|
|
9
|
+
* them — `ChatSession.mergeConfig` treats per-call config as an
|
|
10
|
+
* overlay on top of `defaultConfig`. These presets only fill in the
|
|
11
|
+
* parameters clients never send (`top_k`, `min_p`, penalties).
|
|
12
|
+
*/
|
|
13
|
+
import type { ChatConfig } from '@mlx-node/core';
|
|
14
|
+
/**
|
|
15
|
+
* Sampling defaults from Unsloth's Qwen3.6 guide:
|
|
16
|
+
* https://unsloth.ai/docs/models/qwen3.6#recommended-settings
|
|
17
|
+
*
|
|
18
|
+
* All modes pin `top_k = 20` and `min_p = 0.0`; they differ in
|
|
19
|
+
* `temperature`, `top_p`, and `presence_penalty`.
|
|
20
|
+
*
|
|
21
|
+
* The native anti-repetition cutoff is now disabled by default
|
|
22
|
+
* (vLLM-aligned — vLLM ships no repetition-stop heuristic), so these
|
|
23
|
+
* presets no longer pin `maxConsecutiveTokens` / `maxNgramRepeats` /
|
|
24
|
+
* `ngramSize`. Repetition is shaped by the sampling penalties above and
|
|
25
|
+
* bounded by the per-model `maxOutputTokens`. An operator or client can
|
|
26
|
+
* still opt in by setting those fields explicitly — a per-request config
|
|
27
|
+
* value wins via `ChatSession.mergeConfig`.
|
|
28
|
+
*/
|
|
29
|
+
export declare const QWEN_SAMPLING_DEFAULTS: {
|
|
30
|
+
/** Thinking mode for precise coding tasks: temp=0.6, top_p=0.95, pp=0.0 */
|
|
31
|
+
readonly thinkingCoding: {
|
|
32
|
+
temperature: number;
|
|
33
|
+
topP: number;
|
|
34
|
+
topK: number;
|
|
35
|
+
minP: number;
|
|
36
|
+
presencePenalty: number;
|
|
37
|
+
repetitionPenalty: number;
|
|
38
|
+
};
|
|
39
|
+
/** Thinking mode for general tasks: temp=1.0, top_p=0.95, pp=1.5 */
|
|
40
|
+
readonly thinkingGeneral: {
|
|
41
|
+
temperature: number;
|
|
42
|
+
topP: number;
|
|
43
|
+
topK: number;
|
|
44
|
+
minP: number;
|
|
45
|
+
presencePenalty: number;
|
|
46
|
+
repetitionPenalty: number;
|
|
47
|
+
};
|
|
48
|
+
/** Instruct (non-thinking) for general tasks: temp=0.7, top_p=0.8, pp=1.5 */
|
|
49
|
+
readonly instructGeneral: {
|
|
50
|
+
temperature: number;
|
|
51
|
+
topP: number;
|
|
52
|
+
topK: number;
|
|
53
|
+
minP: number;
|
|
54
|
+
presencePenalty: number;
|
|
55
|
+
repetitionPenalty: number;
|
|
56
|
+
};
|
|
57
|
+
/** Instruct (non-thinking) for reasoning tasks: temp=1.0, top_p=0.95, pp=1.5 */
|
|
58
|
+
readonly instructReasoning: {
|
|
59
|
+
temperature: number;
|
|
60
|
+
topP: number;
|
|
61
|
+
topK: number;
|
|
62
|
+
minP: number;
|
|
63
|
+
presencePenalty: number;
|
|
64
|
+
repetitionPenalty: number;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/** Sampling defaults for Gemma4 Instruct. */
|
|
68
|
+
export declare const GEMMA4_SAMPLING_DEFAULTS: ChatConfig;
|
|
69
|
+
/** Sampling defaults for LFM2.5 Thinking. */
|
|
70
|
+
export declare const LFM2_SAMPLING_DEFAULTS: ChatConfig;
|
|
71
|
+
/** Sampling + per-model output token cap exposed by {@link LAUNCH_PRESETS}. */
|
|
72
|
+
export interface LaunchPreset {
|
|
73
|
+
sampling: ChatConfig;
|
|
74
|
+
maxOutputTokens: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Per-`ModelType` presets used by `mlx launch claude` to pre-wire a
|
|
78
|
+
* discovered model with sensible sampling defaults + a max output
|
|
79
|
+
* token budget. Keyed on the string returned by `detectModelType()`.
|
|
80
|
+
*/
|
|
81
|
+
export declare const LAUNCH_PRESETS: Record<string, LaunchPreset>;
|
|
82
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB;IACjC,2EAA2E;;;;;;;;;IAU3E,oEAAoE;;;;;;;;;IAUpE,6EAA6E;;;;;;;;;IAU7E,gFAAgF;;;;;;;;;CASxE,CAAC;AAEX,6CAA6C;AAC7C,eAAO,MAAM,wBAAwB,EAAE,UAOtC,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,sBAAsB,EAAE,UAOpC,CAAC;AAEF,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,UAAU,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAqBvD,CAAC"}
|
package/dist/presets.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sampling defaults from Unsloth's Qwen3.6 guide:
|
|
3
|
+
* https://unsloth.ai/docs/models/qwen3.6#recommended-settings
|
|
4
|
+
*
|
|
5
|
+
* All modes pin `top_k = 20` and `min_p = 0.0`; they differ in
|
|
6
|
+
* `temperature`, `top_p`, and `presence_penalty`.
|
|
7
|
+
*
|
|
8
|
+
* The native anti-repetition cutoff is now disabled by default
|
|
9
|
+
* (vLLM-aligned — vLLM ships no repetition-stop heuristic), so these
|
|
10
|
+
* presets no longer pin `maxConsecutiveTokens` / `maxNgramRepeats` /
|
|
11
|
+
* `ngramSize`. Repetition is shaped by the sampling penalties above and
|
|
12
|
+
* bounded by the per-model `maxOutputTokens`. An operator or client can
|
|
13
|
+
* still opt in by setting those fields explicitly — a per-request config
|
|
14
|
+
* value wins via `ChatSession.mergeConfig`.
|
|
15
|
+
*/
|
|
16
|
+
export const QWEN_SAMPLING_DEFAULTS = {
|
|
17
|
+
/** Thinking mode for precise coding tasks: temp=0.6, top_p=0.95, pp=0.0 */
|
|
18
|
+
thinkingCoding: {
|
|
19
|
+
temperature: 0.6,
|
|
20
|
+
topP: 0.95,
|
|
21
|
+
topK: 20,
|
|
22
|
+
minP: 0.0,
|
|
23
|
+
presencePenalty: 0.0,
|
|
24
|
+
repetitionPenalty: 1.0,
|
|
25
|
+
},
|
|
26
|
+
/** Thinking mode for general tasks: temp=1.0, top_p=0.95, pp=1.5 */
|
|
27
|
+
thinkingGeneral: {
|
|
28
|
+
temperature: 1.0,
|
|
29
|
+
topP: 0.95,
|
|
30
|
+
topK: 20,
|
|
31
|
+
minP: 0.0,
|
|
32
|
+
presencePenalty: 1.5,
|
|
33
|
+
repetitionPenalty: 1.0,
|
|
34
|
+
},
|
|
35
|
+
/** Instruct (non-thinking) for general tasks: temp=0.7, top_p=0.8, pp=1.5 */
|
|
36
|
+
instructGeneral: {
|
|
37
|
+
temperature: 0.7,
|
|
38
|
+
topP: 0.8,
|
|
39
|
+
topK: 20,
|
|
40
|
+
minP: 0.0,
|
|
41
|
+
presencePenalty: 1.5,
|
|
42
|
+
repetitionPenalty: 1.0,
|
|
43
|
+
},
|
|
44
|
+
/** Instruct (non-thinking) for reasoning tasks: temp=1.0, top_p=0.95, pp=1.5 */
|
|
45
|
+
instructReasoning: {
|
|
46
|
+
temperature: 1.0,
|
|
47
|
+
topP: 0.95,
|
|
48
|
+
topK: 20,
|
|
49
|
+
minP: 0.0,
|
|
50
|
+
presencePenalty: 1.5,
|
|
51
|
+
repetitionPenalty: 1.0,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
/** Sampling defaults for Gemma4 Instruct. */
|
|
55
|
+
export const GEMMA4_SAMPLING_DEFAULTS = {
|
|
56
|
+
temperature: 0.7,
|
|
57
|
+
topP: 0.95,
|
|
58
|
+
topK: 64,
|
|
59
|
+
minP: 0.0,
|
|
60
|
+
presencePenalty: 0.0,
|
|
61
|
+
repetitionPenalty: 1.0,
|
|
62
|
+
};
|
|
63
|
+
/** Sampling defaults for LFM2.5 Thinking. */
|
|
64
|
+
export const LFM2_SAMPLING_DEFAULTS = {
|
|
65
|
+
temperature: 0.05,
|
|
66
|
+
topP: 1.0,
|
|
67
|
+
topK: 50,
|
|
68
|
+
minP: 0.0,
|
|
69
|
+
presencePenalty: 0.0,
|
|
70
|
+
repetitionPenalty: 1.05,
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Per-`ModelType` presets used by `mlx launch claude` to pre-wire a
|
|
74
|
+
* discovered model with sensible sampling defaults + a max output
|
|
75
|
+
* token budget. Keyed on the string returned by `detectModelType()`.
|
|
76
|
+
*/
|
|
77
|
+
export const LAUNCH_PRESETS = {
|
|
78
|
+
qwen3: {
|
|
79
|
+
sampling: QWEN_SAMPLING_DEFAULTS.thinkingCoding,
|
|
80
|
+
maxOutputTokens: 38912,
|
|
81
|
+
},
|
|
82
|
+
qwen3_5: {
|
|
83
|
+
sampling: QWEN_SAMPLING_DEFAULTS.thinkingCoding,
|
|
84
|
+
maxOutputTokens: 81920,
|
|
85
|
+
},
|
|
86
|
+
qwen3_5_moe: {
|
|
87
|
+
sampling: QWEN_SAMPLING_DEFAULTS.thinkingCoding,
|
|
88
|
+
maxOutputTokens: 81920,
|
|
89
|
+
},
|
|
90
|
+
gemma4: {
|
|
91
|
+
sampling: GEMMA4_SAMPLING_DEFAULTS,
|
|
92
|
+
maxOutputTokens: 16384,
|
|
93
|
+
},
|
|
94
|
+
lfm2: {
|
|
95
|
+
sampling: LFM2_SAMPLING_DEFAULTS,
|
|
96
|
+
maxOutputTokens: 8192,
|
|
97
|
+
},
|
|
98
|
+
};
|
package/dist/registry.d.ts
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* `body.model`. Instance ids recognise them as the same binding
|
|
37
37
|
* and the continuation is accepted.
|
|
38
38
|
*/
|
|
39
|
+
import type { ChatConfig } from '@mlx-node/core';
|
|
39
40
|
import type { SessionCapableModel } from '@mlx-node/lm';
|
|
40
41
|
import { SessionRegistry } from './session-registry.js';
|
|
41
42
|
/** Minimal contract for a model that can be served via chat sessions. */
|
|
@@ -64,6 +65,35 @@ export interface ModelRegistryOptions {
|
|
|
64
65
|
*/
|
|
65
66
|
maxQueueDepth?: number;
|
|
66
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Per-registration options for {@link ModelRegistry.register}.
|
|
70
|
+
*/
|
|
71
|
+
export interface RegisterOptions {
|
|
72
|
+
/**
|
|
73
|
+
* Per-model sampling defaults forwarded through the bound
|
|
74
|
+
* `SessionRegistry` into every `ChatSession` it allocates (as the
|
|
75
|
+
* session's `defaultConfig`). Clients' per-request sampling values
|
|
76
|
+
* (OpenAI `temperature`/`top_p`, Anthropic equivalents) still win
|
|
77
|
+
* where present because `ChatSession.mergeConfig` treats them as an
|
|
78
|
+
* overlay — these defaults only fill the gaps for parameters the
|
|
79
|
+
* client never sent (`top_k`, `min_p`, penalties, etc.).
|
|
80
|
+
*
|
|
81
|
+
* Re-registering the same name with a fresh `samplingDefaults` value
|
|
82
|
+
* overwrites the binding's defaults in place so the next
|
|
83
|
+
* `ChatSession` allocated out of the registry picks up the new
|
|
84
|
+
* values. Warm sessions already in flight keep the previous defaults
|
|
85
|
+
* until they settle; this matches how the refresh path treats other
|
|
86
|
+
* per-binding state.
|
|
87
|
+
*/
|
|
88
|
+
samplingDefaults?: ChatConfig;
|
|
89
|
+
/**
|
|
90
|
+
* Optional per-model upper bound for generated output tokens. This is
|
|
91
|
+
* intentionally separate from `samplingDefaults.maxNewTokens`: client
|
|
92
|
+
* requests still provide the desired length, while endpoint handlers can
|
|
93
|
+
* clamp pathological values before dispatch.
|
|
94
|
+
*/
|
|
95
|
+
maxOutputTokens?: number;
|
|
96
|
+
}
|
|
67
97
|
export declare class ModelRegistry {
|
|
68
98
|
private readonly maxQueueDepth;
|
|
69
99
|
private readonly models;
|
|
@@ -140,7 +170,7 @@ export declare class ModelRegistry {
|
|
|
140
170
|
* preserves the id because `instanceIds.has(model)` is already
|
|
141
171
|
* true.
|
|
142
172
|
*/
|
|
143
|
-
register(name: string, model: ServableModel): void;
|
|
173
|
+
register(name: string, model: ServableModel, opts?: RegisterOptions): void;
|
|
144
174
|
/**
|
|
145
175
|
* Unregister a model by name.
|
|
146
176
|
*
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,yEAAyE;AACzE,MAAM,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAEhD,0CAA0C;AAC1C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,eAAe,EAAE,eAAe,CAAC;CAClC;AAsCD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAoD;IAC7F;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;IAChE,yDAAyD;IACzD,OAAO,CAAC,cAAc,CAAK;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAkF;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.js
CHANGED
|
@@ -115,13 +115,23 @@ export class ModelRegistry {
|
|
|
115
115
|
* preserves the id because `instanceIds.has(model)` is already
|
|
116
116
|
* true.
|
|
117
117
|
*/
|
|
118
|
-
register(name, model) {
|
|
118
|
+
register(name, model, opts) {
|
|
119
|
+
const samplingDefaults = opts?.samplingDefaults;
|
|
120
|
+
const maxOutputTokens = opts?.maxOutputTokens;
|
|
119
121
|
const existing = this.models.get(name);
|
|
120
122
|
if (existing && existing.model === model) {
|
|
121
123
|
// Same name + same model object: leave the binding and refcount
|
|
122
124
|
// alone. Refresh createdAt so `/v1/models` surfaces the most
|
|
123
|
-
// recent registration time.
|
|
125
|
+
// recent registration time. A fresh `samplingDefaults` from the
|
|
126
|
+
// re-registration is applied in place so the operator can tune
|
|
127
|
+
// per-model knobs without fully unregistering first.
|
|
124
128
|
existing.createdAt = Math.floor(Date.now() / 1000);
|
|
129
|
+
if (opts && 'samplingDefaults' in opts) {
|
|
130
|
+
existing.sessionRegistry.setSamplingDefaults(samplingDefaults);
|
|
131
|
+
}
|
|
132
|
+
if (opts && 'maxOutputTokens' in opts) {
|
|
133
|
+
existing.sessionRegistry.setMaxOutputTokens(maxOutputTokens);
|
|
134
|
+
}
|
|
125
135
|
return;
|
|
126
136
|
}
|
|
127
137
|
if (existing) {
|
|
@@ -138,7 +148,12 @@ export class ModelRegistry {
|
|
|
138
148
|
let binding = this.sessionRegistriesByModel.get(model);
|
|
139
149
|
if (!binding) {
|
|
140
150
|
binding = {
|
|
141
|
-
registry: new SessionRegistry({
|
|
151
|
+
registry: new SessionRegistry({
|
|
152
|
+
model,
|
|
153
|
+
maxQueueDepth: this.maxQueueDepth,
|
|
154
|
+
samplingDefaults,
|
|
155
|
+
maxOutputTokens,
|
|
156
|
+
}),
|
|
142
157
|
refCount: 0,
|
|
143
158
|
inFlight: 0,
|
|
144
159
|
pendingPersists: 0,
|
|
@@ -146,8 +161,21 @@ export class ModelRegistry {
|
|
|
146
161
|
};
|
|
147
162
|
this.sessionRegistriesByModel.set(model, binding);
|
|
148
163
|
}
|
|
149
|
-
else
|
|
150
|
-
binding.pendingTeardown
|
|
164
|
+
else {
|
|
165
|
+
if (binding.pendingTeardown) {
|
|
166
|
+
binding.pendingTeardown = false;
|
|
167
|
+
}
|
|
168
|
+
// Aliasing or reviving an existing binding: if this call passed
|
|
169
|
+
// `samplingDefaults` explicitly, overwrite the shared binding's
|
|
170
|
+
// defaults so the latest registration wins for every alias.
|
|
171
|
+
// Call sites that omit the field leave the existing defaults
|
|
172
|
+
// intact.
|
|
173
|
+
if (opts && 'samplingDefaults' in opts) {
|
|
174
|
+
binding.registry.setSamplingDefaults(samplingDefaults);
|
|
175
|
+
}
|
|
176
|
+
if (opts && 'maxOutputTokens' in opts) {
|
|
177
|
+
binding.registry.setMaxOutputTokens(maxOutputTokens);
|
|
178
|
+
}
|
|
151
179
|
}
|
|
152
180
|
binding.refCount += 1;
|
|
153
181
|
// Allocate a fresh monotonic instance id on first sight of this
|
package/dist/router.d.ts
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
/** Path-based router for /v1/* endpoints. */
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
3
|
import type { ResponseStore } from '@mlx-node/core';
|
|
4
|
+
import type { PublicModelEntry } from './handler.js';
|
|
5
|
+
import { type ServerHealth } from './health.js';
|
|
6
|
+
import type { IdleSweeper } from './idle-sweeper.js';
|
|
7
|
+
import type { ModelWorkCoordinator } from './model-work-coordinator.js';
|
|
4
8
|
import type { ModelRegistry } from './registry.js';
|
|
5
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The request's pathname, parsed against a CONSTANT base.
|
|
11
|
+
*
|
|
12
|
+
* Never against `Host`. That header is attacker-controlled text on every
|
|
13
|
+
* request — `Host: [` makes `new URL()` throw `ERR_INVALID_URL`, and a throw
|
|
14
|
+
* from an async request listener is an unhandled rejection, which under Node's
|
|
15
|
+
* default `--unhandled-rejections=throw` takes the whole process down. One
|
|
16
|
+
* malformed byte from any client that can reach the socket was enough to end
|
|
17
|
+
* inference. A pathname does not depend on the authority anyway, so a fixed
|
|
18
|
+
* base is both safer and equivalent: an absolute-form request URI
|
|
19
|
+
* (`GET http://host/v1/models HTTP/1.1`, legal in HTTP/1.1) still wins over
|
|
20
|
+
* the base and yields the same path it always did.
|
|
21
|
+
*
|
|
22
|
+
* `req.url` itself is guarded too, for the same reason rather than a known
|
|
23
|
+
* input: this function's contract is that no request can make it throw.
|
|
24
|
+
*/
|
|
25
|
+
export declare function requestPathname(req: IncomingMessage): string;
|
|
26
|
+
/**
|
|
27
|
+
* Trailing options bag. Added as an object rather than two more positional
|
|
28
|
+
* parameters — `routeRequest` already carries nine, and the two knobs here
|
|
29
|
+
* are unrelated to each other.
|
|
30
|
+
*/
|
|
31
|
+
export interface RouteExtras {
|
|
32
|
+
/** Builds the `/health` body. Omitted ⇒ the legacy constant `{ status: 'ok' }`. */
|
|
33
|
+
health?: () => ServerHealth;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the caller presented a valid token. Only consulted by `/health`,
|
|
36
|
+
* which is the one route reachable without one. `true` when no token is
|
|
37
|
+
* configured at all, so an unprotected server keeps serving the full body.
|
|
38
|
+
*/
|
|
39
|
+
authenticated?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function routeRequest(req: IncomingMessage, res: ServerResponse, registry: ModelRegistry, store: ResponseStore | null, responseRetentionSec?: number, idleSweeper?: IdleSweeper | null, resolveModel?: (name: string) => Promise<void>, listModels?: () => PublicModelEntry[], modelWorkCoordinator?: ModelWorkCoordinator, extras?: RouteExtras): Promise<void>;
|
|
6
42
|
//# sourceMappingURL=router.d.ts.map
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAapD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAOnD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAS5D;AAoBD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,YAAY,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,oBAAoB,CAAC,EAAE,MAAM,EAC7B,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,EAChC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAC9C,UAAU,CAAC,EAAE,MAAM,gBAAgB,EAAE,EACrC,oBAAoB,CAAC,EAAE,oBAAoB,EAC3C,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAuHf"}
|