@mlx-node/core 0.0.6 → 0.0.8
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/index.cjs +94 -69
- package/index.d.cts +2132 -784
- package/package.json +7 -6
package/index.d.cts
CHANGED
|
@@ -26,7 +26,12 @@ export declare class BatchGenerationResult {
|
|
|
26
26
|
get groupSize(): number;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Handle returned by the streaming chat-session entry points
|
|
31
|
+
* (`chat_stream_session_start`, `chat_stream_session_continue`,
|
|
32
|
+
* `chat_stream_session_continue_tool`) to control an in-progress
|
|
33
|
+
* streaming generation.
|
|
34
|
+
*/
|
|
30
35
|
export declare class ChatStreamHandle {
|
|
31
36
|
cancel(): void;
|
|
32
37
|
}
|
|
@@ -103,6 +108,168 @@ export declare class DocUnwarpModel {
|
|
|
103
108
|
unwarp(imageData: Uint8Array): UnwarpResult;
|
|
104
109
|
}
|
|
105
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Gemma 4 dense language model.
|
|
113
|
+
*
|
|
114
|
+
* Supports E2B (2.3B), E4B (4.5B), and 31B variants.
|
|
115
|
+
* Features: hybrid attention (sliding + global), GeGLU MLP, logit softcapping,
|
|
116
|
+
* embedding scaling, and optional per-layer embeddings.
|
|
117
|
+
*
|
|
118
|
+
* All model state lives on a dedicated OS thread. NAPI methods dispatch
|
|
119
|
+
* commands via channels and await responses.
|
|
120
|
+
*/
|
|
121
|
+
export declare class Gemma4Model {
|
|
122
|
+
/**
|
|
123
|
+
* Create an uninitialized `Gemma4Model` stub from a config.
|
|
124
|
+
*
|
|
125
|
+
* **Prefer [`Gemma4Model::load`]** for any real usage — `new(config)`
|
|
126
|
+
* is a config-only stub that matches the OCR-model pattern
|
|
127
|
+
* (`VLModel::new(config)`, `QianfanOCRModel::new(config)`) and is
|
|
128
|
+
* intentionally NOT runnable. It was introduced in the cache-limit
|
|
129
|
+
* coordinator work so that the coordinator's per-model delta is
|
|
130
|
+
* registered exclusively on the `load()` path, eliminating a
|
|
131
|
+
* baseline-registration gap where a no-op `new(config)` would have
|
|
132
|
+
* leaked an empty guard into the coordinator.
|
|
133
|
+
*
|
|
134
|
+
* This path does NOT spawn a model thread, NOT materialize any
|
|
135
|
+
* weights, and NOT register with the cache-limit coordinator. The
|
|
136
|
+
* returned instance is only useful for config inspection — every
|
|
137
|
+
* session method (`chatSessionStart` / `chatSessionContinue` /
|
|
138
|
+
* `chatSessionContinueTool` and their streaming variants) rejects
|
|
139
|
+
* with a `napi::Error` whose message is exactly
|
|
140
|
+
* `"Model not initialized. Call Gemma4Model.load() first."` until
|
|
141
|
+
* `load()` runs and installs the underlying model thread. The
|
|
142
|
+
* synchronous `resetCaches()` call is a silent no-op on the stub
|
|
143
|
+
* to keep `ChatSession.reset()` idempotent across both runnable
|
|
144
|
+
* and stub instances.
|
|
145
|
+
*
|
|
146
|
+
* A runnable model requires `await Gemma4Model.load(path)`. The
|
|
147
|
+
* constructor signature is fixed by NAPI-RS; the stub-only behavior is
|
|
148
|
+
* covered by the regression tests in
|
|
149
|
+
* `__test__/models/model-loader-gemma4.test.ts`.
|
|
150
|
+
*/
|
|
151
|
+
constructor(config: Gemma4Config);
|
|
152
|
+
/** Returns true if weights have been loaded via `load()`. */
|
|
153
|
+
get isInitialized(): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Whether the block-paged KV cache adapter is active on this model
|
|
156
|
+
* instance.
|
|
157
|
+
*
|
|
158
|
+
* `true` iff `Gemma4Inner::paged_adapter` was successfully
|
|
159
|
+
* constructed at load time (driven by
|
|
160
|
+
* `Gemma4Config::use_block_paged_cache`). The
|
|
161
|
+
* `gemma4_paged_vs_flat_parity` integration test pins greedy
|
|
162
|
+
* byte-equal at BF16 against real Gemma-4-E2B-IT weights. Stubs
|
|
163
|
+
* constructed via `new(config)` always return `false`. Surfaced
|
|
164
|
+
* through this NAPI method so server endpoints can branch on it
|
|
165
|
+
* without a model-thread roundtrip.
|
|
166
|
+
*/
|
|
167
|
+
hasBlockPagedCache(): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Whether this loaded instance can execute image-bearing chat turns.
|
|
170
|
+
* Config-only stubs and incomplete/non-paged physical paths return false.
|
|
171
|
+
*/
|
|
172
|
+
supportsImages(): boolean;
|
|
173
|
+
modelId(): number;
|
|
174
|
+
/**
|
|
175
|
+
* Whether a draft model — DSpark or Google assistant — is loaded on
|
|
176
|
+
* this instance (via `Gemma4LoadOptions::draft_model_path`), enabling
|
|
177
|
+
* the speculative-decode whole-turn path.
|
|
178
|
+
*
|
|
179
|
+
* Note: this only reports draft availability. Whether speculative
|
|
180
|
+
* decoding actually runs on a given call also requires the per-request
|
|
181
|
+
* `enableMtp` flag. Named `hasMtpWeights` for parity with the Qwen3.5
|
|
182
|
+
* surface, but it reports an external draft model (either variant),
|
|
183
|
+
* not in-checkpoint MTP heads. Stubs from `new(config)` always return
|
|
184
|
+
* `false`.
|
|
185
|
+
*/
|
|
186
|
+
hasMtpWeights(): boolean;
|
|
187
|
+
/** Load a Gemma4 model from a directory. */
|
|
188
|
+
static load(modelPath: string, options?: Gemma4LoadOptions | undefined | null): Promise<Gemma4Model>;
|
|
189
|
+
/**
|
|
190
|
+
* Reset all caches and clear cached token history. Exposed
|
|
191
|
+
* so tests and session-management code can start from a
|
|
192
|
+
* known clean state between turns.
|
|
193
|
+
*/
|
|
194
|
+
resetCaches(): void;
|
|
195
|
+
/**
|
|
196
|
+
* Start a new chat session.
|
|
197
|
+
*
|
|
198
|
+
* Runs the full jinja chat template once, decodes until the
|
|
199
|
+
* family's session stop token, and leaves the KV caches on a
|
|
200
|
+
* clean turn boundary so subsequent `chatSessionContinue` /
|
|
201
|
+
* `chatSessionContinueTool` calls can append a raw delta on
|
|
202
|
+
* top without re-rendering the chat template.
|
|
203
|
+
*/
|
|
204
|
+
chatSessionStart(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
205
|
+
/**
|
|
206
|
+
* Continue an existing chat session with a new user message.
|
|
207
|
+
*
|
|
208
|
+
* Appends a raw user/assistant delta to the session's cached
|
|
209
|
+
* KV state, then decodes the assistant reply, stopping on the
|
|
210
|
+
* family's session boundary token.
|
|
211
|
+
*
|
|
212
|
+
* `images` is an opt-in guard parameter: when non-empty the
|
|
213
|
+
* native side returns an error whose message begins with
|
|
214
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` so the TypeScript
|
|
215
|
+
* `ChatSession` layer can route image-changes back through a
|
|
216
|
+
* fresh `chatSessionStart`.
|
|
217
|
+
*/
|
|
218
|
+
chatSessionContinue(
|
|
219
|
+
userMessage: string,
|
|
220
|
+
images: Uint8Array[] | null | undefined,
|
|
221
|
+
audio: Uint8Array[] | null | undefined,
|
|
222
|
+
config: ChatConfig | null | undefined,
|
|
223
|
+
): Promise<ChatResult>;
|
|
224
|
+
/**
|
|
225
|
+
* Continue an existing chat session with a tool-result turn.
|
|
226
|
+
*
|
|
227
|
+
* Builds the family's tool-result delta from `content` and
|
|
228
|
+
* prefills it on top of the live session caches, then decodes
|
|
229
|
+
* the assistant reply.
|
|
230
|
+
*
|
|
231
|
+
* `is_error` is the structured tool-error signal. When
|
|
232
|
+
* `Some(true)`, the renderer prepends the shared
|
|
233
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
234
|
+
* rendered tool block.
|
|
235
|
+
*/
|
|
236
|
+
chatSessionContinueTool(
|
|
237
|
+
toolCallId: string,
|
|
238
|
+
content: string,
|
|
239
|
+
config?: ChatConfig | undefined | null,
|
|
240
|
+
isError?: boolean | undefined | null,
|
|
241
|
+
): Promise<ChatResult>;
|
|
242
|
+
/** Streaming variant of `chatSessionStart`. */
|
|
243
|
+
chatStreamSessionStart(
|
|
244
|
+
messages: ChatMessage[],
|
|
245
|
+
config: ChatConfig | null | undefined,
|
|
246
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
247
|
+
): Promise<ChatStreamHandle>;
|
|
248
|
+
/** Streaming variant of `chatSessionContinue`. */
|
|
249
|
+
chatStreamSessionContinue(
|
|
250
|
+
userMessage: string,
|
|
251
|
+
images: Uint8Array[] | null | undefined,
|
|
252
|
+
audio: Uint8Array[] | null | undefined,
|
|
253
|
+
config: ChatConfig | null | undefined,
|
|
254
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
255
|
+
): Promise<ChatStreamHandle>;
|
|
256
|
+
/**
|
|
257
|
+
* Streaming variant of `chatSessionContinueTool`.
|
|
258
|
+
*
|
|
259
|
+
* `is_error` mirrors the non-streaming entry point — when
|
|
260
|
+
* `Some(true)`, the renderer prepends the shared
|
|
261
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the rendered
|
|
262
|
+
* tool block.
|
|
263
|
+
*/
|
|
264
|
+
chatStreamSessionContinueTool(
|
|
265
|
+
toolCallId: string,
|
|
266
|
+
content: string,
|
|
267
|
+
config: ChatConfig | null | undefined,
|
|
268
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
269
|
+
isError?: boolean | null | undefined,
|
|
270
|
+
): Promise<ChatStreamHandle>;
|
|
271
|
+
}
|
|
272
|
+
|
|
106
273
|
/** Result from text generation with detailed metadata */
|
|
107
274
|
export declare class GenerationResult {
|
|
108
275
|
/** Get the decoded text */
|
|
@@ -120,14 +287,15 @@ export declare class GenerationResult {
|
|
|
120
287
|
/**
|
|
121
288
|
* GRPO Training Engine
|
|
122
289
|
*
|
|
123
|
-
*
|
|
290
|
+
* Thin coordinator that routes all MLX operations through the model thread.
|
|
291
|
+
* No MxArrays or model state live here — only plain data crosses the boundary.
|
|
124
292
|
*/
|
|
125
293
|
export declare class GrpoTrainingEngine {
|
|
126
294
|
/**
|
|
127
295
|
* Create a new training engine from a Qwen3 model
|
|
128
296
|
*
|
|
129
297
|
* # Arguments
|
|
130
|
-
* * `model` - The Qwen3 model
|
|
298
|
+
* * `model` - The Qwen3 model (must be loaded via load())
|
|
131
299
|
* * `config` - Engine configuration
|
|
132
300
|
*/
|
|
133
301
|
constructor(model: Qwen3Model, config: GrpoEngineConfig);
|
|
@@ -143,8 +311,8 @@ export declare class GrpoTrainingEngine {
|
|
|
143
311
|
* This method performs the complete training cycle:
|
|
144
312
|
* 1. Generate completions for each prompt (G times per prompt)
|
|
145
313
|
* 2. Use provided rewards to compute advantages
|
|
146
|
-
* 3. Compute GRPO loss and gradients
|
|
147
|
-
* 4. Apply gradients (respecting accumulation steps)
|
|
314
|
+
* 3. Compute GRPO loss and gradients (on model thread)
|
|
315
|
+
* 4. Apply gradients (respecting accumulation steps, on model thread)
|
|
148
316
|
*
|
|
149
317
|
* # Arguments
|
|
150
318
|
* * `prompts` - Array of chat conversations to use as prompts
|
|
@@ -171,13 +339,14 @@ export declare class GrpoTrainingEngine {
|
|
|
171
339
|
/**
|
|
172
340
|
* Run a training step with pre-generated completions
|
|
173
341
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
342
|
+
* Uses the cached MxArrays from the most recent generate_batch_for_training
|
|
343
|
+
* call on the model thread. The generation_result parameter is used only for
|
|
344
|
+
* validation (the actual MxArrays are cached on the model thread).
|
|
176
345
|
*
|
|
177
346
|
* # Arguments
|
|
178
347
|
* * `prompts` - Array of chat conversations to use as prompts
|
|
179
348
|
* * `rewards` - Reward values for each completion (num_prompts * group_size)
|
|
180
|
-
* * `generation_result` - Pre-generated completion data
|
|
349
|
+
* * `generation_result` - Pre-generated completion data (used for validation)
|
|
181
350
|
*
|
|
182
351
|
* # Returns
|
|
183
352
|
* * Training step metrics
|
|
@@ -190,8 +359,8 @@ export declare class GrpoTrainingEngine {
|
|
|
190
359
|
/**
|
|
191
360
|
* Unified training step with JS reward callback and optional output recording
|
|
192
361
|
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
362
|
+
* Generates completions via the model thread, calls the JS reward function
|
|
363
|
+
* with plain data, then dispatches the training step to the model thread.
|
|
195
364
|
*
|
|
196
365
|
* # Arguments
|
|
197
366
|
* * `prompts` - Array of chat conversations to use as prompts
|
|
@@ -222,7 +391,16 @@ export declare class GrpoTrainingEngine {
|
|
|
222
391
|
startEpoch(): void;
|
|
223
392
|
/** End the current epoch and get metrics */
|
|
224
393
|
endEpoch(epochTimeSecs: number): EngineEpochMetrics;
|
|
225
|
-
/**
|
|
394
|
+
/**
|
|
395
|
+
* Reset the engine for a fresh training run.
|
|
396
|
+
*
|
|
397
|
+
* This is a TERMINAL operation on this handle. It drops the training
|
|
398
|
+
* state (optimizer, step counter) on the model thread so a fresh
|
|
399
|
+
* `GRPOTrainingEngine` can be constructed on the same model, and marks
|
|
400
|
+
* THIS handle as invalidated. Any subsequent dispatch-requiring method
|
|
401
|
+
* on this handle returns an error — callers must construct a new
|
|
402
|
+
* engine to continue training.
|
|
403
|
+
*/
|
|
226
404
|
reset(): void;
|
|
227
405
|
/** Check if reward registry has any rewards registered */
|
|
228
406
|
get hasBuiltinRewards(): boolean;
|
|
@@ -242,25 +420,214 @@ export declare class GrpoTrainingEngine {
|
|
|
242
420
|
/**
|
|
243
421
|
* Save optimizer state (moment tensors + step) to a SafeTensors file.
|
|
244
422
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* No-op if the engine uses SGD (no optimizer state to save).
|
|
423
|
+
* Routes through the model thread so AdamW moments and step counter
|
|
424
|
+
* survive across checkpoint/resume. No-op if the engine uses SGD
|
|
425
|
+
* (no optimizer to save) or before the first optimizer update has
|
|
426
|
+
* populated any moment tensors.
|
|
250
427
|
*/
|
|
251
|
-
saveOptimizerState(path: string): void
|
|
428
|
+
saveOptimizerState(path: string): Promise<void>;
|
|
252
429
|
/**
|
|
253
430
|
* Load optimizer state (moment tensors + step) from a SafeTensors file.
|
|
254
431
|
*
|
|
255
|
-
*
|
|
256
|
-
* tensors for each parameter found in the file.
|
|
257
|
-
*
|
|
258
|
-
* No-op if the engine uses SGD (no optimizer to restore).
|
|
432
|
+
* Routes through the model thread. No-op if the engine uses SGD.
|
|
259
433
|
*/
|
|
260
|
-
loadOptimizerState(path: string): void
|
|
434
|
+
loadOptimizerState(path: string): Promise<void>;
|
|
261
435
|
}
|
|
262
436
|
export type GRPOTrainingEngine = GrpoTrainingEngine;
|
|
263
437
|
|
|
438
|
+
/**
|
|
439
|
+
* Harrier embedding model (Qwen3 backbone for text embeddings).
|
|
440
|
+
*
|
|
441
|
+
* Uses last-token pooling and L2 normalization to produce fixed-size
|
|
442
|
+
* embedding vectors from variable-length text inputs.
|
|
443
|
+
*/
|
|
444
|
+
export declare class HarrierModel {
|
|
445
|
+
constructor(config: HarrierConfig);
|
|
446
|
+
/**
|
|
447
|
+
* Forward pass returning hidden states (no lm_head projection).
|
|
448
|
+
*
|
|
449
|
+
* # Arguments
|
|
450
|
+
* * `input_ids` - Token IDs, shape: [batch_size, seq_len]
|
|
451
|
+
*
|
|
452
|
+
* # Returns
|
|
453
|
+
* * Hidden states, shape: [batch_size, seq_len, hidden_size]
|
|
454
|
+
*/
|
|
455
|
+
forward(inputIds: MxArray): MxArray;
|
|
456
|
+
/**
|
|
457
|
+
* Encode a single text into a normalized embedding vector.
|
|
458
|
+
*
|
|
459
|
+
* Tokenizes the text, runs the forward pass, applies last-token pooling,
|
|
460
|
+
* and L2-normalizes the result. Truncates to `max_position_embeddings`.
|
|
461
|
+
*
|
|
462
|
+
* # Arguments
|
|
463
|
+
* * `text` - Input text to encode
|
|
464
|
+
* * `instruction` - Optional task instruction prefix or preset name
|
|
465
|
+
* (e.g. `"web_search_query"` resolves to the full Harrier prompt).
|
|
466
|
+
* Pass `null` for documents/passages that need no instruction.
|
|
467
|
+
*
|
|
468
|
+
* # Returns
|
|
469
|
+
* * Embedding vector, shape: [hidden_size]
|
|
470
|
+
*/
|
|
471
|
+
encode(text: string, instruction?: string | undefined | null): Promise<MxArray>;
|
|
472
|
+
/**
|
|
473
|
+
* Encode a batch of texts into normalized embedding vectors.
|
|
474
|
+
*
|
|
475
|
+
* Each text is independently tokenized and encoded (no padding needed
|
|
476
|
+
* since each goes through its own forward pass). Truncates each text
|
|
477
|
+
* to `max_position_embeddings`.
|
|
478
|
+
*
|
|
479
|
+
* # Arguments
|
|
480
|
+
* * `texts` - Input texts to encode
|
|
481
|
+
* * `instruction` - Optional task instruction prefix or preset name
|
|
482
|
+
* (e.g. `"web_search_query"` resolves to the full Harrier prompt).
|
|
483
|
+
* Pass `null` for documents/passages that need no instruction.
|
|
484
|
+
*
|
|
485
|
+
* # Returns
|
|
486
|
+
* * Embedding matrix, shape: [batch_size, hidden_size]
|
|
487
|
+
*/
|
|
488
|
+
encodeBatch(texts: Array<string>, instruction?: string | undefined | null): Promise<MxArray>;
|
|
489
|
+
/** Get the model configuration. */
|
|
490
|
+
getConfig(): HarrierConfig;
|
|
491
|
+
/**
|
|
492
|
+
* Get available prompt presets loaded from config_sentence_transformers.json.
|
|
493
|
+
*
|
|
494
|
+
* Returns a map of task name -> full instruction prefix.
|
|
495
|
+
* Pass a task name to `encode()`/`encodeBatch()` as the `instruction` parameter
|
|
496
|
+
* to use a preset instead of a raw prefix string.
|
|
497
|
+
*/
|
|
498
|
+
getPrompts(): Record<string, string>;
|
|
499
|
+
/** Get the total number of model parameters. */
|
|
500
|
+
numParameters(): number;
|
|
501
|
+
/**
|
|
502
|
+
* Load a Harrier embedding model from a directory.
|
|
503
|
+
*
|
|
504
|
+
* Expects the standard HuggingFace layout:
|
|
505
|
+
* - config.json (model configuration)
|
|
506
|
+
* - model.safetensors or weights.safetensors (weights)
|
|
507
|
+
* - tokenizer.json (tokenizer)
|
|
508
|
+
* - config_sentence_transformers.json (optional, prompt presets)
|
|
509
|
+
*/
|
|
510
|
+
static load(modelPath: string): Promise<HarrierModel>;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* LFM2 language model (LFM2.5-1.2B-Thinking).
|
|
515
|
+
*
|
|
516
|
+
* Hybrid conv+attention architecture from Liquid AI. 16 layers total:
|
|
517
|
+
* 10 conv layers + 6 full_attention layers. Features gated short
|
|
518
|
+
* convolutions for local processing and standard attention for global context.
|
|
519
|
+
*
|
|
520
|
+
* All model state lives on a dedicated OS thread. NAPI methods dispatch
|
|
521
|
+
* commands via channels and await responses.
|
|
522
|
+
*/
|
|
523
|
+
export declare class Lfm2Model {
|
|
524
|
+
/** Load an LFM2 model from a directory containing safetensors and config.json. */
|
|
525
|
+
static load(modelPath: string): Promise<Lfm2Model>;
|
|
526
|
+
/**
|
|
527
|
+
* Whether the block-paged KV cache adapter is active on this model
|
|
528
|
+
* instance.
|
|
529
|
+
*
|
|
530
|
+
* `true` iff `Lfm2Inner::paged_adapter` was successfully constructed
|
|
531
|
+
* at load time (driven by `Lfm2Config::use_block_paged_cache`,
|
|
532
|
+
* defaulting to `true` after paged-vs-flat parity verification).
|
|
533
|
+
* LFM2 is hybrid (10 conv + 6 full-attention layers); only the
|
|
534
|
+
* full-attention layers route through the adapter, conv layers stay
|
|
535
|
+
* on flat `Lfm2LayerCache::Conv` regardless. When `true`, the native
|
|
536
|
+
* cache reuses SYS blocks across `chatSessionStart` calls via
|
|
537
|
+
* content-addressing, so the JS-side warm slot in
|
|
538
|
+
* `SessionRegistry.getOrCreateWarmAny` is redundant and the
|
|
539
|
+
* `/v1/messages` server endpoint allocates a fresh `ChatSession` per
|
|
540
|
+
* request.
|
|
541
|
+
*/
|
|
542
|
+
hasBlockPagedCache(): boolean;
|
|
543
|
+
/** Get the model configuration. */
|
|
544
|
+
getConfig(): Lfm2Config;
|
|
545
|
+
/** Estimated number of model parameters. */
|
|
546
|
+
numParameters(): number;
|
|
547
|
+
/**
|
|
548
|
+
* Reset all caches and clear cached token history. Exposed
|
|
549
|
+
* so tests and session-management code can start from a
|
|
550
|
+
* known clean state between turns.
|
|
551
|
+
*/
|
|
552
|
+
resetCaches(): void;
|
|
553
|
+
/**
|
|
554
|
+
* Start a new chat session.
|
|
555
|
+
*
|
|
556
|
+
* Runs the full jinja chat template once, decodes until the
|
|
557
|
+
* family's session stop token, and leaves the KV caches on a
|
|
558
|
+
* clean turn boundary so subsequent `chatSessionContinue` /
|
|
559
|
+
* `chatSessionContinueTool` calls can append a raw delta on
|
|
560
|
+
* top without re-rendering the chat template.
|
|
561
|
+
*/
|
|
562
|
+
chatSessionStart(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
563
|
+
/**
|
|
564
|
+
* Continue an existing chat session with a new user message.
|
|
565
|
+
*
|
|
566
|
+
* Appends a raw user/assistant delta to the session's cached
|
|
567
|
+
* KV state, then decodes the assistant reply, stopping on the
|
|
568
|
+
* family's session boundary token.
|
|
569
|
+
*
|
|
570
|
+
* `images` is an opt-in guard parameter: when non-empty the
|
|
571
|
+
* native side returns an error whose message begins with
|
|
572
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` so the TypeScript
|
|
573
|
+
* `ChatSession` layer can route image-changes back through a
|
|
574
|
+
* fresh `chatSessionStart`.
|
|
575
|
+
*/
|
|
576
|
+
chatSessionContinue(
|
|
577
|
+
userMessage: string,
|
|
578
|
+
images: Uint8Array[] | null | undefined,
|
|
579
|
+
audio: Uint8Array[] | null | undefined,
|
|
580
|
+
config: ChatConfig | null | undefined,
|
|
581
|
+
): Promise<ChatResult>;
|
|
582
|
+
/**
|
|
583
|
+
* Continue an existing chat session with a tool-result turn.
|
|
584
|
+
*
|
|
585
|
+
* Builds the family's tool-result delta from `content` and
|
|
586
|
+
* prefills it on top of the live session caches, then decodes
|
|
587
|
+
* the assistant reply.
|
|
588
|
+
*
|
|
589
|
+
* `is_error` is the structured tool-error signal. When
|
|
590
|
+
* `Some(true)`, the renderer prepends the shared
|
|
591
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
592
|
+
* rendered tool block.
|
|
593
|
+
*/
|
|
594
|
+
chatSessionContinueTool(
|
|
595
|
+
toolCallId: string,
|
|
596
|
+
content: string,
|
|
597
|
+
config?: ChatConfig | undefined | null,
|
|
598
|
+
isError?: boolean | undefined | null,
|
|
599
|
+
): Promise<ChatResult>;
|
|
600
|
+
/** Streaming variant of `chatSessionStart`. */
|
|
601
|
+
chatStreamSessionStart(
|
|
602
|
+
messages: ChatMessage[],
|
|
603
|
+
config: ChatConfig | null,
|
|
604
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
605
|
+
): Promise<ChatStreamHandle>;
|
|
606
|
+
/** Streaming variant of `chatSessionContinue`. */
|
|
607
|
+
chatStreamSessionContinue(
|
|
608
|
+
userMessage: string,
|
|
609
|
+
images: Uint8Array[] | null | undefined,
|
|
610
|
+
audio: Uint8Array[] | null | undefined,
|
|
611
|
+
config: ChatConfig | null,
|
|
612
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
613
|
+
): Promise<ChatStreamHandle>;
|
|
614
|
+
/**
|
|
615
|
+
* Streaming variant of `chatSessionContinueTool`.
|
|
616
|
+
*
|
|
617
|
+
* `is_error` mirrors the non-streaming entry point — when
|
|
618
|
+
* `Some(true)`, the renderer prepends the shared
|
|
619
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the rendered
|
|
620
|
+
* tool block.
|
|
621
|
+
*/
|
|
622
|
+
chatStreamSessionContinueTool(
|
|
623
|
+
toolCallId: string,
|
|
624
|
+
content: string,
|
|
625
|
+
config: ChatConfig | null,
|
|
626
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
627
|
+
isError?: boolean | null | undefined,
|
|
628
|
+
): Promise<ChatStreamHandle>;
|
|
629
|
+
}
|
|
630
|
+
|
|
264
631
|
export declare class MxArray {
|
|
265
632
|
equal(other: MxArray): MxArray;
|
|
266
633
|
notEqual(other: MxArray): MxArray;
|
|
@@ -382,9 +749,20 @@ export declare class MxArray {
|
|
|
382
749
|
divScalar(value: number): MxArray;
|
|
383
750
|
matmul(other: MxArray): MxArray;
|
|
384
751
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
752
|
+
* Matrix multiply-add: D = beta * C + alpha * (self @ B), where self is A.
|
|
753
|
+
* Default: alpha=1.0, beta=1.0, giving D = C + (self @ B).
|
|
754
|
+
*
|
|
755
|
+
* Computed explicitly (matmul, optional alpha scale, then add beta*C)
|
|
756
|
+
* rather than via the fused `mlx::core::addmm` primitive. The fused
|
|
757
|
+
* primitive is correct on a well-formed metallib, but this project's local
|
|
758
|
+
* release build is known to non-deterministically miscompile fused GEMM
|
|
759
|
+
* kernels (see the metallib-corruption notes), which manifested as the
|
|
760
|
+
* fused addmm dropping `beta*C` and corrupting every biased linear — most
|
|
761
|
+
* visibly the vision tower (`qkv`, `proj`, `fc1`, `fc2`, merger all carry a
|
|
762
|
+
* bias; bias-free LM/MoE linears pass a zero `C` and were unaffected). The
|
|
763
|
+
* explicit form keeps the `C` term robust to that build hazard; the
|
|
764
|
+
* `nn::linear` unit tests assert it applies a non-zero `C`, so they double
|
|
765
|
+
* as a canary if a future build corrupts the matmul kernel too.
|
|
388
766
|
*/
|
|
389
767
|
addmm(c: MxArray, b: MxArray, alpha?: number | undefined | null, beta?: number | undefined | null): MxArray;
|
|
390
768
|
abs(): MxArray;
|
|
@@ -399,6 +777,8 @@ export declare class MxArray {
|
|
|
399
777
|
sinh(): MxArray;
|
|
400
778
|
cosh(): MxArray;
|
|
401
779
|
tanh(): MxArray;
|
|
780
|
+
/** Error function: erf(x) = (2/sqrt(pi)) * integral(0..x, exp(-t^2) dt) */
|
|
781
|
+
erf(): MxArray;
|
|
402
782
|
floor(): MxArray;
|
|
403
783
|
ceil(): MxArray;
|
|
404
784
|
round(): MxArray;
|
|
@@ -640,522 +1020,542 @@ export declare class OutputStore {
|
|
|
640
1020
|
}
|
|
641
1021
|
|
|
642
1022
|
/**
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
* Pass this back to the next chat() call via `model.setCache(cache)`
|
|
646
|
-
* to enable incremental prefill — only new tokens since the last turn
|
|
647
|
-
* are processed, avoiding redundant computation.
|
|
1023
|
+
* NAPI-exported view of [`PrivacyFilterModel`].
|
|
648
1024
|
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
1025
|
+
* Construct via [`PrivacyFilterModelJs::load`] and run end-to-end
|
|
1026
|
+
* classification via [`PrivacyFilterModelJs::classify`].
|
|
651
1027
|
*/
|
|
652
|
-
export declare class
|
|
653
|
-
/**
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
1028
|
+
export declare class PrivacyFilterModel {
|
|
1029
|
+
/**
|
|
1030
|
+
* Load a privacy-filter checkpoint from a directory.
|
|
1031
|
+
*
|
|
1032
|
+
* The directory must contain `config.json`, `model.safetensors`,
|
|
1033
|
+
* `tokenizer.json`, and optionally `viterbi_calibration.json` and
|
|
1034
|
+
* `tokenizer_config.json`. Synchronous to match the loader pattern
|
|
1035
|
+
* used by every other model in this crate (e.g. `TextDetModel`).
|
|
1036
|
+
*/
|
|
1037
|
+
static load(modelPath: string): PrivacyFilterModel;
|
|
1038
|
+
/**
|
|
1039
|
+
* Classify `text` and return detected PII entities (and optionally
|
|
1040
|
+
* per-token tags).
|
|
1041
|
+
*
|
|
1042
|
+
* Pipeline:
|
|
1043
|
+
* 1. Tokenize the text with byte offsets, no special tokens.
|
|
1044
|
+
* 2. Run the forward pass to get `[1, T, 33]` logits.
|
|
1045
|
+
* 3. Compute softmax (for per-tag confidences) and log-softmax (for
|
|
1046
|
+
* Viterbi emissions) over the class axis.
|
|
1047
|
+
* 4. Build the transition matrix from the default calibration
|
|
1048
|
+
* merged with any per-call overrides.
|
|
1049
|
+
* 5. Viterbi-decode using log-softmax emissions to get the BIOES
|
|
1050
|
+
* tag sequence.
|
|
1051
|
+
* 6. For each token, take the softmax probability of the
|
|
1052
|
+
* Viterbi-emitted tag (so per-token `tag` and `score` share
|
|
1053
|
+
* decoders), then walk the tags + offsets + those probabilities
|
|
1054
|
+
* to extract coherent spans whose mean probability clears
|
|
1055
|
+
* `threshold`.
|
|
1056
|
+
*/
|
|
1057
|
+
classify(text: string, opts?: PrivacyClassifyOptions | undefined | null): PrivacyClassifyResult;
|
|
659
1058
|
}
|
|
1059
|
+
export type PrivacyFilterModelJs = PrivacyFilterModel;
|
|
660
1060
|
|
|
661
1061
|
/**
|
|
662
|
-
*
|
|
1062
|
+
* Qianfan-OCR Vision-Language Model (InternVL architecture).
|
|
1063
|
+
*
|
|
1064
|
+
* Combines InternViT vision encoder, MLP bridge with pixel shuffle,
|
|
1065
|
+
* and Qwen3 language model for OCR and document understanding.
|
|
663
1066
|
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
* This matches the pattern used by Qwen3Model.
|
|
1067
|
+
* All inference state lives on a dedicated OS thread. NAPI methods
|
|
1068
|
+
* dispatch commands via channels and await responses.
|
|
667
1069
|
*/
|
|
668
|
-
export declare class
|
|
669
|
-
/** Create a new Qwen3.5 model with the given configuration. */
|
|
670
|
-
constructor(config: Qwen35Config);
|
|
671
|
-
/** Initialize caches for incremental generation. */
|
|
672
|
-
initCaches(): void;
|
|
673
|
-
/** Reset all caches. */
|
|
674
|
-
resetCaches(): void;
|
|
675
|
-
/**
|
|
676
|
-
* Take the KV cache from the model, returning a `PromptCache` handle.
|
|
677
|
-
*
|
|
678
|
-
* The cache is moved out of the model — calling `takeCache()` twice
|
|
679
|
-
* returns `null` the second time. Pass the cache back via `setCache()`
|
|
680
|
-
* before the next `chat()` call for incremental prefill.
|
|
681
|
-
*/
|
|
682
|
-
takeCache(): PromptCache | null;
|
|
683
|
-
/**
|
|
684
|
-
* Restore a previously taken `PromptCache` into the model.
|
|
685
|
-
*
|
|
686
|
-
* On the next `chat()` call with `reuseCache: true`, the model will
|
|
687
|
-
* prefix-match the new tokens against the cache and only prefill the delta.
|
|
688
|
-
*/
|
|
689
|
-
setCache(cache: PromptCache): void;
|
|
690
|
-
/**
|
|
691
|
-
* Forward pass through the model.
|
|
692
|
-
*
|
|
693
|
-
* # Arguments
|
|
694
|
-
* * `input_ids` - Token IDs [B, T]
|
|
695
|
-
*
|
|
696
|
-
* # Returns
|
|
697
|
-
* Logits [B, T, vocab_size]
|
|
698
|
-
*/
|
|
699
|
-
forward(inputIds: MxArray): MxArray;
|
|
700
|
-
/** Forward pass with cache for incremental generation. */
|
|
701
|
-
forwardWithCache(inputIds: MxArray): MxArray;
|
|
1070
|
+
export declare class QianfanOCRModel {
|
|
702
1071
|
/**
|
|
703
|
-
*
|
|
1072
|
+
* Create a new QianfanOCRModel from config (uninitialized, no weights).
|
|
704
1073
|
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
*
|
|
1074
|
+
* This constructor path does not spawn a model thread — the returned
|
|
1075
|
+
* instance is only useful for `is_initialized` queries until
|
|
1076
|
+
* [`QianfanOCRModel::load`] is called to actually run inference. The
|
|
1077
|
+
* `config` argument is accepted to preserve the `new
|
|
1078
|
+
* QianfanOCRModel(config)` JS surface; the value is discarded because
|
|
1079
|
+
* nothing on the uninitialized path consults it (any future config
|
|
1080
|
+
* getter would forward to the inner thread state populated by
|
|
1081
|
+
* `load()`).
|
|
709
1082
|
*/
|
|
710
|
-
|
|
1083
|
+
constructor(config: QianfanOcrConfig);
|
|
1084
|
+
/** Returns true if weights have been loaded via `load()`. */
|
|
1085
|
+
get isInitialized(): boolean;
|
|
711
1086
|
/**
|
|
712
|
-
*
|
|
1087
|
+
* Load a QianfanOCRModel from a directory.
|
|
713
1088
|
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
1089
|
+
* Reads config.json, loads SafeTensors weights (single or sharded),
|
|
1090
|
+
* builds vision encoder, bridge, and language model, and loads tokenizer.
|
|
1091
|
+
* All heavy work runs on the dedicated model thread.
|
|
716
1092
|
*/
|
|
717
|
-
|
|
1093
|
+
static load(modelPath: string): Promise<QianfanOCRModel>;
|
|
718
1094
|
/**
|
|
719
|
-
*
|
|
1095
|
+
* Generate text tokens given pre-tokenized input.
|
|
720
1096
|
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
1097
|
+
* Lower-level API — prefer the session chat methods
|
|
1098
|
+
* (`chatSessionStart` / `chatSessionContinue` and their streaming
|
|
1099
|
+
* variants) for typical usage.
|
|
723
1100
|
*/
|
|
724
|
-
|
|
1101
|
+
generate(
|
|
1102
|
+
inputIds: MxArray,
|
|
1103
|
+
maxNewTokens?: number | undefined | null,
|
|
1104
|
+
temperature?: number | undefined | null,
|
|
1105
|
+
): Promise<Array<number>>;
|
|
1106
|
+
/** Reset KV caches and token history. */
|
|
1107
|
+
resetCaches(): void;
|
|
725
1108
|
/**
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
|
|
732
|
-
|
|
1109
|
+
* Start a new chat session.
|
|
1110
|
+
*
|
|
1111
|
+
* Runs the full chat template once, decodes until `<|im_end|>`,
|
|
1112
|
+
* and leaves the KV caches on a clean turn boundary so subsequent
|
|
1113
|
+
* `chatSessionContinue` / `chatSessionContinueTool` calls can
|
|
1114
|
+
* append a raw ChatML delta on top without re-rendering the chat
|
|
1115
|
+
* template.
|
|
1116
|
+
*
|
|
1117
|
+
* Qianfan-OCR is always a VLM (InternViT + Qwen3 language model), so
|
|
1118
|
+
* this entry point accepts images in `messages` without the text-only
|
|
1119
|
+
* fast-fail used by plain language models.
|
|
1120
|
+
*/
|
|
1121
|
+
chatSessionStart(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
1122
|
+
/**
|
|
1123
|
+
* Continue an existing chat session with a new user message.
|
|
1124
|
+
*
|
|
1125
|
+
* Appends a raw ChatML user/assistant delta to the session's cached
|
|
1126
|
+
* KV state, then decodes the model reply. Stops on `<|im_end|>` so
|
|
1127
|
+
* the cache remains on a clean turn boundary for the next turn.
|
|
1128
|
+
*
|
|
1129
|
+
* Requires a live session started via `chatSessionStart`. Errors
|
|
1130
|
+
* if the session is empty or if `config.reuse_cache` is
|
|
1131
|
+
* explicitly set to `false`.
|
|
1132
|
+
*
|
|
1133
|
+
* `images` is an opt-in guard parameter: when non-empty the native
|
|
1134
|
+
* side returns an error whose message begins with
|
|
1135
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` so the TypeScript
|
|
1136
|
+
* `ChatSession` layer can catch the prefix and route image-changes
|
|
1137
|
+
* back through a fresh `chatSessionStart` uniformly across all
|
|
1138
|
+
* model backends. Qianfan-OCR is a VLM but the continue path cannot
|
|
1139
|
+
* splice new vision features into a live KV cache — image changes
|
|
1140
|
+
* always require a fresh session start.
|
|
1141
|
+
*
|
|
1142
|
+
* `audio` exists only to keep this method's positional ABI aligned
|
|
1143
|
+
* with the shared chat surface every other family exposes (the
|
|
1144
|
+
* `chat_napi_surface!` macro inserts `audio` between `images` and
|
|
1145
|
+
* `config`). Qianfan-OCR has no audio support, so a non-empty
|
|
1146
|
+
* `audio` is rejected at the boundary with the shared no-audio
|
|
1147
|
+
* error; `None` / empty is a complete no-op and audio is never
|
|
1148
|
+
* threaded into the model thread.
|
|
1149
|
+
*/
|
|
1150
|
+
chatSessionContinue(
|
|
1151
|
+
userMessage: string,
|
|
1152
|
+
images: Uint8Array[] | null | undefined,
|
|
1153
|
+
audio: Uint8Array[] | null | undefined,
|
|
1154
|
+
config: ChatConfig | null | undefined,
|
|
1155
|
+
): Promise<ChatResult>;
|
|
1156
|
+
/**
|
|
1157
|
+
* Continue an existing chat session with a tool-result turn.
|
|
1158
|
+
*
|
|
1159
|
+
* Builds a ChatML `<tool_response>` delta from `tool_call_id` and
|
|
1160
|
+
* `content` and prefills it on top of the live session caches, then
|
|
1161
|
+
* decodes the model reply. Stops on `<|im_end|>` so the cache stays
|
|
1162
|
+
* on a clean turn boundary for the next turn.
|
|
1163
|
+
*
|
|
1164
|
+
* `is_error` is the structured tool-error signal. When `Some(true)`,
|
|
1165
|
+
* the renderer prepends the shared
|
|
1166
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
1167
|
+
* `<tool_response>` wrapper so the model receives a clear text-level
|
|
1168
|
+
* cue. `None` / `Some(false)` keep the wire bytes byte-equal to the
|
|
1169
|
+
* pre-feature output.
|
|
1170
|
+
*
|
|
1171
|
+
* Requires a live session started via `chatSessionStart`.
|
|
1172
|
+
*/
|
|
1173
|
+
chatSessionContinueTool(
|
|
1174
|
+
toolCallId: string,
|
|
1175
|
+
content: string,
|
|
1176
|
+
config?: ChatConfig | undefined | null,
|
|
1177
|
+
isError?: boolean | undefined | null,
|
|
1178
|
+
): Promise<ChatResult>;
|
|
1179
|
+
/** Streaming variant of `chatSessionStart`. */
|
|
1180
|
+
chatStreamSessionStart(
|
|
733
1181
|
messages: ChatMessage[],
|
|
734
|
-
config: ChatConfig | null,
|
|
1182
|
+
config: ChatConfig | null | undefined,
|
|
735
1183
|
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
736
1184
|
): Promise<ChatStreamHandle>;
|
|
737
|
-
/** Get the number of parameters in the model. */
|
|
738
|
-
numParameters(): number;
|
|
739
1185
|
/**
|
|
740
|
-
*
|
|
1186
|
+
* Streaming variant of `chatSessionContinue`.
|
|
741
1187
|
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
* -
|
|
745
|
-
* -
|
|
746
|
-
*
|
|
747
|
-
* # Arguments
|
|
748
|
-
* * `save_path` - Directory to save the model
|
|
749
|
-
*/
|
|
750
|
-
saveModel(savePath: string): Promise<undefined>;
|
|
751
|
-
}
|
|
752
|
-
export type Qwen3_5Model = Qwen35Model;
|
|
753
|
-
|
|
754
|
-
/**
|
|
755
|
-
* Qwen3.5 MoE Model -- hybrid linear/full attention with Mixture-of-Experts.
|
|
756
|
-
*
|
|
757
|
-
* Supports C++ MoE forward path (non-compiled, builds fresh graph per step)
|
|
758
|
-
* when weights are registered via `register_moe_weights_with_cpp`.
|
|
759
|
-
* Falls back to Rust forward_inner path for test models without stored weights.
|
|
760
|
-
*/
|
|
761
|
-
export declare class Qwen35MoeModel {
|
|
762
|
-
constructor(config: Qwen35MoeConfig);
|
|
763
|
-
/**
|
|
764
|
-
* Take the KV cache from the model, returning a `PromptCache` handle.
|
|
765
|
-
*
|
|
766
|
-
* The cache is moved out of the model — calling `takeCache()` twice
|
|
767
|
-
* returns `null` the second time. Pass the cache back via `setCache()`
|
|
768
|
-
* before the next `chat()` call for incremental prefill.
|
|
1188
|
+
* `audio` mirrors the non-streaming entry point: it exists only to
|
|
1189
|
+
* keep the positional ABI aligned with the shared chat surface, and
|
|
1190
|
+
* a non-empty value is rejected at the boundary with the shared
|
|
1191
|
+
* no-audio error. `None` / empty is a complete no-op.
|
|
769
1192
|
*/
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
* prefix-match the new tokens against the cache and only prefill the delta.
|
|
776
|
-
*/
|
|
777
|
-
setCache(cache: PromptCache): void;
|
|
778
|
-
initCaches(): void;
|
|
779
|
-
resetCaches(): void;
|
|
780
|
-
forward(inputIds: MxArray): MxArray;
|
|
781
|
-
forwardWithCache(inputIds: MxArray): MxArray;
|
|
782
|
-
static load(path: string): Promise<Qwen35MoeModel>;
|
|
783
|
-
generate(promptTokens: MxArray, config: Qwen35MoeGenerationConfig): Promise<Qwen35MoeGenerationResult>;
|
|
784
|
-
chat(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
785
|
-
/**
|
|
786
|
-
* Streaming chat API with tool calling support.
|
|
787
|
-
*
|
|
788
|
-
* Same as `chat()` but streams tokens one-by-one via the callback.
|
|
789
|
-
* Returns a `ChatStreamHandle` immediately; generation runs in background.
|
|
790
|
-
* Call `handle.cancel()` to abort generation early.
|
|
791
|
-
*/
|
|
792
|
-
chatStream(
|
|
793
|
-
messages: ChatMessage[],
|
|
794
|
-
config: ChatConfig | null,
|
|
1193
|
+
chatStreamSessionContinue(
|
|
1194
|
+
userMessage: string,
|
|
1195
|
+
images: Uint8Array[] | null | undefined,
|
|
1196
|
+
audio: Uint8Array[] | null | undefined,
|
|
1197
|
+
config: ChatConfig | null | undefined,
|
|
795
1198
|
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
796
1199
|
): Promise<ChatStreamHandle>;
|
|
797
|
-
numParameters(): number;
|
|
798
1200
|
/**
|
|
799
|
-
*
|
|
1201
|
+
* Streaming variant of `chatSessionContinueTool`.
|
|
800
1202
|
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
* # Arguments
|
|
807
|
-
* * `save_path` - Directory to save the model
|
|
1203
|
+
* `is_error` mirrors the non-streaming entry point — when
|
|
1204
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1205
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
1206
|
+
* `<tool_response>` wrapper.
|
|
808
1207
|
*/
|
|
809
|
-
|
|
1208
|
+
chatStreamSessionContinueTool(
|
|
1209
|
+
toolCallId: string,
|
|
1210
|
+
content: string,
|
|
1211
|
+
config: ChatConfig | null | undefined,
|
|
1212
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1213
|
+
isError?: boolean | null | undefined,
|
|
1214
|
+
): Promise<ChatStreamHandle>;
|
|
810
1215
|
}
|
|
811
|
-
export type Qwen3_5MoeModel = Qwen35MoeModel;
|
|
812
1216
|
|
|
813
1217
|
/**
|
|
814
|
-
* Qwen3 Model with
|
|
1218
|
+
* Qwen3.5 Model -- hybrid linear/full attention with optional MoE.
|
|
815
1219
|
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
1220
|
+
* All inference and training state lives on a dedicated OS thread. NAPI methods
|
|
1221
|
+
* dispatch commands via channels and await responses. Training commands are
|
|
1222
|
+
* routed through `TrainingDispatch` to the model thread.
|
|
819
1223
|
*/
|
|
820
|
-
export declare class
|
|
821
|
-
/** Create a new Qwen3 model with the given configuration */
|
|
822
|
-
constructor(config: Qwen3Config);
|
|
823
|
-
/**
|
|
824
|
-
* Reset the KV cache used for cache reuse across chat() calls.
|
|
825
|
-
* Call this when starting a new conversation to ensure a full prefill.
|
|
826
|
-
*/
|
|
827
|
-
resetCache(): void;
|
|
828
|
-
/**
|
|
829
|
-
* Forward pass through the model
|
|
830
|
-
*
|
|
831
|
-
* # Arguments
|
|
832
|
-
* * `input_ids` - Token IDs, shape: [batch_size, seq_len]
|
|
833
|
-
*
|
|
834
|
-
* # Returns
|
|
835
|
-
* * Logits, shape: [batch_size, seq_len, vocab_size]
|
|
836
|
-
*/
|
|
837
|
-
forward(inputIds: MxArray): MxArray;
|
|
838
|
-
/**
|
|
839
|
-
* Initialize KV caches for incremental generation
|
|
840
|
-
*
|
|
841
|
-
* Creates one KV cache per transformer layer. Call this before starting generation.
|
|
842
|
-
*/
|
|
843
|
-
initKvCaches(): void;
|
|
1224
|
+
export declare class Qwen35Model {
|
|
844
1225
|
/**
|
|
845
|
-
*
|
|
1226
|
+
* Whether the block-paged KV cache adapter is active on this model
|
|
1227
|
+
* instance.
|
|
846
1228
|
*
|
|
847
|
-
*
|
|
1229
|
+
* `true` iff `Qwen35Inner::paged_adapter` was successfully
|
|
1230
|
+
* constructed at load time (driven by
|
|
1231
|
+
* `Qwen3_5Config::use_block_paged_cache`, default-OFF for text-only
|
|
1232
|
+
* checkpoints because parity is pending real-weights validation, and
|
|
1233
|
+
* default-ON for VLM checkpoints). On VLM checkpoints dense image turns
|
|
1234
|
+
* ONLY run on the paged-vision core; a vision turn that reaches a None
|
|
1235
|
+
* adapter errors at dispatch. Surfaced through this NAPI method so
|
|
1236
|
+
* server endpoints can branch on it without round-tripping through
|
|
1237
|
+
* the model thread.
|
|
848
1238
|
*/
|
|
849
|
-
|
|
850
|
-
/** Check if paged attention is enabled for this model */
|
|
851
|
-
hasPagedAttention(): boolean;
|
|
1239
|
+
hasBlockPagedCache(): boolean;
|
|
852
1240
|
/**
|
|
853
|
-
*
|
|
1241
|
+
* Whether this checkpoint shipped an MTP head (module loaded by
|
|
1242
|
+
* `persistence::apply_weights_inner`). Snapshotted at load time from
|
|
1243
|
+
* `Qwen35Inner::has_mtp_weights()` so the TS `ChatSession` can
|
|
1244
|
+
* auto-default `enableMtp = true` for MTP-capable checkpoints without
|
|
1245
|
+
* dispatching a command into the model thread.
|
|
854
1246
|
*
|
|
855
|
-
*
|
|
1247
|
+
* Note: this only reports weight availability. Whether the
|
|
1248
|
+
* speculative-decode path actually runs on a given call also requires the
|
|
1249
|
+
* per-request `enableMtp` flag.
|
|
856
1250
|
*/
|
|
857
|
-
|
|
1251
|
+
hasMtpWeights(): boolean;
|
|
858
1252
|
/**
|
|
859
|
-
*
|
|
1253
|
+
* Whether this loaded model instance can execute image-bearing turns.
|
|
860
1254
|
*
|
|
861
|
-
*
|
|
1255
|
+
* This is an authoritative load-time snapshot, not a `config.json`
|
|
1256
|
+
* family guess: it requires a loaded vision encoder, image processor,
|
|
1257
|
+
* and the block-paged KV adapter used by the dense vision path.
|
|
862
1258
|
*/
|
|
863
|
-
|
|
1259
|
+
supportsImages(): boolean;
|
|
864
1260
|
/**
|
|
865
|
-
*
|
|
866
|
-
*
|
|
867
|
-
* # Arguments
|
|
868
|
-
* * `input_ids` - Token IDs, shape: [batch_size, seq_len]
|
|
869
|
-
* * `use_cache` - Whether to use KV caching (must call init_kv_caches() first)
|
|
870
|
-
*
|
|
871
|
-
* # Returns
|
|
872
|
-
* * Logits, shape: [batch_size, seq_len, vocab_size]
|
|
1261
|
+
* Synchronous snapshot used by higher layers to preflight rendered
|
|
1262
|
+
* prompts and clamp output before native cache allocation.
|
|
873
1263
|
*/
|
|
874
|
-
|
|
1264
|
+
contextLimits(): Qwen35ContextLimits;
|
|
875
1265
|
/**
|
|
876
|
-
*
|
|
1266
|
+
* Compute the exact prompt length after Qwen image-placeholder expansion
|
|
1267
|
+
* without running the vision encoder or touching inference caches.
|
|
877
1268
|
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
881
|
-
* - Long context support beyond GPU memory limits
|
|
882
|
-
*
|
|
883
|
-
* # Arguments
|
|
884
|
-
* * `input_ids` - Token IDs, shape: [num_seqs, 1] for decode
|
|
885
|
-
* * `slot_mapping` - Slot indices for cache updates, shape: [num_seqs]
|
|
886
|
-
* * `seq_ids` - Sequence IDs in the batch (for looking up block tables/context lens)
|
|
887
|
-
* * `positions` - Token positions for RoPE, shape: [num_seqs] (per-sequence positions)
|
|
888
|
-
*
|
|
889
|
-
* # Returns
|
|
890
|
-
* * Logits, shape: [num_seqs, 1, vocab_size] for decode
|
|
891
|
-
*/
|
|
892
|
-
forwardPaged(inputIds: MxArray, slotMapping: MxArray, seqIds: Array<number>, positions: MxArray): MxArray;
|
|
893
|
-
/**
|
|
894
|
-
* Prefill a sequence using standard attention and write K/V to paged cache.
|
|
895
|
-
*
|
|
896
|
-
* This method should be called before `step_paged_generation()` for each
|
|
897
|
-
* new prompt. It runs the full forward pass using standard attention
|
|
898
|
-
* (which is faster for long sequences), then writes the K/V cache to
|
|
899
|
-
* the paged cache for subsequent decode steps.
|
|
900
|
-
*
|
|
901
|
-
* # Arguments
|
|
902
|
-
* * `prompt_tokens` - Token IDs for the prompt (as u32 array)
|
|
903
|
-
* * `seq_id` - Sequence ID (obtained from scheduler)
|
|
904
|
-
*
|
|
905
|
-
* # Returns
|
|
906
|
-
* * Logits for the last token, shape: [1, vocab_size]
|
|
1269
|
+
* `prompt_tokens` is the already-rendered chat-template output. `messages`
|
|
1270
|
+
* supplies the complete image history so both fresh and leased-session
|
|
1271
|
+
* preflights account for every image in template order.
|
|
907
1272
|
*/
|
|
908
|
-
|
|
1273
|
+
expandedPromptTokenCount(promptTokens: Uint32Array, messages: Array<ChatMessage>): Promise<number>;
|
|
909
1274
|
/**
|
|
910
|
-
*
|
|
911
|
-
*
|
|
912
|
-
* The scheduler queues requests and allocates blocks for KV cache.
|
|
913
|
-
* Use `step_paged_generation()` to process the scheduled batch.
|
|
914
|
-
*
|
|
915
|
-
* Note: The actual sequence ID is assigned during scheduling, not when the
|
|
916
|
-
* request is added. Use the `request_id` to track your requests through
|
|
917
|
-
* the generation process.
|
|
918
|
-
*
|
|
919
|
-
* # Arguments
|
|
920
|
-
* * `request_id` - Unique identifier for the request (returned in outputs)
|
|
921
|
-
* * `prompt_tokens` - Token IDs for the prompt
|
|
922
|
-
* * `max_new_tokens` - Maximum new tokens to generate
|
|
923
|
-
* * `priority` - Optional priority (higher = scheduled first)
|
|
924
|
-
*
|
|
925
|
-
* # Returns
|
|
926
|
-
* * Number of pending requests in the queue
|
|
927
|
-
*/
|
|
928
|
-
addPagedRequest(
|
|
929
|
-
requestId: string,
|
|
930
|
-
promptTokens: Array<number>,
|
|
931
|
-
maxNewTokens: number,
|
|
932
|
-
priority?: number | undefined | null,
|
|
933
|
-
): number;
|
|
934
|
-
/**
|
|
935
|
-
* Schedule and execute one step of paged generation.
|
|
936
|
-
*
|
|
937
|
-
* This method:
|
|
938
|
-
* 1. Schedules the next batch of sequences
|
|
939
|
-
* 2. Runs forward pass with paged attention
|
|
940
|
-
* 3. Samples next tokens
|
|
941
|
-
* 4. Returns the generated tokens for each sequence
|
|
942
|
-
*
|
|
943
|
-
* # Arguments
|
|
944
|
-
* * `config` - Generation configuration (temperature, top_k, etc.)
|
|
945
|
-
*
|
|
946
|
-
* # Returns
|
|
947
|
-
* * `PagedGenerationStep` with token outputs for each sequence
|
|
948
|
-
*/
|
|
949
|
-
stepPagedGeneration(config?: GenerationConfig | undefined | null): PagedGenerationStep | null;
|
|
950
|
-
/**
|
|
951
|
-
* Get completed sequences from the scheduler.
|
|
1275
|
+
* Load a pretrained model from a directory.
|
|
952
1276
|
*
|
|
953
|
-
*
|
|
1277
|
+
* Expects the directory to contain:
|
|
1278
|
+
* - config.json
|
|
1279
|
+
* - model.safetensors (or model-*.safetensors)
|
|
1280
|
+
* - tokenizer.json + tokenizer_config.json
|
|
954
1281
|
*/
|
|
955
|
-
|
|
956
|
-
/**
|
|
957
|
-
|
|
958
|
-
/** Get model configuration */
|
|
959
|
-
getConfig(): Qwen3Config;
|
|
1282
|
+
static load(path: string): Promise<Qwen35Model>;
|
|
1283
|
+
/** Generate text from a prompt token sequence. */
|
|
1284
|
+
generate(promptTokens: MxArray, config: Qwen35GenerationConfig): Promise<Qwen35GenerationResult>;
|
|
960
1285
|
/**
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
* Speculative decoding uses a smaller draft model to generate tokens speculatively,
|
|
964
|
-
* then verifies them with the target model in a single forward pass. This can achieve
|
|
965
|
-
* 2-3x speedup when the draft model has high acceptance rate.
|
|
966
|
-
*
|
|
967
|
-
* # Algorithm
|
|
968
|
-
* 1. Draft model generates N tokens speculatively (cheap forward passes)
|
|
969
|
-
* 2. Target model (self) verifies all N tokens in one forward pass
|
|
970
|
-
* 3. Accept/reject using rejection sampling
|
|
971
|
-
* 4. On rejection, resample from adjusted distribution
|
|
972
|
-
* 5. Rewind caches and continue
|
|
973
|
-
*
|
|
974
|
-
* # Arguments
|
|
975
|
-
* * `draft_model` - Smaller model for speculative generation (should share tokenizer)
|
|
976
|
-
* * `input_ids` - Input token IDs [1, seq_len]
|
|
977
|
-
* * `config` - Generation configuration (includes num_draft_tokens)
|
|
1286
|
+
* Get the number of parameters in the model.
|
|
978
1287
|
*
|
|
979
|
-
*
|
|
980
|
-
* GenerationResult with tokens, logprobs, and speculative stats in finish_reason
|
|
981
|
-
*
|
|
982
|
-
* # Example (TypeScript)
|
|
983
|
-
* ```typescript
|
|
984
|
-
* const targetModel = await loadModel('qwen3-7b');
|
|
985
|
-
* const draftModel = await loadModel('qwen3-0.5b');
|
|
986
|
-
*
|
|
987
|
-
* const result = targetModel.generateSpeculativeSync(draftModel, inputIds, {
|
|
988
|
-
* numDraftTokens: 5,
|
|
989
|
-
* maxNewTokens: 100,
|
|
990
|
-
* temperature: 0.7,
|
|
991
|
-
* });
|
|
992
|
-
* ```
|
|
1288
|
+
* Pure config computation — no model-thread dispatch needed.
|
|
993
1289
|
*/
|
|
994
|
-
generateSpeculativeSync(
|
|
995
|
-
draftModel: Qwen3Model,
|
|
996
|
-
inputIds: MxArray,
|
|
997
|
-
config?: GenerationConfig | undefined | null,
|
|
998
|
-
): GenerationResult;
|
|
999
|
-
/** Count total number of parameters in the model */
|
|
1000
1290
|
numParameters(): number;
|
|
1001
1291
|
/**
|
|
1002
|
-
*
|
|
1292
|
+
* Save the model weights and configuration to a directory.
|
|
1003
1293
|
*
|
|
1004
|
-
*
|
|
1294
|
+
* Dispatches to model thread.
|
|
1005
1295
|
*/
|
|
1006
|
-
|
|
1007
|
-
/** Load parameters from a dictionary */
|
|
1008
|
-
loadParameters(params: Record<string, MxArray>): void;
|
|
1296
|
+
saveModel(savePath: string): Promise<undefined>;
|
|
1009
1297
|
/**
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
* * `input_ids` - Input token IDs, shape: [batch_size, seq_len]
|
|
1014
|
-
* * `labels` - Target token IDs, shape: [batch_size, seq_len]
|
|
1015
|
-
*
|
|
1016
|
-
* # Returns
|
|
1017
|
-
* * Scalar loss value
|
|
1298
|
+
* Reset all caches and clear cached token history. Exposed
|
|
1299
|
+
* so tests and session-management code can start from a
|
|
1300
|
+
* known clean state between turns.
|
|
1018
1301
|
*/
|
|
1019
|
-
|
|
1302
|
+
resetCaches(): void;
|
|
1020
1303
|
/**
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
*
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
*
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
* -
|
|
1304
|
+
* Start a new chat session.
|
|
1305
|
+
*
|
|
1306
|
+
* Runs the full jinja chat template once, decodes until the
|
|
1307
|
+
* family's session stop token, and leaves the KV caches on a
|
|
1308
|
+
* clean turn boundary so subsequent `chatSessionContinue` /
|
|
1309
|
+
* `chatSessionContinueTool` calls can append a raw delta on
|
|
1310
|
+
* top without re-rendering the chat template.
|
|
1311
|
+
*/
|
|
1312
|
+
chatSessionStart(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
1313
|
+
/**
|
|
1314
|
+
* Continue an existing chat session with a new user message.
|
|
1315
|
+
*
|
|
1316
|
+
* Appends a raw user/assistant delta to the session's cached
|
|
1317
|
+
* KV state, then decodes the assistant reply, stopping on the
|
|
1318
|
+
* family's session boundary token.
|
|
1319
|
+
*
|
|
1320
|
+
* `images` is an opt-in guard parameter: when non-empty the
|
|
1321
|
+
* native side returns an error whose message begins with
|
|
1322
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` so the TypeScript
|
|
1323
|
+
* `ChatSession` layer can route image-changes back through a
|
|
1324
|
+
* fresh `chatSessionStart`.
|
|
1325
|
+
*/
|
|
1326
|
+
chatSessionContinue(
|
|
1327
|
+
userMessage: string,
|
|
1328
|
+
images: Uint8Array[] | null | undefined,
|
|
1329
|
+
audio: Uint8Array[] | null | undefined,
|
|
1330
|
+
config: ChatConfig | null | undefined,
|
|
1331
|
+
): Promise<ChatResult>;
|
|
1332
|
+
/**
|
|
1333
|
+
* Continue an existing chat session with a tool-result turn.
|
|
1334
|
+
*
|
|
1335
|
+
* Builds the family's tool-result delta from `content` and
|
|
1336
|
+
* prefills it on top of the live session caches, then decodes
|
|
1337
|
+
* the assistant reply.
|
|
1338
|
+
*
|
|
1339
|
+
* `is_error` is the structured tool-error signal. When
|
|
1340
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1341
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
1342
|
+
* rendered tool block.
|
|
1343
|
+
*/
|
|
1344
|
+
chatSessionContinueTool(
|
|
1345
|
+
toolCallId: string,
|
|
1346
|
+
content: string,
|
|
1347
|
+
config?: ChatConfig | undefined | null,
|
|
1348
|
+
isError?: boolean | undefined | null,
|
|
1349
|
+
): Promise<ChatResult>;
|
|
1350
|
+
/** Streaming variant of `chatSessionStart`. */
|
|
1351
|
+
chatStreamSessionStart(
|
|
1352
|
+
messages: ChatMessage[],
|
|
1353
|
+
config: ChatConfig | null,
|
|
1354
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1355
|
+
): Promise<ChatStreamHandle>;
|
|
1356
|
+
/** Streaming variant of `chatSessionContinue`. */
|
|
1357
|
+
chatStreamSessionContinue(
|
|
1358
|
+
userMessage: string,
|
|
1359
|
+
images: Uint8Array[] | null | undefined,
|
|
1360
|
+
audio: Uint8Array[] | null | undefined,
|
|
1361
|
+
config: ChatConfig | null,
|
|
1362
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1363
|
+
): Promise<ChatStreamHandle>;
|
|
1364
|
+
/**
|
|
1365
|
+
* Streaming variant of `chatSessionContinueTool`.
|
|
1038
1366
|
*
|
|
1039
|
-
*
|
|
1367
|
+
* `is_error` mirrors the non-streaming entry point — when
|
|
1368
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1369
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the rendered
|
|
1370
|
+
* tool block.
|
|
1040
1371
|
*/
|
|
1041
|
-
|
|
1372
|
+
chatStreamSessionContinueTool(
|
|
1373
|
+
toolCallId: string,
|
|
1374
|
+
content: string,
|
|
1375
|
+
config: ChatConfig | null,
|
|
1376
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1377
|
+
isError?: boolean | null | undefined,
|
|
1378
|
+
): Promise<ChatStreamHandle>;
|
|
1379
|
+
}
|
|
1380
|
+
export type Qwen3_5Model = Qwen35Model;
|
|
1381
|
+
|
|
1382
|
+
/**
|
|
1383
|
+
* Qwen3.5 MoE Model -- hybrid linear/full attention with Mixture-of-Experts.
|
|
1384
|
+
*
|
|
1385
|
+
* All inference and training state lives on a dedicated OS thread. NAPI methods
|
|
1386
|
+
* dispatch commands via channels and await responses. Training commands are
|
|
1387
|
+
* routed through `TrainingDispatch` to the model thread.
|
|
1388
|
+
*/
|
|
1389
|
+
export declare class Qwen35MoeModel {
|
|
1042
1390
|
/**
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
* This method uses automatic differentiation to compute gradients, eliminating
|
|
1046
|
-
* the need for manual backward pass implementation. This is the preferred approach.
|
|
1391
|
+
* Whether the block-paged KV cache adapter is active on this model
|
|
1392
|
+
* instance.
|
|
1047
1393
|
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1057
|
-
* # Returns
|
|
1058
|
-
* * Tuple of (loss_value, metrics_dict)
|
|
1394
|
+
* `true` iff `Qwen35MoeInner::paged_adapter` was successfully
|
|
1395
|
+
* constructed at load time (driven by
|
|
1396
|
+
* `Qwen3_5MoeConfig::use_block_paged_cache`, currently default-OFF
|
|
1397
|
+
* because parity is pending real-weights validation). On VLM
|
|
1398
|
+
* checkpoints the adapter can still be active for text-only
|
|
1399
|
+
* inference; image-bearing chat turns are rejected at runtime by
|
|
1400
|
+
* the chat-entry sites. Surfaced through this NAPI method so
|
|
1401
|
+
* server endpoints can branch on it without round-tripping through
|
|
1402
|
+
* the model thread.
|
|
1059
1403
|
*/
|
|
1060
|
-
|
|
1061
|
-
promptTokens: Array<MxArray>,
|
|
1062
|
-
completionTokens: Array<MxArray>,
|
|
1063
|
-
completionLogprobs: Array<MxArray>,
|
|
1064
|
-
rewards: Float64Array,
|
|
1065
|
-
groupSize: number,
|
|
1066
|
-
config: GrpoLossConfig,
|
|
1067
|
-
learningRate: number,
|
|
1068
|
-
): [number, Record<string, number>];
|
|
1404
|
+
hasBlockPagedCache(): boolean;
|
|
1069
1405
|
/**
|
|
1070
|
-
*
|
|
1406
|
+
* Whether this checkpoint shipped an MTP head (module loaded by
|
|
1407
|
+
* `persistence::apply_weights_moe_inner`). Snapshotted at load time from
|
|
1408
|
+
* `Qwen35MoeInner::has_mtp_weights()` so the TS `ChatSession` can
|
|
1409
|
+
* auto-default `enableMtp = true` for MTP-capable checkpoints without
|
|
1410
|
+
* dispatching a command into the model thread. Mirrors
|
|
1411
|
+
* `Qwen3_5Model::has_mtp_weights`.
|
|
1071
1412
|
*
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
* # Arguments
|
|
1077
|
-
* * `prompt_tokens` - Prompt token sequences [batch_size, seq_len] (1D arrays)
|
|
1078
|
-
* * `completion_tokens` - Completion sequences [batch*G, completion_len] (1D arrays)
|
|
1079
|
-
* * `completion_logprobs` - Logprobs from generation [batch*G, completion_len] (1D arrays)
|
|
1080
|
-
* * `rewards` - Reward scores for each completion [batch*G]
|
|
1081
|
-
* * `group_size` - Number of completions per prompt (G)
|
|
1082
|
-
* * `config` - GRPO loss configuration
|
|
1083
|
-
*
|
|
1084
|
-
* # Returns
|
|
1085
|
-
* * Tuple of (loss_value, gradients_dict, metrics_dict)
|
|
1413
|
+
* Note: this only reports weight availability. Whether the
|
|
1414
|
+
* speculative-decode path actually runs on a given call also requires
|
|
1415
|
+
* the per-request `enableMtp` flag.
|
|
1086
1416
|
*/
|
|
1087
|
-
|
|
1088
|
-
promptTokens: Array<MxArray>,
|
|
1089
|
-
completionTokens: Array<MxArray>,
|
|
1090
|
-
completionLogprobs: Array<MxArray>,
|
|
1091
|
-
rewards: Float64Array,
|
|
1092
|
-
groupSize: number,
|
|
1093
|
-
config: GrpoLossConfig,
|
|
1094
|
-
): [number, Record<string, MxArray>, Record<string, number>];
|
|
1417
|
+
hasMtpWeights(): boolean;
|
|
1095
1418
|
/**
|
|
1096
|
-
*
|
|
1419
|
+
* Whether this loaded model instance can execute image-bearing turns.
|
|
1097
1420
|
*
|
|
1098
|
-
* This is
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1101
|
-
* # Arguments
|
|
1102
|
-
* * `accumulated_gradients` - Existing accumulated gradients (will be modified in-place conceptually, but returns new dict)
|
|
1103
|
-
* * `new_gradients` - New gradients to add
|
|
1104
|
-
*
|
|
1105
|
-
* # Returns
|
|
1106
|
-
* * Updated gradient dictionary with accumulated values
|
|
1421
|
+
* This is an authoritative load-time snapshot, not a model-family guess:
|
|
1422
|
+
* it requires the loaded vision encoder, image processor, and block-paged
|
|
1423
|
+
* KV adapter used by the MoE vision path.
|
|
1107
1424
|
*/
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
): Record<string, MxArray>;
|
|
1425
|
+
supportsImages(): boolean;
|
|
1426
|
+
/** Synchronous active-context snapshot shared with the dense wrapper. */
|
|
1427
|
+
contextLimits(): Qwen35ContextLimits;
|
|
1112
1428
|
/**
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
* This method performs a full GRPO training iteration:
|
|
1116
|
-
* 1. Takes completions (already generated) with their logprobs and rewards
|
|
1117
|
-
* 2. Computes advantages
|
|
1118
|
-
* 3. Computes GRPO loss and gradients
|
|
1119
|
-
* 4. Updates model parameters
|
|
1120
|
-
*
|
|
1121
|
-
* NOTE: Use train_step_grpo_autograd instead for automatic differentiation.
|
|
1122
|
-
*
|
|
1123
|
-
* # Arguments
|
|
1124
|
-
* * `prompt_tokens` - Prompt token sequences [batch_size, seq_len] (1D arrays)
|
|
1125
|
-
* * `completion_tokens` - Completion sequences [batch*G, completion_len] (1D arrays)
|
|
1126
|
-
* * `completion_logprobs` - Logprobs from generation [batch*G, completion_len] (1D arrays)
|
|
1127
|
-
* * `rewards` - Reward scores for each completion [batch*G]
|
|
1128
|
-
* * `group_size` - Number of completions per prompt (G)
|
|
1129
|
-
* * `config` - GRPO loss configuration
|
|
1130
|
-
* * `learning_rate` - Learning rate for parameter updates
|
|
1131
|
-
*
|
|
1132
|
-
* # Returns
|
|
1133
|
-
* * Tuple of (loss_value, metrics_dict)
|
|
1429
|
+
* Exact, non-mutating Qwen image-placeholder expansion count for a fully
|
|
1430
|
+
* rendered prompt and complete message history.
|
|
1134
1431
|
*/
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
groupSize: number,
|
|
1141
|
-
config: GrpoLossConfig,
|
|
1142
|
-
learningRate: number,
|
|
1143
|
-
): [number, Record<string, number>];
|
|
1432
|
+
expandedPromptTokenCount(promptTokens: Uint32Array, messages: Array<ChatMessage>): Promise<number>;
|
|
1433
|
+
/** Load a pretrained model from a directory. */
|
|
1434
|
+
static load(path: string): Promise<Qwen35MoeModel>;
|
|
1435
|
+
/** Generate text from a prompt token sequence. */
|
|
1436
|
+
generate(promptTokens: MxArray, config: Qwen35MoeGenerationConfig): Promise<Qwen35MoeGenerationResult>;
|
|
1144
1437
|
/**
|
|
1145
|
-
*
|
|
1438
|
+
* Get the number of parameters in the model.
|
|
1146
1439
|
*
|
|
1147
|
-
*
|
|
1148
|
-
|
|
1149
|
-
|
|
1440
|
+
* Pure config computation -- no model-thread dispatch needed.
|
|
1441
|
+
*/
|
|
1442
|
+
numParameters(): number;
|
|
1443
|
+
/**
|
|
1444
|
+
* Save the model weights and configuration to a directory.
|
|
1150
1445
|
*
|
|
1151
|
-
*
|
|
1152
|
-
|
|
1446
|
+
* Dispatches to model thread.
|
|
1447
|
+
*/
|
|
1448
|
+
saveModel(savePath: string): Promise<undefined>;
|
|
1449
|
+
/**
|
|
1450
|
+
* Reset all caches and clear cached token history. Exposed
|
|
1451
|
+
* so tests and session-management code can start from a
|
|
1452
|
+
* known clean state between turns.
|
|
1453
|
+
*/
|
|
1454
|
+
resetCaches(): void;
|
|
1455
|
+
/**
|
|
1456
|
+
* Start a new chat session.
|
|
1457
|
+
*
|
|
1458
|
+
* Runs the full jinja chat template once, decodes until the
|
|
1459
|
+
* family's session stop token, and leaves the KV caches on a
|
|
1460
|
+
* clean turn boundary so subsequent `chatSessionContinue` /
|
|
1461
|
+
* `chatSessionContinueTool` calls can append a raw delta on
|
|
1462
|
+
* top without re-rendering the chat template.
|
|
1463
|
+
*/
|
|
1464
|
+
chatSessionStart(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
1465
|
+
/**
|
|
1466
|
+
* Continue an existing chat session with a new user message.
|
|
1467
|
+
*
|
|
1468
|
+
* Appends a raw user/assistant delta to the session's cached
|
|
1469
|
+
* KV state, then decodes the assistant reply, stopping on the
|
|
1470
|
+
* family's session boundary token.
|
|
1471
|
+
*
|
|
1472
|
+
* `images` is an opt-in guard parameter: when non-empty the
|
|
1473
|
+
* native side returns an error whose message begins with
|
|
1474
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` so the TypeScript
|
|
1475
|
+
* `ChatSession` layer can route image-changes back through a
|
|
1476
|
+
* fresh `chatSessionStart`.
|
|
1477
|
+
*/
|
|
1478
|
+
chatSessionContinue(
|
|
1479
|
+
userMessage: string,
|
|
1480
|
+
images: Uint8Array[] | null | undefined,
|
|
1481
|
+
audio: Uint8Array[] | null | undefined,
|
|
1482
|
+
config: ChatConfig | null | undefined,
|
|
1483
|
+
): Promise<ChatResult>;
|
|
1484
|
+
/**
|
|
1485
|
+
* Continue an existing chat session with a tool-result turn.
|
|
1486
|
+
*
|
|
1487
|
+
* Builds the family's tool-result delta from `content` and
|
|
1488
|
+
* prefills it on top of the live session caches, then decodes
|
|
1489
|
+
* the assistant reply.
|
|
1490
|
+
*
|
|
1491
|
+
* `is_error` is the structured tool-error signal. When
|
|
1492
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1493
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
1494
|
+
* rendered tool block.
|
|
1495
|
+
*/
|
|
1496
|
+
chatSessionContinueTool(
|
|
1497
|
+
toolCallId: string,
|
|
1498
|
+
content: string,
|
|
1499
|
+
config?: ChatConfig | undefined | null,
|
|
1500
|
+
isError?: boolean | undefined | null,
|
|
1501
|
+
): Promise<ChatResult>;
|
|
1502
|
+
/** Streaming variant of `chatSessionStart`. */
|
|
1503
|
+
chatStreamSessionStart(
|
|
1504
|
+
messages: ChatMessage[],
|
|
1505
|
+
config: ChatConfig | null,
|
|
1506
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1507
|
+
): Promise<ChatStreamHandle>;
|
|
1508
|
+
/** Streaming variant of `chatSessionContinue`. */
|
|
1509
|
+
chatStreamSessionContinue(
|
|
1510
|
+
userMessage: string,
|
|
1511
|
+
images: Uint8Array[] | null | undefined,
|
|
1512
|
+
audio: Uint8Array[] | null | undefined,
|
|
1513
|
+
config: ChatConfig | null,
|
|
1514
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1515
|
+
): Promise<ChatStreamHandle>;
|
|
1516
|
+
/**
|
|
1517
|
+
* Streaming variant of `chatSessionContinueTool`.
|
|
1153
1518
|
*
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1519
|
+
* `is_error` mirrors the non-streaming entry point — when
|
|
1520
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1521
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the rendered
|
|
1522
|
+
* tool block.
|
|
1157
1523
|
*/
|
|
1158
|
-
|
|
1524
|
+
chatStreamSessionContinueTool(
|
|
1525
|
+
toolCallId: string,
|
|
1526
|
+
content: string,
|
|
1527
|
+
config: ChatConfig | null,
|
|
1528
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1529
|
+
isError?: boolean | null | undefined,
|
|
1530
|
+
): Promise<ChatStreamHandle>;
|
|
1531
|
+
}
|
|
1532
|
+
export type Qwen3_5MoeModel = Qwen35MoeModel;
|
|
1533
|
+
|
|
1534
|
+
/**
|
|
1535
|
+
* Qwen3 Model with automatic differentiation support
|
|
1536
|
+
*
|
|
1537
|
+
* Uses a dedicated model thread for inference and training commands.
|
|
1538
|
+
* Training commands are routed via `TrainingDispatch`.
|
|
1539
|
+
*/
|
|
1540
|
+
export declare class Qwen3Model {
|
|
1541
|
+
/**
|
|
1542
|
+
* Whether the block-paged KV cache adapter is active on this model
|
|
1543
|
+
* instance.
|
|
1544
|
+
*
|
|
1545
|
+
* `true` iff `Qwen3Inner::paged_adapter` was successfully constructed
|
|
1546
|
+
* at load time (driven by `Qwen3Config::use_block_paged_cache`,
|
|
1547
|
+
* defaulting to `true` for Qwen3 since paged-vs-flat parity has been
|
|
1548
|
+
* verified). When `true`, the native cache reuses SYS blocks across
|
|
1549
|
+
* `chatSessionStart` calls via content-addressing in
|
|
1550
|
+
* `BlockAllocator`'s prefix-hash table — the JS-side warm slot in
|
|
1551
|
+
* `SessionRegistry.getOrCreateWarmAny` becomes redundant and the
|
|
1552
|
+
* `/v1/messages` server endpoint allocates a fresh `ChatSession` per
|
|
1553
|
+
* request. See `packages/server/src/endpoints/messages.ts` for the
|
|
1554
|
+
* runtime-routing decision.
|
|
1555
|
+
*/
|
|
1556
|
+
hasBlockPagedCache(): boolean;
|
|
1557
|
+
/** Get model configuration */
|
|
1558
|
+
getConfig(): Qwen3Config;
|
|
1159
1559
|
/**
|
|
1160
1560
|
* Text-to-text generation with integrated tokenization
|
|
1161
1561
|
*
|
|
@@ -1187,77 +1587,6 @@ export declare class Qwen3Model {
|
|
|
1187
1587
|
* ```
|
|
1188
1588
|
*/
|
|
1189
1589
|
generate(messages: Array<ChatMessage>, config?: GenerationConfig | undefined | null): Promise<GenerationResult>;
|
|
1190
|
-
/**
|
|
1191
|
-
* High-level chat API with structured response parsing
|
|
1192
|
-
*
|
|
1193
|
-
* The primary API for conversational AI. Handles:
|
|
1194
|
-
* - Chat message formatting with Jinja2 templates
|
|
1195
|
-
* - Tool/function calling with structured output
|
|
1196
|
-
* - Thinking extraction from `<think>` tags
|
|
1197
|
-
* - Clean response text with all special tags stripped
|
|
1198
|
-
*
|
|
1199
|
-
* ## `chat()` vs `generate()`
|
|
1200
|
-
*
|
|
1201
|
-
* | Feature | `chat()` | `generate()` |
|
|
1202
|
-
* |---------|----------|--------------|
|
|
1203
|
-
* | **Purpose** | Conversational AI with tools | Raw text generation |
|
|
1204
|
-
* | **Input** | Chat messages | Token IDs (MxArray) |
|
|
1205
|
-
* | **Tool Support** | Built-in parsing | None |
|
|
1206
|
-
* | **Thinking** | Extracts `<think>` content | Raw text only |
|
|
1207
|
-
* | **Output** | Structured `ChatResult` | Basic `GenerationResult` |
|
|
1208
|
-
* | **Use Case** | Chat apps, agents, assistants | Training, low-level control |
|
|
1209
|
-
*
|
|
1210
|
-
* ## When to use `chat()`
|
|
1211
|
-
* - Building conversational applications
|
|
1212
|
-
* - Need tool/function calling
|
|
1213
|
-
* - Want structured responses with thinking separated
|
|
1214
|
-
* - Working with chat message format
|
|
1215
|
-
*
|
|
1216
|
-
* ## When to use `generate()`
|
|
1217
|
-
* - Training and fine-tuning (need raw logprobs)
|
|
1218
|
-
* - Custom tokenization pipeline
|
|
1219
|
-
* - Low-level generation control
|
|
1220
|
-
* - Non-chat use cases
|
|
1221
|
-
*
|
|
1222
|
-
* # Arguments
|
|
1223
|
-
* * `messages` - Array of chat messages (user/assistant/system roles)
|
|
1224
|
-
* * `config` - Chat configuration including optional tools and generation params
|
|
1225
|
-
*
|
|
1226
|
-
* # Returns
|
|
1227
|
-
* * `ChatResult` containing:
|
|
1228
|
-
* - `text`: Clean response (tool_call and think tags stripped)
|
|
1229
|
-
* - `thinking`: Extracted chain-of-thought reasoning (or null)
|
|
1230
|
-
* - `toolCalls`: Parsed tool calls with native JS object arguments
|
|
1231
|
-
* - `finishReason`: "stop" | "length" | "tool_calls"
|
|
1232
|
-
* - `rawText`: Original text before processing (for debugging)
|
|
1233
|
-
*
|
|
1234
|
-
* # Example
|
|
1235
|
-
* ```typescript
|
|
1236
|
-
* // Simple chat
|
|
1237
|
-
* const result = await model.chat(messages);
|
|
1238
|
-
* console.log(result.text);
|
|
1239
|
-
*
|
|
1240
|
-
* // With tools
|
|
1241
|
-
* const result = await model.chat(messages, {
|
|
1242
|
-
* tools: [{ type: 'function', function: { name: 'get_weather' } }],
|
|
1243
|
-
* maxNewTokens: 2048,
|
|
1244
|
-
* temperature: 0.7,
|
|
1245
|
-
* });
|
|
1246
|
-
*
|
|
1247
|
-
* // Handle tool calls
|
|
1248
|
-
* for (const call of result.toolCalls) {
|
|
1249
|
-
* if (call.status === 'ok') {
|
|
1250
|
-
* console.log(call.name, call.arguments); // Arguments is a JS object!
|
|
1251
|
-
* }
|
|
1252
|
-
* }
|
|
1253
|
-
*
|
|
1254
|
-
* // Access thinking (chain-of-thought)
|
|
1255
|
-
* if (result.thinking) {
|
|
1256
|
-
* console.log('Model reasoning:', result.thinking);
|
|
1257
|
-
* }
|
|
1258
|
-
* ```
|
|
1259
|
-
*/
|
|
1260
|
-
chat(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
1261
1590
|
/**
|
|
1262
1591
|
* Generate multiple completions for multiple prompts in batch
|
|
1263
1592
|
*
|
|
@@ -1297,20 +1626,6 @@ export declare class Qwen3Model {
|
|
|
1297
1626
|
groupSize: number,
|
|
1298
1627
|
config?: GenerationConfig | undefined | null,
|
|
1299
1628
|
): Promise<BatchGenerationResult>;
|
|
1300
|
-
/**
|
|
1301
|
-
* Decode token IDs to text using the internal tokenizer
|
|
1302
|
-
*
|
|
1303
|
-
* Helper method for decoding generated tokens. The model must have been loaded
|
|
1304
|
-
* via load() to have a tokenizer available.
|
|
1305
|
-
*
|
|
1306
|
-
* # Arguments
|
|
1307
|
-
* * `token_ids` - Token IDs to decode as Uint32Array
|
|
1308
|
-
* * `skip_special_tokens` - Whether to skip special tokens (default: true)
|
|
1309
|
-
*
|
|
1310
|
-
* # Returns
|
|
1311
|
-
* * Decoded text string
|
|
1312
|
-
*/
|
|
1313
|
-
decode(tokenIds: Uint32Array, skipSpecialTokens?: boolean | undefined | null): Promise<string>;
|
|
1314
1629
|
/**
|
|
1315
1630
|
* Apply chat template and encode to token IDs
|
|
1316
1631
|
*
|
|
@@ -1332,6 +1647,88 @@ export declare class Qwen3Model {
|
|
|
1332
1647
|
tools?: Array<ToolDefinition> | undefined | null,
|
|
1333
1648
|
enableThinking?: boolean | undefined | null,
|
|
1334
1649
|
): Promise<Uint32Array>;
|
|
1650
|
+
/**
|
|
1651
|
+
* Reset all caches and clear cached token history. Exposed
|
|
1652
|
+
* so tests and session-management code can start from a
|
|
1653
|
+
* known clean state between turns.
|
|
1654
|
+
*/
|
|
1655
|
+
resetCaches(): void;
|
|
1656
|
+
/**
|
|
1657
|
+
* Start a new chat session.
|
|
1658
|
+
*
|
|
1659
|
+
* Runs the full jinja chat template once, decodes until the
|
|
1660
|
+
* family's session stop token, and leaves the KV caches on a
|
|
1661
|
+
* clean turn boundary so subsequent `chatSessionContinue` /
|
|
1662
|
+
* `chatSessionContinueTool` calls can append a raw delta on
|
|
1663
|
+
* top without re-rendering the chat template.
|
|
1664
|
+
*/
|
|
1665
|
+
chatSessionStart(messages: Array<ChatMessage>, config?: ChatConfig | undefined | null): Promise<ChatResult>;
|
|
1666
|
+
/**
|
|
1667
|
+
* Continue an existing chat session with a new user message.
|
|
1668
|
+
*
|
|
1669
|
+
* Appends a raw user/assistant delta to the session's cached
|
|
1670
|
+
* KV state, then decodes the assistant reply, stopping on the
|
|
1671
|
+
* family's session boundary token.
|
|
1672
|
+
*
|
|
1673
|
+
* `images` is an opt-in guard parameter: when non-empty the
|
|
1674
|
+
* native side returns an error whose message begins with
|
|
1675
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` so the TypeScript
|
|
1676
|
+
* `ChatSession` layer can route image-changes back through a
|
|
1677
|
+
* fresh `chatSessionStart`.
|
|
1678
|
+
*/
|
|
1679
|
+
chatSessionContinue(
|
|
1680
|
+
userMessage: string,
|
|
1681
|
+
images: Uint8Array[] | null | undefined,
|
|
1682
|
+
audio: Uint8Array[] | null | undefined,
|
|
1683
|
+
config: ChatConfig | null | undefined,
|
|
1684
|
+
): Promise<ChatResult>;
|
|
1685
|
+
/**
|
|
1686
|
+
* Continue an existing chat session with a tool-result turn.
|
|
1687
|
+
*
|
|
1688
|
+
* Builds the family's tool-result delta from `content` and
|
|
1689
|
+
* prefills it on top of the live session caches, then decodes
|
|
1690
|
+
* the assistant reply.
|
|
1691
|
+
*
|
|
1692
|
+
* `is_error` is the structured tool-error signal. When
|
|
1693
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1694
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the
|
|
1695
|
+
* rendered tool block.
|
|
1696
|
+
*/
|
|
1697
|
+
chatSessionContinueTool(
|
|
1698
|
+
toolCallId: string,
|
|
1699
|
+
content: string,
|
|
1700
|
+
config?: ChatConfig | undefined | null,
|
|
1701
|
+
isError?: boolean | undefined | null,
|
|
1702
|
+
): Promise<ChatResult>;
|
|
1703
|
+
/** Streaming variant of `chatSessionStart`. */
|
|
1704
|
+
chatStreamSessionStart(
|
|
1705
|
+
messages: ChatMessage[],
|
|
1706
|
+
config: ChatConfig | null,
|
|
1707
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1708
|
+
): Promise<ChatStreamHandle>;
|
|
1709
|
+
/** Streaming variant of `chatSessionContinue`. */
|
|
1710
|
+
chatStreamSessionContinue(
|
|
1711
|
+
userMessage: string,
|
|
1712
|
+
images: Uint8Array[] | null | undefined,
|
|
1713
|
+
audio: Uint8Array[] | null | undefined,
|
|
1714
|
+
config: ChatConfig | null,
|
|
1715
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1716
|
+
): Promise<ChatStreamHandle>;
|
|
1717
|
+
/**
|
|
1718
|
+
* Streaming variant of `chatSessionContinueTool`.
|
|
1719
|
+
*
|
|
1720
|
+
* `is_error` mirrors the non-streaming entry point — when
|
|
1721
|
+
* `Some(true)`, the renderer prepends the shared
|
|
1722
|
+
* [`crate::tokenizer::TOOL_ERROR_MARKER`] inside the rendered
|
|
1723
|
+
* tool block.
|
|
1724
|
+
*/
|
|
1725
|
+
chatStreamSessionContinueTool(
|
|
1726
|
+
toolCallId: string,
|
|
1727
|
+
content: string,
|
|
1728
|
+
config: ChatConfig | null,
|
|
1729
|
+
callback: (err: Error | null, chunk: ChatStreamChunk) => void,
|
|
1730
|
+
isError?: boolean | null | undefined,
|
|
1731
|
+
): Promise<ChatStreamHandle>;
|
|
1335
1732
|
/**
|
|
1336
1733
|
* Load a pretrained model from disk
|
|
1337
1734
|
*
|
|
@@ -1355,6 +1752,10 @@ export declare class Qwen3Model {
|
|
|
1355
1752
|
* - weights.safetensors: Full model weights in SafeTensors format
|
|
1356
1753
|
* - weights.mlx: Parameter metadata (for reference)
|
|
1357
1754
|
*
|
|
1755
|
+
* Dispatches to the dedicated model thread — all MxArray reads must
|
|
1756
|
+
* happen on the thread that owns them to avoid the MLX cross-thread
|
|
1757
|
+
* `CommandEncoder` crash.
|
|
1758
|
+
*
|
|
1358
1759
|
* # Arguments
|
|
1359
1760
|
* * `save_path` - Directory to save the model
|
|
1360
1761
|
*/
|
|
@@ -1507,7 +1908,33 @@ export declare class Qwen3Tokenizer {
|
|
|
1507
1908
|
getEndoftextToken(): string;
|
|
1508
1909
|
}
|
|
1509
1910
|
|
|
1510
|
-
/**
|
|
1911
|
+
/**
|
|
1912
|
+
* Response store for OpenAI Responses API persistence.
|
|
1913
|
+
*
|
|
1914
|
+
* Stores responses in SQLite to support `previous_response_id`
|
|
1915
|
+
* for multi-turn conversation state.
|
|
1916
|
+
*/
|
|
1917
|
+
export declare class ResponseStore {
|
|
1918
|
+
/** Open (or create) a response store at the given path. */
|
|
1919
|
+
static open(path: string): Promise<ResponseStore>;
|
|
1920
|
+
/** Store a response. */
|
|
1921
|
+
store(response: StoredResponseRecord): Promise<void>;
|
|
1922
|
+
/** Get a single response by ID. */
|
|
1923
|
+
get(id: string): Promise<StoredResponseRecord | null>;
|
|
1924
|
+
/** Get the full conversation chain for a response (oldest first). */
|
|
1925
|
+
getChain(id: string): Promise<Array<StoredResponseRecord>>;
|
|
1926
|
+
/** Delete a response by ID. Returns true if a row was deleted. */
|
|
1927
|
+
delete(id: string): Promise<boolean>;
|
|
1928
|
+
/** Delete expired responses. Returns the number of rows deleted. */
|
|
1929
|
+
cleanupExpired(): Promise<number>;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
/**
|
|
1933
|
+
* SFT Training Engine
|
|
1934
|
+
*
|
|
1935
|
+
* Thin coordinator that routes all MLX operations through the model thread.
|
|
1936
|
+
* No MxArrays or model state live here - only plain data crosses the boundary.
|
|
1937
|
+
*/
|
|
1511
1938
|
export declare class SftTrainingEngine {
|
|
1512
1939
|
/** Create a new SFT training engine from a Qwen3 model */
|
|
1513
1940
|
constructor(model: Qwen3Model, config: SftEngineConfig);
|
|
@@ -1524,9 +1951,10 @@ export declare class SftTrainingEngine {
|
|
|
1524
1951
|
/**
|
|
1525
1952
|
* Flush any accumulated gradients at epoch end
|
|
1526
1953
|
*
|
|
1527
|
-
*
|
|
1528
|
-
*
|
|
1529
|
-
*
|
|
1954
|
+
* With the model thread architecture, gradient accumulation is handled
|
|
1955
|
+
* on the model thread. This method is kept for API compatibility but
|
|
1956
|
+
* currently logs a warning. Partial accumulation at epoch boundaries
|
|
1957
|
+
* will be handled in a future update.
|
|
1530
1958
|
*/
|
|
1531
1959
|
flushGradients(): boolean;
|
|
1532
1960
|
/**
|
|
@@ -1549,15 +1977,46 @@ export declare class SftTrainingEngine {
|
|
|
1549
1977
|
startEpoch(epoch: number): void;
|
|
1550
1978
|
/** End current epoch and return metrics */
|
|
1551
1979
|
endEpoch(epochTimeSecs: number): SftEpochMetrics;
|
|
1552
|
-
/**
|
|
1980
|
+
/**
|
|
1981
|
+
* Reset training state (for new training run)
|
|
1982
|
+
*
|
|
1983
|
+
* This is a TERMINAL operation on this handle. It drops the training
|
|
1984
|
+
* state (optimizer, step counter) on the model thread so a fresh
|
|
1985
|
+
* `SftTrainingEngine` can be constructed on the same model, and marks
|
|
1986
|
+
* THIS handle as invalidated. Any subsequent dispatch-requiring method
|
|
1987
|
+
* on this handle returns an error — callers must construct a new
|
|
1988
|
+
* engine to continue training.
|
|
1989
|
+
*/
|
|
1553
1990
|
reset(): void;
|
|
1554
|
-
/**
|
|
1991
|
+
/**
|
|
1992
|
+
* Restore training state (for resuming from checkpoint)
|
|
1993
|
+
*
|
|
1994
|
+
* Updates both the engine's read-through cache and the model thread's
|
|
1995
|
+
* authoritative `ts.step`. Does NOT touch optimizer state — that is
|
|
1996
|
+
* loaded via `loadOptimizerState`, which restores the AdamW bias-
|
|
1997
|
+
* correction step separately.
|
|
1998
|
+
*/
|
|
1555
1999
|
restoreState(step: number, epoch: number): void;
|
|
1556
|
-
/**
|
|
2000
|
+
/**
|
|
2001
|
+
* Get the underlying Qwen3 model for checkpointing
|
|
2002
|
+
*
|
|
2003
|
+
* NOTE: With the model thread architecture, direct model access is no longer
|
|
2004
|
+
* supported. Use save_checkpoint() on the model directly instead.
|
|
2005
|
+
*/
|
|
1557
2006
|
getModel(): Qwen3Model;
|
|
1558
|
-
/**
|
|
2007
|
+
/**
|
|
2008
|
+
* Get the underlying Qwen3.5 dense model for checkpointing
|
|
2009
|
+
*
|
|
2010
|
+
* NOTE: With the model thread architecture, direct model access is no longer
|
|
2011
|
+
* supported. Use save_checkpoint() on the model directly instead.
|
|
2012
|
+
*/
|
|
1559
2013
|
getQwen35Model(): Qwen35Model;
|
|
1560
|
-
/**
|
|
2014
|
+
/**
|
|
2015
|
+
* Get the underlying Qwen3.5 MoE model for checkpointing
|
|
2016
|
+
*
|
|
2017
|
+
* NOTE: With the model thread architecture, direct model access is no longer
|
|
2018
|
+
* supported. Use save_checkpoint() on the model directly instead.
|
|
2019
|
+
*/
|
|
1561
2020
|
getQwen35MoeModel(): Qwen35MoeModel;
|
|
1562
2021
|
}
|
|
1563
2022
|
|
|
@@ -1730,14 +2189,18 @@ export type VLMChatResult = VlmChatResult;
|
|
|
1730
2189
|
*
|
|
1731
2190
|
* A generic VLM for OCR and document understanding tasks.
|
|
1732
2191
|
* Currently supports PaddleOCR-VL architecture (vision encoder + ERNIE language model).
|
|
2192
|
+
*
|
|
2193
|
+
* All model state lives on a dedicated OS thread. NAPI methods dispatch
|
|
2194
|
+
* commands via channels and await responses.
|
|
1733
2195
|
*/
|
|
1734
2196
|
export declare class VLModel {
|
|
1735
|
-
/**
|
|
2197
|
+
/**
|
|
2198
|
+
* Create a new PaddleOCR-VL model (empty, not loaded).
|
|
2199
|
+
*
|
|
2200
|
+
* Creates a model thread with an empty inner. Use `VLModel.load()` instead
|
|
2201
|
+
* for loading a model from disk.
|
|
2202
|
+
*/
|
|
1736
2203
|
constructor(config: ModelConfig);
|
|
1737
|
-
/** Set the tokenizer */
|
|
1738
|
-
setTokenizer(tokenizer: Qwen3Tokenizer): void;
|
|
1739
|
-
/** Check if tokenizer is available */
|
|
1740
|
-
get hasTokenizer(): boolean;
|
|
1741
2204
|
/**
|
|
1742
2205
|
* Chat with the VLM model
|
|
1743
2206
|
*
|
|
@@ -1778,82 +2241,6 @@ export declare class VLModel {
|
|
|
1778
2241
|
* ```
|
|
1779
2242
|
*/
|
|
1780
2243
|
ocr(imageData: Buffer, prompt?: string | undefined | null): Promise<string>;
|
|
1781
|
-
/**
|
|
1782
|
-
* Get input embeddings with vision features merged
|
|
1783
|
-
*
|
|
1784
|
-
* # Arguments
|
|
1785
|
-
* * `input_ids` - Token IDs [batch, seq_len]
|
|
1786
|
-
* * `pixel_values` - Optional image patches [batch, seq, channels, patch_h, patch_w]
|
|
1787
|
-
* * `image_grid_thw` - Optional grid dimensions [num_images, 3]
|
|
1788
|
-
*
|
|
1789
|
-
* # Returns
|
|
1790
|
-
* * Input embeddings with vision features inserted at image token positions
|
|
1791
|
-
*/
|
|
1792
|
-
getInputEmbeddings(
|
|
1793
|
-
inputIds: MxArray,
|
|
1794
|
-
pixelValues?: MxArray | undefined | null,
|
|
1795
|
-
imageGridThw?: MxArray | undefined | null,
|
|
1796
|
-
): MxArray;
|
|
1797
|
-
/**
|
|
1798
|
-
* Forward pass
|
|
1799
|
-
*
|
|
1800
|
-
* # Arguments
|
|
1801
|
-
* * `input_ids` - Token IDs [batch, seq_len]
|
|
1802
|
-
* * `pixel_values` - Optional image patches
|
|
1803
|
-
* * `image_grid_thw` - Optional grid dimensions
|
|
1804
|
-
* * `mask` - Optional attention mask
|
|
1805
|
-
*
|
|
1806
|
-
* # Returns
|
|
1807
|
-
* * Logits [batch, seq_len, vocab_size]
|
|
1808
|
-
*/
|
|
1809
|
-
forward(
|
|
1810
|
-
inputIds: MxArray,
|
|
1811
|
-
pixelValues?: MxArray | undefined | null,
|
|
1812
|
-
imageGridThw?: MxArray | undefined | null,
|
|
1813
|
-
mask?: MxArray | undefined | null,
|
|
1814
|
-
): MxArray;
|
|
1815
|
-
/**
|
|
1816
|
-
* Generate text tokens given input tokens and optional image
|
|
1817
|
-
*
|
|
1818
|
-
* Uses KV caching for efficient generation - each step only processes the
|
|
1819
|
-
* new token(s) while reusing cached key-value states from previous tokens.
|
|
1820
|
-
* Vision features are computed once at the start and cached.
|
|
1821
|
-
*
|
|
1822
|
-
* # Arguments
|
|
1823
|
-
* * `input_ids` - Input token IDs [1, seq_len]
|
|
1824
|
-
* * `pixel_values` - Optional image patches [1, num_patches, C, H, W]
|
|
1825
|
-
* * `image_grid_thw` - Optional grid dimensions [1, 3]
|
|
1826
|
-
* * `config` - Generation configuration
|
|
1827
|
-
*
|
|
1828
|
-
* # Returns
|
|
1829
|
-
* * GenerationResult with tokens, logprobs, and finish reason
|
|
1830
|
-
*/
|
|
1831
|
-
generate(
|
|
1832
|
-
inputIds: MxArray,
|
|
1833
|
-
pixelValues?: MxArray | undefined | null,
|
|
1834
|
-
imageGridThw?: MxArray | undefined | null,
|
|
1835
|
-
config?: GenerationConfig | undefined | null,
|
|
1836
|
-
): Promise<GenerationResult>;
|
|
1837
|
-
/**
|
|
1838
|
-
* Batch OCR: extract text from multiple images simultaneously
|
|
1839
|
-
*
|
|
1840
|
-
* Processes N images with sequential prefill + batched decode for ~N× decode throughput.
|
|
1841
|
-
*
|
|
1842
|
-
* # Arguments
|
|
1843
|
-
* * `images` - Encoded image buffers
|
|
1844
|
-
* * `config` - Optional chat configuration (shared across all items)
|
|
1845
|
-
*
|
|
1846
|
-
* # Returns
|
|
1847
|
-
* * Vec of extracted text strings, one per image
|
|
1848
|
-
*
|
|
1849
|
-
* # Example
|
|
1850
|
-
* ```typescript
|
|
1851
|
-
* import { readFileSync } from 'fs';
|
|
1852
|
-
* const images = ['page1.jpg', 'page2.jpg'].map(p => readFileSync(p));
|
|
1853
|
-
* const texts = await model.ocrBatch(images);
|
|
1854
|
-
* ```
|
|
1855
|
-
*/
|
|
1856
|
-
ocrBatch(images: Array<Buffer>, config?: VlmChatConfig | undefined | null): Promise<Array<string>>;
|
|
1857
2244
|
/**
|
|
1858
2245
|
* Batch chat: process multiple items simultaneously
|
|
1859
2246
|
*
|
|
@@ -1892,25 +2279,6 @@ export declare class VLModel {
|
|
|
1892
2279
|
* ```
|
|
1893
2280
|
*/
|
|
1894
2281
|
static load(modelPath: string): Promise<VLModel>;
|
|
1895
|
-
/**
|
|
1896
|
-
* Load model configuration from disk without loading weights
|
|
1897
|
-
*
|
|
1898
|
-
* This is useful for inspecting model configuration before loading the full model.
|
|
1899
|
-
*
|
|
1900
|
-
* # Arguments
|
|
1901
|
-
* * `model_path` - Path to the model directory containing config.json
|
|
1902
|
-
*
|
|
1903
|
-
* # Returns
|
|
1904
|
-
* * ModelConfig with vision and text configuration
|
|
1905
|
-
*
|
|
1906
|
-
* # Example
|
|
1907
|
-
* ```typescript
|
|
1908
|
-
* import { VLModel } from '@mlx-node/vlm';
|
|
1909
|
-
* const config = await VLModel.loadConfig('./models/paddleocr-vl');
|
|
1910
|
-
* console.log(config.visionConfig.hiddenSize);
|
|
1911
|
-
* ```
|
|
1912
|
-
*/
|
|
1913
|
-
static loadConfig(modelPath: string): Promise<ModelConfig>;
|
|
1914
2282
|
}
|
|
1915
2283
|
|
|
1916
2284
|
/**
|
|
@@ -1961,8 +2329,68 @@ export declare const enum BuiltinRewardType {
|
|
|
1961
2329
|
JsonSchema = 'JsonSchema',
|
|
1962
2330
|
}
|
|
1963
2331
|
|
|
2332
|
+
/**
|
|
2333
|
+
* Data-free static FP8 activation-amax calibration over RAW-text PREFILL
|
|
2334
|
+
* (NVIDIA modelopt `MaxCalibrator` parity), end to end in native code.
|
|
2335
|
+
*
|
|
2336
|
+
* The nvidia recipe covers BOTH `qwen3_5` (dense) and `qwen3_5_moe` (MoE), so
|
|
2337
|
+
* this reads `<model_path>/config.json`'s `model_type` and dispatches to the
|
|
2338
|
+
* matching loader + `CalibratePrefillRaw` command (any other `model_type` is a
|
|
2339
|
+
* clear error). Both loaders are the SAME ones the inference session uses
|
|
2340
|
+
* ([`persistence::load_with_thread`]) — the model is only usable on its
|
|
2341
|
+
* dedicated model thread. Then:
|
|
2342
|
+
* 1. dispatches `{Qwen35Cmd,Qwen35MoeCmd}::CalibratePrefillRaw`, which on the
|
|
2343
|
+
* model thread SELF-ARMS that thread's thread-local
|
|
2344
|
+
* [`ActivationAmaxCollector`] flag (RAII, AFTER load so no load-time eval
|
|
2345
|
+
* is recorded), tokenizes each `text` WITHOUT the chat template, truncates
|
|
2346
|
+
* to `calib_seq` tokens, and runs PREFILL ONLY (no generation) so every
|
|
2347
|
+
* mxfp8 attn/GDN projection's activation tap fires over realistic raw-text
|
|
2348
|
+
* activations, resetting caches between rows, then disarms on exit;
|
|
2349
|
+
* 2. ONLY if the full loop succeeded — drains the per-tensor amax and
|
|
2350
|
+
* ATOMICALLY writes it into `<model_path>/config.json` (temp file +
|
|
2351
|
+
* `rename`).
|
|
2352
|
+
*
|
|
2353
|
+
* CONCURRENCY: the whole clear→prefill→take→write section is serialized by
|
|
2354
|
+
* [`calib_guard`] (a process-wide `try_lock`); a second concurrent calibration
|
|
2355
|
+
* fails fast with "another calibration is in progress". The arm flag is
|
|
2356
|
+
* thread-local (so a concurrent inference model can't contaminate the run), but
|
|
2357
|
+
* the running-max MAP is process-global, so serializing RUNS keeps two
|
|
2358
|
+
* calibrations from interleaving `record`/`take` on it. The map is CLEARED at
|
|
2359
|
+
* the very start so stale amax from a prior PANICKED run cannot leak into this
|
|
2360
|
+
* write.
|
|
2361
|
+
*
|
|
2362
|
+
* On ANY error before the final write, the partial amax is discarded and
|
|
2363
|
+
* `config.json` is left UNTOUCHED (a failed calibration must not mutate the
|
|
2364
|
+
* live model in place). A run that prefilled ZERO rows (empty dataset, or every
|
|
2365
|
+
* row tokenized to nothing) is likewise an ERROR that leaves `config.json`
|
|
2366
|
+
* untouched — a no-op calibration must not report a silent success. Returns the
|
|
2367
|
+
* number of projections calibrated (the count of collected amax entries); 0
|
|
2368
|
+
* means a real prefill ran but the model exercised no activation-fp8 sites (not
|
|
2369
|
+
* an nvidia-recipe checkpoint), and in that case `config.json` is left
|
|
2370
|
+
* UNCHANGED (no rewrite).
|
|
2371
|
+
*/
|
|
2372
|
+
export declare function calibrateActivationAmaxRaw(
|
|
2373
|
+
modelPath: string,
|
|
2374
|
+
texts: Array<string>,
|
|
2375
|
+
calibSeq: number,
|
|
2376
|
+
): Promise<number>;
|
|
2377
|
+
|
|
1964
2378
|
/** Unified chat configuration shared by all model variants (Qwen3, Qwen3.5, Qwen3.5 MoE). */
|
|
1965
2379
|
export interface ChatConfig {
|
|
2380
|
+
/**
|
|
2381
|
+
* Internal logical cache owner. The agent provider forwards Pi's stable
|
|
2382
|
+
* session id so model-global GDN sidecars can retain parent and child
|
|
2383
|
+
* branches independently. This does not namespace the physical paged KV
|
|
2384
|
+
* cache; exact token/extra-key hashes remain shareable across owners.
|
|
2385
|
+
*/
|
|
2386
|
+
cacheOwnerId?: string | undefined;
|
|
2387
|
+
/**
|
|
2388
|
+
* Internal top-level owner for the bounded Qwen3.5 GDN sidecar store.
|
|
2389
|
+
* `cache_owner_id` may identify a child Pi session; this separately
|
|
2390
|
+
* identifies the current interactive root so /new and /resume can rotate
|
|
2391
|
+
* the protected branch without changing PagedAttention cache identity.
|
|
2392
|
+
*/
|
|
2393
|
+
cacheRootOwnerId?: string | undefined;
|
|
1966
2394
|
maxNewTokens?: number | undefined;
|
|
1967
2395
|
temperature?: number | undefined;
|
|
1968
2396
|
topK?: number | undefined;
|
|
@@ -1972,28 +2400,107 @@ export interface ChatConfig {
|
|
|
1972
2400
|
repetitionPenalty?: number | undefined;
|
|
1973
2401
|
/** Size of the context window for repetition penalty (default: 256) */
|
|
1974
2402
|
repetitionContextSize?: number | undefined;
|
|
1975
|
-
/**
|
|
2403
|
+
/**
|
|
2404
|
+
* Presence penalty (0.0 = disabled). Subtracts a flat penalty from logits of any
|
|
2405
|
+
* token that appeared at least once in context. Matches OpenAI API semantics.
|
|
2406
|
+
*/
|
|
2407
|
+
presencePenalty?: number | undefined;
|
|
2408
|
+
/** Number of recent tokens to consider for presence penalty (default: 20) */
|
|
2409
|
+
presenceContextSize?: number | undefined;
|
|
2410
|
+
/**
|
|
2411
|
+
* Frequency penalty (0.0 = disabled). Subtracts penalty * occurrence_count from
|
|
2412
|
+
* logits of each token in context. Matches OpenAI API semantics.
|
|
2413
|
+
*/
|
|
2414
|
+
frequencyPenalty?: number | undefined;
|
|
2415
|
+
/** Number of recent tokens to consider for frequency penalty (default: 20) */
|
|
2416
|
+
frequencyContextSize?: number | undefined;
|
|
2417
|
+
/** Max consecutive identical tokens before stopping (default: 0 = disabled; opt in with a positive value) */
|
|
1976
2418
|
maxConsecutiveTokens?: number | undefined;
|
|
1977
|
-
/** Max n-gram repetitions before stopping (default:
|
|
2419
|
+
/** Max n-gram repetitions before stopping (default: 0 = disabled; opt in with a positive value) */
|
|
1978
2420
|
maxNgramRepeats?: number | undefined;
|
|
1979
|
-
/** Max pattern size for n-gram repetition detection (default:
|
|
2421
|
+
/** Max pattern size for n-gram repetition detection (default: 0 = disabled; opt in with a positive value) */
|
|
1980
2422
|
ngramSize?: number | undefined;
|
|
1981
2423
|
tools?: Array<ToolDefinition>;
|
|
1982
2424
|
/**
|
|
1983
|
-
*
|
|
1984
|
-
*
|
|
2425
|
+
* Reasoning effort level. Controls whether the model thinks before answering.
|
|
2426
|
+
* - "none" / "low": thinking disabled (template injects closed think block).
|
|
2427
|
+
* "none" also sets includeReasoning to false by default.
|
|
2428
|
+
* - "medium" / "high": thinking enabled (default behavior).
|
|
2429
|
+
* - Not set: thinking enabled (model thinks naturally).
|
|
2430
|
+
*/
|
|
2431
|
+
reasoningEffort?: string | undefined;
|
|
2432
|
+
/**
|
|
2433
|
+
* Maximum number of thinking tokens before forcing </think>.
|
|
2434
|
+
* When the model has generated this many tokens while in thinking mode,
|
|
2435
|
+
* the next token is forced to be the think_end token. None = unlimited.
|
|
2436
|
+
*/
|
|
2437
|
+
thinkingTokenBudget?: number | undefined;
|
|
2438
|
+
/**
|
|
2439
|
+
* Whether to include reasoning/thinking content in the output.
|
|
2440
|
+
* When false, the `thinking` field of ChatResult/ChatStreamChunk will always be None.
|
|
2441
|
+
* Default: true (false when reasoningEffort is "none").
|
|
1985
2442
|
*/
|
|
1986
|
-
|
|
2443
|
+
includeReasoning?: boolean | undefined;
|
|
1987
2444
|
/** When true, include performance metrics (TTFT, prefill tok/s, decode tok/s) in the result */
|
|
1988
2445
|
reportPerformance?: boolean | undefined;
|
|
1989
2446
|
/**
|
|
1990
|
-
* Reuse KV cache across chat
|
|
2447
|
+
* Reuse KV cache across chat-session turns for incremental prefill. Default: true.
|
|
1991
2448
|
* When true, the model preserves its KV cache after generation. On the next
|
|
1992
|
-
*
|
|
1993
|
-
* tokens and only prefills the delta —
|
|
1994
|
-
* multi-turn conversations.
|
|
2449
|
+
* `chatSessionStart` / `chatSessionContinue` call, it prefix-matches the new
|
|
2450
|
+
* token sequence against the cached tokens and only prefills the delta —
|
|
2451
|
+
* avoiding redundant computation for multi-turn conversations.
|
|
1995
2452
|
*/
|
|
1996
2453
|
reuseCache?: boolean | undefined;
|
|
2454
|
+
/**
|
|
2455
|
+
* MTP: opt-in flag enabling the Multi-Token Prediction speculative decode
|
|
2456
|
+
* loop (pure-Rust eager; qwen3.5 dense and MoE). Requires the model
|
|
2457
|
+
* checkpoint to carry an MTP head (otherwise silently ignored). Default:
|
|
2458
|
+
* `false`.
|
|
2459
|
+
*/
|
|
2460
|
+
enableMtp?: boolean | undefined;
|
|
2461
|
+
/**
|
|
2462
|
+
* MTP: number of draft tokens per speculative cycle.
|
|
2463
|
+
*
|
|
2464
|
+
* On Qwen3.5 native MTP heads it is clamped to `[1, 5]` by the verify
|
|
2465
|
+
* FFI contract, and when unset native code currently pins depth 1.
|
|
2466
|
+
* When `mtpAdaptiveDepth` is `true`, this value is used as the
|
|
2467
|
+
* throughput-policy seed and the expected-value policy's max depth.
|
|
2468
|
+
* Adaptive depth is opt-in; set `mtpAdaptiveDepth: true` explicitly to
|
|
2469
|
+
* enable it.
|
|
2470
|
+
*
|
|
2471
|
+
* Gemma4 external drafts (`draftModelPath`) resolve the field per draft
|
|
2472
|
+
* variant instead (`gemma4/model.rs` `resolve_params`, always from the
|
|
2473
|
+
* RAW config value — the engine's central `[1, 5]` clamp is an MTP-head
|
|
2474
|
+
* contract that does not apply to external drafts):
|
|
2475
|
+
* - DSpark: with both knobs unset, full draft blocks (the checkpoint's
|
|
2476
|
+
* block size — 7 tokens on `dspark_gemma4_12b_block7`) run behind a
|
|
2477
|
+
* short target-AR/DSpark break-even calibration. A short generation
|
|
2478
|
+
* budget that cannot finish calibration retains the fixed-block
|
|
2479
|
+
* schedule. An explicit
|
|
2480
|
+
* `mtpDepth` caps and pins the block unless `mtpAdaptiveDepth: true`
|
|
2481
|
+
* opts the guard back in; explicit `false` disables it.
|
|
2482
|
+
* - Assistant (Google `gemma-4-*-it-assistant`): an unset `mtpDepth`
|
|
2483
|
+
* drafts 3 tokens per cycle (`ASSISTANT_DEFAULT_DEPTH`), and an
|
|
2484
|
+
* explicit `mtpDepth` clamps to `[1, 8]` (`ASSISTANT_MAX_DEPTH`).
|
|
2485
|
+
*
|
|
2486
|
+
* `mtpAdaptiveDepth` is ignored for the Gemma4 assistant variant.
|
|
2487
|
+
*/
|
|
2488
|
+
mtpDepth?: number | undefined;
|
|
2489
|
+
/**
|
|
2490
|
+
* MTP: when true, the decode loop runs the adaptive
|
|
2491
|
+
* depth policy. Default mode is a per-depth EMA hill-climb plus
|
|
2492
|
+
* DFlash-style 3-state machine `full | reduced | probe`.
|
|
2493
|
+
* `MLX_MTP_ADAPTIVE_DEPTH_MODE=expected-value` instead uses the
|
|
2494
|
+
* MTPLX-style intra-cycle expected-value gate, which deepens toward
|
|
2495
|
+
* `mtpDepth` by default (T=0 byte-parity verified); set
|
|
2496
|
+
* `MLX_MTP_EV_ALLOW_DEEPEN=0` to pin the base depth.
|
|
2497
|
+
* When false, the loop pins `mtpDepth` for every cycle.
|
|
2498
|
+
*
|
|
2499
|
+
* Default: false, except Gemma4 DSpark enables its measured break-even
|
|
2500
|
+
* guard when both this field and `mtpDepth` are unset. An explicit value
|
|
2501
|
+
* always wins over the family default.
|
|
2502
|
+
*/
|
|
2503
|
+
mtpAdaptiveDepth?: boolean | undefined;
|
|
1997
2504
|
}
|
|
1998
2505
|
|
|
1999
2506
|
/** Chat message with tool calling support */
|
|
@@ -2006,10 +2513,40 @@ export interface ChatMessage {
|
|
|
2006
2513
|
toolCalls?: Array<ToolCall>;
|
|
2007
2514
|
/** Tool call ID this message is responding to (for tool messages) */
|
|
2008
2515
|
toolCallId?: string;
|
|
2516
|
+
/**
|
|
2517
|
+
* Whether this tool-role message represents an errored tool result.
|
|
2518
|
+
*
|
|
2519
|
+
* Authoritative, structured signal of tool-call failure. Set to
|
|
2520
|
+
* `Some(true)` when the caller (e.g. the Anthropic
|
|
2521
|
+
* `tool_result.is_error === true` translator) wants the model to
|
|
2522
|
+
* treat the tool output as an error. The renderer prepends a short
|
|
2523
|
+
* `[tool error]` prefix to `content` when emitting the wire-format
|
|
2524
|
+
* tool response so the model receives a clear text-level cue, but
|
|
2525
|
+
* the original `content` stays byte-for-byte intact in the
|
|
2526
|
+
* structured form — no JSON wrapping, no in-band marker that could
|
|
2527
|
+
* collide with a successful tool result whose literal content
|
|
2528
|
+
* happens to start with the same prefix.
|
|
2529
|
+
*
|
|
2530
|
+
* `None` / `Some(false)` produce the unmarked wire format.
|
|
2531
|
+
*/
|
|
2532
|
+
isError?: boolean;
|
|
2009
2533
|
/** Reasoning content for thinking mode (used with <think> tags) */
|
|
2010
2534
|
reasoningContent?: string;
|
|
2535
|
+
/**
|
|
2536
|
+
* Thinking mode used when this assistant message was generated.
|
|
2537
|
+
*
|
|
2538
|
+
* This is replay provenance, not a request override. Gemma4's disabled-
|
|
2539
|
+
* thinking generation prefix contains an explicit empty thought channel,
|
|
2540
|
+
* while an enabled-thinking turn that emitted no reasoning contains no
|
|
2541
|
+
* such channel. Keeping the historical mode on the message lets the chat
|
|
2542
|
+
* template reproduce either byte sequence even when a later request
|
|
2543
|
+
* changes its current thinking setting.
|
|
2544
|
+
*/
|
|
2545
|
+
thinkingEnabled?: boolean;
|
|
2011
2546
|
/** Image data for VLM models (encoded image bytes: PNG/JPEG, passed as Uint8Array/Buffer) */
|
|
2012
2547
|
images?: Array<Uint8Array> | undefined;
|
|
2548
|
+
/** Audio data for unified Gemma 4 (encoded audio bytes: WAV, passed as Uint8Array/Buffer) */
|
|
2549
|
+
audio?: Array<Uint8Array> | undefined;
|
|
2013
2550
|
}
|
|
2014
2551
|
|
|
2015
2552
|
/** Unified chat result shared by all model variants (Qwen3, Qwen3.5, Qwen3.5 MoE). */
|
|
@@ -2018,8 +2555,21 @@ export interface ChatResult {
|
|
|
2018
2555
|
toolCalls: Array<ToolCallResult>;
|
|
2019
2556
|
thinking?: string;
|
|
2020
2557
|
numTokens: number;
|
|
2558
|
+
promptTokens: number;
|
|
2559
|
+
reasoningTokens: number;
|
|
2021
2560
|
finishReason: string;
|
|
2022
2561
|
rawText: string;
|
|
2562
|
+
/**
|
|
2563
|
+
* Number of prompt tokens served from the reused KV-cache prefix.
|
|
2564
|
+
*
|
|
2565
|
+
* When the native prefix-cache machinery successfully matches the new
|
|
2566
|
+
* prompt against the cached conversation history (via
|
|
2567
|
+
* `verify_cache_prefix_direct`), only the trailing delta is re-prefilled
|
|
2568
|
+
* and this field reports the length of the reused prefix. `0` when
|
|
2569
|
+
* the cache was missed or disabled and the full prompt had to be
|
|
2570
|
+
* re-prefilled.
|
|
2571
|
+
*/
|
|
2572
|
+
cachedTokens: number;
|
|
2023
2573
|
/** Performance metrics (present when `reportPerformance: true` in config) */
|
|
2024
2574
|
performance?: PerformanceMetrics;
|
|
2025
2575
|
}
|
|
@@ -2044,9 +2594,30 @@ export interface ChatStreamChunk {
|
|
|
2044
2594
|
toolCalls?: Array<ToolCallResult>;
|
|
2045
2595
|
thinking?: string;
|
|
2046
2596
|
numTokens?: number;
|
|
2597
|
+
promptTokens?: number;
|
|
2598
|
+
reasoningTokens?: number;
|
|
2047
2599
|
rawText?: string;
|
|
2600
|
+
/**
|
|
2601
|
+
* Number of prompt tokens served from the reused KV-cache prefix on
|
|
2602
|
+
* this turn. Populated on the terminal chunk (`done == true`) only;
|
|
2603
|
+
* `None` on mid-stream delta chunks.
|
|
2604
|
+
*
|
|
2605
|
+
* Zero on a cache miss or disabled reuse; equal to the matched
|
|
2606
|
+
* prefix length on a hit. Mirrors `ChatResult.cached_tokens`
|
|
2607
|
+
* verbatim so session-aware streaming consumers can observe
|
|
2608
|
+
* prefix-cache reuse without round-tripping to the non-streaming
|
|
2609
|
+
* path. Non-terminal chunks always carry `None` — only the
|
|
2610
|
+
* terminal chunk is authoritative.
|
|
2611
|
+
*/
|
|
2612
|
+
cachedTokens?: number | undefined;
|
|
2048
2613
|
/** Performance metrics (only present in the final chunk when `reportPerformance: true`) */
|
|
2049
2614
|
performance?: PerformanceMetrics;
|
|
2615
|
+
/**
|
|
2616
|
+
* Whether this delta chunk contains reasoning/thinking content.
|
|
2617
|
+
* true = reasoning (inside <think>...</think>), false = content (after </think>).
|
|
2618
|
+
* Only present on intermediate (non-final) chunks.
|
|
2619
|
+
*/
|
|
2620
|
+
isReasoning?: boolean | undefined;
|
|
2050
2621
|
}
|
|
2051
2622
|
|
|
2052
2623
|
/** Result from classify_and_rotate: orientation info + corrected image bytes. */
|
|
@@ -2109,7 +2680,11 @@ export interface ConversionOptions {
|
|
|
2109
2680
|
quantBits?: number;
|
|
2110
2681
|
/** Quantization group size (default: 64 for affine, 32 for mxfp8) */
|
|
2111
2682
|
quantGroupSize?: number;
|
|
2112
|
-
/**
|
|
2683
|
+
/**
|
|
2684
|
+
* Quantization mode: "affine" (default), "mxfp4", "mxfp8", "nvfp4", or
|
|
2685
|
+
* "sym8" (per-output-channel symmetric int8; qwen3_5 + qwen3_5_moe + lfm2/lfm2_moe + gemma4,
|
|
2686
|
+
* implies bits=8, no group_size — consciously NOT mlx-lm-loadable)
|
|
2687
|
+
*/
|
|
2113
2688
|
quantMode?: string;
|
|
2114
2689
|
/**
|
|
2115
2690
|
* Quantization recipe for per-layer mixed-bit quantization.
|
|
@@ -2121,6 +2696,35 @@ export interface ConversionOptions {
|
|
|
2121
2696
|
* Improves quantization quality by amplifying important weight channels.
|
|
2122
2697
|
*/
|
|
2123
2698
|
imatrixPath?: string;
|
|
2699
|
+
/**
|
|
2700
|
+
* Upgrade quantization to micro-scaling FP (mxfp4 / mxfp8).
|
|
2701
|
+
* When true, applies after the recipe predicate: eligible 8-bit affine
|
|
2702
|
+
* decisions become mxfp8 and 4-bit become mxfp4. Kept affine (not upgraded):
|
|
2703
|
+
* affine-only loaders (lm_head, embed_tokens, router.proj,
|
|
2704
|
+
* embedding_projection) at their recipe bits, MoE router gates (8-bit affine),
|
|
2705
|
+
* and the recipe-pinned attention/GDN projections (o_proj / out_proj /
|
|
2706
|
+
* in_proj_a / in_proj_b, 8-bit affine). Requires `quant_mode = "affine"`.
|
|
2707
|
+
* Forces `group_size = 32` for upgraded layers.
|
|
2708
|
+
*/
|
|
2709
|
+
quantMxfp?: boolean;
|
|
2710
|
+
/**
|
|
2711
|
+
* Optional Qwen MTP quantization policy: "off" (default), "cyankiwi", "all",
|
|
2712
|
+
* or "split" (alias "drafter").
|
|
2713
|
+
* "cyankiwi" keeps mtp.fc dense and quantizes only the MTP layer linears as
|
|
2714
|
+
* 4-bit affine group_size=32. For dense `qwen3_5` the quantized linears are
|
|
2715
|
+
* emitted into an MTPLX-compatible mtp.safetensors sidecar; for MoE
|
|
2716
|
+
* (`qwen3_5_moe`) there is no sidecar — they are quantized in place and stored
|
|
2717
|
+
* inline in the main safetensors shards.
|
|
2718
|
+
* "all" additionally quantizes mtp.fc. For dense `qwen3_5` the quantized MTP
|
|
2719
|
+
* linears land in the mtp.safetensors sidecar; for MoE (`qwen3_5_moe`) there
|
|
2720
|
+
* is no sidecar — they are quantized in place and stored inline in the main
|
|
2721
|
+
* safetensors shards.
|
|
2722
|
+
* "split"/"drafter" emits a body checkpoint with NO mtp.* tensors plus a
|
|
2723
|
+
* separate `mtp-drafter/` directory in mlx-vlm's `qwen3_5_mtp` format
|
|
2724
|
+
* (bare-keyed MTP head, format:mlx). It does NOT require --quantize/--q-recipe;
|
|
2725
|
+
* the body may be bf16 or already-quantized and the MTP head stays bf16.
|
|
2726
|
+
*/
|
|
2727
|
+
quantMtp?: string;
|
|
2124
2728
|
}
|
|
2125
2729
|
|
|
2126
2730
|
export interface ConversionResult {
|
|
@@ -2174,6 +2778,45 @@ export declare function convertParquetToJsonl(inputPath: string, outputPath: str
|
|
|
2174
2778
|
/** Create a default PaddleOCR-VL 1.5 configuration (JS factory function) */
|
|
2175
2779
|
export declare function createPaddleocrVlConfig(): ModelConfig;
|
|
2176
2780
|
|
|
2781
|
+
/** Create a default Qianfan-OCR configuration (JS factory function) */
|
|
2782
|
+
export declare function createQianfanOcrConfig(): QianfanOcrConfig;
|
|
2783
|
+
|
|
2784
|
+
/**
|
|
2785
|
+
* Create a random-init Qwen3.5 model and save it to disk.
|
|
2786
|
+
*
|
|
2787
|
+
* Spawns a dedicated `ModelThread<Qwen35Cmd>` whose init builds a fresh
|
|
2788
|
+
* random-weight `Qwen35Inner` directly, then dispatches `Qwen35Cmd::SaveModel`
|
|
2789
|
+
* on that thread. The thread is dropped at the end of the promise, so the
|
|
2790
|
+
* in-memory model is released once the checkpoint has been written. Used by
|
|
2791
|
+
* TypeScript test fixtures that need an on-disk checkpoint without keeping a
|
|
2792
|
+
* NAPI model instance alive.
|
|
2793
|
+
*/
|
|
2794
|
+
export declare function createRandomQwen35Checkpoint(config: Qwen35Config, savePath: string): Promise<undefined>;
|
|
2795
|
+
|
|
2796
|
+
/**
|
|
2797
|
+
* Create a random-init Qwen3.5 MoE model and save it to disk.
|
|
2798
|
+
*
|
|
2799
|
+
* Spawns a dedicated model thread whose init runs
|
|
2800
|
+
* [`create_random_qwen35_moe_checkpoint_sync`] (random-init inner + save);
|
|
2801
|
+
* the thread holds no state and is dropped once the promise resolves, so
|
|
2802
|
+
* the in-memory model is released as soon as the checkpoint has been
|
|
2803
|
+
* written. Used by TypeScript test fixtures that need an on-disk
|
|
2804
|
+
* checkpoint without keeping a NAPI model instance alive.
|
|
2805
|
+
*/
|
|
2806
|
+
export declare function createRandomQwen35MoeCheckpoint(config: Qwen35MoeConfig, savePath: string): Promise<undefined>;
|
|
2807
|
+
|
|
2808
|
+
/**
|
|
2809
|
+
* Create a random-init Qwen3 model and save it to disk.
|
|
2810
|
+
*
|
|
2811
|
+
* Spawns a dedicated `ModelThread<Qwen3Cmd>` whose init builds a fresh
|
|
2812
|
+
* random-weight `Qwen3Inner` directly, then dispatches `Qwen3Cmd::SaveModel`
|
|
2813
|
+
* on that thread. The thread is dropped at the end of the promise, so the
|
|
2814
|
+
* in-memory model is released once the checkpoint has been written. Used by
|
|
2815
|
+
* TypeScript test fixtures that need an on-disk checkpoint without keeping a
|
|
2816
|
+
* NAPI model instance alive.
|
|
2817
|
+
*/
|
|
2818
|
+
export declare function createRandomQwen3Checkpoint(config: Qwen3Config, savePath: string): Promise<undefined>;
|
|
2819
|
+
|
|
2177
2820
|
/** Document element - either a table or paragraph */
|
|
2178
2821
|
export interface DocumentElement {
|
|
2179
2822
|
elementType: ElementType;
|
|
@@ -2208,6 +2851,8 @@ export declare const enum DType {
|
|
|
2208
2851
|
BFloat16 = 3,
|
|
2209
2852
|
Uint32 = 4,
|
|
2210
2853
|
Uint8 = 5,
|
|
2854
|
+
/** Signed int8 — sym8 per-output-channel symmetric quantized weights. */
|
|
2855
|
+
Int8 = 6,
|
|
2211
2856
|
}
|
|
2212
2857
|
|
|
2213
2858
|
/** Document element type */
|
|
@@ -2290,14 +2935,186 @@ export interface FunctionDefinition {
|
|
|
2290
2935
|
parameters?: FunctionParameters;
|
|
2291
2936
|
}
|
|
2292
2937
|
|
|
2293
|
-
/** Function parameters schema (JSON Schema subset) */
|
|
2294
|
-
export interface FunctionParameters {
|
|
2295
|
-
/** Type (usually "object") */
|
|
2296
|
-
type: string;
|
|
2297
|
-
/** JSON string of property definitions */
|
|
2298
|
-
properties?: string;
|
|
2299
|
-
/** List of required parameter names */
|
|
2300
|
-
required?: Array<string>;
|
|
2938
|
+
/** Function parameters schema (JSON Schema subset) */
|
|
2939
|
+
export interface FunctionParameters {
|
|
2940
|
+
/** Type (usually "object") */
|
|
2941
|
+
type: string;
|
|
2942
|
+
/** JSON string of property definitions */
|
|
2943
|
+
properties?: string;
|
|
2944
|
+
/** List of required parameter names */
|
|
2945
|
+
required?: Array<string>;
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
/**
|
|
2949
|
+
* Gemma 4 model configuration (dense variant).
|
|
2950
|
+
*
|
|
2951
|
+
* Supports E2B (2.3B), E4B (4.5B), and 31B dense models.
|
|
2952
|
+
* For MoE models (26B-A4B), use `Gemma4MoeConfig` from `gemma4_moe`.
|
|
2953
|
+
*/
|
|
2954
|
+
export interface Gemma4Config {
|
|
2955
|
+
vocabSize: number;
|
|
2956
|
+
hiddenSize: number;
|
|
2957
|
+
numHiddenLayers: number;
|
|
2958
|
+
numAttentionHeads: number;
|
|
2959
|
+
numKeyValueHeads: number;
|
|
2960
|
+
headDim: number;
|
|
2961
|
+
intermediateSize: number;
|
|
2962
|
+
rmsNormEps: number;
|
|
2963
|
+
tieWordEmbeddings: boolean;
|
|
2964
|
+
maxPositionEmbeddings: number;
|
|
2965
|
+
slidingWindow: number;
|
|
2966
|
+
/**
|
|
2967
|
+
* Explicit per-layer attention type: "sliding_attention" or "full_attention".
|
|
2968
|
+
* Parsed from `text_config.layer_types` in the HuggingFace config.
|
|
2969
|
+
*/
|
|
2970
|
+
layerTypes: Array<string>;
|
|
2971
|
+
/** RoPE theta for global (full) attention layers. */
|
|
2972
|
+
ropeTheta: number;
|
|
2973
|
+
/** RoPE theta for sliding (local) attention layers. */
|
|
2974
|
+
ropeLocalBaseFreq: number;
|
|
2975
|
+
/** Fraction of head_dim to rotate for global attention (0.25 = 25%). */
|
|
2976
|
+
partialRotaryFactor: number;
|
|
2977
|
+
/** KV heads for global layers. If None, uses num_key_value_heads. */
|
|
2978
|
+
globalNumKeyValueHeads?: number;
|
|
2979
|
+
/** Head dimension for global layers. If None, uses head_dim. */
|
|
2980
|
+
globalHeadDim?: number;
|
|
2981
|
+
attentionKEqV: boolean;
|
|
2982
|
+
/**
|
|
2983
|
+
* True for the unified multimodal Gemma 4 checkpoint
|
|
2984
|
+
* (`model_type == "gemma4_unified"` or
|
|
2985
|
+
* `architectures[0] == "Gemma4UnifiedForConditionalGeneration"`).
|
|
2986
|
+
* The text decoder is shared, but the unified checkpoint carries
|
|
2987
|
+
* vision/audio embedder weights that must be dropped in a text-only load.
|
|
2988
|
+
*/
|
|
2989
|
+
isUnified: boolean;
|
|
2990
|
+
/**
|
|
2991
|
+
* `text_config.use_bidirectional_attention` from the unified checkpoint
|
|
2992
|
+
* (e.g. `"vision"`). Parsed for a stable struct surface; the text-only
|
|
2993
|
+
* decode path does not consume it.
|
|
2994
|
+
*/
|
|
2995
|
+
useBidirectionalAttention?: string;
|
|
2996
|
+
finalLogitSoftcapping?: number;
|
|
2997
|
+
perLayerInputEmbeds: boolean;
|
|
2998
|
+
hiddenSizePerLayerInput?: number;
|
|
2999
|
+
vocabSizePerLayerInput?: number;
|
|
3000
|
+
padTokenId: number;
|
|
3001
|
+
eosTokenIds: Array<number>;
|
|
3002
|
+
bosTokenId: number;
|
|
3003
|
+
attentionBias: boolean;
|
|
3004
|
+
useDoubleWideMlp: boolean;
|
|
3005
|
+
numKvSharedLayers?: number;
|
|
3006
|
+
defaultTemperature?: number;
|
|
3007
|
+
defaultTopK?: number;
|
|
3008
|
+
defaultTopP?: number;
|
|
3009
|
+
enableMoeBlock: boolean;
|
|
3010
|
+
numExperts?: number;
|
|
3011
|
+
topKExperts?: number;
|
|
3012
|
+
moeIntermediateSize?: number;
|
|
3013
|
+
visionConfig?: Gemma4VisionConfig;
|
|
3014
|
+
/**
|
|
3015
|
+
* Encoder-free vision config for the unified multimodal checkpoint.
|
|
3016
|
+
* `Some` only when `is_unified` and the checkpoint carries a
|
|
3017
|
+
* `vision_config` sub-dict. Disjoint from `vision_config` (the SigLIP
|
|
3018
|
+
* path) — the unified vision embedder is built from this instead.
|
|
3019
|
+
*/
|
|
3020
|
+
unifiedVisionConfig?: UnifiedVisionConfig;
|
|
3021
|
+
imageTokenId?: number;
|
|
3022
|
+
boiTokenId?: number;
|
|
3023
|
+
eoiTokenId?: number;
|
|
3024
|
+
visionSoftTokensPerImage?: number;
|
|
3025
|
+
/**
|
|
3026
|
+
* True when the checkpoint declares an `audio_config` sub-dict. Parallels
|
|
3027
|
+
* `unified_vision_config.is_some()`; gates the un-drop + load of
|
|
3028
|
+
* `embed_audio` weights and the audio merge path.
|
|
3029
|
+
*/
|
|
3030
|
+
hasAudio: boolean;
|
|
3031
|
+
/**
|
|
3032
|
+
* Audio placeholder token id (258881). Each `<audio>` placeholder expands to
|
|
3033
|
+
* `boa + audio_token × n_frames + eoa`.
|
|
3034
|
+
*/
|
|
3035
|
+
audioTokenId?: number;
|
|
3036
|
+
/** Begin-of-audio token id (256000), emitted before the audio token run. */
|
|
3037
|
+
boaTokenId?: number;
|
|
3038
|
+
/**
|
|
3039
|
+
* End-of-audio token id, parsed from the config's `eoa_token_index` (258883).
|
|
3040
|
+
* A real appended token (like `eoi`), despite the "index" name.
|
|
3041
|
+
*/
|
|
3042
|
+
eoaTokenId?: number;
|
|
3043
|
+
/**
|
|
3044
|
+
* Raw audio samples per audio token (640 = 40 ms @ 16 kHz), from
|
|
3045
|
+
* `audio_config.audio_samples_per_token`. Frame size for the encoder-free
|
|
3046
|
+
* pad+reshape feature extractor.
|
|
3047
|
+
*/
|
|
3048
|
+
audioSamplesPerToken?: number;
|
|
3049
|
+
/**
|
|
3050
|
+
* GPU memory budget for paged KV cache in megabytes.
|
|
3051
|
+
* Only used when `use_block_paged_cache` is true.
|
|
3052
|
+
* Default: auto-sized to cover `max_position_embeddings` for the
|
|
3053
|
+
* physical full-attention layers.
|
|
3054
|
+
*/
|
|
3055
|
+
pagedCacheMemoryMb?: number | undefined;
|
|
3056
|
+
/**
|
|
3057
|
+
* Block size for paged attention (tokens per block).
|
|
3058
|
+
* Only used when `use_block_paged_cache` is true.
|
|
3059
|
+
* Default: 16.
|
|
3060
|
+
*/
|
|
3061
|
+
pagedBlockSize?: number | undefined;
|
|
3062
|
+
/**
|
|
3063
|
+
* Use the new block-paged KV cache adapter (`PagedKVCacheAdapter`).
|
|
3064
|
+
*
|
|
3065
|
+
* When `Some(true)` or unset (the default), `Gemma4Inner` builds
|
|
3066
|
+
* model-independent KV-cache specs, groups them, and allocates a
|
|
3067
|
+
* `BlockAllocator` + `LayerKVPool` pair for physical full-attention
|
|
3068
|
+
* layers. Sliding-window layers still use `RotatingKVCache` until
|
|
3069
|
+
* true paged sliding-window groups are wired. KV-shared layers are
|
|
3070
|
+
* aliases: they reuse their anchor's cache slot and do not allocate
|
|
3071
|
+
* separate physical storage.
|
|
3072
|
+
*
|
|
3073
|
+
* Default: `true` (paged adapter on; opt-out via
|
|
3074
|
+
* `use_block_paged_cache: false` in `config.json` to use the flat
|
|
3075
|
+
* (non-paged) all-`Gemma4LayerCache` path instead). Parity between
|
|
3076
|
+
* the two paths is verified by
|
|
3077
|
+
* `crates/mlx-core/tests/gemma4_paged_vs_flat_parity.rs` against
|
|
3078
|
+
* real Gemma-4-E2B weights.
|
|
3079
|
+
*/
|
|
3080
|
+
useBlockPagedCache?: boolean | undefined;
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
/** Optional load-time settings for [`Gemma4Model::load`]. */
|
|
3084
|
+
export interface Gemma4LoadOptions {
|
|
3085
|
+
/**
|
|
3086
|
+
* Directory of a draft checkpoint (config.json + safetensors) to load
|
|
3087
|
+
* alongside the target model for speculative decoding — either a
|
|
3088
|
+
* DSpark draft or a Google assistant draft; the kind is probed from
|
|
3089
|
+
* the draft config.json. When omitted, `<model_path>/draft/` is loaded
|
|
3090
|
+
* automatically when present. Draft decoding runs only on the flat
|
|
3091
|
+
* KV-cache path: setting this while the model config explicitly enables
|
|
3092
|
+
* `use_block_paged_cache` is a hard load error, and an unset
|
|
3093
|
+
* `use_block_paged_cache` is forced to `false`.
|
|
3094
|
+
*/
|
|
3095
|
+
draftModelPath?: string;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
/**
|
|
3099
|
+
* Vision encoder configuration for Gemma4 multimodal models.
|
|
3100
|
+
*
|
|
3101
|
+
* Parsed from the `vision_config` sub-dict in config.json.
|
|
3102
|
+
*/
|
|
3103
|
+
export interface Gemma4VisionConfig {
|
|
3104
|
+
hiddenSize: number;
|
|
3105
|
+
intermediateSize: number;
|
|
3106
|
+
numHiddenLayers: number;
|
|
3107
|
+
numAttentionHeads: number;
|
|
3108
|
+
numKeyValueHeads: number;
|
|
3109
|
+
headDim: number;
|
|
3110
|
+
rmsNormEps: number;
|
|
3111
|
+
patchSize: number;
|
|
3112
|
+
positionEmbeddingSize: number;
|
|
3113
|
+
defaultOutputLength: number;
|
|
3114
|
+
poolingKernelSize: number;
|
|
3115
|
+
useClippedLinears: boolean;
|
|
3116
|
+
ropeTheta: number;
|
|
3117
|
+
standardize: boolean;
|
|
2301
3118
|
}
|
|
2302
3119
|
|
|
2303
3120
|
/** Result from generate_batch_for_training with all data needed for training */
|
|
@@ -2334,19 +3151,33 @@ export interface GenerationConfig {
|
|
|
2334
3151
|
*/
|
|
2335
3152
|
repetitionContextSize?: number;
|
|
2336
3153
|
/**
|
|
2337
|
-
*
|
|
2338
|
-
*
|
|
3154
|
+
* Presence penalty (0.0 = disabled). Subtracts a flat penalty from logits of any
|
|
3155
|
+
* token that appeared at least once in context. Matches OpenAI API semantics.
|
|
3156
|
+
*/
|
|
3157
|
+
presencePenalty?: number;
|
|
3158
|
+
/** Number of recent tokens to consider for presence penalty (default: 20) */
|
|
3159
|
+
presenceContextSize?: number;
|
|
3160
|
+
/**
|
|
3161
|
+
* Frequency penalty (0.0 = disabled). Subtracts penalty * occurrence_count from
|
|
3162
|
+
* logits of each token in context. Matches OpenAI API semantics.
|
|
3163
|
+
*/
|
|
3164
|
+
frequencyPenalty?: number;
|
|
3165
|
+
/** Number of recent tokens to consider for frequency penalty (default: 20) */
|
|
3166
|
+
frequencyContextSize?: number;
|
|
3167
|
+
/**
|
|
3168
|
+
* Stop if same token repeats this many times consecutively (default: 0 = disabled).
|
|
3169
|
+
* Opt in by setting a positive value to guard against degenerate repetitive generation.
|
|
2339
3170
|
*/
|
|
2340
3171
|
maxConsecutiveTokens?: number;
|
|
2341
3172
|
/**
|
|
2342
|
-
* Stop if a pattern repeats this many times consecutively (default:
|
|
2343
|
-
*
|
|
3173
|
+
* Stop if a pattern repeats this many times consecutively (default: 0 = disabled).
|
|
3174
|
+
* Opt in with a positive value to detect patterns like "A B A B A B".
|
|
2344
3175
|
* Uses range-based detection: checks all pattern sizes from 2 to ngram_size.
|
|
2345
3176
|
*/
|
|
2346
3177
|
maxNgramRepeats?: number;
|
|
2347
3178
|
/**
|
|
2348
|
-
* Maximum pattern size for repetition detection (default:
|
|
2349
|
-
*
|
|
3179
|
+
* Maximum pattern size for repetition detection (default: 0 = disabled).
|
|
3180
|
+
* When enabled, all pattern sizes from 2 up to this value are checked each decode step.
|
|
2350
3181
|
* Larger values catch long phrase-level repetition common in small models.
|
|
2351
3182
|
*/
|
|
2352
3183
|
ngramSize?: number;
|
|
@@ -2361,29 +3192,6 @@ export interface GenerationConfig {
|
|
|
2361
3192
|
* Set to 0 to disable chunking and process the entire prompt at once.
|
|
2362
3193
|
*/
|
|
2363
3194
|
prefillStepSize?: number;
|
|
2364
|
-
/**
|
|
2365
|
-
* KV cache quantization bits (default: 16 = no quantization)
|
|
2366
|
-
* - 16: Full precision (bfloat16/float16), no quantization
|
|
2367
|
-
* - 8: 8-bit quantization, ~2x memory savings, minimal quality loss
|
|
2368
|
-
* - 4: 4-bit quantization, ~4x memory savings, some quality degradation
|
|
2369
|
-
*
|
|
2370
|
-
* Quantized KV cache is useful for long sequences where memory becomes a bottleneck.
|
|
2371
|
-
* Note: Adds dequantization overhead per forward pass.
|
|
2372
|
-
*/
|
|
2373
|
-
kvCacheBits?: number;
|
|
2374
|
-
/**
|
|
2375
|
-
* KV cache quantization group size (default: 64)
|
|
2376
|
-
* Number of elements per quantization group. Smaller groups = better accuracy
|
|
2377
|
-
* but more overhead from storing scales/biases.
|
|
2378
|
-
* Only used when kv_cache_bits is 4 or 8.
|
|
2379
|
-
*/
|
|
2380
|
-
kvCacheGroupSize?: number;
|
|
2381
|
-
/**
|
|
2382
|
-
* Number of draft tokens to generate speculatively (default: 5)
|
|
2383
|
-
* Only used when a draft model is provided for speculative decoding.
|
|
2384
|
-
* Higher values can increase throughput but may reduce acceptance rate.
|
|
2385
|
-
*/
|
|
2386
|
-
numDraftTokens?: number;
|
|
2387
3195
|
}
|
|
2388
3196
|
|
|
2389
3197
|
export interface GenerationProfile {
|
|
@@ -2407,6 +3215,24 @@ export interface GenerationProfile {
|
|
|
2407
3215
|
timeToFirstTokenMs: number;
|
|
2408
3216
|
/** Per-phase breakdown. */
|
|
2409
3217
|
phases: Array<PhaseProfile>;
|
|
3218
|
+
/**
|
|
3219
|
+
* MTP speculative decode: mean accepted *draft* tokens per cycle
|
|
3220
|
+
* (excludes the always-verified token). Historical drafts-only metric.
|
|
3221
|
+
*/
|
|
3222
|
+
mtpMeanAcceptedTokens?: number;
|
|
3223
|
+
/**
|
|
3224
|
+
* MTP speculative decode: mean *committed* tokens per cycle, INCLUDING
|
|
3225
|
+
* the always-verified token (`mtp_accepted_drafts_total / mtp_cycles
|
|
3226
|
+
* + 1.0`). mlx-vlm-comparable headline; equals mlx-vlm's
|
|
3227
|
+
* `(accepted_drafts + rounds) / rounds` (`common.py:247`).
|
|
3228
|
+
*/
|
|
3229
|
+
mtpMeanAcceptedTokensTotal?: number;
|
|
3230
|
+
/** MTP speculative decode: per-draft-position acceptance rate. */
|
|
3231
|
+
mtpAcceptanceByPosition?: Array<number>;
|
|
3232
|
+
/** MTP speculative decode: number of draft+verify cycles executed. */
|
|
3233
|
+
mtpCycles?: number;
|
|
3234
|
+
/** MTP speculative decode: mean attempted draft depth per cycle. */
|
|
3235
|
+
mtpMeanDepth?: number;
|
|
2410
3236
|
/** Memory snapshot before generation. */
|
|
2411
3237
|
memoryBefore?: MemorySnapshot;
|
|
2412
3238
|
/** Memory snapshot after generation. */
|
|
@@ -2433,8 +3259,8 @@ export interface GenerationWithToolCalls {
|
|
|
2433
3259
|
toolCalls: Array<ToolCallRecord>;
|
|
2434
3260
|
}
|
|
2435
3261
|
|
|
2436
|
-
/**
|
|
2437
|
-
export declare function
|
|
3262
|
+
/** Sample MLX's GPU memory counters. See [`GpuMemorySnapshot`]. */
|
|
3263
|
+
export declare function getMemorySnapshot(): GpuMemorySnapshot;
|
|
2438
3264
|
|
|
2439
3265
|
/** Retrieve all collected profiling data as a `ProfilingSession`. */
|
|
2440
3266
|
export declare function getProfilingData(): ProfilingSession;
|
|
@@ -2444,6 +3270,13 @@ export interface GgufConversionOptions {
|
|
|
2444
3270
|
inputPath: string;
|
|
2445
3271
|
/** Output directory for converted SafeTensors model */
|
|
2446
3272
|
outputDir: string;
|
|
3273
|
+
/**
|
|
3274
|
+
* Optional directory containing the authoritative HuggingFace config and
|
|
3275
|
+
* tokenizer/processor assets. GGUF metadata is not rich enough to recreate
|
|
3276
|
+
* unified Gemma4 config fields such as head_dim, layer_types, vision, and
|
|
3277
|
+
* audio configuration exactly.
|
|
3278
|
+
*/
|
|
3279
|
+
configSourceDir?: string;
|
|
2447
3280
|
/** Target dtype: "float32", "float16", "bfloat16" (default: keep original) */
|
|
2448
3281
|
dtype?: string;
|
|
2449
3282
|
/** Enable verbose logging */
|
|
@@ -2477,6 +3310,17 @@ export interface GgufConversionOptions {
|
|
|
2477
3310
|
* This makes the safetensors compatible with mlx-vlm.
|
|
2478
3311
|
*/
|
|
2479
3312
|
vlmKeyPrefix?: boolean;
|
|
3313
|
+
/**
|
|
3314
|
+
* Upgrade quantization to micro-scaling FP (mxfp4 / mxfp8).
|
|
3315
|
+
* When true, applies after the recipe predicate: eligible 8-bit affine
|
|
3316
|
+
* decisions become mxfp8 and 4-bit become mxfp4. Kept affine (not upgraded):
|
|
3317
|
+
* affine-only loaders (lm_head, embed_tokens, router.proj,
|
|
3318
|
+
* embedding_projection) at their recipe bits, MoE router gates (8-bit affine),
|
|
3319
|
+
* and the recipe-pinned attention/GDN projections (o_proj / out_proj /
|
|
3320
|
+
* in_proj_a / in_proj_b, 8-bit affine). Requires `quant_mode = "affine"`.
|
|
3321
|
+
* Forces `group_size = 32` for upgraded layers.
|
|
3322
|
+
*/
|
|
3323
|
+
quantMxfp?: boolean;
|
|
2480
3324
|
}
|
|
2481
3325
|
|
|
2482
3326
|
export interface GgufConversionResult {
|
|
@@ -2492,6 +3336,33 @@ export interface GpuInfo {
|
|
|
2492
3336
|
architectureGen: number;
|
|
2493
3337
|
}
|
|
2494
3338
|
|
|
3339
|
+
/**
|
|
3340
|
+
* Snapshot of MLX's GPU memory counters at this instant. All values
|
|
3341
|
+
* are in bytes. On Apple Silicon, GPU and CPU share unified memory,
|
|
3342
|
+
* so these are NOT a separate "VRAM" pool — they reflect MLX's own
|
|
3343
|
+
* tracking of `StorageModePrivate` Metal buffers (model weights,
|
|
3344
|
+
* `LayerKVPool`, transient intermediate tensors) attributed to the
|
|
3345
|
+
* MLX runtime in this process.
|
|
3346
|
+
*
|
|
3347
|
+
* Useful for live observability during long-running sessions:
|
|
3348
|
+
*
|
|
3349
|
+
* ```js
|
|
3350
|
+
* const { getMemorySnapshot } = require('@mlx-node/core');
|
|
3351
|
+
* setInterval(() => {
|
|
3352
|
+
* const m = getMemorySnapshot();
|
|
3353
|
+
* console.log(`active=${(m.activeBytes/1e9).toFixed(2)}GB peak=${(m.peakBytes/1e9).toFixed(2)}GB cache=${(m.cacheBytes/1e9).toFixed(2)}GB`);
|
|
3354
|
+
* }, 1000);
|
|
3355
|
+
* ```
|
|
3356
|
+
*/
|
|
3357
|
+
export interface GpuMemorySnapshot {
|
|
3358
|
+
/** Current actively-used GPU buffer bytes (excludes cache pool). */
|
|
3359
|
+
activeBytes: number;
|
|
3360
|
+
/** Peak GPU buffer bytes since the last `resetPeakMemory()` call. */
|
|
3361
|
+
peakBytes: number;
|
|
3362
|
+
/** Bytes held in MLX's caching allocator (released by `clearCache`). */
|
|
3363
|
+
cacheBytes: number;
|
|
3364
|
+
}
|
|
3365
|
+
|
|
2495
3366
|
/** Configuration for the GRPO training engine */
|
|
2496
3367
|
export interface GrpoEngineConfig {
|
|
2497
3368
|
/** Learning rate (default: 1e-6) */
|
|
@@ -2526,6 +3397,16 @@ export interface GrpoEngineConfig {
|
|
|
2526
3397
|
topK?: number;
|
|
2527
3398
|
/** Repetition penalty (default: 1.1) */
|
|
2528
3399
|
repetitionPenalty?: number;
|
|
3400
|
+
/**
|
|
3401
|
+
* Presence penalty (0.0 = disabled). Subtracts a flat penalty from logits of any
|
|
3402
|
+
* token that appeared at least once in context.
|
|
3403
|
+
*/
|
|
3404
|
+
presencePenalty?: number;
|
|
3405
|
+
/**
|
|
3406
|
+
* Frequency penalty (0.0 = disabled). Subtracts penalty * occurrence_count from
|
|
3407
|
+
* logits of each token in context.
|
|
3408
|
+
*/
|
|
3409
|
+
frequencyPenalty?: number;
|
|
2529
3410
|
/**
|
|
2530
3411
|
* Maximum allowed NaN gradient occurrences before stopping training (default: 100)
|
|
2531
3412
|
* When exceeded, training will stop with an error to prevent model corruption.
|
|
@@ -2659,6 +3540,46 @@ export interface GrpoLossConfig {
|
|
|
2659
3540
|
vocabChunkSize?: number;
|
|
2660
3541
|
}
|
|
2661
3542
|
|
|
3543
|
+
/**
|
|
3544
|
+
* Configuration for Harrier embedding model (Qwen3 backbone).
|
|
3545
|
+
*
|
|
3546
|
+
* Only includes backbone dimensions needed for encoding.
|
|
3547
|
+
* No generation fields (token IDs, paged attention, etc.).
|
|
3548
|
+
*/
|
|
3549
|
+
export interface HarrierConfig {
|
|
3550
|
+
hiddenSize: number;
|
|
3551
|
+
numLayers: number;
|
|
3552
|
+
numHeads: number;
|
|
3553
|
+
numKeyValueHeads: number;
|
|
3554
|
+
intermediateSize: number;
|
|
3555
|
+
rmsNormEps: number;
|
|
3556
|
+
ropeTheta: number;
|
|
3557
|
+
maxPositionEmbeddings: number;
|
|
3558
|
+
headDim: number;
|
|
3559
|
+
/**
|
|
3560
|
+
* Qwen3 always uses QK normalization. Omit to use the default (true).
|
|
3561
|
+
* Explicitly passing false is allowed but produces a model incompatible
|
|
3562
|
+
* with published Harrier weights.
|
|
3563
|
+
*/
|
|
3564
|
+
useQkNorm?: boolean;
|
|
3565
|
+
vocabSize: number;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
/** InternViT vision encoder configuration */
|
|
3569
|
+
export interface InternVisionConfig {
|
|
3570
|
+
hiddenSize: number;
|
|
3571
|
+
intermediateSize: number;
|
|
3572
|
+
numHiddenLayers: number;
|
|
3573
|
+
numAttentionHeads: number;
|
|
3574
|
+
numChannels: number;
|
|
3575
|
+
imageSize: number;
|
|
3576
|
+
patchSize: number;
|
|
3577
|
+
layerNormEps: number;
|
|
3578
|
+
qkvBias: boolean;
|
|
3579
|
+
/** Drop path rate (inference only, always 0) */
|
|
3580
|
+
dropPathRate: number;
|
|
3581
|
+
}
|
|
3582
|
+
|
|
2662
3583
|
/** Check whether profiling is currently enabled. */
|
|
2663
3584
|
export declare function isProfilingEnabled(): boolean;
|
|
2664
3585
|
|
|
@@ -2676,6 +3597,98 @@ export interface LayoutElement {
|
|
|
2676
3597
|
order: number;
|
|
2677
3598
|
}
|
|
2678
3599
|
|
|
3600
|
+
/**
|
|
3601
|
+
* LFM2 model configuration.
|
|
3602
|
+
*
|
|
3603
|
+
* Supports LiquidAI's LFM2.5 hybrid conv+attention architecture.
|
|
3604
|
+
* 16 layers total: 10 conv + 6 full_attention, defined by `layer_types` array.
|
|
3605
|
+
*/
|
|
3606
|
+
export interface Lfm2Config {
|
|
3607
|
+
vocabSize: number;
|
|
3608
|
+
hiddenSize: number;
|
|
3609
|
+
numHiddenLayers: number;
|
|
3610
|
+
numAttentionHeads: number;
|
|
3611
|
+
numKeyValueHeads: number;
|
|
3612
|
+
maxPositionEmbeddings: number;
|
|
3613
|
+
normEps: number;
|
|
3614
|
+
convBias: boolean;
|
|
3615
|
+
convLCache: number;
|
|
3616
|
+
blockDim: number;
|
|
3617
|
+
blockFfDim: number;
|
|
3618
|
+
blockMultipleOf: number;
|
|
3619
|
+
blockFfnDimMultiplier: number;
|
|
3620
|
+
blockAutoAdjustFfDim: boolean;
|
|
3621
|
+
ropeTheta: number;
|
|
3622
|
+
layerTypes: Array<string>;
|
|
3623
|
+
tieEmbedding: boolean;
|
|
3624
|
+
eosTokenId: number;
|
|
3625
|
+
bosTokenId: number;
|
|
3626
|
+
padTokenId: number;
|
|
3627
|
+
/**
|
|
3628
|
+
* GPU memory budget for paged KV cache in megabytes.
|
|
3629
|
+
* Only used when `use_block_paged_cache` is true.
|
|
3630
|
+
* Default: 2048 (2GB).
|
|
3631
|
+
*/
|
|
3632
|
+
pagedCacheMemoryMb?: number | undefined;
|
|
3633
|
+
/**
|
|
3634
|
+
* Block size for paged attention (tokens per block).
|
|
3635
|
+
* Only used when `use_block_paged_cache` is true.
|
|
3636
|
+
* Default: 16.
|
|
3637
|
+
*/
|
|
3638
|
+
pagedBlockSize?: number | undefined;
|
|
3639
|
+
/**
|
|
3640
|
+
* Use the new block-paged KV cache adapter (`PagedKVCacheAdapter`).
|
|
3641
|
+
*
|
|
3642
|
+
* Default: `true` since 2026-04-28 (parity-verified via
|
|
3643
|
+
* `crates/mlx-core/tests/lfm2_paged_vs_flat_parity.rs` against real
|
|
3644
|
+
* LFM2.5-1.2B weights: byte-equal greedy decode + prefix-reuse
|
|
3645
|
+
* byte-equal at BF16). Wired through
|
|
3646
|
+
* `Lfm2DecoderLayer::forward_paged_or_flat`.
|
|
3647
|
+
*
|
|
3648
|
+
* Per-layer routing: LFM2's hybrid architecture means only
|
|
3649
|
+
* `full_attention` layers go through the paged adapter; conv layers
|
|
3650
|
+
* stay on the existing flat `Lfm2LayerCache::Conv(ArraysCache)`
|
|
3651
|
+
* storage regardless of this flag. The `LayerKVPool` is sized to
|
|
3652
|
+
* the count of `full_attention` layers and indexed by
|
|
3653
|
+
* attention-ordinal (via `config.full_attn_idxs()`), not by absolute
|
|
3654
|
+
* layer index.
|
|
3655
|
+
*
|
|
3656
|
+
* Opt out with `use_block_paged_cache: Some(false)` to revert to the
|
|
3657
|
+
* fully flat `Lfm2LayerCache` path on all layers.
|
|
3658
|
+
*/
|
|
3659
|
+
useBlockPagedCache?: boolean | undefined;
|
|
3660
|
+
/**
|
|
3661
|
+
* MLP intermediate size for the DENSE-in-MoE layers (`layer_idx <
|
|
3662
|
+
* num_dense_layers`). Used DIRECTLY (no 2/3 `computed_ff_dim()` shrink).
|
|
3663
|
+
* Only present on MoE checkpoints.
|
|
3664
|
+
*/
|
|
3665
|
+
intermediateSize?: number | undefined;
|
|
3666
|
+
/** Per-expert MLP intermediate size for the sparse MoE layers. */
|
|
3667
|
+
moeIntermediateSize?: number | undefined;
|
|
3668
|
+
/** Total number of routed experts. */
|
|
3669
|
+
numExperts?: number | undefined;
|
|
3670
|
+
/** Top-k experts selected per token. */
|
|
3671
|
+
numExpertsPerTok?: number | undefined;
|
|
3672
|
+
/** Number of leading DENSE layers before MoE layers begin. */
|
|
3673
|
+
numDenseLayers?: number | undefined;
|
|
3674
|
+
/**
|
|
3675
|
+
* Renormalize the top-k routing weights to sum to 1 (`/(sum+1e-20)`).
|
|
3676
|
+
*
|
|
3677
|
+
* `Option<bool>` so TS callers may omit it (napi renders bare `bool` as
|
|
3678
|
+
* required). Absent (None) is read as `true` everywhere via
|
|
3679
|
+
* `.unwrap_or(true)`, matching the prior `default = "default_true"`.
|
|
3680
|
+
*/
|
|
3681
|
+
normTopkProb?: boolean | undefined;
|
|
3682
|
+
/**
|
|
3683
|
+
* Add the learned per-expert bias to the post-softmax gates BEFORE top-k.
|
|
3684
|
+
*
|
|
3685
|
+
* `Option<bool>` so TS callers may omit it (napi renders bare `bool` as
|
|
3686
|
+
* required). Absent (None) is read as `true` everywhere via
|
|
3687
|
+
* `.unwrap_or(true)`, matching the prior `default = "default_true"`.
|
|
3688
|
+
*/
|
|
3689
|
+
useExpertBias?: boolean | undefined;
|
|
3690
|
+
}
|
|
3691
|
+
|
|
2679
3692
|
export interface MemorySnapshot {
|
|
2680
3693
|
/** Active (non-cached) memory in bytes. */
|
|
2681
3694
|
activeBytes: number;
|
|
@@ -2685,6 +3698,28 @@ export interface MemorySnapshot {
|
|
|
2685
3698
|
cacheBytes: number;
|
|
2686
3699
|
}
|
|
2687
3700
|
|
|
3701
|
+
/**
|
|
3702
|
+
* Return a snapshot of the MLX allocator's memory counters. Primarily
|
|
3703
|
+
* useful for dashboards and for debugging the `MLX_CACHE_LIMIT_GB`
|
|
3704
|
+
* override. Read-only — does not mutate allocator state.
|
|
3705
|
+
*/
|
|
3706
|
+
export declare function memoryStats(): MemoryStats;
|
|
3707
|
+
|
|
3708
|
+
/**
|
|
3709
|
+
* Snapshot of the MLX Metal allocator's memory state. All values are in
|
|
3710
|
+
* bytes and returned as `f64` to avoid forcing BigInt round-trips in JS.
|
|
3711
|
+
*/
|
|
3712
|
+
export interface MemoryStats {
|
|
3713
|
+
/** Actively-used memory (excludes the cached free-pool). */
|
|
3714
|
+
active: number;
|
|
3715
|
+
/** Peak memory usage since load / the last `resetPeakMemory`. */
|
|
3716
|
+
peak: number;
|
|
3717
|
+
/** Cache / free-pool memory currently held by the allocator. */
|
|
3718
|
+
cache: number;
|
|
3719
|
+
/** Metal `max_recommended_working_set_size` snapshot (0 on non-Metal). */
|
|
3720
|
+
wiredLimit: number;
|
|
3721
|
+
}
|
|
3722
|
+
|
|
2688
3723
|
/** Full model configuration */
|
|
2689
3724
|
export interface ModelConfig {
|
|
2690
3725
|
visionConfig: VisionConfig;
|
|
@@ -2728,56 +3763,6 @@ export interface OutputStoreConfig {
|
|
|
2728
3763
|
localPath: string;
|
|
2729
3764
|
}
|
|
2730
3765
|
|
|
2731
|
-
/** Paged attention memory statistics (NAPI-compatible) */
|
|
2732
|
-
export interface PagedCacheStats {
|
|
2733
|
-
/** Total number of blocks in the pool */
|
|
2734
|
-
totalBlocks: number;
|
|
2735
|
-
/** Number of free blocks */
|
|
2736
|
-
freeBlocks: number;
|
|
2737
|
-
/** Number of allocated blocks */
|
|
2738
|
-
allocatedBlocks: number;
|
|
2739
|
-
/** Total memory in MB */
|
|
2740
|
-
totalMemoryMb: number;
|
|
2741
|
-
/** Used memory in MB */
|
|
2742
|
-
usedMemoryMb: number;
|
|
2743
|
-
/** Utilization percentage */
|
|
2744
|
-
utilizationPercent: number;
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2747
|
-
/** A completed sequence from paged generation */
|
|
2748
|
-
export interface PagedCompletedSequence {
|
|
2749
|
-
/** Original request ID */
|
|
2750
|
-
requestId: string;
|
|
2751
|
-
/** All generated tokens (excluding prompt) */
|
|
2752
|
-
tokens: Array<number>;
|
|
2753
|
-
/** Reason for completion ("stop", "length", "repetition", "tool_calls") */
|
|
2754
|
-
finishReason: string;
|
|
2755
|
-
}
|
|
2756
|
-
|
|
2757
|
-
/** Result of a paged generation step */
|
|
2758
|
-
export interface PagedGenerationStep {
|
|
2759
|
-
/** Token outputs for each sequence in the batch */
|
|
2760
|
-
outputs: Array<PagedTokenOutput>;
|
|
2761
|
-
/** Number of sequences that were in prefill phase */
|
|
2762
|
-
numPrefill: number;
|
|
2763
|
-
/** Number of sequences that were in decode phase */
|
|
2764
|
-
numDecode: number;
|
|
2765
|
-
}
|
|
2766
|
-
|
|
2767
|
-
/** Output from a single token generation step in paged attention */
|
|
2768
|
-
export interface PagedTokenOutput {
|
|
2769
|
-
/** Sequence ID in the scheduler */
|
|
2770
|
-
seqId: number;
|
|
2771
|
-
/** Request ID for this sequence */
|
|
2772
|
-
requestId: string;
|
|
2773
|
-
/** Generated token ID */
|
|
2774
|
-
token: number;
|
|
2775
|
-
/** Log probability of the token (f64 for NAPI compatibility) */
|
|
2776
|
-
logprob: number;
|
|
2777
|
-
/** Whether this sequence has finished */
|
|
2778
|
-
isFinished: boolean;
|
|
2779
|
-
}
|
|
2780
|
-
|
|
2781
3766
|
/** A text paragraph */
|
|
2782
3767
|
export interface Paragraph {
|
|
2783
3768
|
content: string;
|
|
@@ -2859,6 +3844,52 @@ export interface PerformanceMetrics {
|
|
|
2859
3844
|
* Excludes the first token (counted as prefill).
|
|
2860
3845
|
*/
|
|
2861
3846
|
decodeTokensPerSecond: number;
|
|
3847
|
+
/**
|
|
3848
|
+
* MTP speculative decode: mean accepted *draft* tokens per cycle
|
|
3849
|
+
* (range `[0, depth]`). EXCLUDES the always-verified token each cycle
|
|
3850
|
+
* commits. `None` on plain autoregressive runs where no MTP cycle
|
|
3851
|
+
* executed. This is the historical drafts-only metric; for the
|
|
3852
|
+
* mlx-vlm-comparable headline see [`Self::mtp_mean_accepted_tokens_total`].
|
|
3853
|
+
*/
|
|
3854
|
+
mtpMeanAcceptedTokens?: number;
|
|
3855
|
+
/**
|
|
3856
|
+
* MTP speculative decode: mean *committed* tokens per cycle, INCLUDING
|
|
3857
|
+
* the single always-verified token each cycle emits — i.e.
|
|
3858
|
+
* `mtp_accepted_drafts_total / mtp_cycles + 1.0`. This is the
|
|
3859
|
+
* mlx-vlm-comparable headline accept rate: it equals mlx-vlm's
|
|
3860
|
+
* `mean_accepted_tokens = (accepted_drafts + rounds) / rounds`
|
|
3861
|
+
* (`mlx-vlm/mlx_vlm/speculative/common.py:247`), where our
|
|
3862
|
+
* `mtp_cycles` is the 1:1 analog of mlx-vlm's `rounds` (one
|
|
3863
|
+
* draft+verify iteration; `record_mtp_cycle` is called exactly once
|
|
3864
|
+
* per cycle). The per-cycle `+1.0` matches mlx-vlm's `+rounds`
|
|
3865
|
+
* assumption — every round commits exactly one verified token
|
|
3866
|
+
* (the residual on partial-accept, the bonus on full-accept), even
|
|
3867
|
+
* when the final cycle's tail is EOS/length-truncated downstream
|
|
3868
|
+
* (mlx-vlm makes the same assumption: it appends to `accept_lens`
|
|
3869
|
+
* once per round regardless of truncation). `None` on plain
|
|
3870
|
+
* autoregressive runs.
|
|
3871
|
+
*/
|
|
3872
|
+
mtpMeanAcceptedTokensTotal?: number;
|
|
3873
|
+
/**
|
|
3874
|
+
* MTP speculative decode: per-draft-position acceptance rate
|
|
3875
|
+
* (index = draft position). `None` on plain autoregressive runs.
|
|
3876
|
+
*/
|
|
3877
|
+
mtpAcceptanceByPosition?: Array<number>;
|
|
3878
|
+
/**
|
|
3879
|
+
* MTP speculative decode: number of draft+verify cycles executed.
|
|
3880
|
+
* `None` on plain autoregressive runs.
|
|
3881
|
+
*/
|
|
3882
|
+
mtpCycles?: number;
|
|
3883
|
+
/**
|
|
3884
|
+
* MTP speculative decode: mean attempted draft depth per cycle.
|
|
3885
|
+
* `None` on plain autoregressive runs.
|
|
3886
|
+
*/
|
|
3887
|
+
mtpMeanDepth?: number;
|
|
3888
|
+
/**
|
|
3889
|
+
* Optional decode phase breakdown. Present when decode profiling
|
|
3890
|
+
* is enabled via `MLX_PROFILE_DECODE=1` or `setProfilingEnabled(true)`.
|
|
3891
|
+
*/
|
|
3892
|
+
profilePhases?: Array<PhaseProfile>;
|
|
2862
3893
|
}
|
|
2863
3894
|
|
|
2864
3895
|
export interface PhaseProfile {
|
|
@@ -2872,6 +3903,76 @@ export interface PhaseProfile {
|
|
|
2872
3903
|
count: number;
|
|
2873
3904
|
}
|
|
2874
3905
|
|
|
3906
|
+
/**
|
|
3907
|
+
* Per-call Viterbi calibration overrides.
|
|
3908
|
+
*
|
|
3909
|
+
* Any field set to `Some(_)` overrides the corresponding bias from the
|
|
3910
|
+
* model's default calibration (loaded from `viterbi_calibration.json`
|
|
3911
|
+
* at load time). Missing fields fall back to the default.
|
|
3912
|
+
*/
|
|
3913
|
+
export interface PrivacyCalibration {
|
|
3914
|
+
transitionBiasBackgroundStay?: number;
|
|
3915
|
+
transitionBiasBackgroundToStart?: number;
|
|
3916
|
+
transitionBiasEndToBackground?: number;
|
|
3917
|
+
transitionBiasEndToStart?: number;
|
|
3918
|
+
transitionBiasInsideToContinue?: number;
|
|
3919
|
+
transitionBiasInsideToEnd?: number;
|
|
3920
|
+
}
|
|
3921
|
+
|
|
3922
|
+
/**
|
|
3923
|
+
* Options for [`PrivacyFilterModelJs::classify`].
|
|
3924
|
+
*
|
|
3925
|
+
* - `threshold` (default `0.5`): minimum mean per-token probability for
|
|
3926
|
+
* an extracted span to be returned.
|
|
3927
|
+
* - `calibration`: per-call overrides on top of the checkpoint default.
|
|
3928
|
+
* - `return_tokens` (default `false`): when `true`, the result includes
|
|
3929
|
+
* a `tokens` array with one entry per input token.
|
|
3930
|
+
*/
|
|
3931
|
+
export interface PrivacyClassifyOptions {
|
|
3932
|
+
threshold?: number;
|
|
3933
|
+
calibration?: PrivacyCalibration;
|
|
3934
|
+
returnTokens?: boolean;
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
/** Result of [`PrivacyFilterModelJs::classify`]. */
|
|
3938
|
+
export interface PrivacyClassifyResult {
|
|
3939
|
+
entities: Array<PrivacyEntity>;
|
|
3940
|
+
tokens?: Array<PrivacyToken>;
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
/**
|
|
3944
|
+
* A privacy entity detected by [`PrivacyFilterModelJs::classify`].
|
|
3945
|
+
*
|
|
3946
|
+
* `start`/`end` are byte offsets into the input string (Hugging Face
|
|
3947
|
+
* `tokenizers` convention). `label` is the privacy class without the
|
|
3948
|
+
* BIOES prefix (e.g. `"private_email"`). `score` is the mean — across
|
|
3949
|
+
* the span's tokens — of the softmax probability of the Viterbi-emitted
|
|
3950
|
+
* tag at each token.
|
|
3951
|
+
*/
|
|
3952
|
+
export interface PrivacyEntity {
|
|
3953
|
+
label: string;
|
|
3954
|
+
start: number;
|
|
3955
|
+
end: number;
|
|
3956
|
+
score: number;
|
|
3957
|
+
text: string;
|
|
3958
|
+
}
|
|
3959
|
+
|
|
3960
|
+
/**
|
|
3961
|
+
* Per-token output emitted when [`PrivacyClassifyOptions::return_tokens`]
|
|
3962
|
+
* is `true`. `tag` is the full BIOES tag (`"O"` or `"B-..."`/`"I-..."`/
|
|
3963
|
+
* `"E-..."`/`"S-..."`) chosen by the Viterbi decoder. `score` is the
|
|
3964
|
+
* softmax probability of that emitted tag at this token, so `tag` and
|
|
3965
|
+
* `score` always share decoders (at boundary tokens the Viterbi tag can
|
|
3966
|
+
* differ from the local argmax).
|
|
3967
|
+
*/
|
|
3968
|
+
export interface PrivacyToken {
|
|
3969
|
+
text: string;
|
|
3970
|
+
tag: string;
|
|
3971
|
+
score: number;
|
|
3972
|
+
start: number;
|
|
3973
|
+
end: number;
|
|
3974
|
+
}
|
|
3975
|
+
|
|
2875
3976
|
export interface ProfilingSession {
|
|
2876
3977
|
/** GPU hardware info. */
|
|
2877
3978
|
gpuInfo: GpuInfo;
|
|
@@ -2896,6 +3997,55 @@ export interface ProfilingSummary {
|
|
|
2896
3997
|
avgPrefillMs: number;
|
|
2897
3998
|
}
|
|
2898
3999
|
|
|
4000
|
+
/** Full Qianfan-OCR model configuration */
|
|
4001
|
+
export interface QianfanOcrConfig {
|
|
4002
|
+
visionConfig: InternVisionConfig;
|
|
4003
|
+
llmConfig: Qwen3LmConfig;
|
|
4004
|
+
modelType: string;
|
|
4005
|
+
imgContextTokenId: number;
|
|
4006
|
+
/** `<img>` token ID */
|
|
4007
|
+
imgStartTokenId: number;
|
|
4008
|
+
/** `</img>` token ID */
|
|
4009
|
+
imgEndTokenId: number;
|
|
4010
|
+
/** `<|im_end|>` token ID */
|
|
4011
|
+
eosTokenId: number;
|
|
4012
|
+
/** Which vision encoder layer to extract features from */
|
|
4013
|
+
selectLayer: number;
|
|
4014
|
+
/** Pixel shuffle version */
|
|
4015
|
+
psVersion: string;
|
|
4016
|
+
downsampleRatio: number;
|
|
4017
|
+
dynamicImageSize: boolean;
|
|
4018
|
+
useThumbnail: boolean;
|
|
4019
|
+
maxDynamicPatch: number;
|
|
4020
|
+
minDynamicPatch: number;
|
|
4021
|
+
}
|
|
4022
|
+
|
|
4023
|
+
/** Microbench result for the production quantized qmv dispatch path. */
|
|
4024
|
+
export interface QmvQuantizedMicrobenchResult {
|
|
4025
|
+
/** Median `quantized_matmul` wall-clock per call, in nanoseconds. */
|
|
4026
|
+
medianNs: number;
|
|
4027
|
+
/** A tiny materialized checksum of the final output, used to keep the call live. */
|
|
4028
|
+
checksum: number;
|
|
4029
|
+
}
|
|
4030
|
+
|
|
4031
|
+
/**
|
|
4032
|
+
* Run the production quantized-qmv microbench in the current process.
|
|
4033
|
+
*
|
|
4034
|
+
* To compare `MLX_MTP_SMALL_M_QMV=0` versus `1`, call this from separate
|
|
4035
|
+
* processes. MLX caches the env-backed dispatch predicate statically.
|
|
4036
|
+
*/
|
|
4037
|
+
export declare function quantizedQmvMicrobench(
|
|
4038
|
+
k: number,
|
|
4039
|
+
n: number,
|
|
4040
|
+
m: number,
|
|
4041
|
+
groupSize: number,
|
|
4042
|
+
bits: number,
|
|
4043
|
+
mode: string,
|
|
4044
|
+
dtype: DType,
|
|
4045
|
+
warmup?: number | undefined | null,
|
|
4046
|
+
iters?: number | undefined | null,
|
|
4047
|
+
): QmvQuantizedMicrobenchResult;
|
|
4048
|
+
|
|
2899
4049
|
/**
|
|
2900
4050
|
* Qwen3.5 model configuration (dense variant).
|
|
2901
4051
|
*
|
|
@@ -2924,6 +4074,72 @@ export interface Qwen35Config {
|
|
|
2924
4074
|
fullAttentionInterval: number;
|
|
2925
4075
|
partialRotaryFactor: number;
|
|
2926
4076
|
ropeTheta: number;
|
|
4077
|
+
/**
|
|
4078
|
+
* GPU memory budget for paged KV cache in megabytes.
|
|
4079
|
+
* Only used when `use_block_paged_cache` is true.
|
|
4080
|
+
* Default: automatically sized for one full-context sequence.
|
|
4081
|
+
*/
|
|
4082
|
+
pagedCacheMemoryMb?: number | undefined;
|
|
4083
|
+
/**
|
|
4084
|
+
* Block size for paged attention (tokens per block).
|
|
4085
|
+
* Only used when `use_block_paged_cache` is true.
|
|
4086
|
+
* Default: 16.
|
|
4087
|
+
*/
|
|
4088
|
+
pagedBlockSize?: number | undefined;
|
|
4089
|
+
/**
|
|
4090
|
+
* Use the block-paged KV cache adapter (`PagedKVCacheAdapter`) for
|
|
4091
|
+
* full-attention layers.
|
|
4092
|
+
*
|
|
4093
|
+
* **OPT-IN — experimental.** When `Some(true)`, `Qwen35Inner`
|
|
4094
|
+
* allocates a `BlockAllocator` + `LayerKVPool` pair sized for the
|
|
4095
|
+
* model's full-attention layer count and constructs a
|
|
4096
|
+
* `PagedKVCacheAdapter`. The chat-session forward dispatch routes
|
|
4097
|
+
* full-attention layers through this adapter while linear-attention
|
|
4098
|
+
* (GatedDeltaNet / GDN) layers continue to use the existing
|
|
4099
|
+
* `Qwen3_5LayerCache::Linear(ArraysCache)` path with no
|
|
4100
|
+
* cross-request prefix reuse — vLLM's `MambaManager`-style "no
|
|
4101
|
+
* prefix reuse for recurrent layers" stance.
|
|
4102
|
+
*
|
|
4103
|
+
* **Paged vs flat eager**: this flag selects the eager paged decode
|
|
4104
|
+
* over the eager flat decode. When `Some(true)`, full-attention
|
|
4105
|
+
* layers run through the paged adapter (cross-request prefix reuse);
|
|
4106
|
+
* when unset, they run the eager flat decode. Either way the forward
|
|
4107
|
+
* is pure-Rust eager.
|
|
4108
|
+
*
|
|
4109
|
+
* **VLM under paged**: a VLM checkpoint defaults this flag ON at load, so
|
|
4110
|
+
* dense image turns ONLY run on the paged-vision core. A fresh single-turn
|
|
4111
|
+
* image-bearing prompt prefills through the paged adapter (M-RoPE positions
|
|
4112
|
+
* feed the rotary; the merged vision embeddings feed the forward) and
|
|
4113
|
+
* decodes plain AR — MTP weights are ignored on image turns. Warm
|
|
4114
|
+
* image-bearing session continues / cache-hit reuse are still rejected at
|
|
4115
|
+
* runtime (the GDN two-pass warm prefix is not byte-exact). A vision turn
|
|
4116
|
+
* that reaches a None adapter (explicit `Some(false)`, non-Metal build, or
|
|
4117
|
+
* a sym8 checkpoint) errors at dispatch.
|
|
4118
|
+
*
|
|
4119
|
+
* Default: `None` for text-only checkpoints (eager flat decode);
|
|
4120
|
+
* `Some(true)` for VLM checkpoints (block-paged, set in `parse_config`).
|
|
4121
|
+
*/
|
|
4122
|
+
useBlockPagedCache?: boolean | undefined;
|
|
4123
|
+
/**
|
|
4124
|
+
* Number of MTP (Multi-Token Prediction) head layers shipped with the
|
|
4125
|
+
* checkpoint. Populated from `mtp_num_hidden_layers` /
|
|
4126
|
+
* `num_nextn_predict_layers` in `config.json`. `0` means the
|
|
4127
|
+
* checkpoint has no MTP heads and the speculative-decode path is
|
|
4128
|
+
* unavailable.
|
|
4129
|
+
*/
|
|
4130
|
+
nMtpLayers: number;
|
|
4131
|
+
}
|
|
4132
|
+
|
|
4133
|
+
/**
|
|
4134
|
+
* Trained and physically available active-context limits for one loaded
|
|
4135
|
+
* Qwen3.5 model. Values are snapshots because the physical pool is fixed for
|
|
4136
|
+
* the lifetime of the resident model.
|
|
4137
|
+
*/
|
|
4138
|
+
export interface Qwen35ContextLimits {
|
|
4139
|
+
trainedWindowTokens: number;
|
|
4140
|
+
effectiveWindowTokens: number;
|
|
4141
|
+
pagedBlockCapacity: number;
|
|
4142
|
+
pagedBlockSize: number;
|
|
2927
4143
|
}
|
|
2928
4144
|
|
|
2929
4145
|
/** Generation configuration for Qwen3.5 */
|
|
@@ -2978,6 +4194,47 @@ export interface Qwen35MoeConfig {
|
|
|
2978
4194
|
moeIntermediateSize?: number | undefined;
|
|
2979
4195
|
normTopkProb: boolean;
|
|
2980
4196
|
mlpOnlyLayers?: number[] | undefined;
|
|
4197
|
+
/**
|
|
4198
|
+
* GPU memory budget for paged KV cache in megabytes.
|
|
4199
|
+
* Only used when `use_block_paged_cache` is true.
|
|
4200
|
+
* Default: automatically sized for one full-context sequence.
|
|
4201
|
+
*/
|
|
4202
|
+
pagedCacheMemoryMb?: number | undefined;
|
|
4203
|
+
/**
|
|
4204
|
+
* Block size for paged attention (tokens per block).
|
|
4205
|
+
* Only used when `use_block_paged_cache` is true.
|
|
4206
|
+
* Default: 16.
|
|
4207
|
+
*/
|
|
4208
|
+
pagedBlockSize?: number | undefined;
|
|
4209
|
+
/**
|
|
4210
|
+
* Use the block-paged KV cache adapter for full-attention layers.
|
|
4211
|
+
*
|
|
4212
|
+
* **OPT-IN — experimental.** Same semantics as the dense
|
|
4213
|
+
* `Qwen3_5Config::use_block_paged_cache` field. Selects the eager
|
|
4214
|
+
* paged decode over the eager flat decode: routes full-attention
|
|
4215
|
+
* layers through `PagedKVCacheAdapter` (cross-request prefix reuse);
|
|
4216
|
+
* GDN linear-attention layers stay on `Qwen3_5LayerCache::Linear`
|
|
4217
|
+
* either way. When disabled, full-attention layers run the eager flat
|
|
4218
|
+
* decode instead.
|
|
4219
|
+
*
|
|
4220
|
+
* **VLM under paged**: a VLM checkpoint loads with this flag set, and a
|
|
4221
|
+
* fresh single-turn image-bearing prompt prefills through the paged
|
|
4222
|
+
* adapter (M-RoPE positions feed the rotary; the merged vision embeddings
|
|
4223
|
+
* feed the forward). Image-bearing MTP turns are still rejected at
|
|
4224
|
+
* runtime; warm image-bearing session continues / cache-hit reuse are
|
|
4225
|
+
* cold-started (no warm GDN two-pass prefix).
|
|
4226
|
+
*
|
|
4227
|
+
* Default: `None` / `false`.
|
|
4228
|
+
*/
|
|
4229
|
+
useBlockPagedCache?: boolean | undefined;
|
|
4230
|
+
/**
|
|
4231
|
+
* Number of MTP (Multi-Token Prediction) head layers shipped with
|
|
4232
|
+
* the checkpoint. Populated from `mtp_num_hidden_layers` /
|
|
4233
|
+
* `num_nextn_predict_layers` in `config.json`. `0` means the
|
|
4234
|
+
* checkpoint has no MTP heads and the speculative-decode path is
|
|
4235
|
+
* unavailable.
|
|
4236
|
+
*/
|
|
4237
|
+
nMtpLayers: number;
|
|
2981
4238
|
}
|
|
2982
4239
|
|
|
2983
4240
|
/** Generation configuration for Qwen3.5 MoE */
|
|
@@ -3014,29 +4271,45 @@ export interface Qwen3Config {
|
|
|
3014
4271
|
padTokenId: number;
|
|
3015
4272
|
eosTokenId: number;
|
|
3016
4273
|
bosTokenId: number;
|
|
3017
|
-
/**
|
|
3018
|
-
* Enable paged attention for memory-efficient inference.
|
|
3019
|
-
* Default: false (use standard KVCache)
|
|
3020
|
-
*/
|
|
3021
|
-
usePagedAttention?: boolean | undefined;
|
|
3022
4274
|
/**
|
|
3023
4275
|
* GPU memory budget for paged KV cache in megabytes.
|
|
3024
|
-
* Only used when use_paged_attention is true.
|
|
3025
4276
|
* Default: 2048 (2GB)
|
|
3026
4277
|
*/
|
|
3027
4278
|
pagedCacheMemoryMb?: number | undefined;
|
|
3028
4279
|
/**
|
|
3029
4280
|
* Block size for paged attention (tokens per block).
|
|
3030
|
-
* Only used when use_paged_attention is true.
|
|
3031
4281
|
* Default: 16
|
|
3032
4282
|
*/
|
|
3033
4283
|
pagedBlockSize?: number | undefined;
|
|
3034
4284
|
/**
|
|
3035
|
-
* Use
|
|
3036
|
-
*
|
|
3037
|
-
*
|
|
4285
|
+
* Use the block-paged KV cache adapter (`PagedKVCacheAdapter`).
|
|
4286
|
+
*
|
|
4287
|
+
* When `Some(true)` (the default for Qwen3), `Qwen3Inner` allocates a
|
|
4288
|
+
* `BlockAllocator` + `LayerKVPool` pair and constructs a
|
|
4289
|
+
* `PagedKVCacheAdapter` for cross-request KV prefix reuse (vLLM-style
|
|
4290
|
+
* block-paged storage with refcounted prefix caching). When
|
|
4291
|
+
* `Some(false)`, the flat (non-paged) `Vec<KVCache>` cache path is
|
|
4292
|
+
* used instead.
|
|
4293
|
+
*
|
|
4294
|
+
* Default: true.
|
|
3038
4295
|
*/
|
|
3039
|
-
|
|
4296
|
+
useBlockPagedCache?: boolean | undefined;
|
|
4297
|
+
}
|
|
4298
|
+
|
|
4299
|
+
/** Qwen3 language model configuration */
|
|
4300
|
+
export interface Qwen3LmConfig {
|
|
4301
|
+
hiddenSize: number;
|
|
4302
|
+
numHiddenLayers: number;
|
|
4303
|
+
intermediateSize: number;
|
|
4304
|
+
numAttentionHeads: number;
|
|
4305
|
+
numKeyValueHeads: number;
|
|
4306
|
+
headDim: number;
|
|
4307
|
+
rmsNormEps: number;
|
|
4308
|
+
vocabSize: number;
|
|
4309
|
+
maxPositionEmbeddings: number;
|
|
4310
|
+
ropeTheta: number;
|
|
4311
|
+
useQkNorm: boolean;
|
|
4312
|
+
tieWordEmbeddings: boolean;
|
|
3040
4313
|
}
|
|
3041
4314
|
|
|
3042
4315
|
/** Result of text recognition. */
|
|
@@ -3047,6 +4320,14 @@ export interface RecResult {
|
|
|
3047
4320
|
score: number;
|
|
3048
4321
|
}
|
|
3049
4322
|
|
|
4323
|
+
/**
|
|
4324
|
+
* Reset MLX's peak-memory counter to the current active level.
|
|
4325
|
+
* Useful for measuring per-request peak memory in a long-running
|
|
4326
|
+
* process — call before a request, sample
|
|
4327
|
+
* `getMemorySnapshot().peakBytes` after.
|
|
4328
|
+
*/
|
|
4329
|
+
export declare function resetPeakMemory(): void;
|
|
4330
|
+
|
|
3050
4331
|
/** Clear all collected profiling data and reset session timer. */
|
|
3051
4332
|
export declare function resetProfilingData(): void;
|
|
3052
4333
|
|
|
@@ -3136,22 +4417,6 @@ export interface SamplingConfig {
|
|
|
3136
4417
|
*/
|
|
3137
4418
|
export declare function saveToXlsx(text: string, filePath: string): void;
|
|
3138
4419
|
|
|
3139
|
-
/** Scheduler statistics (NAPI-compatible) */
|
|
3140
|
-
export interface SchedulerStatsNapi {
|
|
3141
|
-
/** Number of requests waiting to be scheduled */
|
|
3142
|
-
numWaiting: number;
|
|
3143
|
-
/** Number of sequences currently running */
|
|
3144
|
-
numRunning: number;
|
|
3145
|
-
/** Number of completed sequences */
|
|
3146
|
-
numCompleted: number;
|
|
3147
|
-
/** Number of sequences in prefill phase */
|
|
3148
|
-
numPrefill: number;
|
|
3149
|
-
/** Number of sequences in decode phase */
|
|
3150
|
-
numDecode: number;
|
|
3151
|
-
/** Total tokens across all running sequences */
|
|
3152
|
-
totalRunningTokens: number;
|
|
3153
|
-
}
|
|
3154
|
-
|
|
3155
4420
|
/** Enable or disable profiling globally. */
|
|
3156
4421
|
export declare function setProfilingEnabled(enabled: boolean): void;
|
|
3157
4422
|
|
|
@@ -3272,6 +4537,22 @@ export interface StepSummary {
|
|
|
3272
4537
|
lengthCount: number;
|
|
3273
4538
|
}
|
|
3274
4539
|
|
|
4540
|
+
/** A stored response record exposed to JavaScript. */
|
|
4541
|
+
export interface StoredResponseRecord {
|
|
4542
|
+
id: string;
|
|
4543
|
+
createdAt: number;
|
|
4544
|
+
model: string;
|
|
4545
|
+
status: string;
|
|
4546
|
+
instructions?: string;
|
|
4547
|
+
inputJson: string;
|
|
4548
|
+
outputJson: string;
|
|
4549
|
+
outputText: string;
|
|
4550
|
+
usageJson: string;
|
|
4551
|
+
previousResponseId?: string;
|
|
4552
|
+
configJson?: string;
|
|
4553
|
+
expiresAt?: number;
|
|
4554
|
+
}
|
|
4555
|
+
|
|
3275
4556
|
/** A table structure */
|
|
3276
4557
|
export interface Table {
|
|
3277
4558
|
rows: Array<TableRow>;
|
|
@@ -3418,6 +4699,35 @@ export interface TrainStepResultWithOutputs {
|
|
|
3418
4699
|
completionLengths: Array<number>;
|
|
3419
4700
|
}
|
|
3420
4701
|
|
|
4702
|
+
/**
|
|
4703
|
+
* Encoder-free vision configuration for the Gemma 4 unified multimodal model.
|
|
4704
|
+
*
|
|
4705
|
+
* Parsed from the `vision_config` sub-dict of a `gemma4_unified` checkpoint
|
|
4706
|
+
* (`model_type == "gemma4_unified_vision"`). This is a different shape from the
|
|
4707
|
+
* SigLIP-style [`super::vision_config::Gemma4VisionConfig`] used by the dense
|
|
4708
|
+
* gemma4 family: the unified vision path has no transformer encoder, only a
|
|
4709
|
+
* patch embedder (LayerNorm + Linear + 2D positional embedding) feeding the
|
|
4710
|
+
* multimodal projection.
|
|
4711
|
+
*/
|
|
4712
|
+
export interface UnifiedVisionConfig {
|
|
4713
|
+
/** Pixel side length of a single image patch (48 = patch_size 16 × pooling 3). */
|
|
4714
|
+
modelPatchSize: number;
|
|
4715
|
+
/** Embedding width inside the vision embedder (3840, == text hidden_size). */
|
|
4716
|
+
mmEmbedDim: number;
|
|
4717
|
+
/** Number of rows in the 2D positional-embedding table (1120). */
|
|
4718
|
+
mmPosembSize: number;
|
|
4719
|
+
/** Maximum soft tokens (patches) per image after resize (280). */
|
|
4720
|
+
numSoftTokens: number;
|
|
4721
|
+
/** Output projection width of `embed_vision` (3840, == text hidden_size). */
|
|
4722
|
+
outputProjDims: number;
|
|
4723
|
+
/** Pixel-grid patch size used by the resize math (16). */
|
|
4724
|
+
patchSize: number;
|
|
4725
|
+
/** Pooling kernel size used by the resize math (3). */
|
|
4726
|
+
poolingKernelSize: number;
|
|
4727
|
+
/** Epsilon for the embedder LayerNorms and the projection RMSNorm. */
|
|
4728
|
+
rmsNormEps: number;
|
|
4729
|
+
}
|
|
4730
|
+
|
|
3421
4731
|
/** Result from document unwarping. */
|
|
3422
4732
|
export interface UnwarpResult {
|
|
3423
4733
|
/** Unwarped image as PNG bytes */
|
|
@@ -3462,6 +4772,20 @@ export interface VlmChatConfig {
|
|
|
3462
4772
|
topP?: number;
|
|
3463
4773
|
/** Repetition penalty (default: 1.5) */
|
|
3464
4774
|
repetitionPenalty?: number;
|
|
4775
|
+
/**
|
|
4776
|
+
* Presence penalty (0.0 = disabled). Subtracts a flat penalty from logits of any
|
|
4777
|
+
* token that appeared at least once in context. Matches OpenAI API semantics.
|
|
4778
|
+
*/
|
|
4779
|
+
presencePenalty?: number;
|
|
4780
|
+
/** Number of recent tokens to consider for presence penalty (default: 20) */
|
|
4781
|
+
presenceContextSize?: number;
|
|
4782
|
+
/**
|
|
4783
|
+
* Frequency penalty (0.0 = disabled). Subtracts penalty * occurrence_count from
|
|
4784
|
+
* logits of each token in context. Matches OpenAI API semantics.
|
|
4785
|
+
*/
|
|
4786
|
+
frequencyPenalty?: number;
|
|
4787
|
+
/** Number of recent tokens to consider for frequency penalty (default: 20) */
|
|
4788
|
+
frequencyContextSize?: number;
|
|
3465
4789
|
/** Whether to return log probabilities (default: false) */
|
|
3466
4790
|
returnLogprobs?: boolean;
|
|
3467
4791
|
}
|
|
@@ -3473,3 +4797,27 @@ export interface VlmChatMessage {
|
|
|
3473
4797
|
/** Text content of the message */
|
|
3474
4798
|
content: string;
|
|
3475
4799
|
}
|
|
4800
|
+
|
|
4801
|
+
export declare namespace __internal__ {
|
|
4802
|
+
/**
|
|
4803
|
+
* Drain the MLX allocator's free-pool.
|
|
4804
|
+
*
|
|
4805
|
+
* @internal
|
|
4806
|
+
*
|
|
4807
|
+
* This is a process-wide drain routed through MLX's default-stream
|
|
4808
|
+
* `mlx_synchronize()`, which does NOT wait on the custom generation
|
|
4809
|
+
* streams that the per-model threads run on. Calling this from user
|
|
4810
|
+
* code while a decode is in flight can race live Metal command buffers
|
|
4811
|
+
* and risk use-after-free. The only safe caller today is
|
|
4812
|
+
* `@mlx-node/server`'s idle sweeper, which only triggers after the
|
|
4813
|
+
* in-flight request counter has returned to zero.
|
|
4814
|
+
*
|
|
4815
|
+
* Exposed under the `__internal__` NAPI namespace — reachable as
|
|
4816
|
+
* `require('@mlx-node/core').__internal__.clearCache()` and NOT on
|
|
4817
|
+
* the root `require('@mlx-node/core')` object. The namespace prefix
|
|
4818
|
+
* is a deliberate speed-bump that forces any caller to acknowledge
|
|
4819
|
+
* this is a private drain with custom-stream caveats; the root
|
|
4820
|
+
* surface stays clean of the footgun.
|
|
4821
|
+
*/
|
|
4822
|
+
export function clearCache(): void;
|
|
4823
|
+
}
|