mlx-bun 0.0.10 → 0.0.12
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 +107 -32
- package/THIRD_PARTY_LICENSES.md +10 -0
- package/docs/archive/mlx-bun-lab-report.html +275 -0
- package/docs/archive/wwdc-mlx-bun.html +848 -0
- package/docs/design/audio-input-plan.md +356 -0
- package/docs/design/batching-perf-path.md +58 -35
- package/docs/design/batching-v2-plan.md +23 -9
- package/docs/design/bucketing-stage.md +2 -1
- package/docs/design/colibri-glm52-port.md +1479 -0
- package/docs/design/compat-cli-surface-design.md +4 -3
- package/docs/design/decode-speed-program.md +172 -0
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dspark-serving-program.md +371 -0
- package/docs/design/dspark-speculative-decoding.md +167 -5
- package/docs/design/faithful-l1-consolidation.md +310 -0
- package/docs/design/generic-model-support.md +8 -5
- package/docs/design/grammar-spec-batching-integration.md +301 -0
- package/docs/design/minicpm5-decode-megakernel.md +16 -11
- package/docs/design/mlx-lm-tool-parity-plan.md +11 -1
- package/docs/design/omlx-adoption-map.md +14 -6
- package/docs/design/orpo-training.md +34 -30
- package/docs/design/paged-kv-cache.md +214 -0
- package/docs/design/parallel-slots.md +82 -49
- package/docs/design/parity-tier-dag.md +43 -33
- package/docs/design/pre-colibri-stabilization.md +329 -0
- package/docs/design/repo-cleanup-plan.md +189 -0
- package/docs/design/runtime-isolation.md +19 -3
- package/docs/design/segmented-backward-training.md +3 -2
- package/docs/design/ssd-kv-cold-tier.md +130 -0
- package/docs/design/structured-output.md +484 -0
- package/docs/design/the-dreaming-master-plan.md +2 -3
- package/docs/design/turboquant-kv.md +235 -0
- package/docs/design/unified-engine-frontier-plan.md +774 -0
- package/docs/design/web-chat-beat-matrix.md +315 -0
- package/docs/design/web-chat-redesign.md +1112 -0
- package/docs/investigations/colibri-oracle-pin.md +1284 -0
- package/docs/investigations/dspark-handoff.md +182 -16
- package/docs/investigations/indexshare-performance-spike.md +357 -0
- package/docs/investigations/lab-build-journal.md +2 -2
- package/docs/investigations/openwiki-evaluation.md +249 -0
- package/docs/planning/IDEAS.md +14 -0
- package/docs/planning/PRODUCT_ROADMAP.md +2 -3
- package/docs/planning/chat-ui-vision-memory-first.md +199 -0
- package/docs/planning/chat-ui-vision.md +50 -0
- package/docs/planning/memory-docs-and-dag-plan.md +15 -6
- package/docs/planning/release-notes-v0.0.11.md +239 -0
- package/docs/planning/release-notes-v0.0.12.md +80 -0
- package/docs/reference/cli.md +63 -18
- package/docs/reference/distribution.md +37 -6
- package/docs/reference/embedding.md +40 -16
- package/docs/reference/features-matrix.md +99 -0
- package/docs/reference/library-api.md +69 -20
- package/docs/reference/memory.md +26 -6
- package/docs/reference/models.md +60 -3
- package/docs/reference/orpo-quickstart.md +3 -4
- package/docs/reference/server-api.md +717 -24
- package/docs/reference/server-config.md +265 -129
- package/docs/reference/training.md +24 -16
- package/package.json +5 -3
- package/src/anthropic.ts +67 -44
- package/src/audio/conformer.ts +647 -0
- package/src/audio/decode.ts +133 -0
- package/src/audio/features.ts +202 -0
- package/src/audio/transcode.ts +67 -0
- package/src/chat-template.ts +155 -10
- package/src/cli.ts +483 -113
- package/src/config.ts +116 -24
- package/src/diffusion/diffusion-generate.ts +14 -8
- package/src/download.ts +143 -12
- package/src/eval/README.md +7 -6
- package/src/eval/ifeval.ts +63 -120
- package/src/eval/kl.ts +59 -3
- package/src/eval/quality-db.ts +2 -2
- package/src/eval/runner.ts +17 -8
- package/src/eval/tasks/ifeval.ts +167 -31
- package/src/expert-io.ts +391 -0
- package/src/expert-offload.ts +15 -2
- package/src/expert-residency.ts +1134 -0
- package/src/expert-usage.ts +415 -0
- package/src/flags.ts +13 -0
- package/src/generate.ts +438 -35
- package/src/grammar.ts +585 -0
- package/src/hf-push.ts +1 -1
- package/src/hub-rest.ts +242 -0
- package/src/index.ts +14 -2
- package/src/jobs/runner.ts +37 -18
- package/src/kv-store.ts +586 -93
- package/src/lora.ts +85 -14
- package/src/md-modules.d.ts +42 -0
- package/src/media-fetch.ts +426 -0
- package/src/memory/rest.ts +245 -0
- package/src/memory/vault.ts +74 -0
- package/src/mlx/array.ts +149 -19
- package/src/mlx/autograd.ts +53 -16
- package/src/mlx/checkpoint.ts +46 -13
- package/src/mlx/custom-vjp.ts +83 -35
- package/src/mlx/ffi.ts +27 -3
- package/src/mlx/metal-kernel.ts +7 -4
- package/src/mlx/ops.ts +153 -23
- package/src/mlx/turboquant-ops.ts +831 -0
- package/src/mlx/turboquant-tables.ts +237 -0
- package/src/model/batched-mask.ts +62 -1
- package/src/model/batched-quant.ts +206 -0
- package/src/model/batched-rotating-quant.ts +346 -0
- package/src/model/batched-rotating.ts +46 -1
- package/src/model/compiled-decode.ts +4 -15
- package/src/model/factory.ts +103 -6
- package/src/model/gemma4-base.ts +395 -39
- package/src/model/gemma4.ts +122 -33
- package/src/model/generated/gemma4-12b.ts +9 -13
- package/src/model/generated/gemma4-26b.ts +10 -5
- package/src/model/generated/gemma4-e4b.ts +14 -9
- package/src/model/glm52-atlas.ts +511 -0
- package/src/model/glm52-cache.ts +706 -0
- package/src/model/glm52-config.ts +262 -0
- package/src/model/glm52-container.ts +305 -0
- package/src/model/glm52-coupling.ts +388 -0
- package/src/model/glm52-dsa.ts +602 -0
- package/src/model/glm52-expert-layout.ts +253 -0
- package/src/model/glm52-layout.ts +152 -0
- package/src/model/glm52-memory.ts +473 -0
- package/src/model/glm52-mla.ts +786 -0
- package/src/model/glm52-moe.ts +223 -0
- package/src/model/glm52-pilot.ts +537 -0
- package/src/model/glm52-reference.ts +445 -0
- package/src/model/glm52-residency.ts +557 -0
- package/src/model/glm52-resident-weights.ts +135 -0
- package/src/model/glm52-streamed-experts.ts +453 -0
- package/src/model/glm52-streamed-metal.ts +610 -0
- package/src/model/glm52-weights.ts +503 -0
- package/src/model/glm52.ts +1153 -0
- package/src/model/minicpm5.ts +58 -102
- package/src/model/paged-kv.ts +253 -0
- package/src/model/qwen3-delta.ts +76 -15
- package/src/model/qwen3-moe.ts +404 -0
- package/src/model/qwen3.ts +9 -8
- package/src/model/qwen3_5.ts +88 -23
- package/src/model/support.ts +19 -1
- package/src/model/universal/dense.ts +40 -5
- package/src/model/universal/rope.ts +36 -21
- package/src/native/expert_io.c +523 -0
- package/src/native-pack.ts +6 -4
- package/src/pi-web.ts +1299 -82
- package/src/preflight.ts +27 -8
- package/src/prompt-cache.ts +293 -33
- package/src/quantize/quantizer.ts +16 -1
- package/src/registry.ts +57 -2
- package/src/responses.ts +62 -49
- package/src/serve/batch-scheduler.ts +1050 -78
- package/src/serve/generation-gateway.ts +252 -24
- package/src/serve/isolate.ts +417 -0
- package/src/serve/lane-registry.ts +44 -0
- package/src/serve/session-search.ts +326 -0
- package/src/server.ts +1701 -175
- package/src/spec/assistant-source.ts +150 -0
- package/src/spec/deepspec-source.ts +143 -0
- package/src/spec/dflash-source.ts +124 -0
- package/src/spec/dspark/ab-stats.ts +136 -0
- package/src/spec/dspark/calibration.ts +112 -0
- package/src/spec/dspark/deepspec-module.ts +801 -0
- package/src/spec/dspark/generate-dflash.ts +72 -20
- package/src/spec/dspark/loader.ts +23 -0
- package/src/spec/dspark/module-dflash.ts +278 -36
- package/src/spec/dspark/quantize-drafter.ts +91 -0
- package/src/spec/generate.ts +59 -25
- package/src/spec/glm52-mtp-source.ts +392 -0
- package/src/spec/ngram-source.ts +132 -0
- package/src/spec/serve-loop.ts +617 -0
- package/src/spec/source.ts +118 -0
- package/src/spec/two-model.ts +171 -0
- package/src/ssd-cache.ts +111 -35
- package/src/tokenizer.ts +288 -2
- package/src/tool-approvals.ts +131 -0
- package/src/tool-call.ts +438 -22
- package/src/train/flash-cce.ts +2 -2
- package/src/train/job.ts +0 -12
- package/src/train/lora-params.ts +17 -6
- package/src/train/trainer.ts +60 -30
- package/src/vision/prompt.ts +217 -48
- package/src/web/app.html +1197 -1791
- package/src/web/app.js +5694 -0
- package/src/web/icon.svg +13 -0
- package/src/web/manifest.webmanifest +24 -0
- package/src/web/src/adapters-panel.ts +288 -0
- package/src/web/src/api.ts +57 -0
- package/src/web/src/assistant.ts +485 -0
- package/src/web/src/chat.ts +1050 -0
- package/src/web/src/composer.ts +959 -0
- package/src/web/src/dataset.ts +132 -0
- package/src/web/src/finetune.ts +267 -0
- package/src/web/src/hub.ts +428 -0
- package/src/web/src/main.ts +98 -0
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +572 -0
- package/src/web/src/model-picker.ts +159 -0
- package/src/web/src/palette.ts +346 -0
- package/src/web/src/protocol.ts +62 -0
- package/src/web/src/quantize.ts +167 -0
- package/src/web/src/rag.ts +274 -0
- package/src/web/src/sessions.ts +469 -0
- package/src/web/src/shell.ts +804 -0
- package/src/web/src/status.ts +300 -0
- package/src/web/src/ui-catalog.ts +92 -0
- package/src/web/sw.js +71 -0
- package/src/web/vendor/README.md +61 -0
- package/src/web/vendor/hljs-LICENSE +29 -0
- package/src/web/vendor/hljs-theme.css +59 -0
- package/src/web/vendor/hljs.js +26 -0
- package/src/web-tools.ts +54 -2
- package/src/weights.ts +82 -19
- package/src/model/fused-decode-kernel.ts +0 -312
- package/src/model/fused-geglu-kernel.ts +0 -198
- package/src/model/fused-mlp-kernel.ts +0 -169
- package/src/model/fused-swiglu-kernel.ts +0 -240
- package/src/model/steel-linear-kernel.ts +0 -96
- package/src/status-page.html +0 -497
|
@@ -22,7 +22,7 @@ Training is reachable several ways — all of them drive the **same** runner
|
|
|
22
22
|
|
|
23
23
|
| Path | How | Use when |
|
|
24
24
|
|---|---|---|
|
|
25
|
-
| **CLI** | `mlx-bun train <model> --data <dir> [options]` — foreground, full ORPO stack on by default; auto-detects e4b/Gemma
|
|
25
|
+
| **CLI** | `mlx-bun train <model> --data <dir> [options]` — foreground, full ORPO stack on by default; auto-detects e4b/Gemma to pick sensible `--seq`/adapter-path defaults; no env flags needed; `--save-every`, `--resume`, `--dry-run`, `--sft-scope full\|response`, `--grad-accum`, `--grad-clip`, `--seed`, `--val-size`; streams loss to the terminal. `mlx-bun help train` for all flags. Run long jobs detached: `nohup mlx-bun train … &` | **The default for CLI users** |
|
|
26
26
|
| **Web UI** | `mlx-bun serve`, open `/finetune` — pick model → dataset → hyperparameters → train; watch live train/val loss; merge/export the adapter | Interactive, in the browser |
|
|
27
27
|
| **HTTP API** | `POST /api/finetune/submit` (job id + SSE events); `POST /api/finetune/inspect-dataset` to probe a file; `POST /api/finetune/merge` to fold an adapter into base weights | Scripted / remote |
|
|
28
28
|
| **ORPO launcher** | [`scripts/train-orpo.ts`](../../scripts/train-orpo.ts) — the same stack driven by env vars (`MODEL=`, `DATA=`, `RANK=`, `RESUME=`, …). See [orpo-quickstart](./orpo-quickstart.md) | Env-var scripting |
|
|
@@ -167,7 +167,7 @@ are `DEFAULT_TRAIN_CONFIG` (trainer.ts:89).
|
|
|
167
167
|
| `target_modules` | string[] | `q,k,v,o,gate,up,down _proj` | Which linears get adapters |
|
|
168
168
|
| `num_layers` | int | `-1` | `-1` = all layers; `N` = last N only |
|
|
169
169
|
| `iters` | int >0 | `100` | Total training steps |
|
|
170
|
-
| `learning_rate` | float >0 | `2e-4` (sft) / `5e-5` (dpo) | AdamW LR |
|
|
170
|
+
| `learning_rate` | float >0 | `2e-4` (sft) / `1e-5` (orpo) / `5e-5` (dpo) | AdamW LR |
|
|
171
171
|
| `max_seq_length` | int >0 | `512` | Truncate/pad sequences to this |
|
|
172
172
|
| `batch_size` | int ≥1 | `1` | Rows per step (B=1 is the safe path; B>1 length-sorts + pads to 32) |
|
|
173
173
|
| `grad_accumulation_steps` | int ≥1 | `1` | Accumulate grads over N micro-steps |
|
|
@@ -177,10 +177,14 @@ are `DEFAULT_TRAIN_CONFIG` (trainer.ts:89).
|
|
|
177
177
|
| `weight_decay` | float ≥0 | `0.01` | AdamW weight decay (β = `[0.9, 0.999]`, fixed) |
|
|
178
178
|
| `lora_dropout` | float [0,1) | `0.0` | LoRA-input dropout (PEFT-style), training-only regularizer for small sets. Recompute-safe (mask keyed by step+layer, so segmented/checkpointed backward reproduces it) |
|
|
179
179
|
| `rs_lora` | bool | `false` | rsLoRA — scale the update by α/√rank instead of α, so `rank_scaling` changes capacity not step size. Recorded in the adapter config; inference applies the same per-layer scale |
|
|
180
|
-
| `lora_plus_ratio` | float ≥1 | `1.0` | LoRA+ — LR multiplier for the B leaves (A stays at base LR). >1 speeds the B-driven early learning (B is zero-init). 1 = off.
|
|
180
|
+
| `lora_plus_ratio` | float ≥1 | `1.0` | LoRA+ — LR multiplier for the B leaves (A stays at base LR). >1 speeds the B-driven early learning (B is zero-init). 1 = off. The same optimizer policy applies to SFT, DPO, and ORPO |
|
|
181
181
|
| `grad_checkpoint` | bool | `false` | Recompute layer activations in backward (memory↔compute; bit-identical) |
|
|
182
|
+
| `mlp_split` | bool | `false` | Gradient-checkpoint MLP splitting (Gemma4-only, requires `grad_checkpoint`) |
|
|
182
183
|
| `segment_size` | int | `0` (off) | `>0` enables segmented backward — layers per segment (see below) |
|
|
183
184
|
| `save_checkpoints` | bool | `false` | Save every eval-step checkpoint + write `metrics.json` |
|
|
185
|
+
| `grad_clip_norm` | float ≥0 | `1.0` | Gradient-norm clipping (on by default); `0` = off |
|
|
186
|
+
| `val_max_examples` | int >0 | `256` | Caps the validation-set size used per eval |
|
|
187
|
+
| `warm_start_adapter` | string | `""` (off) | Adapter dir to warm-start/resume LoRA weights from (the API field behind the CLI's `--resume`) |
|
|
184
188
|
| `dpo_beta` | float >0 | `0.1` | DPO strength (dpo only) |
|
|
185
189
|
| `dpo_warmup_iters` | int ≥0 | `0` | DPO LR warmup (dpo only) |
|
|
186
190
|
| `dpo_lr_schedule` | `constant` \| `cosine` | `cosine` | DPO LR schedule (dpo only) |
|
|
@@ -197,17 +201,14 @@ are `DEFAULT_TRAIN_CONFIG` (trainer.ts:89).
|
|
|
197
201
|
|
|
198
202
|
| Env var | Set for training | Default | Why |
|
|
199
203
|
|---|---|---|---|
|
|
200
|
-
| `MLX_BUN_FUSED_GELU` | **`0` (required for Gemma)** | on | The fused GeGLU is a **CustomKernel with no gradient (vjp)** ([`fused-geglu-kernel.ts`](../../src/model/fused-geglu-kernel.ts)); the Gemma forward uses it ([`gemma4.ts:277`](../../src/model/gemma4.ts)), so a Gemma (e4b/12B/26B) backward fails unless it's off. MiniCPM5 (Llama-arch SwiGLU) never hits it, so the `.ts` script's MiniCPM5 default doesn't need it. |
|
|
201
|
-
| `MLX_BUN_PERF_KERNEL` | **`0` for training** | on | The fused quantized-decode kernel likewise has no vjp. It only fires at decode L=1 (rare in the L>1 training forward), but the e4b recipe sets `0` to be safe. |
|
|
202
204
|
| `MLX_BUN_TRAIN_ATTN` | **leave unset** | unset → `ops.sdpa` | Default `ops.sdpa` **is** mlx's fused flash-attention kernel — the correct, working path. `flash` selects a *different* hand-rolled O(L)-memory kernel: its two port bugs (dK buffer-transpose, dQ divergent causal barrier) are fixed and FD-validated (`tests/flash-attention.test.ts`, T≤256), but it is ~30× slower and the historical e4b ≥2K crash has **not been re-validated at that scale** since the fix — leave unset unless memory-bound and re-verified. |
|
|
203
205
|
| `MLX_BUN_MEM_LOG` | `1` to profile | off | Print per-step peak/active/cache memory |
|
|
204
206
|
|
|
205
|
-
>
|
|
206
|
-
>
|
|
207
|
-
>
|
|
208
|
-
>
|
|
209
|
-
> them
|
|
210
|
-
> you train a Gemma model by hand, set `MLX_BUN_FUSED_GELU=0` yourself.
|
|
207
|
+
> Training needs **no flag sanitization**: the old requirement to export
|
|
208
|
+
> `MLX_BUN_FUSED_GELU=0` / `MLX_BUN_PERF_KERNEL=0` (the no-vjp custom
|
|
209
|
+
> kernels) is gone — those kernels and their env vars were deleted
|
|
210
|
+
> 2026-07-05 ([unified-engine-frontier-plan.md](../design/unified-engine-frontier-plan.md)).
|
|
211
|
+
> Exporting them in an old recipe is harmless but does nothing.
|
|
211
212
|
|
|
212
213
|
## What we actually run (the e4b recipe)
|
|
213
214
|
|
|
@@ -215,7 +216,7 @@ Everything above is the full surface (*what you can do*). In practice the
|
|
|
215
216
|
fine-tune we run is [`scripts/ft-e4b-v2.sh`](../../scripts/ft-e4b-v2.sh):
|
|
216
217
|
e4b (gemma-4-e4b-it-OptiQ-4bit, pinned snapshot) on the lucien `chunk-v2-500`
|
|
217
218
|
curated set (450 train convs) through the segmented-backward trainer. It wraps
|
|
218
|
-
`chunk-finetune.ts` with
|
|
219
|
+
`chunk-finetune.ts` with a two-step workflow:
|
|
219
220
|
|
|
220
221
|
```bash
|
|
221
222
|
scripts/ft-e4b-v2.sh probe # 2-iter memory/stability check (~1 min) — RUN FIRST
|
|
@@ -233,12 +234,10 @@ What the recipe pins (and why it differs from the bare defaults):
|
|
|
233
234
|
| `SEG` | `4` | **segmented backward**, 4 layers/segment — so 8K-ctx activations fit |
|
|
234
235
|
| `RANK` / `SCALE` / `LR` | `16` / `20` / `1e-5` | task-tuned |
|
|
235
236
|
| `ITERS` | `2` (probe) / `900` (train) | ~2 epochs over 450 examples |
|
|
236
|
-
| `MLX_BUN_PERF_KERNEL` / `MLX_BUN_FUSED_GELU` | `0` / `0` | **required** — the fused kernels have no vjp (see env table) |
|
|
237
237
|
| attention | default `ops.sdpa` | mlx's fused flash kernel; **not** `MLX_BUN_TRAIN_ATTN=flash` (~30× slower; e4b ≥2K unvalidated since the kernel fix) |
|
|
238
238
|
|
|
239
|
-
The
|
|
240
|
-
long-context activations fit)
|
|
241
|
-
has gradients). Always run `probe` before `train`.
|
|
239
|
+
The non-negotiable for e4b: **segmented backward** (`SEG>0`, so the
|
|
240
|
+
long-context activations fit). Always run `probe` before `train`.
|
|
242
241
|
|
|
243
242
|
## Methodology
|
|
244
243
|
|
|
@@ -296,6 +295,15 @@ A finished run writes a PEFT-compatible adapter directory:
|
|
|
296
295
|
- `optiq_lora_config.json` — mlx-bun/optiq adapter metadata (per-layer ranks)
|
|
297
296
|
- `adapter_config.json` — PEFT-compatible config
|
|
298
297
|
|
|
298
|
+
The save completes only after both config files are written, including
|
|
299
|
+
eval-step checkpoints, so a successful process exit always leaves an
|
|
300
|
+
immediately mountable directory. Serving accepts both mlx-lm tensor layout
|
|
301
|
+
(`[in, rank]` / `[rank, out]`) and standard PEFT layout
|
|
302
|
+
(`[rank, in]` / `[out, rank]`, including `base_model.model.*` names).
|
|
303
|
+
Standard PEFT `use_rslora` metadata is honored as
|
|
304
|
+
`lora_alpha / sqrt(rank)`, and saved rsLoRA adapters emit that metadata so
|
|
305
|
+
their training and serving scales agree.
|
|
306
|
+
|
|
299
307
|
When `save_checkpoints: true`, each eval step also writes
|
|
300
308
|
`checkpoints/step-<NNNNN>-val<loss>/` and a durable `metrics.json` (config,
|
|
301
309
|
wall seconds, peak GB, final/best train+val loss, full val trajectory).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mlx-bun",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Native MLX inference for Bun on Apple Silicon — local LLM server (OpenAI/Anthropic-compatible) and TypeScript library. No Python.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -55,13 +55,15 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@anthropic-ai/sdk": "^0.104.1",
|
|
57
57
|
"@types/bun": "^1.3.14",
|
|
58
|
+
"happy-dom": "^20.10.6",
|
|
58
59
|
"openai": "^6.42.0"
|
|
59
60
|
},
|
|
60
61
|
"dependencies": {
|
|
61
|
-
"@earendil-works/pi-
|
|
62
|
-
"@earendil-works/pi-
|
|
62
|
+
"@earendil-works/pi-ai": "0.80.3",
|
|
63
|
+
"@earendil-works/pi-coding-agent": "0.80.3",
|
|
63
64
|
"@huggingface/jinja": "^0.5.9",
|
|
64
65
|
"@huggingface/tokenizers": "^0.1.3",
|
|
66
|
+
"@mlc-ai/web-xgrammar": "^0.1.27",
|
|
65
67
|
"fast-png": "^8.0.0",
|
|
66
68
|
"typebox": "1.1.38"
|
|
67
69
|
}
|
package/src/anthropic.ts
CHANGED
|
@@ -150,6 +150,19 @@ export function anthropicToChatBody(body: AnthropicRequest): Record<string, unkn
|
|
|
150
150
|
content: flattenText(block.content),
|
|
151
151
|
});
|
|
152
152
|
break;
|
|
153
|
+
case "audio":
|
|
154
|
+
case "input_audio":
|
|
155
|
+
case "audio_url":
|
|
156
|
+
// The Anthropic Messages protocol has no audio input block type.
|
|
157
|
+
// Reject loudly (the server maps this throw to a 400
|
|
158
|
+
// invalid_request_error) instead of silently dropping the clip —
|
|
159
|
+
// the model answering as if no audio was sent is worse than an
|
|
160
|
+
// error. Audio is served on the OpenAI surface.
|
|
161
|
+
throw new Error(
|
|
162
|
+
`"${block.type}" content blocks are not part of the Anthropic ` +
|
|
163
|
+
`Messages protocol — send audio to the OpenAI endpoint ` +
|
|
164
|
+
`/v1/chat/completions as an input_audio content part`,
|
|
165
|
+
);
|
|
153
166
|
default:
|
|
154
167
|
if (block.text) textParts.push(block.text);
|
|
155
168
|
}
|
|
@@ -456,58 +469,68 @@ export function translateOpenAiSse(
|
|
|
456
469
|
const dec = new TextDecoder();
|
|
457
470
|
let buf = "";
|
|
458
471
|
let finalized = false;
|
|
472
|
+
let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;
|
|
473
|
+
let cancelled = false;
|
|
459
474
|
return new ReadableStream<Uint8Array>({
|
|
460
|
-
|
|
475
|
+
start(controller) {
|
|
461
476
|
const emit = (frames: string[]) => {
|
|
462
477
|
for (const f of frames) controller.enqueue(enc.encode(f));
|
|
463
478
|
};
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
if (
|
|
481
|
-
finalized
|
|
482
|
-
|
|
479
|
+
reader = upstream.getReader();
|
|
480
|
+
void (async () => {
|
|
481
|
+
try {
|
|
482
|
+
while (!cancelled) {
|
|
483
|
+
const { done, value } = await reader!.read();
|
|
484
|
+
if (done) break;
|
|
485
|
+
buf += dec.decode(value, { stream: true });
|
|
486
|
+
let sep: number;
|
|
487
|
+
while ((sep = buf.indexOf("\n\n")) !== -1) {
|
|
488
|
+
const frame = buf.slice(0, sep);
|
|
489
|
+
buf = buf.slice(sep + 2);
|
|
490
|
+
const data = frame
|
|
491
|
+
.split("\n")
|
|
492
|
+
.find((l) => l.startsWith("data: "))
|
|
493
|
+
?.slice(6);
|
|
494
|
+
if (data == null) continue;
|
|
495
|
+
if (data === "[DONE]" || data === '"[DONE]"') {
|
|
496
|
+
if (!finalized) {
|
|
497
|
+
finalized = true;
|
|
498
|
+
emit(translator.finalize());
|
|
499
|
+
}
|
|
500
|
+
continue;
|
|
483
501
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
502
|
+
const parsed = JSON.parse(data);
|
|
503
|
+
if (parsed?.error) {
|
|
504
|
+
emit([
|
|
505
|
+
sse("error", {
|
|
506
|
+
type: "error",
|
|
507
|
+
error: { type: "api_error", message: parsed.error.message ?? "generation failed" },
|
|
508
|
+
}),
|
|
509
|
+
]);
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
emit(translator.addChunk(parsed));
|
|
495
513
|
}
|
|
496
|
-
emit(translator.addChunk(parsed));
|
|
497
514
|
}
|
|
515
|
+
if (!cancelled && !finalized) emit(translator.finalize());
|
|
516
|
+
} catch (e) {
|
|
517
|
+
if (!cancelled)
|
|
518
|
+
emit([
|
|
519
|
+
sse("error", {
|
|
520
|
+
type: "error",
|
|
521
|
+
error: { type: "api_error", message: (e as Error).message },
|
|
522
|
+
}),
|
|
523
|
+
]);
|
|
524
|
+
} finally {
|
|
525
|
+
reader?.releaseLock();
|
|
526
|
+
reader = null;
|
|
527
|
+
if (!cancelled) controller.close();
|
|
498
528
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
error: { type: "api_error", message: (e as Error).message },
|
|
505
|
-
}),
|
|
506
|
-
]);
|
|
507
|
-
} finally {
|
|
508
|
-
reader.releaseLock();
|
|
509
|
-
controller.close();
|
|
510
|
-
}
|
|
529
|
+
})();
|
|
530
|
+
},
|
|
531
|
+
async cancel(reason) {
|
|
532
|
+
cancelled = true;
|
|
533
|
+
await reader?.cancel(reason);
|
|
511
534
|
},
|
|
512
535
|
});
|
|
513
536
|
}
|