mlx-bun library API
    Preparing search index...

    Port of mlx-lm BatchRotatingKVCache; padded singleton chunks use its concat operation with the matching block mask until finalization.

    Reads: the sliding window is maxSize. Decode, which runs with no prefill padding pending (finalize first), writes one position in place at the ring head; a window writes by concatenation, which also serves padded prefill chunks of any length. Each attends with the stock fused SDPA under mlx-lm's batched rotating mask (buildBatchedRotatingMask) for its write, built once per forward through masks. The deprecated updateAndFetch picks the write from the length instead, so a one-row window without pending padding wrote in place there and concatenates here: the same bits until the ring wraps, a different key order after.

    Implements

    Index
    keys: MlxArray | null = null
    masks: AttentionMasks = ...

    The per-forward masks of the model this layout serves.

    maxSize: number
    values: MlxArray | null = null
    • Window: L new positions per row, causal within the window, for prefill chunks, prefill tails and speculative verify windows. Query i of a row sees the row's earlier valid positions and window positions 0..i, limited to the cache's sliding window. Left padding and prepared prefill padding are never visible. Outputs at padded query positions are unspecified and the caller ignores them. To append context without attending, make this call and dispose the read unused.

      Parameters

      Returns AttentionRead

    • mlx-lm BatchRotatingKVCache.extract (models/cache.py:1417): row i as a fresh SERIAL RotatingKVCache — de-rolled to temporal order (the oracle's roll(-_idx) when rotated), left padding stripped (max(0, left_padding[idx]) — post-wrap pads go negative), OWNED contiguous copies. offset = the row's absolute position (may exceed the buffer: wrapped rings have evicted tokens); ring idx = the new buffer length — temporal order ⇔ write head at the end, exactly the oracle's cache._idx = cache.keys.shape[2]. Bit-exact vs a solo run: merge/decode/filter keep each row's ring bytes identical to the serial cache's (02d723a:tests/unit/batched-rotating.test.ts) and this is a pure slice+copy.

      Parameters

      • i: number
      • Optionallimit: number

      Returns RotatingKVCache

    • Same signature as the serial RotatingKVCache — the scheduler's merge guards recognize a batched ring as "rotating-plain + RowBatchCache" (packages/inference/src/execution/batch-group.ts #mergeJoiner prevRot branch); without this the next join sees "unknown", skips the prevRot rows, and replaces the batch's sliding-layer KV with a one-row cache (B≥3 collapse). Guard order everywhere is isRowBatchCache FIRST, so the shared string never misroutes a batched cache into a serial-only path.

      Returns string

    • Drop the last n tokens (future writes overwrite them). bypass (default false → unchanged behavior) skips the isTrimmable guard for the speculative-decode rollback case (trim the last n ≤ γ tips right after a

      1 concat write); rotating caches then physically shrink the buffer tail.

      Parameters

      • n: number

      Returns void

    • Assemble a batch from per-row temporal KV slices (port of merge). Each row is its solo cache's temporalView ([1,H,Li,D], Li ≤ maxSize, temporal order) and offsets[i] its absolute position. Left-pads to the longest row; the result is in temporal order (rotated=false, idx=offset=width).

      Parameters

      • rows: { keys: MlxArray; values: MlxArray }[]
      • offsets: number[]
      • maxSize: number
      • masks: AttentionMasks = ...

      Returns BatchedRotatingCache