@mlx-node/lm 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -46
- package/dist/chat-session.d.ts +455 -0
- package/dist/chat-session.d.ts.map +1 -0
- package/dist/chat-session.js +920 -0
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -4
- package/dist/interfaces.d.ts +11 -1
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/models/lfm2-configs.d.ts +6 -0
- package/dist/models/lfm2-configs.d.ts.map +1 -0
- package/dist/models/lfm2-configs.js +48 -0
- package/dist/models/model-loader.d.ts +25 -4
- package/dist/models/model-loader.d.ts.map +1 -1
- package/dist/models/model-loader.js +62 -7
- package/dist/stream.d.ts +154 -26
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +346 -37
- package/dist/tools/index.d.ts +38 -11
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +38 -11
- package/dist/tools/types.d.ts +5 -25
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +5 -30
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -12,9 +12,17 @@
|
|
|
12
12
|
* const result = await model.generate([{ role: 'user', content: 'Hello!' }]);
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export {
|
|
15
|
+
export { Qwen3Tokenizer } from '@mlx-node/core';
|
|
16
|
+
export { Qwen3Model } from './stream.js';
|
|
17
|
+
export { Gemma4Model, Gemma4Model as Gemma4_Model } from './stream.js';
|
|
18
|
+
export type { Gemma4Config } from '@mlx-node/core';
|
|
19
|
+
export { HarrierModel } from '@mlx-node/core';
|
|
20
|
+
export type { HarrierConfig } from '@mlx-node/core';
|
|
16
21
|
export { Qwen35Model, Qwen35Model as Qwen3_5Model } from './stream.js';
|
|
17
22
|
export type { Qwen35Config, Qwen35GenerationConfig, Qwen35GenerationResult } from '@mlx-node/core';
|
|
23
|
+
export { Lfm2Model } from './stream.js';
|
|
24
|
+
export type { Lfm2Config } from '@mlx-node/core';
|
|
25
|
+
export { LFM2_CONFIGS, getLfm2Config } from './models/lfm2-configs.js';
|
|
18
26
|
export { Qwen35MoeModel, Qwen35MoeModel as Qwen3_5MoeModel } from './stream.js';
|
|
19
27
|
export type { Qwen35MoeConfig, Qwen35MoeGenerationConfig, Qwen35MoeGenerationResult } from '@mlx-node/core';
|
|
20
28
|
export type { DType } from '@mlx-node/core';
|
|
@@ -22,10 +30,12 @@ export type { SamplingConfig, BatchGenerationResult } from '@mlx-node/core';
|
|
|
22
30
|
export type { ChatConfig, ChatResult, ChatMessage, ToolCallResult, PerformanceMetrics } from '@mlx-node/core';
|
|
23
31
|
export type { ChatStreamDelta, ChatStreamFinal, ChatStreamEvent } from './stream.js';
|
|
24
32
|
export type { ChatStreamChunk, ChatStreamHandle } from '@mlx-node/core';
|
|
25
|
-
export {
|
|
33
|
+
export { _runChatStream } from './stream.js';
|
|
34
|
+
export { ChatSession } from './chat-session.js';
|
|
35
|
+
export type { ChatSessionOptions, SendOptions, SessionCapableModel } from './chat-session.js';
|
|
26
36
|
export { type Qwen3Config, QWEN3_CONFIGS, type GenerationResult, type GenerationConfig, getQwen3Config, } from './models/qwen3-configs.js';
|
|
27
|
-
export { loadModel, detectModelType, type ModelType } from './models/model-loader.js';
|
|
28
|
-
export type { TrainableModel } from './interfaces.js';
|
|
37
|
+
export { loadModel, loadSession, detectModelType, type ModelType } from './models/model-loader.js';
|
|
38
|
+
export type { TrainableModel, LoadableModel, EmbeddingModel } from './interfaces.js';
|
|
29
39
|
export { QWEN35_CONFIGS, getQwen35Config } from './models/qwen3_5-configs.js';
|
|
30
40
|
export * from './tools/index.js';
|
|
31
41
|
export { enableProfiling, disableProfiling } from './profiling.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,WAAW,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAGnG,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,cAAc,IAAI,eAAe,EAAE,MAAM,aAAa,CAAC;AAChF,YAAY,EAAE,eAAe,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAK5G,YAAY,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAG5E,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG9G,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACrF,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMxE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAM7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG9F,OAAO,EACL,KAAK,WAAW,EAChB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,cAAc,GACf,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGnG,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAErF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9E,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,17 +13,34 @@
|
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
15
|
// Model classes (for inference)
|
|
16
|
-
export {
|
|
16
|
+
export { Qwen3Tokenizer } from '@mlx-node/core';
|
|
17
|
+
export { Qwen3Model } from './stream.js';
|
|
18
|
+
// Gemma4 models
|
|
19
|
+
export { Gemma4Model, Gemma4Model as Gemma4_Model } from './stream.js';
|
|
20
|
+
// Embedding models
|
|
21
|
+
export { HarrierModel } from '@mlx-node/core';
|
|
17
22
|
export { Qwen35Model, Qwen35Model as Qwen3_5Model } from './stream.js';
|
|
23
|
+
// LFM2 models
|
|
24
|
+
export { Lfm2Model } from './stream.js';
|
|
25
|
+
export { LFM2_CONFIGS, getLfm2Config } from './models/lfm2-configs.js';
|
|
18
26
|
// MoE variant
|
|
19
27
|
export { Qwen35MoeModel, Qwen35MoeModel as Qwen3_5MoeModel } from './stream.js';
|
|
20
28
|
// Internal: exported for testing the callback-to-AsyncGenerator bridge
|
|
21
|
-
// Not part of the public API — may change without notice
|
|
22
|
-
|
|
29
|
+
// Not part of the public API — may change without notice.
|
|
30
|
+
// `_runChatStream` is the generic adapter used by every model wrapper
|
|
31
|
+
// (and the VLM package's QianfanOCR wrapper) to turn a callback-based
|
|
32
|
+
// native stream into an `AsyncGenerator<ChatStreamEvent>`.
|
|
33
|
+
export { _runChatStream } from './stream.js';
|
|
34
|
+
// Cross-model chat session wrapper (see chat-session.ts for design notes).
|
|
35
|
+
// `SessionCapableModel` is the structural interface matched by every
|
|
36
|
+
// generative model wrapper and used as the upper-bound for
|
|
37
|
+
// `ChatSession<M>`; exported so the VLM wrapper can pin a compile-time
|
|
38
|
+
// conformance assertion.
|
|
39
|
+
export { ChatSession } from './chat-session.js';
|
|
23
40
|
// Model utilities (TypeScript-only)
|
|
24
41
|
export { QWEN3_CONFIGS, getQwen3Config, } from './models/qwen3-configs.js';
|
|
25
42
|
// Model loading
|
|
26
|
-
export { loadModel, detectModelType } from './models/model-loader.js';
|
|
43
|
+
export { loadModel, loadSession, detectModelType } from './models/model-loader.js';
|
|
27
44
|
export { QWEN35_CONFIGS, getQwen35Config } from './models/qwen3_5-configs.js';
|
|
28
45
|
// Tool calling utilities
|
|
29
46
|
export * from './tools/index.js';
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import type { Qwen3Model, Qwen35Model, Qwen35MoeModel } from '@mlx-node/core';
|
|
1
|
+
import type { Gemma4Model, HarrierModel, Lfm2Model, Qwen3Model, Qwen35Model, Qwen35MoeModel, QianfanOCRModel } from '@mlx-node/core';
|
|
2
2
|
/**
|
|
3
3
|
* Union of all model classes that can be used with training engines.
|
|
4
4
|
* Uses the native (core) types so trainers can pass instances directly
|
|
5
5
|
* to Rust engine factory methods without type conflicts.
|
|
6
6
|
*/
|
|
7
7
|
export type TrainableModel = Qwen3Model | Qwen35Model | Qwen35MoeModel;
|
|
8
|
+
/**
|
|
9
|
+
* Union of all embedding model classes.
|
|
10
|
+
* These models encode text into fixed-size embedding vectors.
|
|
11
|
+
*/
|
|
12
|
+
export type EmbeddingModel = HarrierModel;
|
|
13
|
+
/**
|
|
14
|
+
* Union of all model classes that loadModel can return.
|
|
15
|
+
* Includes trainable models, inference-only models, and embedding models.
|
|
16
|
+
*/
|
|
17
|
+
export type LoadableModel = TrainableModel | QianfanOCRModel | EmbeddingModel | Gemma4Model | Lfm2Model;
|
|
8
18
|
//# sourceMappingURL=interfaces.d.ts.map
|
package/dist/interfaces.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,cAAc,EACd,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAExB;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,cAAc,CAAC;AAEvE;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC;AAE1C;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,eAAe,GAAG,cAAc,GAAG,WAAW,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lfm2-configs.d.ts","sourceRoot":"","sources":["../../src/models/lfm2-configs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,eAAO,MAAM,YAAY,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAA;CAwCrD,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAMtD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const LFM2_CONFIGS = {
|
|
2
|
+
'lfm2.5-1.2b-thinking': {
|
|
3
|
+
vocabSize: 65536,
|
|
4
|
+
hiddenSize: 2048,
|
|
5
|
+
numHiddenLayers: 16,
|
|
6
|
+
numAttentionHeads: 32,
|
|
7
|
+
numKeyValueHeads: 8,
|
|
8
|
+
maxPositionEmbeddings: 128000,
|
|
9
|
+
normEps: 1e-5,
|
|
10
|
+
convBias: false,
|
|
11
|
+
convLCache: 3,
|
|
12
|
+
blockDim: 2048,
|
|
13
|
+
blockFfDim: 12288,
|
|
14
|
+
blockMultipleOf: 256,
|
|
15
|
+
blockFfnDimMultiplier: 1.0,
|
|
16
|
+
blockAutoAdjustFfDim: true,
|
|
17
|
+
ropeTheta: 1000000.0,
|
|
18
|
+
layerTypes: [
|
|
19
|
+
'conv',
|
|
20
|
+
'conv',
|
|
21
|
+
'full_attention',
|
|
22
|
+
'conv',
|
|
23
|
+
'conv',
|
|
24
|
+
'full_attention',
|
|
25
|
+
'conv',
|
|
26
|
+
'conv',
|
|
27
|
+
'full_attention',
|
|
28
|
+
'conv',
|
|
29
|
+
'full_attention',
|
|
30
|
+
'conv',
|
|
31
|
+
'full_attention',
|
|
32
|
+
'conv',
|
|
33
|
+
'full_attention',
|
|
34
|
+
'conv',
|
|
35
|
+
],
|
|
36
|
+
tieEmbedding: true,
|
|
37
|
+
eosTokenId: 7,
|
|
38
|
+
bosTokenId: 1,
|
|
39
|
+
padTokenId: 0,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export function getLfm2Config(name) {
|
|
43
|
+
const config = LFM2_CONFIGS[name];
|
|
44
|
+
if (!config) {
|
|
45
|
+
throw new Error(`Unknown LFM2 config: ${name}. Available: ${Object.keys(LFM2_CONFIGS).join(', ')}`);
|
|
46
|
+
}
|
|
47
|
+
return config;
|
|
48
|
+
}
|
|
@@ -3,11 +3,32 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles loading pretrained weights from MLX format or converting from HuggingFace.
|
|
5
5
|
*/
|
|
6
|
-
import type
|
|
7
|
-
|
|
6
|
+
import { ChatSession, type SessionCapableModel } from '../chat-session.js';
|
|
7
|
+
import type { LoadableModel } from '../interfaces.js';
|
|
8
|
+
export type ModelType = 'qwen3' | 'qwen3_5' | 'qwen3_5_moe' | 'internvl_chat' | 'qianfan-ocr' | 'harrier' | 'gemma4' | 'lfm2';
|
|
8
9
|
/**
|
|
9
|
-
* Load a
|
|
10
|
+
* Load a model from disk, auto-detecting architecture from config.json.
|
|
11
|
+
*
|
|
12
|
+
* Supports both language models (Qwen3, Qwen3.5) and vision-language models
|
|
13
|
+
* (Qianfan-OCR / InternVL). Use `instanceof` to narrow the returned type.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadModel(modelPath: string): Promise<LoadableModel>;
|
|
16
|
+
/**
|
|
17
|
+
* Load a model and wrap it in a {@link ChatSession} for multi-turn chat.
|
|
18
|
+
*
|
|
19
|
+
* Convenience around `loadModel()` + `new ChatSession(model)` for the
|
|
20
|
+
* common case where a caller just wants an ergonomic session handle.
|
|
21
|
+
*
|
|
22
|
+
* Rejects models that cannot be driven by a `ChatSession`:
|
|
23
|
+
* - Embedding models (`HarrierModel`) have no chat surface.
|
|
24
|
+
* - The native `QianfanOCRModel` exposes callback-based streaming
|
|
25
|
+
* methods that do not structurally satisfy `SessionCapableModel`'s
|
|
26
|
+
* `AsyncGenerator` overloads. The VLM AsyncGenerator wrapper lives
|
|
27
|
+
* in `@mlx-node/vlm` (importing it here would create a circular
|
|
28
|
+
* package dependency), so callers who want a Qianfan-OCR session
|
|
29
|
+
* must import `QianfanOCRModel` from `@mlx-node/vlm` and construct
|
|
30
|
+
* `new ChatSession(model)` directly.
|
|
10
31
|
*/
|
|
11
|
-
export declare function
|
|
32
|
+
export declare function loadSession(modelPath: string): Promise<ChatSession<SessionCapableModel>>;
|
|
12
33
|
export declare function detectModelType(modelPath: string): Promise<ModelType>;
|
|
13
34
|
//# sourceMappingURL=model-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-loader.d.ts","sourceRoot":"","sources":["../../src/models/model-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"model-loader.d.ts","sourceRoot":"","sources":["../../src/models/model-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,kBAAkB,CAAC;AAGtE,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,SAAS,GACT,aAAa,GACb,eAAe,GACf,aAAa,GACb,SAAS,GACT,QAAQ,GACR,MAAM,CAAC;AAaX;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAoBzE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,CAW9F;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAyB3E"}
|
|
@@ -5,30 +5,85 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { readFile } from 'node:fs/promises';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import { HarrierModel, QianfanOCRModel } from '@mlx-node/core';
|
|
9
|
+
import { ChatSession } from '../chat-session.js';
|
|
10
|
+
import { Gemma4Model, Lfm2Model, Qwen3Model, Qwen35Model, Qwen35MoeModel } from '../stream.js';
|
|
11
|
+
const SUPPORTED_MODEL_TYPES = new Set([
|
|
12
|
+
'qwen3',
|
|
13
|
+
'qwen3_5',
|
|
14
|
+
'qwen3_5_moe',
|
|
15
|
+
'internvl_chat',
|
|
16
|
+
'qianfan-ocr',
|
|
17
|
+
'harrier',
|
|
18
|
+
'gemma4',
|
|
19
|
+
'lfm2',
|
|
20
|
+
]);
|
|
11
21
|
/**
|
|
12
|
-
* Load a
|
|
22
|
+
* Load a model from disk, auto-detecting architecture from config.json.
|
|
23
|
+
*
|
|
24
|
+
* Supports both language models (Qwen3, Qwen3.5) and vision-language models
|
|
25
|
+
* (Qianfan-OCR / InternVL). Use `instanceof` to narrow the returned type.
|
|
13
26
|
*/
|
|
14
27
|
export async function loadModel(modelPath) {
|
|
15
28
|
const modelType = await detectModelType(modelPath);
|
|
16
29
|
switch (modelType) {
|
|
17
30
|
case 'qwen3_5_moe':
|
|
18
|
-
// Cast: stream wrapper extends native — safe for instanceof and engine factories
|
|
19
31
|
return Qwen35MoeModel.load(modelPath);
|
|
20
32
|
case 'qwen3_5':
|
|
21
|
-
// load() auto-detects vision weights and loads encoder if present
|
|
22
33
|
return Qwen35Model.load(modelPath);
|
|
23
34
|
case 'qwen3':
|
|
24
35
|
return Qwen3Model.load(modelPath);
|
|
36
|
+
case 'harrier':
|
|
37
|
+
return HarrierModel.load(modelPath);
|
|
38
|
+
case 'internvl_chat':
|
|
39
|
+
case 'qianfan-ocr':
|
|
40
|
+
return QianfanOCRModel.load(modelPath);
|
|
41
|
+
case 'gemma4':
|
|
42
|
+
return Gemma4Model.load(modelPath);
|
|
43
|
+
case 'lfm2':
|
|
44
|
+
return Lfm2Model.load(modelPath);
|
|
25
45
|
}
|
|
26
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Load a model and wrap it in a {@link ChatSession} for multi-turn chat.
|
|
49
|
+
*
|
|
50
|
+
* Convenience around `loadModel()` + `new ChatSession(model)` for the
|
|
51
|
+
* common case where a caller just wants an ergonomic session handle.
|
|
52
|
+
*
|
|
53
|
+
* Rejects models that cannot be driven by a `ChatSession`:
|
|
54
|
+
* - Embedding models (`HarrierModel`) have no chat surface.
|
|
55
|
+
* - The native `QianfanOCRModel` exposes callback-based streaming
|
|
56
|
+
* methods that do not structurally satisfy `SessionCapableModel`'s
|
|
57
|
+
* `AsyncGenerator` overloads. The VLM AsyncGenerator wrapper lives
|
|
58
|
+
* in `@mlx-node/vlm` (importing it here would create a circular
|
|
59
|
+
* package dependency), so callers who want a Qianfan-OCR session
|
|
60
|
+
* must import `QianfanOCRModel` from `@mlx-node/vlm` and construct
|
|
61
|
+
* `new ChatSession(model)` directly.
|
|
62
|
+
*/
|
|
63
|
+
export async function loadSession(modelPath) {
|
|
64
|
+
const m = await loadModel(modelPath);
|
|
65
|
+
if (m instanceof HarrierModel) {
|
|
66
|
+
throw new Error('loadSession: embedding models (Harrier) cannot be wrapped in a ChatSession');
|
|
67
|
+
}
|
|
68
|
+
if (m instanceof QianfanOCRModel) {
|
|
69
|
+
throw new Error('loadSession: Qianfan-OCR / InternVL session support lives in @mlx-node/vlm. Import QianfanOCRModel from @mlx-node/vlm and construct ChatSession(model) directly.');
|
|
70
|
+
}
|
|
71
|
+
return new ChatSession(m);
|
|
72
|
+
}
|
|
27
73
|
export async function detectModelType(modelPath) {
|
|
28
74
|
try {
|
|
29
75
|
const raw = await readFile(join(modelPath, 'config.json'), 'utf-8');
|
|
30
76
|
const config = JSON.parse(raw);
|
|
31
|
-
const
|
|
77
|
+
const rawModelType = config.model_type ?? 'qwen3';
|
|
78
|
+
// Normalize model_type: gemma4_text → gemma4
|
|
79
|
+
let modelType = (rawModelType === 'gemma4_text' ? 'gemma4' : rawModelType);
|
|
80
|
+
// Detect embedding models: Qwen3 backbone with base architecture (no ForCausalLM)
|
|
81
|
+
if (modelType === 'qwen3') {
|
|
82
|
+
const architectures = config.architectures ?? [];
|
|
83
|
+
if (architectures.includes('Qwen3Model') && !architectures.includes('Qwen3ForCausalLM')) {
|
|
84
|
+
modelType = 'harrier';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
32
87
|
if (!SUPPORTED_MODEL_TYPES.has(modelType)) {
|
|
33
88
|
throw new Error(`Unsupported model_type "${modelType}" in ${modelPath}/config.json`);
|
|
34
89
|
}
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Qwen35Model as Qwen35ModelNative, Qwen35MoeModel as Qwen35MoeModelNative } from '@mlx-node/core';
|
|
1
|
+
import { Gemma4Model as Gemma4ModelNative, Lfm2Model as Lfm2ModelNative, Qwen3Model as Qwen3ModelNative, Qwen35Model as Qwen35ModelNative, Qwen35MoeModel as Qwen35MoeModelNative } from '@mlx-node/core';
|
|
2
2
|
import type { ChatConfig, ChatMessage, ChatStreamChunk, ChatStreamHandle, PerformanceMetrics, ToolCallResult } from '@mlx-node/core';
|
|
3
3
|
export interface ChatStreamDelta {
|
|
4
4
|
text: string;
|
|
5
5
|
done: false;
|
|
6
|
+
isReasoning?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export interface ChatStreamFinal {
|
|
8
9
|
text: string;
|
|
@@ -11,46 +12,173 @@ export interface ChatStreamFinal {
|
|
|
11
12
|
toolCalls: ToolCallResult[];
|
|
12
13
|
thinking: string | null;
|
|
13
14
|
numTokens: number;
|
|
15
|
+
promptTokens: number;
|
|
16
|
+
reasoningTokens: number;
|
|
14
17
|
rawText: string;
|
|
15
18
|
performance?: PerformanceMetrics;
|
|
16
19
|
}
|
|
17
20
|
export type ChatStreamEvent = ChatStreamDelta | ChatStreamFinal;
|
|
18
21
|
/**
|
|
19
|
-
* Shared AsyncGenerator
|
|
20
|
-
* chatStream into a `for await...of`-compatible stream.
|
|
22
|
+
* Shared AsyncGenerator adapter for callback-based native streaming methods.
|
|
21
23
|
*
|
|
22
|
-
*
|
|
24
|
+
* Takes a `startCall` closure that, given the JS-side callback, dispatches
|
|
25
|
+
* the underlying native stream (whatever method signature that is — the
|
|
26
|
+
* closure captures `messages` / `config` / `userMessage` etc) and resolves
|
|
27
|
+
* with a `ChatStreamHandle`. The generator pumps the resulting chunk queue,
|
|
28
|
+
* transforms each chunk into a `ChatStreamEvent`, and calls `handle.cancel()`
|
|
29
|
+
* in a `finally` block so early termination (user `break`, exception) still
|
|
30
|
+
* cleans up native state.
|
|
31
|
+
*
|
|
32
|
+
* ## Signal-driven fast-abort
|
|
33
|
+
*
|
|
34
|
+
* When an optional `AbortSignal` is supplied and fires, the adapter:
|
|
35
|
+
* 1. Calls `handle.cancel()` immediately so the native decode stops
|
|
36
|
+
* on the next safepoint rather than running to completion.
|
|
37
|
+
* 2. Wakes the pending `waitForItem()` await by pushing a synthetic
|
|
38
|
+
* "aborted" marker into the queue and calling `notify()`. Without
|
|
39
|
+
* this wake-up the generator would stay parked on the `await`
|
|
40
|
+
* until the next native chunk arrived, which on a fast-abort
|
|
41
|
+
* path (client disconnect before first token) never happens.
|
|
42
|
+
* 3. The generator sees the marker, breaks out of its loop, and the
|
|
43
|
+
* finally block runs `cancelOnce()` — which is a no-op because
|
|
44
|
+
* `triggerAbort` already flipped the `cancelled` flag. Some
|
|
45
|
+
* backends throw on double-cancel, so routing every cancel site
|
|
46
|
+
* through `cancelOnce` keeps abort behavior deterministic.
|
|
47
|
+
*
|
|
48
|
+
* The finally block is also the landing site for the consumer calling
|
|
49
|
+
* `.return()` on the outer generator — the existing `yield` cleanup
|
|
50
|
+
* covers that case. Signal-driven abort covers the window where the
|
|
51
|
+
* consumer cannot reach `.return()` because they are blocked waiting
|
|
52
|
+
* for the very `yield` that `waitForItem()` is gating.
|
|
53
|
+
*
|
|
54
|
+
* @internal Exported so the VLM wrapper (`@mlx-node/vlm`) can reuse the
|
|
55
|
+
* exact same bridge without duplicating the plumbing. Not part of the
|
|
56
|
+
* public API — may change without notice.
|
|
23
57
|
*/
|
|
24
|
-
|
|
25
|
-
export declare function _createChatStream(nativeMethod: (messages: ChatMessage[], config: any, callback: (err: Error | null, chunk: ChatStreamChunk) => void) => Promise<ChatStreamHandle>, self: unknown, messages: ChatMessage[], config: unknown): AsyncGenerator<ChatStreamEvent>;
|
|
58
|
+
export declare function _runChatStream(startCall: (callback: (err: Error | null, chunk: ChatStreamChunk) => void) => Promise<ChatStreamHandle>, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
26
59
|
/**
|
|
27
|
-
* Qwen3.5 dense model with AsyncGenerator-based
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
60
|
+
* Qwen3.5 dense model with AsyncGenerator-based session streaming.
|
|
61
|
+
*
|
|
62
|
+
* Streaming is driven through the session API — `chatStreamSessionStart`,
|
|
63
|
+
* `chatStreamSessionContinue`, and `chatStreamSessionContinueTool` below —
|
|
64
|
+
* which adapt the callback-based native methods to
|
|
65
|
+
* `AsyncGenerator<ChatStreamEvent>` so the wrapper structurally satisfies
|
|
66
|
+
* `SessionCapableModel` and can be passed to `ChatSession<Qwen35Model>`.
|
|
36
67
|
*/
|
|
37
68
|
export declare class Qwen35Model extends Qwen35ModelNative {
|
|
38
69
|
static load(modelPath: string): Promise<Qwen35Model>;
|
|
39
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Streaming variant of {@link Qwen35Model#chatSessionStart}.
|
|
72
|
+
*
|
|
73
|
+
* Resets the KV caches, runs the jinja chat template, prefills on
|
|
74
|
+
* top of the fresh caches, and streams the decoded reply token-by-
|
|
75
|
+
* token. Stops on `<|im_end|>` so the cached history ends on a
|
|
76
|
+
* clean ChatML boundary that subsequent `chatStreamSessionContinue`
|
|
77
|
+
* deltas can append to. Text-only.
|
|
78
|
+
*
|
|
79
|
+
* The optional `signal` parameter wires an AbortSignal into the
|
|
80
|
+
* `_runChatStream` adapter's fast-abort path. Callers that need
|
|
81
|
+
* client-disconnect-aware cancellation (e.g. HTTP endpoints) pass
|
|
82
|
+
* one here and the native decode winds down at the next safepoint.
|
|
83
|
+
*/
|
|
84
|
+
chatStreamSessionStart(messages: ChatMessage[], config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
85
|
+
/**
|
|
86
|
+
* Streaming variant of {@link Qwen35Model#chatSessionContinue}.
|
|
87
|
+
*
|
|
88
|
+
* Builds a raw ChatML delta on top of the live session caches,
|
|
89
|
+
* tokenizes it, prefills the delta, and streams the decoded reply.
|
|
90
|
+
* Requires a live session started via `chatSessionStart` or
|
|
91
|
+
* `chatStreamSessionStart`. Stops on `<|im_end|>`.
|
|
92
|
+
*
|
|
93
|
+
* `images` is the native opt-in guard parameter — callers that
|
|
94
|
+
* attach a new image set must restart the session via
|
|
95
|
+
* `chatStreamSessionStart` with the full history. The high-level
|
|
96
|
+
* `ChatSession` wrapper handles that routing; callers that drive
|
|
97
|
+
* the wrapper directly should pass `null` for text-only continues.
|
|
98
|
+
*/
|
|
99
|
+
chatStreamSessionContinue(userMessage: string, images: Uint8Array[] | null, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
100
|
+
/**
|
|
101
|
+
* Streaming variant of {@link Qwen35Model#chatSessionContinueTool}.
|
|
102
|
+
*
|
|
103
|
+
* Builds a ChatML `<tool_response>` delta on top of the live
|
|
104
|
+
* session caches and streams the decoded assistant reply. Requires
|
|
105
|
+
* a live session started via `chatSessionStart` /
|
|
106
|
+
* `chatStreamSessionStart`.
|
|
107
|
+
*/
|
|
108
|
+
chatStreamSessionContinueTool(toolCallId: string, content: string, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
40
109
|
}
|
|
41
110
|
/**
|
|
42
|
-
* Qwen3.5 MoE model
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* if (!event.done) process.stdout.write(event.text);
|
|
49
|
-
* }
|
|
50
|
-
* ```
|
|
111
|
+
* Qwen3.5 MoE model wrapper.
|
|
112
|
+
*
|
|
113
|
+
* Streaming is driven through the `ChatSession` API — overrides below
|
|
114
|
+
* adapt the callback-based native methods to
|
|
115
|
+
* `AsyncGenerator<ChatStreamEvent>` so the wrapper structurally
|
|
116
|
+
* satisfies `SessionCapableModel`.
|
|
51
117
|
*/
|
|
52
118
|
export declare class Qwen35MoeModel extends Qwen35MoeModelNative {
|
|
53
119
|
static load(modelPath: string): Promise<Qwen35MoeModel>;
|
|
54
|
-
|
|
120
|
+
/** Streaming variant of {@link Qwen35MoeModel#chatSessionStart}. */
|
|
121
|
+
chatStreamSessionStart(messages: ChatMessage[], config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
122
|
+
/** Streaming variant of {@link Qwen35MoeModel#chatSessionContinue}. */
|
|
123
|
+
chatStreamSessionContinue(userMessage: string, images: Uint8Array[] | null, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
124
|
+
/** Streaming variant of {@link Qwen35MoeModel#chatSessionContinueTool}. */
|
|
125
|
+
chatStreamSessionContinueTool(toolCallId: string, content: string, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* LFM2 model wrapper.
|
|
129
|
+
*
|
|
130
|
+
* Streaming is driven through the `ChatSession` API — overrides below
|
|
131
|
+
* adapt the callback-based native methods to
|
|
132
|
+
* `AsyncGenerator<ChatStreamEvent>` so the wrapper structurally
|
|
133
|
+
* satisfies `SessionCapableModel`. LFM2 is text-only; the native
|
|
134
|
+
* `images` guard rejects non-empty image sets with an
|
|
135
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` prefix.
|
|
136
|
+
*/
|
|
137
|
+
export declare class Lfm2Model extends Lfm2ModelNative {
|
|
138
|
+
static load(modelPath: string): Promise<Lfm2Model>;
|
|
139
|
+
/** Streaming variant of {@link Lfm2Model#chatSessionStart}. */
|
|
140
|
+
chatStreamSessionStart(messages: ChatMessage[], config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
141
|
+
/** Streaming variant of {@link Lfm2Model#chatSessionContinue}. */
|
|
142
|
+
chatStreamSessionContinue(userMessage: string, images: Uint8Array[] | null, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
143
|
+
/** Streaming variant of {@link Lfm2Model#chatSessionContinueTool}. */
|
|
144
|
+
chatStreamSessionContinueTool(toolCallId: string, content: string, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Gemma4 model wrapper.
|
|
148
|
+
*
|
|
149
|
+
* Streaming is driven through the `ChatSession` API — overrides below
|
|
150
|
+
* adapt the callback-based native methods to
|
|
151
|
+
* `AsyncGenerator<ChatStreamEvent>` so the wrapper structurally
|
|
152
|
+
* satisfies `SessionCapableModel`. Gemma4 is text-only in the
|
|
153
|
+
* current refactor scope; the native `images` guard rejects non-empty
|
|
154
|
+
* image sets with an `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` prefix.
|
|
155
|
+
*/
|
|
156
|
+
export declare class Gemma4Model extends Gemma4ModelNative {
|
|
157
|
+
static load(modelPath: string): Promise<Gemma4Model>;
|
|
158
|
+
/** Streaming variant of {@link Gemma4Model#chatSessionStart}. */
|
|
159
|
+
chatStreamSessionStart(messages: ChatMessage[], config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
160
|
+
/** Streaming variant of {@link Gemma4Model#chatSessionContinue}. */
|
|
161
|
+
chatStreamSessionContinue(userMessage: string, images: Uint8Array[] | null, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
162
|
+
/** Streaming variant of {@link Gemma4Model#chatSessionContinueTool}. */
|
|
163
|
+
chatStreamSessionContinueTool(toolCallId: string, content: string, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Qwen3 (legacy) model wrapper.
|
|
167
|
+
*
|
|
168
|
+
* Streaming is driven through the `ChatSession` API — overrides below
|
|
169
|
+
* adapt the callback-based native methods to
|
|
170
|
+
* `AsyncGenerator<ChatStreamEvent>` so the wrapper structurally
|
|
171
|
+
* satisfies `SessionCapableModel`. Qwen3 legacy is text-only; the
|
|
172
|
+
* native `images` guard rejects non-empty image sets with an
|
|
173
|
+
* `IMAGE_CHANGE_REQUIRES_SESSION_RESTART:` prefix.
|
|
174
|
+
*/
|
|
175
|
+
export declare class Qwen3Model extends Qwen3ModelNative {
|
|
176
|
+
static load(modelPath: string): Promise<Qwen3Model>;
|
|
177
|
+
/** Streaming variant of {@link Qwen3Model#chatSessionStart}. */
|
|
178
|
+
chatStreamSessionStart(messages: ChatMessage[], config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
179
|
+
/** Streaming variant of {@link Qwen3Model#chatSessionContinue}. */
|
|
180
|
+
chatStreamSessionContinue(userMessage: string, images: Uint8Array[] | null, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
181
|
+
/** Streaming variant of {@link Qwen3Model#chatSessionContinueTool}. */
|
|
182
|
+
chatStreamSessionContinueTool(toolCallId: string, content: string, config?: ChatConfig | null, signal?: AbortSignal): AsyncGenerator<ChatStreamEvent>;
|
|
55
183
|
}
|
|
56
184
|
//# sourceMappingURL=stream.d.ts.map
|
package/dist/stream.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
|