@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/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 { Qwen3Model, Qwen3Tokenizer } from '@mlx-node/core';
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 { _createChatStream } from './stream.js';
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';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC5D,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,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;AAGxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EACL,KAAK,WAAW,EAChB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,cAAc,GACf,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGtF,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9E,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
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 { Qwen3Model, Qwen3Tokenizer } from '@mlx-node/core';
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
- export { _createChatStream } from './stream.js';
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';
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,cAAc,CAAC"}
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,6 @@
1
+ import type { Lfm2Config } from '@mlx-node/core';
2
+ export declare const LFM2_CONFIGS: {
3
+ [key: string]: Lfm2Config;
4
+ };
5
+ export declare function getLfm2Config(name: string): Lfm2Config;
6
+ //# sourceMappingURL=lfm2-configs.d.ts.map
@@ -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 { TrainableModel } from '../interfaces.js';
7
- export type ModelType = 'qwen3' | 'qwen3_5' | 'qwen3_5_moe';
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 language model from disk, auto-detecting architecture from config.json.
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 loadModel(modelPath: string): Promise<TrainableModel>;
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,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;AAI5D;;GAEG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAa1E;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAa3E"}
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 { Qwen3Model } from '@mlx-node/core';
9
- import { Qwen35Model, Qwen35MoeModel } from '../stream.js';
10
- const SUPPORTED_MODEL_TYPES = new Set(['qwen3', 'qwen3_5', 'qwen3_5_moe']);
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 language model from disk, auto-detecting architecture from config.json.
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 modelType = config.model_type ?? 'qwen3';
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 implementation that wraps a native callback-based
20
- * chatStream into a `for await...of`-compatible stream.
22
+ * Shared AsyncGenerator adapter for callback-based native streaming methods.
21
23
  *
22
- * Cancellation is automatic via the generator's `finally` block.
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
- /** @internal Exported for testing only. */
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 `chatStream()`.
28
- *
29
- * @example
30
- * ```typescript
31
- * const model = await Qwen35Model.load('./models/qwen3.5-3b');
32
- * for await (const event of model.chatStream(messages)) {
33
- * if (!event.done) process.stdout.write(event.text);
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
- chatStream(messages: ChatMessage[], config?: ChatConfig | null): AsyncGenerator<ChatStreamEvent>;
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 with AsyncGenerator-based `chatStream()`.
43
- *
44
- * @example
45
- * ```typescript
46
- * const model = await Qwen35MoeModel.load('./models/qwen3.5-moe');
47
- * for await (const event of model.chatStream(messages)) {
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
- chatStream(messages: ChatMessage[], config?: ChatConfig | null): AsyncGenerator<ChatStreamEvent>;
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
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,cAAc,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC1G,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;AAQhE;;;;;GAKG;AACH,2CAA2C;AAC3C,wBAAuB,iBAAiB,CAEtC,YAAY,EAAE,CACZ,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,eAAe,KAAK,IAAI,KAC1D,OAAO,CAAC,gBAAgB,CAAC,EAC9B,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,EAAE,OAAO,GACd,cAAc,CAAC,eAAe,CAAC,CAoDjC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,WAAY,SAAQ,iBAAiB;WAC1B,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAO5D,UAAU,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,cAAc,CAAC,eAAe,CAAC;CAGxG;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,oBAAoB;WAChC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAO/D,UAAU,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,cAAc,CAAC,eAAe,CAAC;CAGxG"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}