@mlx-node/lm 0.0.8 → 0.0.10
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 +45 -27
- package/dist/chat-session.d.ts +37 -14
- package/dist/chat-session.d.ts.map +1 -1
- package/dist/chat-session.js +236 -79
- package/dist/models/model-loader.d.ts +2 -0
- package/dist/models/model-loader.d.ts.map +1 -1
- package/dist/models/paged-config-override.d.ts +13 -1
- package/dist/models/paged-config-override.d.ts.map +1 -1
- package/dist/models/paged-config-override.js +47 -10
- package/dist/stream.d.ts +43 -7
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +50 -20
- package/package.json +2 -2
|
@@ -112,6 +112,7 @@ declare const MODEL_FAMILY_REGISTRY: readonly [{
|
|
|
112
112
|
};
|
|
113
113
|
readonly load: (modelPath: string) => Promise<import("../stream.js").StreamingInstance<typeof NativeLfm2Model, {
|
|
114
114
|
readonly recordModelPath: true;
|
|
115
|
+
readonly replayAssistantRawText: true;
|
|
115
116
|
}>>;
|
|
116
117
|
readonly nativeModelClass: typeof NativeLfm2Model;
|
|
117
118
|
}, {
|
|
@@ -122,6 +123,7 @@ declare const MODEL_FAMILY_REGISTRY: readonly [{
|
|
|
122
123
|
};
|
|
123
124
|
readonly load: (modelPath: string) => Promise<import("../stream.js").StreamingInstance<typeof NativeLfm2Model, {
|
|
124
125
|
readonly recordModelPath: true;
|
|
126
|
+
readonly replayAssistantRawText: true;
|
|
125
127
|
}>>;
|
|
126
128
|
readonly nativeModelClass: typeof NativeLfm2Model;
|
|
127
129
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-loader.d.ts","sourceRoot":"","sources":["../../src/models/model-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,YAAY,EACZ,SAAS,IAAI,eAAe,EAC5B,eAAe,EACf,UAAU,IAAI,gBAAgB,EAC9B,WAAW,IAAI,iBAAiB,EAChC,cAAc,IAAI,oBAAoB,EACvC,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG3E,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAID,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC7C;AAED,UAAU,uBAAwB,SAAQ,qBAAqB;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAgCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,QAAA,MAAM,qBAAqB;wBAEZ,QAAQ;mBACb,UAAU;;;;;+BAKE,MAAM,YAAY,gBAAgB;;;;;;wBASzC,SAAS;mBACd,WAAW;;;;;+BAMC,MAAM;;;wBAIb,OAAO;mBACZ,WAAW;;iBACR,aAAa;;+BACJ,MAAM;;;;;;;wBAKb,SAAS;mBACd,WAAW;;iBACR,aAAa;;+BACJ,MAAM;;;;;wBAIb,aAAa;mBAClB,WAAW;;iBACR,aAAa;;+BACJ,MAAM;;;;;wBAIb,MAAM;mBACX,UAAU;;iBACP,aAAa;;+BACJ,MAAM
|
|
1
|
+
{"version":3,"file":"model-loader.d.ts","sourceRoot":"","sources":["../../src/models/model-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,YAAY,EACZ,SAAS,IAAI,eAAe,EAC5B,eAAe,EACf,UAAU,IAAI,gBAAgB,EAC9B,WAAW,IAAI,iBAAiB,EAChC,cAAc,IAAI,oBAAoB,EACvC,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG3E,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAID,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC7C;AAED,UAAU,uBAAwB,SAAQ,qBAAqB;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAgCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,QAAA,MAAM,qBAAqB;wBAEZ,QAAQ;mBACb,UAAU;;;;;+BAKE,MAAM,YAAY,gBAAgB;;;;;;wBASzC,SAAS;mBACd,WAAW;;;;;+BAMC,MAAM;;;wBAIb,OAAO;mBACZ,WAAW;;iBACR,aAAa;;+BACJ,MAAM;;;;;;;wBAKb,SAAS;mBACd,WAAW;;iBACR,aAAa;;+BACJ,MAAM;;;;;wBAIb,aAAa;mBAClB,WAAW;;iBACR,aAAa;;+BACJ,MAAM;;;;;wBAIb,MAAM;mBACX,UAAU;;iBACP,aAAa;;+BACJ,MAAM;;;;;;wBAIb,UAAU;mBACf,UAAU;;iBACP,aAAa;;+BACJ,MAAM;;;;;;wBAIb,eAAe;mBACpB,KAAK;;iBACF,aAAa;;+BACJ,MAAM;;;wBAIb,aAAa;mBAClB,KAAK;;iBACF,aAAa;;+BACJ,MAAM;;EAGyB,CAAC;AAEtD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;AAE5E,KAAK,qBAAqB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,KAAK,yBAAyB,GAAG,OAAO,CAAC,qBAAqB,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AAEhG;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAEpF;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC,GACtD,YAAY,CAAC,yBAAyB,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAsIhE;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAGrG;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,CAa3C;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAkB3E"}
|
|
@@ -48,8 +48,20 @@ export declare class PagedConfigOverrideManager {
|
|
|
48
48
|
* A caller-supplied canonical family takes precedence over the raw config
|
|
49
49
|
* type (for example, `gemma4` for a `gemma4_unified` checkpoint).
|
|
50
50
|
* Unmanaged, unreadable, or malformed checkpoints pass through unchanged.
|
|
51
|
+
*
|
|
52
|
+
* `persistPagedCache` is a tri-state cold-tier directive. `undefined` leaves
|
|
53
|
+
* the field untouched (families with no cold-tier opt-in). A boolean is
|
|
54
|
+
* AUTHORITATIVE: it writes `persist_paged_cache: <value>` into the cloned
|
|
55
|
+
* config, overriding whatever the source config.json carries (either alias),
|
|
56
|
+
* and forces a clone whenever the source's value disagrees so the directive
|
|
57
|
+
* actually reaches the loader. Callers gate the boolean to the families whose
|
|
58
|
+
* paged cold restore is sound — the allowlist in
|
|
59
|
+
* `packages/agent/src/cold-tier.ts`, mirrored by `COLD_RESTORE_FAMILIES` in
|
|
60
|
+
* `crates/mlx-core/src/cold_tier.rs`. It is a SET, not one family, and it is
|
|
61
|
+
* deliberately not repeated here: `MlxModelHost` calls this for every
|
|
62
|
+
* allowlisted family, and a second copy of the list would drift.
|
|
51
63
|
*/
|
|
52
|
-
resolve(modelPath: string, canonicalModelType?: string): Promise<string>;
|
|
64
|
+
resolve(modelPath: string, canonicalModelType?: string, persistPagedCache?: boolean): Promise<string>;
|
|
53
65
|
private resolveInternal;
|
|
54
66
|
/** Remove this manager's temporary root without affecting other managers. */
|
|
55
67
|
cleanup(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paged-config-override.d.ts","sourceRoot":"","sources":["../../src/models/paged-config-override.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,YAAI,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAElH,iEAAiE;AACjE,eAAO,MAAM,wBAAwB,YAAI,SAAS,EAAE,aAAa,CAAU,CAAC;AAO5E,MAAM,WAAW,iCAAiC;IAChD,qFAAqF;IACrF,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAU;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;IAChE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA8B;IAC7D,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,OAAO,GAAE,iCAAsC,EAI1D;IAED
|
|
1
|
+
{"version":3,"file":"paged-config-override.d.ts","sourceRoot":"","sources":["../../src/models/paged-config-override.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,YAAI,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAElH,iEAAiE;AACjE,eAAO,MAAM,wBAAwB,YAAI,SAAS,EAAE,aAAa,CAAU,CAAC;AAO5E,MAAM,WAAW,iCAAiC;IAChD,qFAAqF;IACrF,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;GAOG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAU;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;IAChE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA8B;IAC7D,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,OAAO,GAAE,iCAAsC,EAI1D;IAED;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY1G;YAEa,eAAe;IAuE7B,6EAA6E;IAC7E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAKvB;YAEa,cAAc;YAad,cAAc;IAsD5B,OAAO,CAAC,OAAO;CAIhB"}
|
|
@@ -47,12 +47,24 @@ export class PagedConfigOverrideManager {
|
|
|
47
47
|
* A caller-supplied canonical family takes precedence over the raw config
|
|
48
48
|
* type (for example, `gemma4` for a `gemma4_unified` checkpoint).
|
|
49
49
|
* Unmanaged, unreadable, or malformed checkpoints pass through unchanged.
|
|
50
|
+
*
|
|
51
|
+
* `persistPagedCache` is a tri-state cold-tier directive. `undefined` leaves
|
|
52
|
+
* the field untouched (families with no cold-tier opt-in). A boolean is
|
|
53
|
+
* AUTHORITATIVE: it writes `persist_paged_cache: <value>` into the cloned
|
|
54
|
+
* config, overriding whatever the source config.json carries (either alias),
|
|
55
|
+
* and forces a clone whenever the source's value disagrees so the directive
|
|
56
|
+
* actually reaches the loader. Callers gate the boolean to the families whose
|
|
57
|
+
* paged cold restore is sound — the allowlist in
|
|
58
|
+
* `packages/agent/src/cold-tier.ts`, mirrored by `COLD_RESTORE_FAMILIES` in
|
|
59
|
+
* `crates/mlx-core/src/cold_tier.rs`. It is a SET, not one family, and it is
|
|
60
|
+
* deliberately not repeated here: `MlxModelHost` calls this for every
|
|
61
|
+
* allowlisted family, and a second copy of the list would drift.
|
|
50
62
|
*/
|
|
51
|
-
async resolve(modelPath, canonicalModelType) {
|
|
63
|
+
async resolve(modelPath, canonicalModelType, persistPagedCache) {
|
|
52
64
|
if (this.disposed) {
|
|
53
65
|
throw new Error('PagedConfigOverrideManager: resolve() called after cleanup()');
|
|
54
66
|
}
|
|
55
|
-
const operation = this.resolveInternal(modelPath, canonicalModelType);
|
|
67
|
+
const operation = this.resolveInternal(modelPath, canonicalModelType, persistPagedCache);
|
|
56
68
|
this.activeResolves.add(operation);
|
|
57
69
|
try {
|
|
58
70
|
return await operation;
|
|
@@ -61,7 +73,7 @@ export class PagedConfigOverrideManager {
|
|
|
61
73
|
this.activeResolves.delete(operation);
|
|
62
74
|
}
|
|
63
75
|
}
|
|
64
|
-
async resolveInternal(modelPath, canonicalModelType) {
|
|
76
|
+
async resolveInternal(modelPath, canonicalModelType, persistPagedCache) {
|
|
65
77
|
const sourcePath = isAbsolute(modelPath) ? modelPath : resolve(modelPath);
|
|
66
78
|
let config;
|
|
67
79
|
try {
|
|
@@ -75,6 +87,15 @@ export class PagedConfigOverrideManager {
|
|
|
75
87
|
if (modelType === null || !this.modelTypes.has(modelType)) {
|
|
76
88
|
return modelPath;
|
|
77
89
|
}
|
|
90
|
+
// A boolean persist directive is authoritative: force a clone whenever the
|
|
91
|
+
// source config's EFFECTIVE value disagrees, so the directive actually reaches
|
|
92
|
+
// the loader (both `--no-persist-cache` off AND default-on). Mirror the native
|
|
93
|
+
// parser's snake-first precedence — `persist_paged_cache` wins when present,
|
|
94
|
+
// else the camelCase alias — so a config with snake=false AND camel=true does
|
|
95
|
+
// not read as `true` here (an OR) while native reads snake=false, silently
|
|
96
|
+
// dropping an authoritative `true` request.
|
|
97
|
+
const sourcePersist = typeof config.persist_paged_cache === 'boolean' ? config.persist_paged_cache : config.persistPagedCache === true;
|
|
98
|
+
const persistOverrideNeeded = persistPagedCache !== undefined && persistPagedCache !== sourcePersist;
|
|
78
99
|
// Gemma4's DSpark / assistant speculative executor currently owns flat KV
|
|
79
100
|
// caches. Preserve native draft discovery only for explicit callers; the
|
|
80
101
|
// default paged clone intentionally omits subdirectories, hiding `draft/`
|
|
@@ -89,20 +110,28 @@ export class PagedConfigOverrideManager {
|
|
|
89
110
|
const memorySatisfied = cacheFloorMb === undefined || (configuredMemoryMb ?? 0) >= cacheFloorMb;
|
|
90
111
|
// Even an already-paged Gemma config must be cloned when `draft/` exists:
|
|
91
112
|
// returning the source would expose the draft to native auto-discovery and
|
|
92
|
-
// trigger the flat-speculation/paged-cache conflict.
|
|
93
|
-
|
|
113
|
+
// trigger the flat-speculation/paged-cache conflict. An authoritative
|
|
114
|
+
// persist directive that disagrees with the source likewise blocks the
|
|
115
|
+
// pass-through so the resolved value reaches the loader.
|
|
116
|
+
if (pagedEnabled && memorySatisfied && !hasEmbeddedGemmaDraft && !persistOverrideNeeded) {
|
|
94
117
|
return modelPath;
|
|
95
118
|
}
|
|
96
|
-
|
|
119
|
+
// Memoize per (source, resolved family, persist directive): the same
|
|
120
|
+
// checkpoint resolved with a different persist tri-state must yield a distinct
|
|
121
|
+
// clone, not the first one cached under the bare path. `cleanup()` iterates
|
|
122
|
+
// every value, so multiple entries per path are all still disposed.
|
|
123
|
+
const persistKey = persistPagedCache === undefined ? 'u' : persistPagedCache ? 't' : 'f';
|
|
124
|
+
const cacheKey = `${sourcePath}\0${modelType}\0${persistKey}`;
|
|
125
|
+
const existing = this.overrides.get(cacheKey);
|
|
97
126
|
if (existing !== undefined)
|
|
98
127
|
return existing;
|
|
99
|
-
const pending = this.createOverride(sourcePath, config, cacheFloorMb, modelType);
|
|
100
|
-
this.overrides.set(
|
|
128
|
+
const pending = this.createOverride(sourcePath, config, cacheFloorMb, modelType, persistPagedCache);
|
|
129
|
+
this.overrides.set(cacheKey, pending);
|
|
101
130
|
try {
|
|
102
131
|
return await pending;
|
|
103
132
|
}
|
|
104
133
|
catch (error) {
|
|
105
|
-
this.overrides.delete(
|
|
134
|
+
this.overrides.delete(cacheKey);
|
|
106
135
|
throw error;
|
|
107
136
|
}
|
|
108
137
|
}
|
|
@@ -126,13 +155,21 @@ export class PagedConfigOverrideManager {
|
|
|
126
155
|
await rm(root, { recursive: true, force: true }).catch(() => undefined);
|
|
127
156
|
}
|
|
128
157
|
}
|
|
129
|
-
async createOverride(sourcePath, sourceConfig, cacheFloorMb, modelType) {
|
|
158
|
+
async createOverride(sourcePath, sourceConfig, cacheFloorMb, modelType, persistPagedCache) {
|
|
130
159
|
const root = await this.getRoot();
|
|
131
160
|
const overrideDir = await mkdtemp(join(root, 'model-'));
|
|
132
161
|
const config = {
|
|
133
162
|
...sourceConfig,
|
|
134
163
|
use_block_paged_cache: true,
|
|
135
164
|
};
|
|
165
|
+
if (persistPagedCache !== undefined) {
|
|
166
|
+
// Authoritative: the loader reads snake_case, so that spelling is the one
|
|
167
|
+
// that decides persistence. Reconcile a stray camelCase alias spread from
|
|
168
|
+
// the source config so it can never contradict the authoritative value.
|
|
169
|
+
config.persist_paged_cache = persistPagedCache;
|
|
170
|
+
if ('persistPagedCache' in config)
|
|
171
|
+
config.persistPagedCache = persistPagedCache;
|
|
172
|
+
}
|
|
136
173
|
if (cacheFloorMb !== undefined) {
|
|
137
174
|
config.paged_cache_memory_mb = Math.max(positiveNumber(sourceConfig.paged_cache_memory_mb) ?? 0, cacheFloorMb);
|
|
138
175
|
}
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Gemma4Model as Gemma4ModelNative, Lfm2Model as Lfm2ModelNative, Qwen3Model as Qwen3ModelNative, Qwen35Model as Qwen35ModelNative, Qwen35MoeModel as Qwen35MoeModelNative } from
|
|
2
|
-
import type { ChatStreamChunk, ChatStreamHandle, PerformanceMetrics, ToolCallResult } from
|
|
3
|
-
import type { SessionCapableModel } from
|
|
1
|
+
import { Gemma4Model as Gemma4ModelNative, Lfm2Model as Lfm2ModelNative, Qwen3Model as Qwen3ModelNative, Qwen35Model as Qwen35ModelNative, Qwen35MoeModel as Qwen35MoeModelNative } from "@mlx-node/core";
|
|
2
|
+
import type { ChatStreamChunk, ChatStreamHandle, PerformanceMetrics, ToolCallResult } from "@mlx-node/core";
|
|
3
|
+
import type { SessionCapableModel } from "./chat-session.js";
|
|
4
4
|
export interface ChatStreamDelta {
|
|
5
5
|
text: string;
|
|
6
6
|
done: false;
|
|
@@ -12,10 +12,23 @@ export interface ChatStreamFinal {
|
|
|
12
12
|
finishReason: string;
|
|
13
13
|
toolCalls: ToolCallResult[];
|
|
14
14
|
thinking: string | null;
|
|
15
|
+
/** Effective `enable_thinking` value passed to the model chat template. */
|
|
16
|
+
thinkingEnabled: boolean;
|
|
15
17
|
numTokens: number;
|
|
16
18
|
promptTokens: number;
|
|
17
19
|
reasoningTokens: number;
|
|
18
20
|
rawText: string;
|
|
21
|
+
/**
|
|
22
|
+
* Native token-aware reasoning-redacted raw output. ChatSession uses this
|
|
23
|
+
* when it captures full reasoning internally for deterministic replay while
|
|
24
|
+
* keeping `includeReasoning: false` private to the caller.
|
|
25
|
+
*/
|
|
26
|
+
publicRawText?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Whether terminal `text` is the complete parsed assistant content.
|
|
29
|
+
* Gemma emits visible content exclusively as deltas and sets false.
|
|
30
|
+
*/
|
|
31
|
+
textAuthoritative?: boolean;
|
|
19
32
|
/**
|
|
20
33
|
* Number of prompt tokens served from the reused KV-cache prefix on
|
|
21
34
|
* this turn. Mirrors the `cachedTokens` field on the non-streaming
|
|
@@ -42,6 +55,15 @@ export interface ChatStreamFinal {
|
|
|
42
55
|
performance?: PerformanceMetrics;
|
|
43
56
|
}
|
|
44
57
|
export type ChatStreamEvent = ChatStreamDelta | ChatStreamFinal;
|
|
58
|
+
type TemplateContentOrder = "textThenMedia" | "imagesThenText";
|
|
59
|
+
interface TemplateContentPolicy {
|
|
60
|
+
order: TemplateContentOrder;
|
|
61
|
+
/**
|
|
62
|
+
* When sanitized text already contains this model-owned placeholder, keep
|
|
63
|
+
* the message structured but do not synthesize additional image parts.
|
|
64
|
+
*/
|
|
65
|
+
existingImagePlaceholder?: string;
|
|
66
|
+
}
|
|
45
67
|
/**
|
|
46
68
|
* Shared AsyncGenerator adapter for callback-based native streaming methods.
|
|
47
69
|
*
|
|
@@ -130,6 +152,18 @@ interface StreamingModelOptions {
|
|
|
130
152
|
* only the factory's path-backed replacement.
|
|
131
153
|
*/
|
|
132
154
|
applyTemplate?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Model-specific ordering for structured multimodal content parts. The
|
|
157
|
+
* tokenizer applies this policy after sanitization while the checkpoint
|
|
158
|
+
* Jinja template continues to own all role and wire-format tokens.
|
|
159
|
+
*/
|
|
160
|
+
templateContentPolicy?: TemplateContentPolicy;
|
|
161
|
+
/**
|
|
162
|
+
* Preserve the native raw assistant bytes in session history. LFM2's
|
|
163
|
+
* checkpoint template consumes reasoning inside `message.content` and does
|
|
164
|
+
* not read the structured `reasoning_content` field used by Qwen/Gemma.
|
|
165
|
+
*/
|
|
166
|
+
replayAssistantRawText?: boolean;
|
|
133
167
|
}
|
|
134
168
|
/**
|
|
135
169
|
* Shared base type produced by the factory: a `SessionCapableModel`
|
|
@@ -147,10 +181,10 @@ export type StreamingModel = SessionCapableModel;
|
|
|
147
181
|
*/
|
|
148
182
|
type ResolvedApplyTemplate<O extends StreamingModelOptions> = O extends {
|
|
149
183
|
applyTemplate: boolean;
|
|
150
|
-
} ? O[
|
|
184
|
+
} ? O["applyTemplate"] : O["recordModelPath"];
|
|
151
185
|
/** @internal Method names whose callback ABI is replaced by the generator wrapper. */
|
|
152
186
|
export type NativeStreamingMethod = keyof NativeStreamingInstance;
|
|
153
|
-
type StreamingReplacementMethod<O extends StreamingModelOptions> = NativeStreamingMethod | (ResolvedApplyTemplate<O> extends true ?
|
|
187
|
+
type StreamingReplacementMethod<O extends StreamingModelOptions> = NativeStreamingMethod | (ResolvedApplyTemplate<O> extends true ? "applyChatTemplate" : never);
|
|
154
188
|
/**
|
|
155
189
|
* Instance surface of a generated streaming wrapper. Only methods replaced at
|
|
156
190
|
* runtime are removed from the native instance: the three callback streaming
|
|
@@ -165,7 +199,7 @@ type StreamingReplacementMethod<O extends StreamingModelOptions> = NativeStreami
|
|
|
165
199
|
*
|
|
166
200
|
* @internal Concrete instance type returned by {@link makeStreamingModel}.
|
|
167
201
|
*/
|
|
168
|
-
export type StreamingInstance<C extends NativeStreamingCtor, O extends StreamingModelOptions> = Omit<InstanceType<C>, StreamingReplacementMethod<O>> & SessionCapableModel & (ResolvedApplyTemplate<O> extends true ? Required<Pick<SessionCapableModel,
|
|
202
|
+
export type StreamingInstance<C extends NativeStreamingCtor, O extends StreamingModelOptions> = Omit<InstanceType<C>, StreamingReplacementMethod<O>> & SessionCapableModel & (ResolvedApplyTemplate<O> extends true ? Required<Pick<SessionCapableModel, "applyChatTemplate">> : object);
|
|
169
203
|
/**
|
|
170
204
|
* Build the streaming-model subclass for a native chat model class.
|
|
171
205
|
*
|
|
@@ -185,7 +219,7 @@ export type StreamingInstance<C extends NativeStreamingCtor, O extends Streaming
|
|
|
185
219
|
*/
|
|
186
220
|
export declare function makeStreamingModel<C extends NativeStreamingCtor, const O extends StreamingModelOptions>(NativeClass: C, opts: O): {
|
|
187
221
|
new (...args: ConstructorParameters<C>): StreamingInstance<C, O>;
|
|
188
|
-
load(...args: Parameters<C[
|
|
222
|
+
load(...args: Parameters<C["load"]>): Promise<StreamingInstance<C, O>>;
|
|
189
223
|
};
|
|
190
224
|
declare const Qwen35Model_base: {
|
|
191
225
|
new (): StreamingInstance<typeof Qwen35ModelNative, {
|
|
@@ -219,9 +253,11 @@ export declare class Qwen35MoeModel extends Qwen35MoeModel_base {
|
|
|
219
253
|
declare const Lfm2Model_base: {
|
|
220
254
|
new (): StreamingInstance<typeof Lfm2ModelNative, {
|
|
221
255
|
readonly recordModelPath: true;
|
|
256
|
+
readonly replayAssistantRawText: true;
|
|
222
257
|
}>;
|
|
223
258
|
load(modelPath: string): Promise<StreamingInstance<typeof Lfm2ModelNative, {
|
|
224
259
|
readonly recordModelPath: true;
|
|
260
|
+
readonly replayAssistantRawText: true;
|
|
225
261
|
}>>;
|
|
226
262
|
};
|
|
227
263
|
/** LFM2 model (text-only) — see {@link Qwen35Model} for the wrapper shape. */
|
package/dist/stream.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,SAAS,IAAI,eAAe,EAE5B,UAAU,IAAI,gBAAgB,EAC9B,WAAW,IAAI,iBAAiB,EAChC,cAAc,IAAI,oBAAoB,EACvC,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAGV,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAElB,cAAc,EACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;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,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
|
package/dist/stream.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import { join } from
|
|
2
|
-
import { Gemma4Model as Gemma4ModelNative, Lfm2Model as Lfm2ModelNative, Qwen3Tokenizer, Qwen3Model as Qwen3ModelNative, Qwen35Model as Qwen35ModelNative, Qwen35MoeModel as Qwen35MoeModelNative, } from
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { Gemma4Model as Gemma4ModelNative, Lfm2Model as Lfm2ModelNative, Qwen3Tokenizer, Qwen3Model as Qwen3ModelNative, Qwen35Model as Qwen35ModelNative, Qwen35MoeModel as Qwen35MoeModelNative, } from "@mlx-node/core";
|
|
3
3
|
const modelPathsForTokenizers = new WeakMap();
|
|
4
4
|
const tokenizerPromises = new WeakMap();
|
|
5
5
|
function getNativeIsReasoning(chunk) {
|
|
6
|
-
return typeof chunk.isReasoning ===
|
|
6
|
+
return typeof chunk.isReasoning === "boolean" ? chunk.isReasoning : undefined;
|
|
7
7
|
}
|
|
8
8
|
function rememberModelPath(model, modelPath) {
|
|
9
9
|
modelPathsForTokenizers.set(model, modelPath);
|
|
10
10
|
}
|
|
11
|
-
async function applyChatTemplateFromModelPath(model, messages, addGenerationPrompt, tools, enableThinking) {
|
|
11
|
+
async function applyChatTemplateFromModelPath(model, messages, addGenerationPrompt, tools, enableThinking, contentPolicy) {
|
|
12
12
|
const modelPath = modelPathsForTokenizers.get(model);
|
|
13
13
|
if (modelPath == null) {
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error("applyChatTemplate unavailable: model path was not recorded when this model was loaded");
|
|
15
15
|
}
|
|
16
16
|
let tokenizerPromise = tokenizerPromises.get(model);
|
|
17
17
|
if (tokenizerPromise == null) {
|
|
18
|
-
tokenizerPromise = Qwen3Tokenizer.fromPretrained(join(modelPath,
|
|
18
|
+
tokenizerPromise = Qwen3Tokenizer.fromPretrained(join(modelPath, "tokenizer.json"));
|
|
19
19
|
tokenizerPromises.set(model, tokenizerPromise);
|
|
20
20
|
}
|
|
21
21
|
const tokenizer = await tokenizerPromise;
|
|
22
|
-
|
|
22
|
+
if (contentPolicy == null) {
|
|
23
|
+
return tokenizer.applyChatTemplate(messages, addGenerationPrompt, tools, enableThinking);
|
|
24
|
+
}
|
|
25
|
+
return tokenizer.applyChatTemplate(messages, addGenerationPrompt, tools, enableThinking, contentPolicy.order, contentPolicy.existingImagePlaceholder);
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
25
28
|
* Shared AsyncGenerator adapter for callback-based native streaming methods.
|
|
@@ -127,7 +130,7 @@ export async function* _runChatStream(startCall, signal) {
|
|
|
127
130
|
}
|
|
128
131
|
else {
|
|
129
132
|
onAbort = triggerAbort;
|
|
130
|
-
signal.addEventListener(
|
|
133
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
131
134
|
}
|
|
132
135
|
}
|
|
133
136
|
try {
|
|
@@ -149,6 +152,9 @@ export async function* _runChatStream(startCall, signal) {
|
|
|
149
152
|
throw item.error;
|
|
150
153
|
const chunk = item.chunk;
|
|
151
154
|
if (chunk.done) {
|
|
155
|
+
if (typeof chunk.thinkingEnabled !== "boolean") {
|
|
156
|
+
throw new Error("Native terminal chat stream chunk is missing thinkingEnabled");
|
|
157
|
+
}
|
|
152
158
|
// The native `ChatStreamChunk` carries `cachedTokens` on the
|
|
153
159
|
// terminal (`done == true`) chunk for every streaming entry
|
|
154
160
|
// point. Emit it on the final event verbatim — undefined means
|
|
@@ -164,15 +170,22 @@ export async function* _runChatStream(startCall, signal) {
|
|
|
164
170
|
finishReason: chunk.finishReason,
|
|
165
171
|
toolCalls: chunk.toolCalls ?? [],
|
|
166
172
|
thinking: chunk.thinking ?? null,
|
|
173
|
+
thinkingEnabled: chunk.thinkingEnabled,
|
|
167
174
|
numTokens: chunk.numTokens,
|
|
168
175
|
promptTokens: chunk.promptTokens ?? 0,
|
|
169
176
|
reasoningTokens: chunk.reasoningTokens ?? 0,
|
|
170
177
|
rawText: chunk.rawText,
|
|
171
178
|
performance: chunk.performance ?? undefined,
|
|
172
179
|
};
|
|
173
|
-
if (typeof chunkWithCached.cachedTokens ===
|
|
180
|
+
if (typeof chunkWithCached.cachedTokens === "number") {
|
|
174
181
|
finalEvent.cachedTokens = chunkWithCached.cachedTokens;
|
|
175
182
|
}
|
|
183
|
+
if (typeof chunkWithCached.publicRawText === "string") {
|
|
184
|
+
finalEvent.publicRawText = chunkWithCached.publicRawText;
|
|
185
|
+
}
|
|
186
|
+
if (typeof chunkWithCached.textAuthoritative === "boolean") {
|
|
187
|
+
finalEvent.textAuthoritative = chunkWithCached.textAuthoritative;
|
|
188
|
+
}
|
|
176
189
|
yield finalEvent;
|
|
177
190
|
return;
|
|
178
191
|
}
|
|
@@ -188,7 +201,7 @@ export async function* _runChatStream(startCall, signal) {
|
|
|
188
201
|
finally {
|
|
189
202
|
if (signal != null && onAbort != null) {
|
|
190
203
|
try {
|
|
191
|
-
signal.removeEventListener(
|
|
204
|
+
signal.removeEventListener("abort", onAbort);
|
|
192
205
|
}
|
|
193
206
|
catch {
|
|
194
207
|
// removeEventListener shouldn't throw, but stay defensive —
|
|
@@ -218,6 +231,8 @@ export async function* _runChatStream(startCall, signal) {
|
|
|
218
231
|
export function makeStreamingModel(NativeClass, opts) {
|
|
219
232
|
const recordPath = opts.recordModelPath;
|
|
220
233
|
const applyTemplate = opts.applyTemplate ?? recordPath;
|
|
234
|
+
const templateContentPolicy = opts.templateContentPolicy;
|
|
235
|
+
const replayAssistantRawText = opts.replayAssistantRawText ?? false;
|
|
221
236
|
// Capture the native callback-based methods before the subclass
|
|
222
237
|
// overrides below shadow them on the prototype.
|
|
223
238
|
const nativeStart = NativeClass.prototype.chatStreamSessionStart;
|
|
@@ -228,6 +243,12 @@ export function makeStreamingModel(NativeClass, opts) {
|
|
|
228
243
|
// unchanged — we extend the real native class.
|
|
229
244
|
const Base = NativeClass;
|
|
230
245
|
class StreamingModelImpl extends Base {
|
|
246
|
+
supportsReplayReasoningCapture() {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
replaysAssistantRawText() {
|
|
250
|
+
return replayAssistantRawText;
|
|
251
|
+
}
|
|
231
252
|
static async load(modelPath, ...rest) {
|
|
232
253
|
// Forward any trailing family-specific load options verbatim (e.g.
|
|
233
254
|
// Gemma4's `Gemma4LoadOptions` with `draftModelPath`); families whose
|
|
@@ -251,19 +272,19 @@ export function makeStreamingModel(NativeClass, opts) {
|
|
|
251
272
|
async *chatStreamSessionStart(messages, config, signal) {
|
|
252
273
|
yield* _runChatStream((callback) => nativeStart.call(this, messages, (config ?? null), callback), signal);
|
|
253
274
|
}
|
|
254
|
-
async *chatStreamSessionContinue(
|
|
255
|
-
yield* _runChatStream((callback) => nativeContinue.call(this,
|
|
275
|
+
async *chatStreamSessionContinue(messages, config, signal) {
|
|
276
|
+
yield* _runChatStream((callback) => nativeContinue.call(this, messages, (config ?? null), callback), signal);
|
|
256
277
|
}
|
|
257
|
-
async *chatStreamSessionContinueTool(
|
|
258
|
-
yield* _runChatStream((callback) => nativeContinueTool.call(this,
|
|
278
|
+
async *chatStreamSessionContinueTool(messages, config, signal) {
|
|
279
|
+
yield* _runChatStream((callback) => nativeContinueTool.call(this, messages, (config ?? null), callback), signal);
|
|
259
280
|
}
|
|
260
281
|
}
|
|
261
282
|
if (applyTemplate) {
|
|
262
|
-
Object.defineProperty(StreamingModelImpl.prototype,
|
|
283
|
+
Object.defineProperty(StreamingModelImpl.prototype, "applyChatTemplate", {
|
|
263
284
|
configurable: true,
|
|
264
285
|
writable: true,
|
|
265
286
|
value(messages, addGenerationPrompt, tools, enableThinking) {
|
|
266
|
-
return applyChatTemplateFromModelPath(this, messages, addGenerationPrompt, tools, enableThinking);
|
|
287
|
+
return applyChatTemplateFromModelPath(this, messages, addGenerationPrompt, tools, enableThinking, templateContentPolicy);
|
|
267
288
|
},
|
|
268
289
|
});
|
|
269
290
|
}
|
|
@@ -277,16 +298,25 @@ export function makeStreamingModel(NativeClass, opts) {
|
|
|
277
298
|
* `.name === 'Qwen35Model'` and a working `instanceof`. Records its
|
|
278
299
|
* model path so `applyChatTemplate` can serve a lazily built tokenizer.
|
|
279
300
|
*/
|
|
280
|
-
export class Qwen35Model extends makeStreamingModel(Qwen35ModelNative, {
|
|
301
|
+
export class Qwen35Model extends makeStreamingModel(Qwen35ModelNative, {
|
|
302
|
+
recordModelPath: true,
|
|
303
|
+
}) {
|
|
281
304
|
}
|
|
282
305
|
/** Qwen3.5 MoE model — see {@link Qwen35Model} for the wrapper shape. */
|
|
283
|
-
export class Qwen35MoeModel extends makeStreamingModel(Qwen35MoeModelNative, {
|
|
306
|
+
export class Qwen35MoeModel extends makeStreamingModel(Qwen35MoeModelNative, {
|
|
307
|
+
recordModelPath: true,
|
|
308
|
+
}) {
|
|
284
309
|
}
|
|
285
310
|
/** LFM2 model (text-only) — see {@link Qwen35Model} for the wrapper shape. */
|
|
286
|
-
export class Lfm2Model extends makeStreamingModel(Lfm2ModelNative, {
|
|
311
|
+
export class Lfm2Model extends makeStreamingModel(Lfm2ModelNative, {
|
|
312
|
+
recordModelPath: true,
|
|
313
|
+
replayAssistantRawText: true,
|
|
314
|
+
}) {
|
|
287
315
|
}
|
|
288
316
|
/** Gemma4 model (text-only) — see {@link Qwen35Model} for the wrapper shape. */
|
|
289
|
-
export class Gemma4Model extends makeStreamingModel(Gemma4ModelNative, {
|
|
317
|
+
export class Gemma4Model extends makeStreamingModel(Gemma4ModelNative, {
|
|
318
|
+
recordModelPath: true,
|
|
319
|
+
}) {
|
|
290
320
|
}
|
|
291
321
|
/**
|
|
292
322
|
* Qwen3 (first-gen, text-only) model.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mlx-node/lm",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"homepage": "https://github.com/mlx-node/mlx-node",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/mlx-node/mlx-node/issues"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"test": "vite test run"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@mlx-node/core": "0.0.
|
|
31
|
+
"@mlx-node/core": "0.0.10"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^26.0.0"
|