Laya releases in Laya-Pro¶
The original project's release notes for the versions merged into Laya-Pro, from its README. Laya-Pro 0.3.29 contains everything below, except the Java and .NET SDKs, which it does not carry, and with Laya-Pro's own additions on top: see the README. Issue and pull request numbers refer to the original project.
What's new in 0.3.29¶
predict_longno longer splits a state that fits. The one-pass shortcut compared the state against the default window instead of the room the questions actually leave, so any state in the band between the two was scanned in two windows and answered with the max or the most confident window rather than the plain answer (#966). Onlaya-multilingualthat band is roughly 761 to 989 state tokens, an ordinary email: an 878-token note returned noul 0.998 againstpredict's 0.752, at twice the forward passes. It now matchespredictexactly, and an explicitwindow=still scans.- A line of English acronyms no longer routes to the multilingual checkpoint.
MON,DES,ESTandLAcollide with French stopwords, so one line of ordinary abbreviations inside an English state madeanalysename the whole state French (#1013). The all-caps guard is kept, because a customer shouting in Portuguese is still Portuguese, and the fix separates that case from a line of bare acronyms. A second cause is fixed with it: acronyms were voting in the whole-state verdict too, which no helper was filtering. - A
min_confidencemap key that cannot name a bucket is refused. The validator checked only that a key was a string, so{"choice:2-5": 0.9}passed and then silently gated nothing: the lookup misses, falls back todefault, then to 0.0 (#1002). A caller who mis-spells one key believed that bucket was gated at 0.9 while every answer in it abstained never. - Fine-tuning reports what it learned, on held-out data.
laya-train --eval eval.csvevaluates the base checkpoint before training and the fine-tune after, and writestrain_report.jsonwith accuracy, loss, ECE, Brier and signed deltas (#967, #887). Evaluation items are checked for overlap against both the training and calibration splits, and a set that overlaps is labelledoverlapping_evalrather than reported as generalization. With no--evaland no calibration items, evaluation is skipped rather than reporting training fit. - A fine-tune that collapses to the class prior now says so. On a few hundred rows the default epoch budget can finish at chance with a near-constant logit, and the run still looks successful (#968, #963).
laya-evals evidence --checkpoint DIRreads the calibration evidence a fine-tune persists and reports it asPRESENT,MISSING,INSUFFICIENTorUNKNOWN, so zero calibration items stops reading as healthy (#964). It loads no weights and does not need torch.- The fine-tuning scripts now share one loop.
notebooks/laya_finetune_typed_decisions_mps.pyandresearch/scripts/finetune_single_device.pycalllaya.traininstead of carrying their own copies, which is what #851 and #885 were: the same temperature-clamp bug fixed twice in parallel (#965, #887). - The default loss stays
rlcd, now on evidence. A three-seed panel on typed-decisions says the single-seed soft-CE win does not replicate: pairedsoft-ce − rlcdaccuracy is +0.0002 on average and changes sign between seeds, with soft-CE far noisier (std 0.0155 against 0.0016) (#1012, #887, #741). - Java.
laya-javagains language routing, the preset question sets, the embedding shortlist and the email cleaner, gated against fixtures recorded from the Python package, plus a JDK matrix lane because\p{L}follows the JDK's own Unicode version (#938). Three defects onmainare fixed with it, including a release workflow that could publish a jar named after a branch, and a release test floor that counted skipped tests. - Thirty-one documentation corrections, each landing a gate that fails if the page drifts again (#972 to #1011, from @aashish254). The largest class:
confidencewas documented as one entropy formula across every question type, when it is1 - H/log(k)forchoiceandscoreand equalsanswer_confidencefornoul. Others name parameters a tool actually takes, correct key counts, and stop calling the shippedanswer_confidencecalibrated when the loader itself warns that it is not. - Portability. Six repo reads in
tests/left the codec to the runner, which is cp1252 on the Windows lane, so a UTF-8 page killed the whole suite at the read rather than failing one assertion. A gate now refuses an unpinned repo read (#1001). laya[onnx]no longer caps NumPy for everyone. The cap that torch below 2.3 needs is scoped by marker to macOS on Intel, instead of making the extra unresolvable next to anything requiringnumpy>=2(#947).
44 pull requests from 8 contributors.
What's new in 0.3.28¶
laya.backendswas missing from every published wheel. The package was never added to setuptools' explicit list, so the wheels for 0.3.25, 0.3.26 and 0.3.27 shipped without it (#940). The documented backend selection API was therefore unavailable to anyone who installed with pip:Agent(backend="eager")raisedModuleNotFoundErrorandagent.set_backend("eager")raisedImportError, while the compile guide described both. The default path was unaffected, which is why this went unnoticed; it also only ever worked from a source checkout, which every contributor here uses. A packaging check now keeps the declared list aligned with every importablelayasource package, so the next one fails at build time instead of at install time.- Fine-tuning from the command line.
laya-train --data tickets.csv --out ./ftfine-tunes a checkpoint from a plain labelled CSV, discovering the labels and synthesising the question (#931, #887). It also reads the{state, questions, expected}rowslaya-evalsalready takes, so an evaluation set trains without conversion, and--dry-runprints the item and skip counts before anything loads. The generated question schema is saved beside the checkpoint, so the labels and wording can be reused exactly at inference. - A fine-tune now says how much its calibration can be trusted. A short run could fit temperatures of
[1.0, 1.0, 1.0]from a handful of items and save a checkpoint whose confidences were never calibrated, indistinguishable from one that was.finetunewarns per question type and records the same report in the checkpoint config (#933). Questions whose options run pastmax_lenare skipped and counted rather than crashing the batch mid-run (#934), and a final partial accumulation window is normalised by the micro-batches it actually holds (#941). - Many-option choices.
laya.predict_tournament(agent, state, questions)answers a choice question whose labels do not fit the option budget by splitting them into groups of 16, answering every group in one forward pass and running the winners in a final call (#950). On full test splits: BANKING77 0.430 to 0.610, CLINC150 0.625 to 0.876, with ECE falling from 0.350 to 0.082. No embedder and no new dependency. - Order-invariant checkpoints. An opt-in parallel option layout gives every option the same position ids and blocks attention between options, so reordering can only permute the logits (#951). A checkpoint trained with
TrainConfig(option_layout="parallel")gives the same answer under reordering for 100% of decisions, against 91.7% for the current layout. Every published checkpoint stays on the default sequential layout and nothing changes for them. - Serve your own checkpoints beside the built-ins.
Router(models=...)andRouter.register(name, source)accept any name, with a Hub repo id, a(repo, subfolder)pair or a local directory as the source, and the router loads, evicts and unloads it exactly like a built-in (#937, #919).Router.registeredlists them andRouter.unregisterremoves one. - pydantic
Enumfields work.questions_from_pydantic,decide(schema=Model)andanswer_to_pydanticraisedSchemaErroron every enum field, because pydantic v2 renders them as a$refand the planner never resolved one. Local$defsreferences now resolve, including insideOptional[Enum]and pydantic v1's one-itemallOfwrapper (#960). - Abstention cuts are fitted on the precision the gate reads.
fit_abstention_thresholdschose a cut from full-precision confidences while the gate compares the 4-decimalanswer_confidence. With a binning map installed the whole cut bin was lost: the fitter judged 532 accepted answers and the gate delivered 382 (#957). laya-evalsrefuses a NaN threshold.--min-accuracy nanand--max-ece nanwere accepted and every comparison against NaN is false, so a run at 0% accuracy and ECE 0.99 exited 0 (#954).- MCP keeps
option_order.laya_predict,laya_route,laya_shortlistand everylaya_predict_batchitem dropped the key, so the README's rotation-averaging recipe returned k identical answers (#958). - The ONNX agent catches an in-place question rewrite. A start hook that widens a question in place mutated the before-image
predict_longcompared against, so the scan-budget guard returned early and up to 59% of a document reached no model whileusagereported every window as read. The torch agent already raised on the identical input (#959). - torch 2.0 to 2.3 can run the package again. The action-head dtype check called a form of
torch.is_autocast_enabledthat only exists from torch 2.4, so every forward pass raisedTypeErroracross the bottom of the declaredtorch>=2.0.0range (#945). Two test suites that readtorch.fx.experimental._configat module level no longer fail collection on a torch without it (#946), and the Windows lane's bf16 legs are skipped on a Windows CPU, where they hit an uncatchable SIGILL (#949). - macOS and Intel.
setup_laya.shandLOCAL_SETUP.mdpin the stack that actually runs there, since a plaingit cloneresolves torch 2.2.2 against a transformers that wants 2.4 and nothing in the error message says so (#948). - Docker. The default base image moves to Debian 13 (trixie), with bookworm one build arg away (#953, #739). Verified with a decision diff across both bases: 291 answers per checkpoint on torch CPU, torch CUDA and ONNX Runtime CPU, zero differing decisions.
- TypeScript.
Router.predictBatchandpredictManyforward per-callonPredictStart,onPredictEndandhooksRaise, which were accepted and silently dropped (#936, #935). French mail is cleaned the way Python cleans it, over 4,000 generated messages with zero mismatches (#939). An English word that doubles as a foreign function word is counted once, so plain English likeCome one, come allis no longer routed to the multilingual checkpoint (#955). - .NET and Java. The French device footer is matched with the spacing people actually write (#956), and an empty action-logit row gives
[0.5, 0.5]instead of[NaN, NaN](#942). - Security. The Gradle wrapper jar is validated against Gradle's published checksums before anything executes it, and the distribution it downloads is pinned by sha256. The email examples no longer use a real bank's name with two unregistered lookalike domains as the phishing lure; the preset still flags the generic version at 0.926. A full audit of the repository, the published wheel, both npm packages and all ten workflows found no malicious content.
28 pull requests from 12 contributors.
What's new in 0.3.27¶
- A plain
import layano longer crashes when TensorFlow is installed. transformers 4.x imports TensorFlow while laya builds the model, and a broken TF build turns that intoFatal Python error: Bus errorfrom a library laya never uses (#915). The package now setsUSE_TF=0the way CI, the Dockerfile and the examples already did. - Per-call hooks reach the batch path.
Router.predict_batchtakeshooks,on_predict_start,on_predict_end,hooks_raiseandhooks_timeout, matchingpredict;Router.route_batchtakeshooks,hooks_raiseandhooks_timeout, since it fires onlyon_routeand has no predict events for the convenience callables to bind to (#909). The batched dispatch also composes installed hooks properly, so aset_default_hooksdefault no longer fires onpredictand silently vanishes onpredict_batch. - A stale abstention flag is cleared on re-evaluation. Re-running the gate on a reused result dict with a more permissive threshold used to leave
low_confidence: Truebehind, so downstream callers treated the answer as permanently abstained (#910). predict_longruns its scan after the hook chain rather than as a start hook, so laya's own forward pass no longer executes insidedispatch()and inherits the caller's hook machinery.- Abstention thresholds are fitted on the scale the gate reads. With a histogram-binning map installed, the runtime reports a binned confidence;
fit_abstention_thresholdsnow fits against that instead of the temperature-scaled value, so a fitted cut and the gate agree. - Selective-classification metrics no longer split tied confidences.
selective_accuracyandaurccut at a row index, so with ties the result depended on dataset order. Ties are the normal case foranswer_confidence, not a corner. - Java.
laya-java/is a JVM inference package with the same live parity gate the .NET port uses: fixtures generated from the Python package by a committed script, a drift check, and a skip guard so a missing artifact fails rather than passes. The lane is advisory for the same reason the .NET one is. - French email. Device footers with ordinary spacing are matched, not only the tight spacing the original samples happened to have.
- MPS autocast, measured on an M1 Pro.
mps_amp_min_rowshas defaulted to 5 since #109 on the strength of one M5 measurement, hedged for M1 to M5.BENCHMARKS.mdnow carries paired fp32-against-fp16 numbers on an M1 Pro, with the script that produces them.
9 pull requests from 7 contributors.
What's new in 0.3.26¶
A small release: one new SDK, one TypeScript port, and the dependency bumps.
- .NET SDK.
laya-dotnet/is a C# port of the inference path running the official checkpoints exported to ONNX on ONNX Runtime, so calling Laya from .NET no longer needs a Python sidecar (#673). It ships with a parity lane that re-records its golden fixtures from the Python package at every commit, so drift surfaces on the pull request that causes it; the lane is advisory, because a Python improvement should not wait on a C# port. Long prediction, per-language temperatures, hooks, batching, option ordering, digest controls and usage diagnostics are not ported yet, and there is no NuGet package. - Histogram binning in laya-ts.
applyBinningMap/checkBinningMapport the non-parametric recalibration from core, including the language-override bypass, and the recalibratedanswer_confidenceis what the abstention gate reads. - Dependencies.
@types/node24 to 26, zensical 0.0.65 to 0.0.67, ruff 0.16.8 to 0.16.9, and the CodeQL actions to 4.38.2. The three that could have broken a lane were each verified against that lane before merging.
7 pull requests: 2 from contributors and 5 dependency bumps.
What's new in 0.3.25¶
- Memory on demand.
LAYA_IDLE_UNLOAD_SECONDSletslaya-servegive its checkpoints back after an idle window, andLAYA_BASE_URLletslaya-mcp-serveranswer from a running server over HTTP instead of loading its own copy, so several editor sessions share one resident model (#888). Both default to off. - Backends.
Agent(backend=...)andagent.set_backend(...)selectauto/eager/compile/tilelang/onnxthrough one class layer, with ONNX routed to the existingONNXAgentrather than a second copy of that path. - Compile defaults.
compile=Truewarms during load instead of paying 50 s on the first request, withcompile_warmup=Falseto restore the lazy shape.compile_cachegives Inductor a Laya-specific directory andcompile_modereachesreduce-overhead. - AOTInductor packaging works.
DecisionModel.forwardcast to fp32 before the action head while the encoder ran under AMP, which packaged a graph that died withmat1 and mat2 must have the same dtype. The cast now matches the head's weight dtype outside autocast only, so eager and AMP numerics are untouched. - Oversized batches split instead of collating whole.
/v1/systemone/batchchooses a state chunk size when the token product would exceed the cap, rather than building one 4,096-row forward pass. No request that worked before is refused and none changes its answer. - Calibration. Histogram binning is wired into answers and the calibration payload, so a fitted
binning_mapships and loads like the temperatures. - TileLang. All five kernels now lower for the CPU target as an explicit fp32 specialization, and GEGLU uses two pipeline stages.
- Stricter device handling. A CUDA ordinal past
device_count, andautoin any casing, are resolved at load with the same warn-and-CPU shape as the existing fallbacks instead of dying later in.to(). - Encoding.
layawrites redirected stdout as utf-8, the output half of the stdin fix in #799. - TypeScript. Both clients accept the per-bucket
minConfidencemap, andlaya-tsports it to the on-device engine.
13 pull requests from 9 contributors.
What's new in 0.3.24¶
- Concurrency.
Router.loadbuilds a checkpoint outside the lifecycle lock, so a cold build no longer blocks calls for a checkpoint that is already resident, andunloadis synchronized per checkpoint rather than globally (#848).predict_longholds the tokenizer lock like every other encode, so scanning a document next to ordinary predictions no longer raisesAlready borrowed(#825). - Calibration. Per-option-count abstention thresholds, because one
min_confidencedoes not transfer across option counts (#394):fit_abstention_thresholdsfits one cut per bucket, keyed liketemperature_by_options, and fails closed on a bucket too unreliable to accept anything. Histogram binning (fit_binning_map,apply_binning_map) recalibrates a bucket whose reliability curve temperature scaling cannot reach.save_calibrationwrites atomically, andrecords_from_labeledworks on a loaded agent (#826). - Evals. Selective-classification metrics (Brier, AURC, selective accuracy) from the same pairs ECE already uses, so the abstention gate has a yardstick. A NaN metric, limit or tolerance can no longer pass a gate (#830).
- Stricter inputs. A non-finite
hooks_timeout(#828), a non-scalarchoicelabel, a batch item's untypedlang_guess, and an unvalidatedmin_confidenceorhooks_timeoutonlaya_predict_batchare all refused where they are read.hooks_installedaccepts a sequence, as documented (#829). Anullscore level is a 422 instead of a response no Jev client can parse. - laya-serve.
LAYA_JEV_STRICTprojects the response onto the strict Jev wire contract for clients that reject unknown fields./v1/systemone/batchsumsoutput_tokensinstead of reporting zero, and refuses an unpaired surrogate like the single endpoint. - Fallback notes are warnings, not prints. Eight device- and inference-fallback notes went to stdout, which corrupted
laya --jsonoutput; they arewarnings.warnnow, so they are filterable. - One test list. CI and the release gate run the same shared suite list (
scripts/test_suites.py). They had drifted to 80 suites against 47, so a regression in any of the 33 CI-only suites could reach PyPI. - TypeScript. The SDK types and validates the whole
usagereport, the four confidence fields, and the routing detection'smixed_segment.laya-tsreports collapsed options likelaya.commonand keeps bytecode out of the npm tarball. - Docs and examples. Nine example and page corrections where the prose contradicted the code, each with a test that holds the page to the source. The PyPI README links absolutely, so its 31 relative links no longer 404 on the project page.
56 pull requests from 16 contributors.
What's new in 0.3.23¶
- Security.
GET /healthno longer answers deployment internals to an unauthenticated caller on a server that setLAYA_API_KEY(#812): liveness stays open so every shipped probe keeps working, while the resident checkpoint names, revision SHAs, device state and fallback reasons need the bearer. A deployment with no key set is unchanged.SECURITY.mdnow documents private vulnerability reporting. - Concurrency. A GPU OOM fallback no longer moves the shared model under another in-flight request (#649). Normal forwards stay concurrent through a reader-writer gate; only the device demotion is exclusive.
- Per-call controls reach every surface.
lang,lang_guess,min_confidence,taskand the token budgets now forward through the CLI (--lang-guess,--min-confidence),/v1/systemone/batch, the MCP single-request and batch tools, the TypeScript SDK and the LangChain, CrewAI and LlamaIndex wrappers. The three framework wrappers also gateconfidence_thresholdonanswer_confidencerather than the entropy confidence, matching core's own gate. - Routing. Swedish is detected with MASSIVE evidence across all 51 locales and no locale regressing.
LAYA_DEFAULT_MODELmakes the routing fallback settable from the environment, and a per-checkpoint pin no longer silently disables the caller's digest or revision. - ONNX.
--quantizedefaults to per-tensor, because per-channel collapsed the decision model to 32 percent agreement with eager. Export declares its dynamic dims in a spelling every torch in the supported range accepts, and verifies the symbolic axes it wrote. - Long documents.
predict_longsizes its windows from the room a question actually leaves for the state, so a scan no longer skips part of the document and reports that it read it. - Evals. Opt-in per-slice quality gates catch a slice regressing while the overall metric improves, shortlist runs attribute errors to retrieval or decision,
--min-confidencereaches the abstention gate, and--calibrationworks on the ONNX path. - Abstention reporting. With
min_confidenceset, every answer reportsabstentionandabstention_threshold. With no threshold the payload is byte for byte what it was. - Research. A Spanish phone-turn benchmark (217 frozen sentences, label policy fixed before any model ran) and a Chinese reliability evaluation with source-group isolation and paired bootstrap intervals.
- Email. French mail clients are cleaned the way English, Portuguese and Spanish already were.
64 pull requests from 21 contributors. #742 landed inside #684, which had been rebased onto it. Full list in the 0.3.23 release.
What's new in 0.3.21¶
- ONNX catches up with PyTorch.
ONNXAgentgainspredict_batch(withsort_by_length),predict_longanddecide_batch,scripts/export_onnx.py --quantizewrites a per-channel INT8 copy for CPU, andlaya-evals run --onnxscores an export with the same gates as the torch path. - Opt-in abstention.
min_confidence=onpredict,predict_batch,decideanddecide_batchflags answers below a threshold onanswer_confidencewithlow_confidence: True, anddecidereturnsNonefor them. When a threshold is set, every answer also reportsabstention—passed,abstainedorunevaluated— so a caller can tell a gate that cleared from a gate that never ran; with no threshold, nothing is added at all. - Batch everywhere.
decide_batch,Router.predict_long,laya --batch FILE, the MCPlaya_predict_batch/laya_route_batch/laya_decidetools, and LangChainbatch()/abatch()all run on shared forward passes. NewLayaDecision(LangChain), LlamaIndex selectors (laya[llamaindex]) and CrewAI routing (laya[crewai]). - Per-request token budget.
max_len/head_max_lennow reach every surface:laya-serve(capped byLAYA_MAX_TOKEN_BUDGET),Router.predict_batchrequests, the CLI (--questions,--max-len,--head-max-len), MCP tools and LangChain nodes. - Operations.
LAYA_MAX_LOADED,LAYA_REVISIONand per-checkpoint SHA-256 maps;/healthreports the device a checkpoint really runs on and its CPU-fallback count; the 503 busy answer carriesRetry-After;compile=Trueno longer recompiles for every request shape. - Stricter inputs. A null or duplicate
choicelabel, a short temperature list, aNonestate and non-dict questions are refused with a message that names them, andusage["options"]says when the head budget left two options with the same tokens.
Laya evaluates typed questions (choice, score, noul) over text, email, tickets or JSON
documents in a forward pass. Archived T4 measurements were 33 ms for one question and
7.2 ms/question batched. It returns typed decisions without generating text; predictions
can still be wrong.
Three checkpoints, and a Router that picks between them per request:
| encoder | params | context | use it for | |
|---|---|---|---|---|
laya |
ModernBERT-large | 421M | 512 | English |
laya-multilingual |
mmBERT-base | 322M | 1024 (up to 8,192) | 100+ languages, 2x faster |
laya-typed-decisions |
ModernBERT-large | 421M | 1024 | the typed-decisions workflows |