Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/gguf/fileReaders/GgufNetworkFetchFileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class GgufNetworkFetchFileReader extends GgufFileReader {
if (endOffset > this._buffer.length)
return this._fetchToExpandBufferUpToOffset(endOffset)
.then(() => {
if (endOffset >= this._buffer.length)
if (endOffset > this._buffer.length)
throw new Error("Expected buffer to be long enough for the requested byte range");
});

Expand Down
28 changes: 28 additions & 0 deletions test/standalone/gguf/ggufNetworkFileBoundary.test.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of building a dummy gguf and serving it, can you please just use a URL to an example gguf from HuggingFace for testing this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the synthetic server fixture with a pinned Hugging Face GGUF in 5a280387. The tests cover the final byte, a normal read and a read beyond EOF: the original reader fails only the EOF regression, and all three pass with the fix.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {describe, expect, test} from "vitest";
import {GgufNetworkFetchFileReader} from "../../../src/gguf/fileReaders/GgufNetworkFetchFileReader.js";

const remoteGGUFModel = "https://huggingface.co/ggml-org/models-moved/resolve/499bc8821c6b12b4e53c5bffcb21ec206f212d81/tinyllamas/stories260K.gguf";
const remoteGGUFModelSize = 1185376;

describe("gguf network file boundaries", () => {
test("reads the final byte after expanding the buffer to EOF", {timeout: 1000 * 60 * 10}, async () => {
const fileReader = new GgufNetworkFetchFileReader({url: remoteGGUFModel, retryOptions: {retries: 0}});

expect(await fileReader.readUint8(remoteGGUFModelSize - 1))
.toBe(63);
});

test("reads bytes before EOF", {timeout: 1000 * 60 * 10}, async () => {
const fileReader = new GgufNetworkFetchFileReader({url: remoteGGUFModel, retryOptions: {retries: 0}});

expect(await fileReader.readStringWithLength(0, 4))
.toBe("GGUF");
});

test("rejects a byte beyond EOF", {timeout: 1000 * 60 * 10}, async () => {
const fileReader = new GgufNetworkFetchFileReader({url: remoteGGUFModel, retryOptions: {retries: 0}});

await expect(fileReader.readUint8(remoteGGUFModelSize))
.rejects.toThrow("Expected buffer to be long enough for the requested byte range");
});
});