repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/gratis/__bench__/gratis.bench.ts
Rawimport { createServer } from "node:http";
import type { AddressInfo } from "node:net";
import type {
Api,
AssistantMessageEventStream,
Model,
Provider,
TranscriptContext,
} from "@earendil-works/pi-ai";
import { openAICompletionsApi } from "@earendil-works/pi-ai/compat";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { createGratis } from "../index.ts";
import { parseLiveCatalog } from "../src/catalog.ts";
const ROUNDS = 12;
const MINIMUM_ROUND_NS = 200_000_000;
const STREAM_CHUNKS = 512;
let sink = 0;
/** Catalog shaped like live Kilo/OpenRouter: ~400 entries, a few dozen free. */
function livePayload(total: number, free: number) {
return {
data: Array.from({ length: total }, (_, index) => ({
id:
index === 0
? "kilo-auto/free"
: index === 1
? "openrouter/free"
: index < free
? `vendor/model-${index}:free`
: `vendor/model-${index}`,
name: `Model ${index}`,
context_length: 262_144,
pricing:
index < free
? { prompt: "0", completion: "0" }
: { prompt: "0.000001", completion: "0.000002" },
architecture: {
input_modalities: ["text", "image"],
output_modalities: ["text"],
},
top_provider: { context_length: 262_144, max_completion_tokens: 32_768 },
supported_parameters: ["tools", "reasoning", "max_tokens"],
description: "x".repeat(400),
})),
};
}
const kiloPayload = livePayload(400, 16);
const openrouterPayload = livePayload(460, 17);
/**
* Discrete SSE frames per backend API, written one `data:` line at a time like
* the test suite's fake upstream. Each parser must see its own native format:
* OpenAI ends with a `[DONE]` sentinel; the Google adapter (`@google/genai`)
* has no `[DONE]` guard and JSON.parses every data line, so feeding it OpenAI
* frames made `grts/auto`'s first hop (google) throw and abort the cascade.
*/
function openaiFrames(chunks: number): string[] {
const frame = (delta: unknown, finish: string | null) =>
JSON.stringify({
id: "c",
object: "chat.completion.chunk",
created: 0,
model: "m",
choices: [{ index: 0, delta, finish_reason: finish }],
...(finish
? {
usage: {
prompt_tokens: 3,
completion_tokens: chunks,
total_tokens: 3 + chunks,
},
}
: {}),
});
const frames = [frame({ role: "assistant", content: "" }, null)];
for (let index = 0; index < chunks; index++)
frames.push(frame({ content: "token " }, null));
frames.push(frame({}, "stop"), "[DONE]");
return frames;
}
function googleFrames(chunks: number): string[] {
const frame = (text: string, finish: boolean) =>
JSON.stringify({
candidates: [
{
content: { parts: [{ text }], role: "model" },
index: 0,
...(finish ? { finishReason: "STOP" } : {}),
},
],
...(finish
? {
usageMetadata: {
promptTokenCount: 3,
candidatesTokenCount: chunks,
totalTokenCount: 3 + chunks,
},
}
: {}),
});
const frames: string[] = [];
for (let index = 0; index < chunks; index++)
frames.push(frame("token ", false));
frames.push(frame("", true));
return frames;
}
async function startUpstream() {
const openai = openaiFrames(STREAM_CHUNKS);
const google = googleFrames(STREAM_CHUNKS);
const server = createServer((request, response) => {
request.resume();
request.on("end", () => {
// The Google adapter targets `:streamGenerateContent`; everyone else is OpenAI-shaped.
const frames = (request.url ?? "").includes("streamGenerateContent")
? google
: openai;
response.writeHead(200, { "content-type": "text/event-stream" });
for (const data of frames) response.write(`data: ${data}\n\n`);
response.end();
});
});
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
const base = `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
return { base, close: () => server.close() };
}
/** Load gratis against a minimal Pi API and seed its live catalogs. */
async function loadProvider(resolveUrl: (url: string) => string) {
let provider: Provider | undefined;
const pi = {
registerProvider(registered: Provider) {
provider = registered;
},
registerCommand() {},
on() {},
} as unknown as ExtensionAPI;
createGratis({ resolveUrl })(pi);
if (!provider?.refreshModels) throw new Error("gratis did not register");
const stored = [
...parseLiveCatalog("kilo", kiloPayload),
...parseLiveCatalog("openrouter", openrouterPayload),
];
await provider.refreshModels({
stored: { models: stored },
allowNetwork: false,
signal: new AbortController().signal,
publish: async (publication) => {
publication.update?.();
return true;
},
});
return provider;
}
function benchmark(name: string, operation: () => void): void {
for (let index = 0; index < 3; index++) operation();
let iterations = 1;
while (true) {
const started = process.hrtime.bigint();
for (let index = 0; index < iterations; index++) operation();
if (Number(process.hrtime.bigint() - started) >= MINIMUM_ROUND_NS) break;
iterations *= 2;
}
for (let round = 0; round < ROUNDS; round++) {
const started = process.hrtime.bigint();
for (let index = 0; index < iterations; index++) operation();
const elapsed = Number(process.hrtime.bigint() - started);
report(name, iterations, elapsed);
}
}
async function benchmarkAsync(
name: string,
operation: () => Promise<void>,
): Promise<void> {
for (let index = 0; index < 3; index++) await operation();
let iterations = 1;
while (true) {
const started = process.hrtime.bigint();
for (let index = 0; index < iterations; index++) await operation();
if (Number(process.hrtime.bigint() - started) >= MINIMUM_ROUND_NS) break;
iterations *= 2;
}
for (let round = 0; round < ROUNDS; round++) {
const started = process.hrtime.bigint();
for (let index = 0; index < iterations; index++) await operation();
const elapsed = Number(process.hrtime.bigint() - started);
report(name, iterations, elapsed);
}
}
function report(name: string, iterations: number, elapsed: number): void {
console.log(
`Benchmark${name}\t${iterations}\t${(elapsed / iterations).toFixed(0)} ns/op`,
);
}
async function drain(stream: AssistantMessageEventStream): Promise<void> {
const message = await stream.result();
if (message.stopReason !== "stop")
throw new Error(`stream failed: ${message.errorMessage}`);
sink ^= message.content.length;
}
// Every backend keyed: the largest model set gratis can publish.
for (const name of [
"GEMINI_API_KEY",
"OPENROUTER_API_KEY",
"GROQ_API_KEY",
"MISTRAL_API_KEY",
])
process.env[name] = "bench";
const upstream = await startUpstream();
const resolveUrl = (url: string) =>
url.replace(/^https:\/\/[^/]+/, upstream.base);
const provider = await loadProvider(resolveUrl);
const models = provider.getModels() as Model<Api>[];
const find = (id: string) => {
const model = models.find((entry) => entry.id === id);
if (!model) throw new Error(`missing ${id}`);
return model;
};
const pinnedModel = find("kilo/kilo-auto/free");
const autoModel = find("auto");
const context = {
messages: [{ role: "user", content: "hi", timestamp: 0 }],
} as unknown as TranscriptContext;
const direct = openAICompletionsApi();
console.log(`goos: ${process.platform}`);
console.log(`goarch: ${process.arch}`);
console.log("pkg: pi-ext/gratis");
benchmark("GetModels", () => {
sink ^= provider.getModels().length;
});
benchmark("ParseLiveCatalog", () => {
sink ^= parseLiveCatalog("kilo", kiloPayload).length;
});
await benchmarkAsync("StreamDirect", () =>
drain(
direct.streamSimple(
{ ...pinnedModel, id: "kilo-auto/free", baseUrl: upstream.base },
context,
{ apiKey: "bench" },
),
),
);
await benchmarkAsync("StreamPinned", () =>
drain(provider.streamSimple(pinnedModel, context, {})),
);
await benchmarkAsync("StreamAuto", () =>
drain(provider.streamSimple(autoModel, context, {})),
);
upstream.close();
if (sink === 42) console.error(sink);