mlx-bun 0.4.0 → 1.0.0
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 +1453 -88
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +10 -8
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +12 -10
- package/src/{serve → server}/chat-stage.ts +27 -22
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +42 -42
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +42 -83
- package/src/server/generated-token-history.ts +57 -0
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +8 -8
- package/src/{serve → server}/request-prep.ts +82 -68
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -94
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -1841
- package/docs/design/decode-speed-program.md +0 -2349
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -705
- package/docs/design/kv-cache.md +0 -824
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -1990
- package/docs/design/turboquant.md +0 -2212
- package/docs/design/unified-engine-frontier-plan.md +0 -1880
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -594
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/release-notes-v0.4.0.md +0 -45
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3613
- package/docs/reference/cli.md +0 -585
- package/docs/reference/distribution.md +0 -355
- package/docs/reference/environment.md +0 -398
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -674
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -334
- package/docs/reference/server-api.md +0 -1775
- package/docs/reference/server-config.md +0 -846
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/conformer.ts +0 -647
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/transcode.ts +0 -67
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -108
- package/src/backends/mlx/batch-group.ts +0 -1790
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -106
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -45
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -130
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -133
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/model-prompt.ts +0 -164
- package/src/backends/mlx/model-serving.ts +0 -79
- package/src/backends/mlx/prefill-cohort.ts +0 -89
- package/src/backends/mlx/prefill-rows.ts +0 -200
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -41
- package/src/backends/mlx/rollback.ts +0 -89
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -242
- package/src/backends/mlx/speculative-group.ts +0 -359
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -114
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -165
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3168
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -60
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -259
- package/src/contracts/prefix-cache.ts +0 -23
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -45
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -53
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -72
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -452
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1346
- package/src/grammar.ts +0 -591
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -39
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -257
- package/src/kv-store.ts +0 -1099
- package/src/lab/README.md +0 -18
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -83
- package/src/lab/paged-kv/paged-kv.ts +0 -270
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -49
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -388
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -512
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/ops.ts +0 -1021
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -93
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -55
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -189
- package/src/model/fingerprint.ts +0 -33
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2351
- package/src/model/gemma4.ts +0 -1315
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -67
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -443
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -252
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -819
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -102
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -83
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native-pack.ts +0 -162
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1932
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -460
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -81
- package/src/safetensors.ts +0 -158
- package/src/sampler.ts +0 -1011
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -496
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -43
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -147
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/server.ts +0 -1314
- package/src/spec/assistant-rows.ts +0 -92
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -317
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -204
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -219
- package/src/spec/qwen-mtp-source.ts +0 -383
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -585
- package/src/spec/source.ts +0 -215
- package/src/spec/two-model-rows.ts +0 -61
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -372
- package/src/ssd-durability.ts +0 -211
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -168
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -373
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -196
- package/src/vision/qwen3vl-tower.ts +0 -555
- package/src/vision/siglip.ts +0 -599
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2143
- package/src/web/app.js +0 -5703
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1057
- package/src/web/src/composer.ts +0 -959
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// The isolated host's route group: what the parent owns, and the way a request
|
|
2
|
+
// reaches a model worker. Each resident model runs in its own worker process;
|
|
3
|
+
// the model router (model-routes.ts) picks the model a request names and leases
|
|
4
|
+
// its worker, and `forwardToWorker` sends the request over the worker's Unix
|
|
5
|
+
// socket with the body streaming through (hop-by-hop headers stripped, a client
|
|
6
|
+
// abort aborting the proxied fetch so the worker sees the disconnect). The
|
|
7
|
+
// parent answers `/engine`, `/health` and `/stats` (with the workers'
|
|
8
|
+
// contribution) and `/v1/responses` through the history client. The workers' private admin paths never forward.
|
|
9
|
+
import type { WorkerMemory } from "../jobs/worker-memory";
|
|
10
|
+
import { describeExit, EngineUnavailableError, type WorkerSupervisor, type WorkerSupervisorState } from "../jobs/worker-supervisor";
|
|
11
|
+
import type { createResponsesClient } from "./responses-client";
|
|
12
|
+
|
|
13
|
+
const HOP_BY_HOP = new Set([
|
|
14
|
+
"connection", "keep-alive", "proxy-authenticate", "proxy-authorization",
|
|
15
|
+
"te", "trailer", "transfer-encoding", "upgrade",
|
|
16
|
+
]);
|
|
17
|
+
/** Never forwarded to a worker: its private socket surface (which only the
|
|
18
|
+
* parent itself calls; unmatched here, the listener answers 404) and the
|
|
19
|
+
* parent's own synthesis route (served by its earlier group). */
|
|
20
|
+
const PARENT_ONLY = new Set(["/admin/lease", "/admin/drain", "/admin/memory/complete", "/admin/events", "/admin/adapters", "/v1/memory/synthesize"]);
|
|
21
|
+
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
/** A copy without the hop-by-hop headers and the ones `Connection` names
|
|
24
|
+
* (also used by the library host, `cli/library-host.ts`). */
|
|
25
|
+
export const stripHopByHop = (headers: Headers) => {
|
|
26
|
+
const excluded = new Set(HOP_BY_HOP);
|
|
27
|
+
for (const name of (headers.get("connection") ?? "").split(",")) excluded.add(name.trim().toLowerCase());
|
|
28
|
+
const out = new Headers();
|
|
29
|
+
headers.forEach((value, key) => { if (!excluded.has(key.toLowerCase())) out.set(key, value); });
|
|
30
|
+
return out;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** The SSE error frame each protocol's own error path emits, so a client
|
|
34
|
+
* parser ends the stream with an error instead of a silent truncation. */
|
|
35
|
+
export function unavailableFrame(pathname: string, message: string): string {
|
|
36
|
+
if (pathname === "/v1/messages")
|
|
37
|
+
return `event: error\ndata: ${JSON.stringify({ type: "error", error: { type: "api_error", message } })}\n\n`;
|
|
38
|
+
if (pathname === "/v1/responses")
|
|
39
|
+
return `event: error\ndata: ${JSON.stringify({ type: "error", code: "engine_unavailable", message, param: null })}\n\n`;
|
|
40
|
+
return `data: ${JSON.stringify({ error: { message, type: "engine_unavailable" } })}\n\n`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Pass an event stream through unchanged; when the worker dies under it,
|
|
44
|
+
* end with the protocol's error frame instead of dropping the connection. */
|
|
45
|
+
function guardEventStream(body: ReadableStream<Uint8Array>, failure: () => string): ReadableStream<Uint8Array> {
|
|
46
|
+
const reader = body.getReader();
|
|
47
|
+
return new ReadableStream<Uint8Array>({
|
|
48
|
+
async pull(controller) {
|
|
49
|
+
let item: Awaited<ReturnType<typeof reader.read>>;
|
|
50
|
+
try { item = await reader.read(); }
|
|
51
|
+
catch { controller.enqueue(encoder.encode(failure())); controller.close(); return; }
|
|
52
|
+
if (item.done) controller.close(); else controller.enqueue(item.value);
|
|
53
|
+
},
|
|
54
|
+
cancel(reason) { return reader.cancel(reason).catch(() => {}); },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface WorkerEngine {
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly role: "primary" | "companion";
|
|
61
|
+
readonly supervisor: WorkerSupervisor;
|
|
62
|
+
/** The MLX memory the worker last reported; undefined before its first report and while it is down. */
|
|
63
|
+
measured?(): WorkerMemory | undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ProxyRoutesOptions {
|
|
67
|
+
/** The resident workers, and the id of the model requests that name none are answered by. */
|
|
68
|
+
workers(): readonly WorkerEngine[];
|
|
69
|
+
current(): string;
|
|
70
|
+
/** The model router: it leases the worker a request belongs to and forwards to it. */
|
|
71
|
+
models: { handle(request: Request): Promise<Response | null> };
|
|
72
|
+
responses: ReturnType<typeof createResponsesClient>;
|
|
73
|
+
/** The model the server started with. */
|
|
74
|
+
modelId: string;
|
|
75
|
+
startedAt: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** `memory` is the worker's own MLX reading (`active_bytes` and `cache_bytes` are what residency counts), null until it reports. */
|
|
79
|
+
export interface WorkerReport { id: string; role: "primary" | "companion"; pid: number | null; state: WorkerSupervisorState; restarts: number; socket: string;
|
|
80
|
+
memory: { active_bytes: number; cache_bytes: number; peak_bytes: number } | null }
|
|
81
|
+
|
|
82
|
+
/** The current model's worker fields, then every resident worker. `state` is `none` while no worker is resident. */
|
|
83
|
+
export interface EngineReport {
|
|
84
|
+
isolated: true;
|
|
85
|
+
state: WorkerSupervisorState | "none";
|
|
86
|
+
pid: number | null;
|
|
87
|
+
restarts: number | null;
|
|
88
|
+
socket: string | null;
|
|
89
|
+
model: string;
|
|
90
|
+
last_exit: { code: number | null; signal: string | null } | null;
|
|
91
|
+
response_store: { entries: number; bytes: number; max_bytes: number; ttl_ms: number };
|
|
92
|
+
workers: WorkerReport[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const unavailableMessage = (error: unknown) => {
|
|
96
|
+
if (error instanceof EngineUnavailableError) return `inference engine unavailable: ${error.message}${error.state === "restarting" ? " — retry shortly" : ""}`;
|
|
97
|
+
return "inference engine unavailable: the engine worker stopped mid-request; respawning — retry shortly";
|
|
98
|
+
};
|
|
99
|
+
/** The 502 a request gets when its worker cannot take it. */
|
|
100
|
+
export function workerUnavailable(error: unknown, worker: WorkerSupervisor): Response {
|
|
101
|
+
return Response.json({ error: { message: unavailableMessage(error), type: "engine_unavailable",
|
|
102
|
+
state: error instanceof EngineUnavailableError ? error.state : worker.state } }, { status: 502 });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The request goes to the worker as it came, its body streaming through. A worker that cannot take it, or dies under
|
|
106
|
+
* it, answers with the protocol's own unavailable error; nothing is retried. */
|
|
107
|
+
export async function forwardToWorker(worker: WorkerSupervisor, request: Request): Promise<Response> {
|
|
108
|
+
const { pathname } = new URL(request.url);
|
|
109
|
+
try {
|
|
110
|
+
request.signal.throwIfAborted();
|
|
111
|
+
const upstream = await worker.fetch(request.url, {
|
|
112
|
+
method: request.method, headers: stripHopByHop(request.headers), body: request.body,
|
|
113
|
+
signal: request.signal, redirect: "manual", duplex: "half",
|
|
114
|
+
});
|
|
115
|
+
const headers = stripHopByHop(upstream.headers);
|
|
116
|
+
const failure = () => {
|
|
117
|
+
const exit = worker.lastExit;
|
|
118
|
+
return `inference engine unavailable: the engine worker stopped while streaming this response${exit ? ` (${describeExit(exit)})` : ""}; it is being respawned`;
|
|
119
|
+
};
|
|
120
|
+
const stream = upstream.body && (upstream.headers.get("content-type") ?? "").startsWith("text/event-stream")
|
|
121
|
+
? guardEventStream(upstream.body, () => unavailableFrame(pathname, failure()))
|
|
122
|
+
: upstream.body;
|
|
123
|
+
return new Response(stream, { status: upstream.status, statusText: upstream.statusText, headers });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (request.signal.aborted) return new Response(null, { status: 499 });
|
|
126
|
+
return workerUnavailable(error, worker);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function createProxyRoutes(options: ProxyRoutesOptions) {
|
|
131
|
+
const { responses } = options;
|
|
132
|
+
const currentWorker = () => options.workers().find(worker => worker.id === options.current() && worker.role === "primary")?.supervisor;
|
|
133
|
+
const report = (): EngineReport => {
|
|
134
|
+
const engine = currentWorker();
|
|
135
|
+
return {
|
|
136
|
+
isolated: true, state: engine?.state ?? "none", pid: engine?.pid ?? null, restarts: engine?.restarts ?? null,
|
|
137
|
+
socket: engine?.socketPath ?? null, model: options.current(), last_exit: engine?.lastExit ?? null, response_store: responses.stats,
|
|
138
|
+
workers: options.workers().map(({ id, role, supervisor, measured }) => {
|
|
139
|
+
const memory = measured?.();
|
|
140
|
+
return { id, role, pid: supervisor.pid, state: supervisor.state, restarts: supervisor.restarts, socket: supervisor.socketPath,
|
|
141
|
+
memory: memory ? { active_bytes: memory.activeBytes, cache_bytes: memory.cacheBytes, peak_bytes: memory.peakBytes } : null };
|
|
142
|
+
}),
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
const health = async (): Promise<Response> => {
|
|
146
|
+
const engine = currentWorker();
|
|
147
|
+
let contribution: Record<string, unknown> = {};
|
|
148
|
+
if (engine?.state === "ready") {
|
|
149
|
+
try {
|
|
150
|
+
const upstream = await engine.fetch("http://engine/health", { signal: AbortSignal.timeout(2_000) });
|
|
151
|
+
const body = await upstream.json() as Record<string, unknown>;
|
|
152
|
+
if (upstream.ok) contribution = { state: body.state, in_flight: body.in_flight, leases: body.leases };
|
|
153
|
+
else contribution = { state: "unreachable" };
|
|
154
|
+
} catch { contribution = { state: "unreachable" }; }
|
|
155
|
+
}
|
|
156
|
+
const { response_store: _store, isolated: _isolated, workers, ...current } = report();
|
|
157
|
+
return Response.json({ status: "ok", isolated: true, engine: { ...current, ...contribution }, workers });
|
|
158
|
+
};
|
|
159
|
+
const stats = async (request: Request): Promise<Response> => {
|
|
160
|
+
const own = { response_store: responses.stats, engine: report() };
|
|
161
|
+
const upstream = await options.models.handle(request).catch(() => null);
|
|
162
|
+
if (upstream?.ok && (upstream.headers.get("content-type") ?? "").includes("json"))
|
|
163
|
+
return Response.json({ ...(await upstream.json() as Record<string, unknown>), ...own });
|
|
164
|
+
if (upstream && !upstream.ok && upstream.status !== 502) return upstream;
|
|
165
|
+
// The worker's own reason (a 502 from the forward), else that no worker is resident.
|
|
166
|
+
const reason = await upstream?.json().then((body: { error?: { message?: string } }) => body.error?.message).catch(() => undefined);
|
|
167
|
+
if (request.signal.aborted) return new Response(null, { status: 499 });
|
|
168
|
+
return Response.json({ server: { owner: "serve", model: options.current(), started_at: options.startedAt }, ...own,
|
|
169
|
+
unavailable: reason ?? "inference engine unavailable: no model worker is resident" });
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
report,
|
|
174
|
+
async handle(request: Request): Promise<Response | null> {
|
|
175
|
+
const { pathname } = new URL(request.url);
|
|
176
|
+
if (PARENT_ONLY.has(pathname)) return null;
|
|
177
|
+
if (pathname === "/engine") return request.method === "GET" ? Response.json(report()) : null;
|
|
178
|
+
if (request.method === "GET") {
|
|
179
|
+
if (pathname === "/health") return health();
|
|
180
|
+
if (pathname === "/stats") return stats(request);
|
|
181
|
+
}
|
|
182
|
+
if (pathname === "/v1/responses" && request.method === "POST")
|
|
183
|
+
return responses.forward(request, async inner => await options.models.handle(inner) ?? Response.json({ error: { message: "Not found" } }, { status: 404 }));
|
|
184
|
+
return options.models.handle(request);
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { createHfCredentials } from "../publishing/credentials";
|
|
2
|
+
import type { createPublisher, PublishRequest } from "../publishing/upload";
|
|
3
|
+
|
|
4
|
+
/** HTTP parsing and wire errors stay above credential and publishing policy. */
|
|
5
|
+
export function createPublishingRoutes(options: {
|
|
6
|
+
credentials: ReturnType<typeof createHfCredentials>;
|
|
7
|
+
publish: ReturnType<typeof createPublisher>;
|
|
8
|
+
}) {
|
|
9
|
+
const error = (message: string, status = 400) => Response.json({ ok: false, error: message }, { status });
|
|
10
|
+
return { async handle(request: Request): Promise<Response | null> {
|
|
11
|
+
const path = new URL(request.url).pathname;
|
|
12
|
+
const settings = path === "/api/settings/hf-token";
|
|
13
|
+
const push = path.match(/^\/api\/(quantize|finetune|dataset)\/push$/);
|
|
14
|
+
if (!(settings && ["GET", "POST"].includes(request.method)) && !(push && request.method === "POST")) return null;
|
|
15
|
+
try {
|
|
16
|
+
request.signal.throwIfAborted();
|
|
17
|
+
if (settings && request.method === "GET") return Response.json({ ok: true, hasToken: options.credentials.get() !== null });
|
|
18
|
+
const raw: unknown = await request.json().catch(() => null);
|
|
19
|
+
request.signal.throwIfAborted();
|
|
20
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return error("expected a JSON object");
|
|
21
|
+
const body = raw as Record<string, unknown>;
|
|
22
|
+
if (settings) {
|
|
23
|
+
if (typeof body.token !== "string" || !body.token.trim()) return error("token required");
|
|
24
|
+
options.credentials.save(body.token);
|
|
25
|
+
return Response.json({ ok: true });
|
|
26
|
+
}
|
|
27
|
+
if (typeof body.repo_id !== "string" || !body.repo_id.trim()) return error("repo_id required");
|
|
28
|
+
for (const key of ["job_id", "source_path"] as const) {
|
|
29
|
+
if (body[key] != null && (typeof body[key] !== "string" || !body[key].trim())) return error(`${key} must be a nonempty string`);
|
|
30
|
+
}
|
|
31
|
+
if (body.private != null && typeof body.private !== "boolean") return error("private must be a boolean");
|
|
32
|
+
const result = await options.publish({ kind: push![1] as PublishRequest["kind"], repoId: body.repo_id,
|
|
33
|
+
private: body.private as boolean | undefined, sourcePath: body.source_path as string | undefined,
|
|
34
|
+
jobId: body.job_id as string | undefined, signal: request.signal });
|
|
35
|
+
return Response.json({ ok: true, url: result.url });
|
|
36
|
+
} catch (failure) {
|
|
37
|
+
if (request.signal.aborted) return error("Request cancelled", 499);
|
|
38
|
+
return error(failure instanceof Error ? failure.message : String(failure));
|
|
39
|
+
}
|
|
40
|
+
} };
|
|
41
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { snapshotGenerationPolicy } from "
|
|
2
|
-
import type { GenerateOptions } from "
|
|
3
|
-
import type { RequestShape } from "
|
|
4
|
-
import type { DisposableResource } from "
|
|
5
|
-
import { disposeResources, ownResource } from "
|
|
6
|
-
export type { DisposableResource } from "
|
|
1
|
+
import { snapshotGenerationPolicy } from "@mlx-bun/inference/execution/request-policy";
|
|
2
|
+
import type { GenerateOptions } from "@mlx-bun/inference/generation";
|
|
3
|
+
import type { RequestShape } from "../engine/completion";
|
|
4
|
+
import type { DisposableResource } from "@mlx-bun/inference/contracts/portable";
|
|
5
|
+
import { disposeResources, ownResource } from "@mlx-bun/inference/runtime/resources";
|
|
6
|
+
export type { DisposableResource } from "@mlx-bun/inference/contracts/portable";
|
|
7
7
|
|
|
8
8
|
export class RequestOwnership {
|
|
9
9
|
#owner = ownResource(new Set<DisposableResource>(), disposeResources);
|
|
@@ -39,6 +39,7 @@ export interface RequestPlanInput {
|
|
|
39
39
|
topLogprobs: number;
|
|
40
40
|
adapterIds: string[];
|
|
41
41
|
hasVision: boolean;
|
|
42
|
+
hasPreparedPrefixIdentity?: boolean;
|
|
42
43
|
userSeed: boolean;
|
|
43
44
|
hasGrammar: boolean;
|
|
44
45
|
hasDraft: boolean;
|
|
@@ -137,6 +138,7 @@ export function planRequest(input: RequestPlanInput): PlanRequestResult {
|
|
|
137
138
|
|
|
138
139
|
const shape: RequestShape = {
|
|
139
140
|
hasVision: input.hasVision,
|
|
141
|
+
hasPreparedPrefixIdentity: input.hasPreparedPrefixIdentity,
|
|
140
142
|
hasAdapters: !!options.adapters?.length,
|
|
141
143
|
hasRepetitionPenalty: !!options.repetitionPenalty,
|
|
142
144
|
hasLogitsExtras: !!(
|
|
@@ -145,8 +147,6 @@ export function planRequest(input: RequestPlanInput): PlanRequestResult {
|
|
|
145
147
|
),
|
|
146
148
|
wantsLogprobs: captureLogprobs,
|
|
147
149
|
userSeed: input.userSeed,
|
|
148
|
-
kvQuant: !!(options.kvConfig?.length || options.kvBits),
|
|
149
|
-
turboQuant: !!options.turboQuant,
|
|
150
150
|
hasGrammar: input.hasGrammar,
|
|
151
151
|
hasDraft: input.hasDraft,
|
|
152
152
|
};
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
+
import { requireChatTemplate } from "../engine/model-host";
|
|
2
|
+
import { textPrompt } from "./text-prompt";
|
|
1
3
|
// Per-request preparation shared by every completion surface (chat,
|
|
2
4
|
// raw text, /signal, /generate): request → GenerateOptions with the
|
|
3
5
|
// server/model defaults folded in, chat-template rendering + prompt ids,
|
|
4
6
|
// the stable prompt-cache boundary probe, grammar compilation, and the
|
|
5
7
|
// tool-call stream router. Resolved ONCE per server (createRequestPrep) and
|
|
6
|
-
// captured by the route handlers.
|
|
7
|
-
|
|
8
|
-
import type { ToolDefinition } from "../chat-template";
|
|
8
|
+
// captured by the route handlers.
|
|
9
|
+
import type { ChatMessage, ToolDefinition } from "@mlx-bun/inference/input";
|
|
9
10
|
import {
|
|
10
11
|
fillEchoConfig,
|
|
11
12
|
fillMaxSpan,
|
|
12
13
|
FillSession,
|
|
13
14
|
resolveFillMode,
|
|
14
|
-
} from "
|
|
15
|
-
import { compileStrictFillRows, type StrictRowPlan } from "
|
|
16
|
-
import type { GenerateOptions } from "
|
|
17
|
-
import {
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
20
|
-
import type { HlgConfig } from "
|
|
15
|
+
} from "@mlx-bun/inference/generation/fill";
|
|
16
|
+
import { compileStrictFillRows, type StrictRowPlan } from "@mlx-bun/inference/generation/fill";
|
|
17
|
+
import type { GenerateOptions } from "@mlx-bun/inference/generation";
|
|
18
|
+
import type { GrammarRequest } from "@mlx-bun/inference/sampling/grammar";
|
|
19
|
+
import { runtimeValue } from "@mlx-bun/inference/runtime/config";
|
|
20
|
+
import { GENERIC_GENERATION_DEFAULTS } from "@mlx-bun/inference/models/profile";
|
|
21
|
+
import type { HlgConfig } from "@mlx-bun/inference/sampling";
|
|
21
22
|
import {
|
|
22
23
|
nextDefaultSeed,
|
|
23
24
|
normalizeMessages,
|
|
@@ -26,7 +27,8 @@ import {
|
|
|
26
27
|
resolveHlg,
|
|
27
28
|
type ChatRequestParams,
|
|
28
29
|
} from "./chat-request";
|
|
29
|
-
import type {
|
|
30
|
+
import type { LoadedModelContext as ModelContext } from "../engine/model-host";
|
|
31
|
+
import type { PromptTokenHistory } from "./generated-token-history";
|
|
30
32
|
import { selectToolStreamMode, ToolAwareStream, type ToolStreamMode } from "./token-streams";
|
|
31
33
|
|
|
32
34
|
/** The ServerOptions fields request preparation reads (server-wide
|
|
@@ -37,20 +39,18 @@ export interface RequestPrepOptions {
|
|
|
37
39
|
defaultTopP?: number;
|
|
38
40
|
defaultTopK?: number;
|
|
39
41
|
hlg?: HlgConfig;
|
|
40
|
-
pagedKv?: { blockSize?: number };
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export function createRequestPrep(input: {
|
|
44
|
-
ctx:
|
|
45
|
+
ctx: ModelContext;
|
|
45
46
|
serverOptions: RequestPrepOptions;
|
|
46
|
-
/**
|
|
47
|
-
* spread into every request's GenerateOptions. */
|
|
48
|
-
kvScheme: KvSchemeOptions;
|
|
49
|
-
/** `--max-tokens` / the GLM memory plan's generation cap; undefined = the
|
|
47
|
+
/** `--max-tokens` / a runtime memory plan's generation cap; undefined = the
|
|
50
48
|
* surface's own default (chat 65 536, raw completion 512). */
|
|
51
49
|
defaultGeneratedTokens: number | undefined;
|
|
50
|
+
tokenHistory?: PromptTokenHistory;
|
|
52
51
|
}) {
|
|
53
|
-
const { ctx, serverOptions,
|
|
52
|
+
const { ctx, serverOptions, defaultGeneratedTokens } = input;
|
|
53
|
+
const generationDefaults = ctx.generationDefaults ?? GENERIC_GENERATION_DEFAULTS;
|
|
54
54
|
|
|
55
55
|
// XTC never removes EOS or the newline token: mlx_lm.server passes
|
|
56
56
|
// [tokenizer.eos_token_id, tokenizer.encode("\n")] as xtc_special_tokens.
|
|
@@ -65,33 +65,35 @@ export function createRequestPrep(input: {
|
|
|
65
65
|
|
|
66
66
|
// Effective enable_thinking for a request, with the same precedence the chat
|
|
67
67
|
// template uses (extracted so sampling and template rendering can't disagree):
|
|
68
|
-
// explicit chat_template_kwargs.enable_thinking → reasoning_effort ("none" =
|
|
69
|
-
// off) → server --thinking default → model default
|
|
68
|
+
// explicit chat_template_kwargs.enable_thinking (null = template default) → reasoning_effort ("none" =
|
|
69
|
+
// off) → server --thinking default → the model's declared default. undefined
|
|
70
70
|
// means "not a switchable-thinking model / leave the template default".
|
|
71
71
|
const resolveEnableThinking = (req: ChatRequestParams): boolean | undefined => {
|
|
72
72
|
const explicit = req.chat_template_kwargs?.enable_thinking;
|
|
73
|
+
if (explicit === null) return undefined;
|
|
73
74
|
if (typeof explicit === "boolean") return explicit;
|
|
74
75
|
const effort = req.reasoning_effort;
|
|
75
76
|
if (effort !== undefined) return effort !== "none";
|
|
76
77
|
if (serverOptions.defaultThinking !== undefined) return serverOptions.defaultThinking;
|
|
77
|
-
return
|
|
78
|
+
return generationDefaults.enableThinking;
|
|
78
79
|
};
|
|
79
80
|
|
|
80
81
|
const toOptions = (req: ChatRequestParams): GenerateOptions & { stopSequences: string[] } => {
|
|
81
82
|
// Sampling follows the thinking state — which the web UI's thinking button
|
|
82
83
|
// drives via enable_thinking. Model authors publish a SINGLE
|
|
83
84
|
// generation_config temperature (the think-mode value) but recommend a
|
|
84
|
-
// cooler one for direct, no-think replies
|
|
85
|
-
// no-think
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
const NO_THINK_TEMPERATURE = 0.7;
|
|
85
|
+
// cooler one for direct, no-think replies. So with no explicit temperature
|
|
86
|
+
// set, a no-think turn runs at most the model's declared
|
|
87
|
+
// noThinkTemperatureCap while a think turn keeps the model's hotter
|
|
88
|
+
// configured default. An explicit request/CLI temperature always wins.
|
|
89
|
+
// top_p is unchanged by mode.
|
|
90
90
|
const genTemp = ctx.genDefaults.temperature ?? 0.7;
|
|
91
91
|
const defaultTemp = resolveEnableThinking(req) === false
|
|
92
|
-
? Math.min(genTemp,
|
|
92
|
+
? Math.min(genTemp, generationDefaults.noThinkTemperatureCap)
|
|
93
93
|
: genTemp;
|
|
94
94
|
return {
|
|
95
|
+
cacheSessionId: typeof req.session_id === "string" ? req.session_id :
|
|
96
|
+
typeof req.prompt_cache_key === "string" ? req.prompt_cache_key : undefined,
|
|
95
97
|
// Unset means generate until EOS/stop. Only a client cap or an explicit
|
|
96
98
|
// operator limit constrains completion length; fit estimates do not.
|
|
97
99
|
maxTokens: req.max_completion_tokens ?? req.max_tokens ??
|
|
@@ -120,10 +122,6 @@ export function createRequestPrep(input: {
|
|
|
120
122
|
// decode layer below and halts the loop via onToken → false.
|
|
121
123
|
stopSequences: (typeof req.stop === "string" ? [req.stop] : req.stop ?? [])
|
|
122
124
|
.filter((s) => typeof s === "string" && s.length > 0),
|
|
123
|
-
...kvScheme,
|
|
124
|
-
// Paged KV is a server-wide mode like the kv scheme above (v1:
|
|
125
|
-
// serial bf16 gemma4 — the createServer refusals hold the invariants).
|
|
126
|
-
...(serverOptions.pagedKv ? { pagedKv: serverOptions.pagedKv } : {}),
|
|
127
125
|
};
|
|
128
126
|
};
|
|
129
127
|
|
|
@@ -134,13 +132,14 @@ export function createRequestPrep(input: {
|
|
|
134
132
|
* + Warning header (oMLX parity — never 500). Honors MLX_BUN_GRAMMAR=0. */
|
|
135
133
|
const compileGrammarForRequest = async (
|
|
136
134
|
req: ChatRequestParams,
|
|
137
|
-
): Promise<{ controller: import("
|
|
138
|
-
if (
|
|
135
|
+
): Promise<{ controller: import("@mlx-bun/inference/sampling/grammar").GrammarController | null; degradeHint: string | null }> => {
|
|
136
|
+
if (runtimeValue("MLX_BUN_GRAMMAR") === "0") {
|
|
139
137
|
return {
|
|
140
138
|
controller: null,
|
|
141
139
|
degradeHint: "grammar compilation disabled by MLX_BUN_GRAMMAR=0",
|
|
142
140
|
};
|
|
143
141
|
}
|
|
142
|
+
const { compileGrammarRequest } = await import("@mlx-bun/inference/sampling/grammar");
|
|
144
143
|
const r = await compileGrammarRequest(
|
|
145
144
|
req as GrammarRequest,
|
|
146
145
|
ctx.tokenizer,
|
|
@@ -150,11 +149,11 @@ export function createRequestPrep(input: {
|
|
|
150
149
|
return { controller: r.controller, degradeHint: r.degradeHint };
|
|
151
150
|
};
|
|
152
151
|
|
|
153
|
-
// Map OpenAI reasoning_effort levels onto the
|
|
154
|
-
//
|
|
152
|
+
// Map OpenAI reasoning_effort levels onto the depth set a template that reads
|
|
153
|
+
// `reasoning_effort` supports (xhigh|medium|low — such a template raises on anything else). "none"
|
|
155
154
|
// means thinking off (handled by resolveEnableThinking), so no depth is
|
|
156
155
|
// passed. Only consumed for templates with readsReasoningEffort.
|
|
157
|
-
const
|
|
156
|
+
const templateReasoningEffort = (
|
|
158
157
|
effort: ChatRequestParams["reasoning_effort"],
|
|
159
158
|
): "xhigh" | "medium" | "low" | undefined => {
|
|
160
159
|
switch (effort) {
|
|
@@ -177,7 +176,7 @@ export function createRequestPrep(input: {
|
|
|
177
176
|
return {
|
|
178
177
|
tools,
|
|
179
178
|
enableThinking: resolveEnableThinking(req),
|
|
180
|
-
reasoningEffort:
|
|
179
|
+
reasoningEffort: templateReasoningEffort(req.reasoning_effort),
|
|
181
180
|
preserveThinking: req.chat_template_kwargs?.preserve_thinking,
|
|
182
181
|
};
|
|
183
182
|
};
|
|
@@ -186,12 +185,12 @@ export function createRequestPrep(input: {
|
|
|
186
185
|
req: ChatRequestParams,
|
|
187
186
|
tools: ToolDefinition[] | null,
|
|
188
187
|
): { ids: number[]; startInThinking: boolean } => {
|
|
188
|
+
// A context without a template serves only through a supplied prompt builder.
|
|
189
|
+
requireChatTemplate(ctx);
|
|
189
190
|
const opts = templateOptionsFor(req, tools);
|
|
190
|
-
const rendered = ctx.template.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const trimmed = ids[0] === ids[1] && ids[0] === ctx.tokenizer.bosTokenId ? ids.slice(1) : ids;
|
|
194
|
-
return { ids: trimmed, startInThinking: promptEndsInOpenThink(rendered) };
|
|
191
|
+
const { rendered, ids } = textPrompt(ctx.template, ctx.tokenizer, normalizeMessages(req.messages), opts);
|
|
192
|
+
return { ids: input.tokenHistory?.resolve(rendered, ids) ?? ids,
|
|
193
|
+
startInThinking: promptEndsInOpenThink(rendered) };
|
|
195
194
|
};
|
|
196
195
|
|
|
197
196
|
/** STABLE cache boundary: the prompt's tail is a generation primer (e.g.
|
|
@@ -213,24 +212,40 @@ export function createRequestPrep(input: {
|
|
|
213
212
|
tools: ToolDefinition[] | null,
|
|
214
213
|
trimmed: number[],
|
|
215
214
|
): number => {
|
|
215
|
+
// Outside the best-effort probe: a builder asking for it needs a template.
|
|
216
|
+
requireChatTemplate(ctx);
|
|
216
217
|
const opts = templateOptionsFor(req, tools);
|
|
217
218
|
const mode = `${opts.enableThinking}|${!!tools?.length}|${opts.reasoningEffort ?? ""}|${opts.preserveThinking ?? ""}`;
|
|
218
219
|
const primer = primerLenByMode.get(mode);
|
|
219
220
|
if (primer !== undefined) return Math.max(0, trimmed.length - primer);
|
|
220
221
|
let stableLen = trimmed.length;
|
|
221
222
|
try {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
223
|
+
const canonical = ctx.tokenizer.encode(ctx.template.render(normalizeMessages(req.messages), opts));
|
|
224
|
+
const current = canonical[0] === canonical[1] && canonical[0] === ctx.tokenizer.bosTokenId
|
|
225
|
+
? canonical.slice(1) : canonical;
|
|
226
|
+
const replies: ChatMessage[] = [{ role: "assistant", content: "x" }];
|
|
227
|
+
// Some templates retain an empty think primer for text replies but
|
|
228
|
+
// omit it before a tool call. Both reply forms must preserve the
|
|
229
|
+
// boundary retained by an untrimmable recurrent cache.
|
|
230
|
+
if (tools?.length) replies.push({ role: "assistant", content: null, tool_calls: [{
|
|
231
|
+
id: "cache-boundary-probe", type: "function",
|
|
232
|
+
function: { name: tools[0]!.function.name, arguments: {} },
|
|
233
|
+
}] });
|
|
234
|
+
let i = current.length;
|
|
235
|
+
for (const reply of replies) {
|
|
236
|
+
const probe = ctx.tokenizer.encode(ctx.template.render([
|
|
237
|
+
...normalizeMessages(req.messages), reply, { role: "user", content: "x" },
|
|
238
|
+
], opts));
|
|
239
|
+
const probeTrimmed = probe[0] === probe[1] && probe[0] === ctx.tokenizer.bosTokenId ? probe.slice(1) : probe;
|
|
240
|
+
let common = 0;
|
|
241
|
+
const n = Math.min(i, probeTrimmed.length);
|
|
242
|
+
while (common < n && current[common] === probeTrimmed[common]) common++;
|
|
243
|
+
i = common;
|
|
244
|
+
}
|
|
245
|
+
// Generated-history provenance may use a different BPE segmentation
|
|
246
|
+
// inside old turns. Measure the primer canonically, then subtract it
|
|
247
|
+
// from the actual request IDs that inference will receive.
|
|
248
|
+
stableLen = Math.max(0, trimmed.length - (current.length - i));
|
|
234
249
|
// Memoize the mode's primer length (sanity-capped: a "primer" longer
|
|
235
250
|
// than 64 tokens means the probe diverged for content reasons —
|
|
236
251
|
// don't generalize that).
|
|
@@ -241,16 +256,15 @@ export function createRequestPrep(input: {
|
|
|
241
256
|
};
|
|
242
257
|
|
|
243
258
|
const toolStreamMode = (tools: ToolDefinition[] | null): ToolStreamMode =>
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
selectToolStreamMode(ctx.model.config.modelType, !!tools?.length);
|
|
259
|
+
// A model that declares sentinel tokens keeps the token-level path; every
|
|
260
|
+
// other model emits tool calls as DECODED TEXT — see selectToolStreamMode.
|
|
261
|
+
selectToolStreamMode(ctx.sentinels, !!tools?.length);
|
|
248
262
|
|
|
249
263
|
const toolRouter = (
|
|
250
264
|
tools: ToolDefinition[] | null,
|
|
251
265
|
onParseFailure?: () => void,
|
|
252
266
|
): ToolAwareStream =>
|
|
253
|
-
new ToolAwareStream(ctx.tokenizer, toolStreamMode(tools), tools, onParseFailure);
|
|
267
|
+
new ToolAwareStream(ctx.tokenizer, toolStreamMode(tools), tools, onParseFailure, ctx.sentinels);
|
|
254
268
|
|
|
255
269
|
/** Strict fill rows are a function of (template mode, tool signature) only —
|
|
256
270
|
* they are token spans of the assistant turn, which opens with a special
|
|
@@ -266,15 +280,15 @@ export function createRequestPrep(input: {
|
|
|
266
280
|
(t.function?.parameters?.additionalProperties as unknown) ?? null,
|
|
267
281
|
]));
|
|
268
282
|
|
|
269
|
-
/** Token fast-forwarding (docs/design/speculative-decoding.md "Token
|
|
283
|
+
/** Token fast-forwarding (`02d723a:docs/design/speculative-decoding.md` §7 "Token
|
|
270
284
|
* fast-forwarding"): compile this request's determined-span table, or null
|
|
271
285
|
* when the feature is off or the request's shape refuses it.
|
|
272
286
|
*
|
|
273
287
|
* Refusals owned here (body-level); the ones only ChatStage can see —
|
|
274
|
-
* a compiled grammar, media prompts
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
288
|
+
* a compiled grammar, media prompts and a mounted draft model — are applied
|
|
289
|
+
* there. The execution binding owns method support (every cache serves it). Strict
|
|
290
|
+
* shared execution keeps the sampler's absolute token positions, including
|
|
291
|
+
* known tokens; an explicit seed therefore remains replayable.
|
|
278
292
|
*
|
|
279
293
|
* MLX_BUN_FILL=echo additionally arms the echo index (K3c, Lab tier): the
|
|
280
294
|
* strict rows keep policy "assert", and copied spans ride the same
|
|
@@ -287,9 +301,9 @@ export function createRequestPrep(input: {
|
|
|
287
301
|
const mode = resolveFillMode();
|
|
288
302
|
if (mode === "off") return null;
|
|
289
303
|
if (!tools?.length) return null;
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
304
|
+
// The determined spans come from the template; a builder-only context has none.
|
|
305
|
+
if (!ctx.template) return null;
|
|
306
|
+
// Seed support is selected by the execution binding after placement.
|
|
293
307
|
// Injected tokens are never sampled — they have no logprob row.
|
|
294
308
|
if (req.logprobs === true) return null;
|
|
295
309
|
if (typeof req.top_logprobs === "number" && req.top_logprobs > 0) return null;
|
|
@@ -1,21 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
// The parent's Responses conversation history in the isolated server (main's
|
|
2
|
+
// responses-client.ts): `previous_response_id` resolves against the parent's
|
|
3
|
+
// store, the resolved conversation goes to the worker without one, and the
|
|
4
|
+
// completed record is remembered here, so history survives worker restarts.
|
|
5
|
+
// The worker keeps its own bounded store for the requests it answers; the
|
|
6
|
+
// parent never consults it.
|
|
7
|
+
import { ResponseStore, resolveResponsesConversation, type ResponseHistory, type ResponsesRequest } from "./responses";
|
|
8
|
+
|
|
9
|
+
const responsesError = (status: number, message: string) => Response.json({ error: {
|
|
10
|
+
message, type: "invalid_request_error", param: null, code: null,
|
|
11
|
+
} }, { status });
|
|
2
12
|
|
|
3
|
-
/** Application-owned conversation history over a data-only HTTP host. Workers
|
|
4
|
-
* translate/run the request; the parent stores only completed response records. */
|
|
5
13
|
export function createResponsesClient(store: ResponseHistory = new ResponseStore()) {
|
|
6
14
|
return {
|
|
7
15
|
get stats() { return { entries: store.size, bytes: store.totalBytes, max_bytes: store.maxBytes, ttl_ms: store.ttlMs }; },
|
|
16
|
+
/** `forward` sends the rewritten request to the worker and returns its response as is. */
|
|
8
17
|
async forward(request: Request, forward: (request: Request) => Promise<Response>): Promise<Response> {
|
|
9
|
-
const error = (status: number, message: string) => Response.json({ error: {
|
|
10
|
-
message, type: "invalid_request_error", param: null, code: null,
|
|
11
|
-
} }, { status });
|
|
12
18
|
let body: ResponsesRequest;
|
|
13
19
|
try { body = await request.json() as ResponsesRequest; }
|
|
14
|
-
catch { return
|
|
15
|
-
if (!body || typeof body !== "object" || Array.isArray(body)) return
|
|
20
|
+
catch { return responsesError(400, "invalid JSON body"); }
|
|
21
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return responsesError(400, "invalid JSON body");
|
|
22
|
+
// The container is validated before the previous id resolves, as the
|
|
23
|
+
// worker does: only a missing or expired previous response is a 404.
|
|
24
|
+
if ((body.input != null && typeof body.input !== "string" && !Array.isArray(body.input)) ||
|
|
25
|
+
(body.previous_response_id != null && typeof body.previous_response_id !== "string"))
|
|
26
|
+
return responsesError(400, "input must be a string or array; previous_response_id must be a string");
|
|
16
27
|
let conversation: ReturnType<typeof resolveResponsesConversation>;
|
|
17
28
|
try { conversation = resolveResponsesConversation(body, store); }
|
|
18
|
-
catch (
|
|
29
|
+
catch (error) { return responsesError(404, error instanceof Error ? error.message : String(error)); }
|
|
19
30
|
const headers = new Headers(request.headers);
|
|
20
31
|
headers.delete("content-length");
|
|
21
32
|
headers.set("x-mlx-bun-response-owner", "parent");
|
|
@@ -32,15 +43,20 @@ export function createResponsesClient(store: ResponseHistory = new ResponseStore
|
|
|
32
43
|
if (!body.stream) {
|
|
33
44
|
const value = await response.json() as Record<string, unknown>;
|
|
34
45
|
remember(value);
|
|
35
|
-
const
|
|
36
|
-
|
|
46
|
+
const outputHeaders = new Headers(response.headers);
|
|
47
|
+
outputHeaders.delete("content-length");
|
|
48
|
+
return Response.json(restorePrevious(value), { status: response.status, headers: outputHeaders });
|
|
37
49
|
}
|
|
38
50
|
if (!response.body) return response;
|
|
39
51
|
const decoder = new TextDecoder(), encoder = new TextEncoder();
|
|
40
52
|
let pending = "";
|
|
53
|
+
// Frames the worker did not shape as JSON (keep-alive comments, [DONE])
|
|
54
|
+
// pass through; `response.completed` is remembered and every response
|
|
55
|
+
// object gets the previous id the caller sent.
|
|
41
56
|
const rewrite = (frame: string): string => frame.replace(/^data: (.+)$/m, (line, data: string) => {
|
|
42
57
|
if (data === "[DONE]") return line;
|
|
43
|
-
|
|
58
|
+
let event: Record<string, unknown>;
|
|
59
|
+
try { event = JSON.parse(data) as Record<string, unknown>; } catch { return line; }
|
|
44
60
|
if (event.response && typeof event.response === "object") {
|
|
45
61
|
const value = event.response as Record<string, unknown>;
|
|
46
62
|
if (event.type === "response.completed") remember(value);
|
|
@@ -48,7 +64,8 @@ export function createResponsesClient(store: ResponseHistory = new ResponseStore
|
|
|
48
64
|
}
|
|
49
65
|
return `data: ${JSON.stringify(event)}`;
|
|
50
66
|
});
|
|
51
|
-
const outputHeaders = new Headers(response.headers);
|
|
67
|
+
const outputHeaders = new Headers(response.headers);
|
|
68
|
+
outputHeaders.delete("content-length");
|
|
52
69
|
return new Response(response.body.pipeThrough(new TransformStream<Uint8Array, Uint8Array>({
|
|
53
70
|
transform(chunk, controller) {
|
|
54
71
|
pending += decoder.decode(chunk, { stream: true });
|