Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ docs/backlog/
.cursor/
.cursorignore
.cursorindexingignore

# Isolated HOME used by local vitest runs
.vitest-home/
49 changes: 3 additions & 46 deletions packages/core/src/cli/estimate-memory.test.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { cmdEstimateMemory, parseEstimateMemoryArgs, runEstimateMemory } from "./estimate-memory.js";
import { defaultStorePaths } from "../service/config-store.js";
import { writeMachineInfo } from "../service/machine-store.js";
import type { MachineInfo } from "../service/machine-info.js";

function writeString(buf: Buffer, offset: number, value: string): number {
const bytes = Buffer.from(value, "utf8");
buf.writeBigUInt64LE(BigInt(bytes.length), offset);
bytes.copy(buf, offset + 8);
return 8 + bytes.length;
}

function writeUint32(buf: Buffer, offset: number, value: number): number {
buf.writeUInt32LE(value, offset);
return 4;
}

function writeUint64(buf: Buffer, offset: number, value: bigint): number {
buf.writeBigUInt64LE(value, offset);
return 8;
}
import { writeMinimalGguf } from "../test-support/minimal-gguf.js";

function createMinimalGgufFile(
dir: string,
Expand All @@ -34,35 +18,8 @@ function createMinimalGgufFile(
fileSizeBytes?: number;
},
): string {
const metadata: { key: string; type: "uint32" | "string"; value: string | number }[] = [
{ key: "general.architecture", type: "string", value: "llama" },
{ key: "llama.block_count", type: "uint32", value: opts.blockCount },
{ key: "llama.embedding_length", type: "uint32", value: opts.hiddenSize },
{ key: "llama.attention.head_count", type: "uint32", value: opts.headCount },
{ key: "llama.attention.head_count_kv", type: "uint32", value: opts.headCountKv },
];
const buf = Buffer.alloc(4096);
let offset = 0;
buf.write("GGUF", offset, 4, "ascii");
offset += 4;
offset += writeUint32(buf, offset, 3);
offset += writeUint64(buf, offset, 0n);
offset += writeUint64(buf, offset, BigInt(metadata.length));
for (const entry of metadata) {
offset += writeString(buf, offset, entry.key);
buf.writeUInt32LE(entry.type === "uint32" ? 4 : 8, offset);
offset += 4;
if (entry.type === "uint32") {
offset += writeUint32(buf, offset, entry.value as number);
} else {
offset += writeString(buf, offset, entry.value as string);
}
}
const fileSize = opts.fileSizeBytes ?? 1 * 1024 * 1024;
const final = Buffer.alloc(fileSize);
buf.copy(final, 0, 0, offset);
const path = join(dir, "model.gguf");
writeFileSync(path, final);
writeMinimalGguf(path, opts);
return path;
}

Expand Down
45 changes: 3 additions & 42 deletions packages/core/src/service/gguf-memory-estimator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
estimateRecipeMemory,
findMaxFittingCtxSize,
type GgufRecipeShape,
} from "./gguf-memory-estimator.js";
import { estimateRecipeMemory, findMaxFittingCtxSize, type GgufRecipeShape } from "./gguf-memory-estimator.js";
import { writeMinimalGguf } from "../test-support/minimal-gguf.js";

function writeString(buf: Buffer, offset: number, value: string): number {
const bytes = Buffer.from(value, "utf8");
Expand Down Expand Up @@ -54,44 +51,8 @@ interface MinimalGgufOptions {
}

function createMinimalGgufFile(dir: string, opts: MinimalGgufOptions): string {
const metadata: { key: string; type: "uint32" | "string"; value: string | number }[] = [
{ key: "general.architecture", type: "string", value: "llama" },
{ key: "llama.block_count", type: "uint32", value: opts.blockCount },
{ key: "llama.embedding_length", type: "uint32", value: opts.hiddenSize },
{ key: "llama.attention.head_count", type: "uint32", value: opts.headCount },
{ key: "llama.attention.head_count_kv", type: "uint32", value: opts.headCountKv },
...(opts.vocabSize !== undefined ? [{ key: "llama.vocab_size", type: "uint32" as const, value: opts.vocabSize }] : []),
...(opts.ffnDim !== undefined ? [{ key: "llama.feed_forward_length", type: "uint32" as const, value: opts.ffnDim }] : []),
];

// Allocate generously.
const buf = Buffer.alloc(4096);
let offset = 0;

// Magic.
buf.write("GGUF", offset, 4, "ascii");
offset += 4;
// Version.
offset += writeUint32(buf, offset, 3);
// Tensor count.
offset += writeUint64(buf, offset, 0n);
// KV count.
offset += writeUint64(buf, offset, BigInt(metadata.length));

for (const entry of metadata) {
if (entry.type === "uint32") {
offset += writeKvUint32(buf, offset, entry.key, entry.value as number);
} else {
offset += writeKvString(buf, offset, entry.key, entry.value as string);
}
}

const fileSize = opts.fileSizeBytes ?? 1024 * 1024 * 1024; // 1 GB default dummy weight file.
// Pad the file to the requested size so statSync returns the expected size.
const path = join(dir, "model.gguf");
const final = Buffer.alloc(fileSize);
buf.copy(final, 0, 0, offset);
writeFileSync(path, final);
writeMinimalGguf(path, opts);
return path;
}

Expand Down
55 changes: 6 additions & 49 deletions packages/core/src/service/machine-overlay.test.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,11 @@
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { LLAMA_CPP_DEFAULTS, type ResolvedLlamaFlags } from "../mba/index.js";
import type { MachineInfo } from "./machine-info.js";
import { applyMachineOverlay } from "./machine-overlay.js";

function writeString(buf: Buffer, offset: number, value: string): number {
const bytes = Buffer.from(value, "utf8");
buf.writeBigUInt64LE(BigInt(bytes.length), offset);
bytes.copy(buf, offset + 8);
return 8 + bytes.length;
}

function writeUint32(buf: Buffer, offset: number, value: number): number {
buf.writeUInt32LE(value, offset);
return 4;
}

function writeUint64(buf: Buffer, offset: number, value: bigint): number {
buf.writeBigUInt64LE(value, offset);
return 8;
}
import { writeMinimalGguf } from "../test-support/minimal-gguf.js";

function createMinimalGgufFile(
dir: string,
Expand All @@ -33,38 +17,11 @@ function createMinimalGgufFile(
fileSizeBytes?: number;
},
): string {
const metadata: { key: string; type: "uint32" | "string"; value: string | number }[] = [
{ key: "general.architecture", type: "string", value: "llama" },
{ key: "llama.block_count", type: "uint32", value: opts.blockCount },
{ key: "llama.embedding_length", type: "uint32", value: opts.hiddenSize },
{ key: "llama.attention.head_count", type: "uint32", value: opts.headCount },
{ key: "llama.attention.head_count_kv", type: "uint32", value: opts.headCountKv },
];
const buf = Buffer.alloc(4096);
let offset = 0;
buf.write("GGUF", offset, 4, "ascii");
offset += 4;
offset += writeUint32(buf, offset, 3);
offset += writeUint64(buf, offset, 0n);
offset += writeUint64(buf, offset, BigInt(metadata.length));
for (const entry of metadata) {
if (entry.type === "uint32") {
offset += writeString(buf, offset, entry.key);
buf.writeUInt32LE(4, offset);
offset += 4;
offset += writeUint32(buf, offset, entry.value as number);
} else {
offset += writeString(buf, offset, entry.key);
buf.writeUInt32LE(8, offset);
offset += 4;
offset += writeString(buf, offset, entry.value as string);
}
}
const fileSize = opts.fileSizeBytes ?? 1024 * 1024 * 1024;
const final = Buffer.alloc(fileSize);
buf.copy(final, 0, 0, offset);
const path = join(dir, "model.gguf");
writeFileSync(path, final);
writeMinimalGguf(path, {
...opts,
fileSizeBytes: opts.fileSizeBytes ?? 1024 * 1024 * 1024,
});
return path;
}

Expand Down
94 changes: 30 additions & 64 deletions packages/core/src/service/model-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
* current dial values, and validated single-field writes (atomic, with
* before/after reporting and the restartRequired flag).
*/
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, it, expect, beforeEach } from "vitest";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { writeMinimalGguf } from "../test-support/minimal-gguf.js";
import {
findModelFiles,
notesPreview,
Expand Down Expand Up @@ -67,68 +68,11 @@ function writeFixture(root: string): void {
);
}

function writeString(buf: Buffer, offset: number, value: string): number {
const bytes = Buffer.from(value, "utf8");
buf.writeBigUInt64LE(BigInt(bytes.length), offset);
bytes.copy(buf, offset + 8);
return 8 + bytes.length;
}

function writeUint32(buf: Buffer, offset: number, value: number): number {
buf.writeUInt32LE(value, offset);
return 4;
}

function writeUint64(buf: Buffer, offset: number, value: bigint): number {
buf.writeBigUInt64LE(value, offset);
return 8;
}

function writeKvUint32(buf: Buffer, offset: number, key: string, value: number): number {
let written = 0;
written += writeString(buf, offset + written, key);
buf.writeUInt32LE(4, offset + written); // GGUF value type uint32
written += 4;
written += writeUint32(buf, offset + written, value);
return written;
}

function createMinimalGgufFile(path: string, opts: { blockCount: number; hiddenSize: number; headCount: number; headCountKv: number; fileSizeBytes?: number }): void {
const metadata: { key: string; value: number | string; type: "uint32" | "string" }[] = [
{ key: "general.architecture", value: "llama", type: "string" },
{ key: "llama.block_count", value: opts.blockCount, type: "uint32" },
{ key: "llama.embedding_length", value: opts.hiddenSize, type: "uint32" },
{ key: "llama.attention.head_count", value: opts.headCount, type: "uint32" },
{ key: "llama.attention.head_count_kv", value: opts.headCountKv, type: "uint32" },
];
const buf = Buffer.alloc(4096);
let offset = 0;
buf.write("GGUF", offset, 4, "ascii");
offset += 4;
offset += writeUint32(buf, offset, 3);
offset += writeUint64(buf, offset, 0n);
offset += writeUint64(buf, offset, BigInt(metadata.length));
for (const entry of metadata) {
offset += writeString(buf, offset, entry.key);
buf.writeUInt32LE(entry.type === "uint32" ? 4 : 8, offset);
offset += 4;
if (entry.type === "uint32") {
offset += writeUint32(buf, offset, entry.value as number);
} else {
offset += writeString(buf, offset, entry.value as string);
}
}
const fileSize = opts.fileSizeBytes ?? 1 * 1024 * 1024;
const final = Buffer.alloc(fileSize);
buf.copy(final, 0, 0, offset);
writeFileSync(path, final);
}

function writeMachineHintFixture(root: string): void {
const modelDir = join(root, "tiny", "tiny-model");
mkdirSync(modelDir, { recursive: true });
const modelPath = join(modelDir, "tiny.gguf");
createMinimalGgufFile(modelPath, {
writeMinimalGguf(modelPath, {
blockCount: 8,
hiddenSize: 512,
headCount: 8,
Expand Down Expand Up @@ -166,6 +110,10 @@ describe("findModelFiles", () => {
writeFixture(root);
});

afterEach(() => {
rmSync(root, { recursive: true, force: true });
});

it("locates the yaml, server_setup.json (via binding), and env overrides", () => {
const files = findModelFiles(root, "qwen3.8-27b");
expect(files).not.toBeNull();
Expand Down Expand Up @@ -193,6 +141,10 @@ describe("readModelDials", () => {
writeFixture(root);
});

afterEach(() => {
rmSync(root, { recursive: true, force: true });
});

it("reads current values for server_setup and client fields", () => {
const dials = readModelDials(root, "qwen3.8-27b");
expect(dials).not.toBeNull();
Expand Down Expand Up @@ -312,8 +264,14 @@ function writeShelfTree(adapterDir: string, opts?: { emptyNotes?: boolean; model
}

describe("readModelShelf", () => {
let root: string;

afterEach(() => {
rmSync(root, { recursive: true, force: true });
});

it("returns the model notes when the model file exists", () => {
const root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
const adapterDir = join(root, "mba", "adapters");
writeShelfTree(adapterDir);
const shelf = readModelShelf(adapterDir, "qwen3-coder-30b");
Expand All @@ -328,7 +286,7 @@ describe("readModelShelf", () => {
});

it("marks an empty stub empty", () => {
const root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
const adapterDir = join(root, "mba", "adapters");
writeShelfTree(adapterDir, { emptyNotes: true });
const shelf = readModelShelf(adapterDir, "qwen3-coder-30b");
Expand All @@ -338,7 +296,7 @@ describe("readModelShelf", () => {
});

it("inherits family notes when the model yaml omits the binding", () => {
const root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
const adapterDir = join(root, "mba", "adapters");
writeShelfTree(adapterDir, { modelNotes: false });
const shelf = readModelShelf(adapterDir, "qwen3-coder-30b");
Expand All @@ -348,7 +306,7 @@ describe("readModelShelf", () => {
});

it("returns null for an unknown model", () => {
const root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
root = mkdtempSync(join(tmpdir(), "mba-shelf-"));
const adapterDir = join(root, "mba", "adapters");
writeShelfTree(adapterDir);
expect(readModelShelf(adapterDir, "nope")).toBeNull();
Expand All @@ -363,6 +321,10 @@ describe("readModelDials machine hints", () => {
writeFixture(root);
});

afterEach(() => {
rmSync(root, { recursive: true, force: true });
});

it("includes machine-aware hints when machine info is provided", () => {
writeMachineHintFixture(root);
const machine: MachineInfo = {
Expand Down Expand Up @@ -439,6 +401,10 @@ describe("setModelDial", () => {
modelDir = join(root, "qwen", "qwen3.8-27b");
});

afterEach(() => {
rmSync(root, { recursive: true, force: true });
});

it("writes a server_setup field atomically and reports before/after", () => {
const result = setModelDial(root, "qwen3.8-27b", "server_setup", "ctxSize", 120000);
expect(result).toEqual({
Expand Down
Loading
Loading