mlx-bun 0.0.4

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.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +362 -0
  3. package/THIRD_PARTY_LICENSES.md +41 -0
  4. package/bin/mlx-bun.mjs +32 -0
  5. package/docs/curve-designer.html +303 -0
  6. package/docs/design/adapters-end-to-end.md +201 -0
  7. package/docs/design/compat-cli-surface-design.md +227 -0
  8. package/docs/design/docs-reorg-plan.md +152 -0
  9. package/docs/design/hlg-sampling.md +340 -0
  10. package/docs/design/memory-system.md +339 -0
  11. package/docs/design/optimization_plan.md +344 -0
  12. package/docs/design/parallel-slots.md +515 -0
  13. package/docs/design/runtime-isolation.md +247 -0
  14. package/docs/design/segmented-backward-training.md +508 -0
  15. package/docs/investigations/chunk-finetune-experiment.md +84 -0
  16. package/docs/investigations/curve-bisector-routing.md +123 -0
  17. package/docs/investigations/curve-runs/bisector-route.json +98 -0
  18. package/docs/investigations/curve-runs/bisector-trace.json +1393 -0
  19. package/docs/investigations/curve-runs/curve-terrain.json +1179 -0
  20. package/docs/investigations/curve-runs/curve-terrain.svg +42 -0
  21. package/docs/investigations/curve-terrain.html +105 -0
  22. package/docs/investigations/expert-offload-single-user-moe.md +292 -0
  23. package/docs/investigations/hlg-ab.html +34 -0
  24. package/docs/investigations/hlg-explorer.html +238 -0
  25. package/docs/investigations/hlg-figs/cliff.svg +1 -0
  26. package/docs/investigations/hlg-figs/cross.svg +1 -0
  27. package/docs/investigations/hlg-figs/edges.svg +1 -0
  28. package/docs/investigations/hlg-figs/k20-grids.svg +1 -0
  29. package/docs/investigations/hlg-figs/k20-peaks.svg +1 -0
  30. package/docs/investigations/hlg-figs/lw-curve.svg +1 -0
  31. package/docs/investigations/hlg-figs/terrain.svg +1 -0
  32. package/docs/investigations/hlg-report.html +262 -0
  33. package/docs/investigations/hlg-runs/hlg-ab.json +149 -0
  34. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +87 -0
  35. package/docs/investigations/hlg-runs/hlg-blind.json +107 -0
  36. package/docs/investigations/hlg-runs/hlg-cliff.json +197 -0
  37. package/docs/investigations/hlg-runs/hlg-cross.json +505 -0
  38. package/docs/investigations/hlg-runs/hlg-edge.json +388 -0
  39. package/docs/investigations/hlg-runs/hlg-eval1.json +25 -0
  40. package/docs/investigations/hlg-runs/hlg-frontier.json +86 -0
  41. package/docs/investigations/hlg-runs/hlg-grid.json +242 -0
  42. package/docs/investigations/hlg-runs/hlg-grid2.json +343 -0
  43. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +110 -0
  44. package/docs/investigations/hlg-runs/hlg-map.json +383 -0
  45. package/docs/investigations/hlg-runs/run0-original.log +159 -0
  46. package/docs/investigations/hlg-runs/runA-recommended.log +131 -0
  47. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +26 -0
  48. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +18 -0
  49. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +25 -0
  50. package/docs/investigations/hlg-runs/runAD-ab-samples.log +8 -0
  51. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +51 -0
  52. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +10 -0
  53. package/docs/investigations/hlg-runs/runAG-eval-config2.log +16 -0
  54. package/docs/investigations/hlg-runs/runB-gain-variants.log +192 -0
  55. package/docs/investigations/hlg-runs/runC-pivots.log +162 -0
  56. package/docs/investigations/hlg-runs/runD-oetf.log +132 -0
  57. package/docs/investigations/hlg-runs/runE-eotf.log +162 -0
  58. package/docs/investigations/hlg-runs/runF-shaper-working.log +86 -0
  59. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +101 -0
  60. package/docs/investigations/hlg-runs/runH-wsweep.log +176 -0
  61. package/docs/investigations/hlg-runs/runI-asweep.log +176 -0
  62. package/docs/investigations/hlg-runs/runJ-knobmap.log +49 -0
  63. package/docs/investigations/hlg-runs/runK-frontier.log +19 -0
  64. package/docs/investigations/hlg-runs/runL-widemap.log +65 -0
  65. package/docs/investigations/hlg-runs/runM-frontier-emb.log +15 -0
  66. package/docs/investigations/hlg-runs/runN-verify.log +116 -0
  67. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +15 -0
  68. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +15 -0
  69. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +15 -0
  70. package/docs/investigations/hlg-runs/runR-blind-transcript.log +79 -0
  71. package/docs/investigations/hlg-runs/runS-cross-coherence.log +33 -0
  72. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +33 -0
  73. package/docs/investigations/hlg-runs/runU-cross-12b.log +33 -0
  74. package/docs/investigations/hlg-runs/runV-lw-e4b.log +22 -0
  75. package/docs/investigations/hlg-runs/runW-lw-12b.log +22 -0
  76. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +22 -0
  77. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +26 -0
  78. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +26 -0
  79. package/docs/investigations/hlg-sampling-investigation.md +970 -0
  80. package/docs/investigations/lab-build-journal.md +157 -0
  81. package/docs/investigations/pi-builtin-investigation.md +308 -0
  82. package/docs/investigations/starter-model-port-handoff.md +323 -0
  83. package/docs/planning/IDEAS.md +26 -0
  84. package/docs/planning/PRODUCT_ROADMAP.md +426 -0
  85. package/docs/planning/ResearchTopics.md +119 -0
  86. package/docs/planning/chunk-task-roadmap.md +77 -0
  87. package/docs/planning/journal.md +155 -0
  88. package/docs/reference/distribution.md +121 -0
  89. package/docs/reference/embedding.md +168 -0
  90. package/docs/reference/library-api.md +153 -0
  91. package/docs/reference/server-api.md +224 -0
  92. package/docs/reference/server-config.md +243 -0
  93. package/docs/segmented-backward-handoff.md +148 -0
  94. package/package.json +68 -0
  95. package/src/anthropic.ts +491 -0
  96. package/src/chat-template.ts +186 -0
  97. package/src/cli.ts +1075 -0
  98. package/src/config.ts +229 -0
  99. package/src/curve-sampler.ts +122 -0
  100. package/src/dataset/generators.ts +1087 -0
  101. package/src/dataset/index.ts +12 -0
  102. package/src/dataset/job.ts +81 -0
  103. package/src/dataset/llm.ts +71 -0
  104. package/src/dataset/registry.ts +528 -0
  105. package/src/download.ts +283 -0
  106. package/src/eval/README.md +86 -0
  107. package/src/eval/kl-prompts.ts +29 -0
  108. package/src/eval/kl.ts +294 -0
  109. package/src/eval/quality-db.ts +92 -0
  110. package/src/eval/runner.ts +102 -0
  111. package/src/eval/score.ts +49 -0
  112. package/src/eval/tasks/bfcl.ts +500 -0
  113. package/src/eval/tasks/gsm8k.ts +85 -0
  114. package/src/eval/tasks/hashhop.ts +109 -0
  115. package/src/eval/tasks/humaneval.ts +252 -0
  116. package/src/eval/tasks/ifeval.ts +354 -0
  117. package/src/eval/tasks/mmlu.ts +145 -0
  118. package/src/evaldb.ts +199 -0
  119. package/src/expert-offload-build.ts +77 -0
  120. package/src/expert-offload.ts +61 -0
  121. package/src/expert-trace.ts +67 -0
  122. package/src/fit.ts +254 -0
  123. package/src/generate.ts +451 -0
  124. package/src/harness-pi.ts +177 -0
  125. package/src/hf-push.ts +628 -0
  126. package/src/index.ts +22 -0
  127. package/src/jobs/db.ts +139 -0
  128. package/src/jobs/index.ts +29 -0
  129. package/src/jobs/job-entry.ts +106 -0
  130. package/src/jobs/runner.ts +304 -0
  131. package/src/jobs/sse.ts +114 -0
  132. package/src/jobs/types.ts +58 -0
  133. package/src/kv-store.ts +185 -0
  134. package/src/lora.ts +314 -0
  135. package/src/md-modules.d.ts +7 -0
  136. package/src/mlx/array.ts +237 -0
  137. package/src/mlx/autograd.ts +267 -0
  138. package/src/mlx/checkpoint.ts +116 -0
  139. package/src/mlx/compile.ts +158 -0
  140. package/src/mlx/custom-vjp.ts +140 -0
  141. package/src/mlx/ffi.ts +433 -0
  142. package/src/mlx/metal-kernel.ts +130 -0
  143. package/src/mlx/ops.ts +707 -0
  144. package/src/mmap.ts +90 -0
  145. package/src/model/batched-mask.ts +204 -0
  146. package/src/model/batched-rotating.ts +300 -0
  147. package/src/model/compiled-decode.ts +681 -0
  148. package/src/model/factory.ts +27 -0
  149. package/src/model/fingerprint.ts +33 -0
  150. package/src/model/flash-attention.ts +674 -0
  151. package/src/model/fused-decode-kernel.ts +305 -0
  152. package/src/model/fused-geglu-kernel.ts +87 -0
  153. package/src/model/gemma4-base.ts +1616 -0
  154. package/src/model/gemma4.ts +1012 -0
  155. package/src/model/generated/gemma4-12b.ts +526 -0
  156. package/src/model/generated/gemma4-26b.ts +500 -0
  157. package/src/model/generated/gemma4-e4b.ts +757 -0
  158. package/src/model/generated/index.ts +18 -0
  159. package/src/model/minicpm5.ts +278 -0
  160. package/src/model/qwen3-delta.ts +224 -0
  161. package/src/model/qwen3_5.ts +429 -0
  162. package/src/model/support.ts +46 -0
  163. package/src/native-pack.ts +152 -0
  164. package/src/pi-provider.ts +95 -0
  165. package/src/pi-terminal.ts +264 -0
  166. package/src/pi-web.ts +924 -0
  167. package/src/preflight.ts +123 -0
  168. package/src/prompt-cache.ts +113 -0
  169. package/src/quantize/allocator.ts +627 -0
  170. package/src/quantize/calibration.ts +180 -0
  171. package/src/quantize/config-writer.ts +132 -0
  172. package/src/quantize/index.ts +57 -0
  173. package/src/quantize/job.ts +136 -0
  174. package/src/quantize/quantizer.ts +462 -0
  175. package/src/quantize/safetensors-writer.ts +171 -0
  176. package/src/quantize/sensitivity.ts +234 -0
  177. package/src/registry.ts +336 -0
  178. package/src/responses.ts +774 -0
  179. package/src/safetensors.ts +158 -0
  180. package/src/sampler.ts +517 -0
  181. package/src/serve/batch-scheduler.ts +362 -0
  182. package/src/serve/generation-gateway.ts +160 -0
  183. package/src/server.ts +1891 -0
  184. package/src/spec/drafter.ts +261 -0
  185. package/src/spec/generate.ts +221 -0
  186. package/src/status-page.html +497 -0
  187. package/src/tokenizer.ts +38 -0
  188. package/src/tool-call.ts +242 -0
  189. package/src/train/dataset.ts +461 -0
  190. package/src/train/export.ts +32 -0
  191. package/src/train/forward.ts +229 -0
  192. package/src/train/index.ts +43 -0
  193. package/src/train/job.ts +148 -0
  194. package/src/train/lora-params.ts +194 -0
  195. package/src/train/loss.ts +342 -0
  196. package/src/train/merge.ts +195 -0
  197. package/src/train/optimizer.ts +176 -0
  198. package/src/train/rank.ts +101 -0
  199. package/src/train/segmented.ts +520 -0
  200. package/src/train/trainer.ts +600 -0
  201. package/src/tui.ts +161 -0
  202. package/src/vision/embedder.ts +168 -0
  203. package/src/vision/preprocess.ts +247 -0
  204. package/src/vision/prompt.ts +158 -0
  205. package/src/vision/siglip.ts +599 -0
  206. package/src/web/app.html +2471 -0
  207. package/src/web/skills/web-research/SKILL.md +44 -0
  208. package/src/web/skills.ts +59 -0
  209. package/src/web-tools.ts +426 -0
  210. package/src/weights.ts +91 -0
@@ -0,0 +1,186 @@
1
+ // Chat template rendering via @huggingface/jinja (pure JS, purpose-built
2
+ // for HF chat templates). Decision recorded in PLAN.md Phase 1 findings:
3
+ // rendering the model's own chat_template.jinja beats a hand-port because
4
+ // it can't rot when the model updates its template.
5
+
6
+ import { Template } from "@huggingface/jinja";
7
+
8
+ export interface ToolCall {
9
+ id?: string;
10
+ type?: "function";
11
+ function: {
12
+ name: string;
13
+ /** Object form preferred; OpenAI's JSON-string form is normalized by
14
+ * the server before rendering. */
15
+ arguments: Record<string, unknown> | string;
16
+ };
17
+ }
18
+
19
+ export interface ChatMessage {
20
+ role: string;
21
+ content?: string | Array<Record<string, unknown>> | null;
22
+ tool_calls?: ToolCall[];
23
+ tool_call_id?: string;
24
+ name?: string;
25
+ reasoning?: string;
26
+ reasoning_content?: string;
27
+ }
28
+
29
+ /** OpenAI-style tool definition (function type). */
30
+ export interface ToolDefinition {
31
+ type: "function";
32
+ function: {
33
+ name: string;
34
+ description?: string;
35
+ parameters?: Record<string, unknown>;
36
+ };
37
+ }
38
+
39
+ export interface RenderOptions {
40
+ addGenerationPrompt?: boolean;
41
+ tools?: ToolDefinition[] | null;
42
+ enableThinking?: boolean;
43
+ }
44
+
45
+ /** JSON-schema type implied by a literal value. */
46
+ function jsonTypeOf(v: unknown): string {
47
+ if (typeof v === "number") return Number.isInteger(v) ? "integer" : "number";
48
+ if (typeof v === "boolean") return "boolean";
49
+ if (Array.isArray(v)) return "array";
50
+ if (v !== null && typeof v === "object") return "object";
51
+ return "string";
52
+ }
53
+
54
+ /** Infer a JSON-schema `type` for a node that lacks one (enum/const/anyOf/…). */
55
+ function inferSchemaType(node: Record<string, unknown>): string {
56
+ if (Array.isArray(node.enum) && node.enum.length > 0) return jsonTypeOf(node.enum[0]);
57
+ if ("const" in node) return jsonTypeOf(node.const);
58
+ if (node.properties || node.additionalProperties) return "object";
59
+ if (node.items !== undefined || node.prefixItems !== undefined) return "array";
60
+ for (const key of ["anyOf", "oneOf", "allOf"] as const) {
61
+ const subs = node[key];
62
+ if (Array.isArray(subs) && subs.length > 0) {
63
+ const types = subs
64
+ .map((s) => (s && typeof s === "object" ? (s as Record<string, unknown>).type : undefined))
65
+ .filter((t): t is string => typeof t === "string");
66
+ const first = types[0];
67
+ if (first !== undefined) return first;
68
+ }
69
+ }
70
+ return "string";
71
+ }
72
+
73
+ /**
74
+ * Recursively ensure every JSON-schema node carries a `type`.
75
+ *
76
+ * Why: HF chat templates (e.g. Gemma's tool-declaration block) do
77
+ * `value['type'] | upper`, which throws "Cannot apply filter upper to
78
+ * UndefinedValue" for schemas that describe a parameter via `anyOf`/`enum`/
79
+ * `const` without a top-level `type` (TypeBox unions/literals emit exactly
80
+ * this). We synthesize a sensible `type` so any tool renders, regardless of
81
+ * how its schema was authored. Returns a new object; never mutates input.
82
+ */
83
+ export function normalizeSchemaTypes(node: unknown): unknown {
84
+ if (Array.isArray(node)) return node.map(normalizeSchemaTypes);
85
+ if (!node || typeof node !== "object") return node;
86
+ const out: Record<string, unknown> = { ...(node as Record<string, unknown>) };
87
+ if (out.properties && typeof out.properties === "object") {
88
+ const props: Record<string, unknown> = {};
89
+ for (const [k, v] of Object.entries(out.properties as Record<string, unknown>)) props[k] = normalizeSchemaTypes(v);
90
+ out.properties = props;
91
+ }
92
+ if (out.items !== undefined) out.items = normalizeSchemaTypes(out.items);
93
+ if (out.prefixItems !== undefined) out.prefixItems = normalizeSchemaTypes(out.prefixItems);
94
+ if (out.additionalProperties && typeof out.additionalProperties === "object") {
95
+ out.additionalProperties = normalizeSchemaTypes(out.additionalProperties);
96
+ }
97
+ for (const key of ["anyOf", "oneOf", "allOf"] as const) {
98
+ if (Array.isArray(out[key])) out[key] = (out[key] as unknown[]).map(normalizeSchemaTypes);
99
+ }
100
+ if (typeof out.type !== "string") out.type = inferSchemaType(out);
101
+ return out;
102
+ }
103
+
104
+ /** Apply normalizeSchemaTypes to every tool's parameter schema. */
105
+ export function normalizeToolSchemas(tools: ToolDefinition[] | null): ToolDefinition[] | null {
106
+ if (!tools) return tools;
107
+ return tools.map((t) => ({
108
+ ...t,
109
+ function: {
110
+ ...t.function,
111
+ parameters: t.function.parameters
112
+ ? (normalizeSchemaTypes(t.function.parameters) as Record<string, unknown>)
113
+ : t.function.parameters,
114
+ },
115
+ }));
116
+ }
117
+
118
+ export class ChatTemplate {
119
+ readonly #template: Template;
120
+ readonly #bosToken: string | null;
121
+ readonly #eosToken: string | null;
122
+ /** Which reasoning format the template's `enable_thinking` channel uses, or
123
+ * null if the model has no switchable reasoning:
124
+ * - "think-tag": `<think>…</think>` text markers (Qwen3.5, MiniCPM5) — split
125
+ * from decoded text by ThinkingTagSplitter.
126
+ * - "gemma-channel": `<|channel>thought\n…<channel|>` (Gemma 4) — the markers
127
+ * are SPECIAL TOKENS stripped at decode, so reasoning is split at the token
128
+ * level in ToolAwareStream (gemma-sentinel mode), not from decoded text.
129
+ * Drives both the parser path and the reasoning capability advertised to Pi. */
130
+ readonly thinkingFormat: "think-tag" | "gemma-channel" | null;
131
+ /** True when the model has a switchable reasoning channel we can parse. */
132
+ readonly supportsThinking: boolean;
133
+
134
+ private constructor(source: string, bosToken: string | null, eosToken: string | null) {
135
+ this.#template = new Template(source);
136
+ this.#bosToken = bosToken;
137
+ this.#eosToken = eosToken;
138
+ const gatesThinking = source.includes("enable_thinking");
139
+ this.thinkingFormat = gatesThinking && source.includes("<think>")
140
+ ? "think-tag"
141
+ : gatesThinking && source.includes("<|channel>")
142
+ ? "gemma-channel"
143
+ : null;
144
+ this.supportsThinking = this.thinkingFormat !== null;
145
+ }
146
+
147
+ static async load(modelDir: string): Promise<ChatTemplate> {
148
+ const config = (await Bun.file(`${modelDir}/tokenizer_config.json`).json()) as Record<string, any>;
149
+ let source: string | undefined = config.chat_template;
150
+ if (!source) {
151
+ const jinjaFile = Bun.file(`${modelDir}/chat_template.jinja`);
152
+ if (await jinjaFile.exists()) source = await jinjaFile.text();
153
+ }
154
+ if (!source) throw new Error(`${modelDir}: no chat template found`);
155
+ // @huggingface/jinja lacks the `min`/`max` array filters that real
156
+ // Jinja2 has. MiniCPM5's template uses `[a, b]|min` in its assistant
157
+ // tool-call history branch, so without this rewrite every multi-turn
158
+ // tool conversation fails at render time ("Unknown ArrayValue filter").
159
+ source = source
160
+ .replace(
161
+ /\[\s*([\w.]+)\s*,\s*([\w.]+)\s*\]\s*\|\s*min\b/g,
162
+ "($1 if $1 < $2 else $2)",
163
+ )
164
+ .replace(
165
+ /\[\s*([\w.]+)\s*,\s*([\w.]+)\s*\]\s*\|\s*max\b/g,
166
+ "($1 if $1 > $2 else $2)",
167
+ );
168
+ const tokenText = (t: unknown): string | null =>
169
+ t == null ? null : typeof t === "string" ? t : (t as any).content;
170
+ return new ChatTemplate(source, tokenText(config.bos_token), tokenText(config.eos_token));
171
+ }
172
+
173
+ render(messages: ChatMessage[], options: RenderOptions = {}): string {
174
+ const { addGenerationPrompt = true, tools = null, enableThinking } = options;
175
+ return this.#template.render({
176
+ messages,
177
+ add_generation_prompt: addGenerationPrompt,
178
+ // Guarantee every tool param schema has a `type` so templates that do
179
+ // `value['type'] | upper` (Gemma) never see UndefinedValue.
180
+ tools: normalizeToolSchemas(tools),
181
+ ...(enableThinking !== undefined ? { enable_thinking: enableThinking } : {}),
182
+ bos_token: this.#bosToken,
183
+ eos_token: this.#eosToken,
184
+ });
185
+ }
186
+ }