GGUF support and a composable weight inspector panel. One breaking change to ModelGraph.

Breaking

ModelGraph.weights is a discriminated union; hasExternalWeights is gone.

// before
if (graph.weights) graph.weights.get(name);
if (graph.hasExternalWeights) showExternalWeightsPrompt();

// after
if (graph.weights?.kind === "available") graph.weights.source.get(name);
if (graph.weights?.kind === "external") showExternalWeightsPrompt(graph.weights.format);

The external variant names the format ("savedmodel" | "onnx"), so a host app can pick the right checkpoint or external-data loader instead of guessing. See Weights.

decodeWeight returns a wider type. DecodedWeight is now Float64Array | Int32Array | Uint32Array | BigInt64Array | BigUint64Array. uint32 decodes to Uint32Array and uint64 to BigUint64Array. Before, both went into the signed arrays, and any value above the signed maximum came back negative. numericView() still collapses any of them into one numeric array.

@wetron/svelte moved ExportHelpers from ./export-helper.svelte to ./export-helper.ts. Import it from the package root: import type { ExportHelpers } from "@wetron/svelte".

Package metadata: homepage and repository point at GitHub, not Codeberg. llms.md no longer ships in the npm tarballs.

Added

GGUF - @wetron/gguf

New parser package, wired into detectFormat and parseModel. It reads:

  • v2 and v3 headers, little- and big-endian
  • every metadata scalar, string, and array value type, including tokenizer vocabularies, special token IDs, and chat templates
  • quantization metadata, with a readable general.file_type_name
  • every tensor name, shape, and GGML type

The parser groups standardized tensor names into embedding, attention, feed-forward, state-space, transformer-block, and output stages. For little-endian files, graph.weights.source.get(name) returns a zero-copy view into the source buffer. Q4_0 decodes to values; other quantization types keep their descriptors and raw bytes but have no value preview yet. Big-endian files expose descriptors only. See GGUF.

Weight inspectors

Select an initializer and the panel decodes its bytes on demand, then offers the views that fit the tensor: matrix, distribution, axis profile, sparsity, kernel gallery, quantization (Q4_0), diagnostics, and raw values. Both @wetron/react and @wetron/svelte ship them, and every control carries hint text resolved against the selected tensor.

The panel is composable. WeightPanel takes children, DefaultWeightInspectors renders the stock picker plus views, and useWeightInspection() (React) / getWeightInspection() (Svelte) hands a custom inspector the decoded tensor:

<WeightPanel target={target} graph={graph}>
  <DefaultWeightInspectors />
  <MyInspector />
</WeightPanel>

The computation lives in @wetron/core, each piece on its own subpath so a host app can use it without the UI: tensor-index, tensor-slice, weight-distribution, weight-axis-stats, weight-sparsity, weight-kernel, weight-quantization, weight-diagnostics, inspector-hints.

Other additions

  • TensorOrder ("row-major" | "col-major") on ModelGraph.initializers entries. GGUF payloads are col-major; absent means row-major.
  • filterGraph(graph, query) in @wetron/core - returns the IDs of nodes whose op type or name matches the query.
  • elementSize and numericView exported from @wetron/core.
  • Flow node types GraphFlowNode, IoFlowNode, IoNodeData, GraphOperationNodeData.
  • attrNeedsExpand in @wetron/core/panel-utils - a short array still needs expanding when one of its items is long, as GGUF chat templates usually are.

Fixed

  • Svelte: clicking a node’s scope row opens its sub-graph. The row is a real button now, and the nav stack uses $state.raw, so @xyflow/svelte no longer warns about deeply reactive nodes.
  • Axis stats and diagnostics read the wrong slices for col-major tensors.
  • GGML scalar dtype names (F32, F16, BF16, I8-I64) decode, and GGML integer types format as integers rather than floats.
  • Long attribute items truncate in the brief rendering instead of overflowing the row.
  • Quantization blocks decode lazily, so opening the quantization inspector on a large tensor no longer materializes every block.
  • Keras: a failed model.weights.h5 load emits a keras-weight-load-failed warning instead of silently returning a weightless graph.
  • ONNX external data: the loader validates offset and length as non-negative safe integers, and raises ParseError at load time for a slice that runs past its buffer instead of returning short data.

Internal

  • TFLite parsing uses the shared @wetron/common/flatbuffers helpers instead of a local copy of the vtable readers.
  • elementSize lives in core; the duplicate React and Svelte copies are gone.
  • The React bundle externalizes peers and @wetron/* subpaths by predicate, so a new deep import can’t get silently bundled.
  • oxfmt replaces prettier, with an .editorconfig at 2-space indent.
  • Docs: GGUF format page, refreshed screenshots.