feat: add autonomous Surplus seller
This commit is contained in:
225
tests/unit/surplus-client.test.ts
Normal file
225
tests/unit/surplus-client.test.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { SurplusClient } from "../../supplier/src/surplus/client.js";
|
||||
|
||||
const SELLER_KEY = "si_seller_test_only";
|
||||
const PROVIDER_KEY = "sk-or-v1-test-only";
|
||||
|
||||
function ndjsonResponse(chunks: string[]): Response {
|
||||
const encoder = new TextEncoder();
|
||||
const body = new ReadableStream<Uint8Array>({
|
||||
start(controller) {
|
||||
for (const chunk of chunks) controller.enqueue(encoder.encode(chunk));
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
return new Response(body, {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/x-ndjson" },
|
||||
});
|
||||
}
|
||||
|
||||
function discoveryRow(model: string, providerModelId: string): string {
|
||||
return JSON.stringify({
|
||||
model,
|
||||
supported: true,
|
||||
pricing: {
|
||||
input_per_1m: 0.07952,
|
||||
output_per_1m: 0.15904,
|
||||
price_unit: "M",
|
||||
price_variable: false,
|
||||
},
|
||||
metadata: {
|
||||
provider_model_id: providerModelId,
|
||||
model_type: "text",
|
||||
availability_status: "available",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe("SurplusClient", () => {
|
||||
it("authenticates and parses fragmented NDJSON discovery", async () => {
|
||||
const first = discoveryRow("alpha", "vendor/alpha");
|
||||
const second = discoveryRow("beta", "vendor/beta");
|
||||
const fetchFn = vi.fn(async (_url: string | URL | Request, init?: RequestInit) => {
|
||||
const headers = new Headers(init?.headers);
|
||||
expect(headers.get("authorization")).toBe(`Bearer ${SELLER_KEY}`);
|
||||
expect(JSON.parse(String(init?.body))).toEqual({
|
||||
api_key: PROVIDER_KEY,
|
||||
base_url: "https://openrouter.ai/api/v1",
|
||||
});
|
||||
return ndjsonResponse([
|
||||
first.slice(0, 25),
|
||||
`${first.slice(25)}\r\n\r\n${second.slice(0, 11)}`,
|
||||
second.slice(11),
|
||||
]);
|
||||
});
|
||||
const client = new SurplusClient({
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: SELLER_KEY,
|
||||
timeoutMs: 1_000,
|
||||
fetchFn,
|
||||
});
|
||||
|
||||
const result = await client.discoverModels(
|
||||
PROVIDER_KEY,
|
||||
"https://openrouter.ai/api/v1",
|
||||
);
|
||||
|
||||
expect(result.map((model) => [model.model, model.providerModelId])).toEqual([
|
||||
["alpha", "vendor/alpha"],
|
||||
["beta", "vendor/beta"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("rejects one malformed discovery line without returning a partial catalog", async () => {
|
||||
const client = new SurplusClient({
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: SELLER_KEY,
|
||||
timeoutMs: 1_000,
|
||||
fetchFn: async () => ndjsonResponse([
|
||||
`${discoveryRow("alpha", "vendor/alpha")}\n`,
|
||||
'{"model":"truncated"',
|
||||
]),
|
||||
});
|
||||
|
||||
await expect(client.discoverModels(PROVIDER_KEY, "https://openrouter.ai/api/v1"))
|
||||
.rejects.toThrow("line 2 was not complete JSON");
|
||||
});
|
||||
|
||||
it("follows every seller-offer page and normalizes micro-USD prices", async () => {
|
||||
const requested: string[] = [];
|
||||
const fetchFn = vi.fn(async (url: string | URL | Request) => {
|
||||
const value = String(url);
|
||||
requested.push(value);
|
||||
if (value.includes("next_token=page-2")) {
|
||||
return Response.json({
|
||||
items: [{
|
||||
offer_id: "offer-2",
|
||||
model: "beta",
|
||||
seller_base_url: "https://openrouter.ai/api/v1",
|
||||
status: "inactive",
|
||||
cap_daily_usd: 1,
|
||||
price_input_per_1m: 4_100,
|
||||
price_output_per_1m: 8_200,
|
||||
}],
|
||||
next_token: null,
|
||||
});
|
||||
}
|
||||
return Response.json({
|
||||
items: [{
|
||||
id: "offer-1",
|
||||
model: "alpha",
|
||||
seller_base_url: "https://openrouter.ai/api/v1",
|
||||
status: "active",
|
||||
cap_daily_usd: 1,
|
||||
price_input_per_1m: 3_972,
|
||||
price_output_per_1m: 7_944,
|
||||
}],
|
||||
next_token: "page-2",
|
||||
});
|
||||
});
|
||||
const client = new SurplusClient({
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: SELLER_KEY,
|
||||
timeoutMs: 1_000,
|
||||
fetchFn,
|
||||
});
|
||||
|
||||
const result = await client.listAllOffers();
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: "offer-1",
|
||||
status: "active",
|
||||
inputMicroUsdPer1m: 3_972,
|
||||
outputMicroUsdPer1m: 7_944,
|
||||
});
|
||||
expect(requested[1]).toContain("next_token=page-2");
|
||||
});
|
||||
|
||||
it("fails closed when offer pagination repeats a token", async () => {
|
||||
const client = new SurplusClient({
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: SELLER_KEY,
|
||||
timeoutMs: 1_000,
|
||||
fetchFn: async () => Response.json({ items: [], next_token: "same" }),
|
||||
});
|
||||
|
||||
await expect(client.listAllOffers()).rejects.toThrow("repeated a next_token");
|
||||
});
|
||||
|
||||
it("normalizes live market envelopes and effective micro-USD fields", async () => {
|
||||
const fetchFn = vi.fn(async (url: string | URL | Request) => {
|
||||
if (String(url).endsWith("/api/markets")) {
|
||||
return Response.json({ markets: [{
|
||||
model: "alpha:model",
|
||||
requests_24h: 100,
|
||||
volume_24h: 1_000,
|
||||
best_input_per_1m: 3_976,
|
||||
best_output_per_1m: 7_952,
|
||||
healthy_seller_count: 2,
|
||||
}] });
|
||||
}
|
||||
return Response.json({
|
||||
model: "alpha:model",
|
||||
offers: [{
|
||||
id: "external",
|
||||
seller: "0x2222222222222222222222222222222222222222",
|
||||
seller_base_url: "https://openrouter.ai/api/v1",
|
||||
effective_input_per_1m: 3_976,
|
||||
effective_output_per_1m: 7_952,
|
||||
available: true,
|
||||
healthy: true,
|
||||
trusted: true,
|
||||
trades_24h: 7,
|
||||
}],
|
||||
});
|
||||
});
|
||||
const client = new SurplusClient({
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: SELLER_KEY,
|
||||
timeoutMs: 1_000,
|
||||
fetchFn,
|
||||
});
|
||||
|
||||
expect(await client.getMarkets()).toEqual([expect.objectContaining({
|
||||
model: "alpha:model",
|
||||
bestInputMicroUsdPer1m: 3_976,
|
||||
})]);
|
||||
expect(await client.getOrderBook("alpha:model")).toEqual({
|
||||
model: "alpha:model",
|
||||
offers: [expect.objectContaining({ id: "external", trades24h: 7 })],
|
||||
});
|
||||
expect(String(fetchFn.mock.calls[1][0])).toContain("alpha%3Amodel");
|
||||
});
|
||||
|
||||
it("sends one absolute PATCH with plain USD prices and the cap", async () => {
|
||||
let request: RequestInit | undefined;
|
||||
const client = new SurplusClient({
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: SELLER_KEY,
|
||||
timeoutMs: 1_000,
|
||||
fetchFn: async (_url, init) => {
|
||||
request = init;
|
||||
return Response.json({ ok: true });
|
||||
},
|
||||
});
|
||||
|
||||
await client.updateOffer("offer/one", {
|
||||
inputUsdPer1m: 0.003972,
|
||||
outputUsdPer1m: 0.007944,
|
||||
dailyCapUsd: 1,
|
||||
idempotencyKey: "mutation-1",
|
||||
});
|
||||
|
||||
expect(request?.method).toBe("PATCH");
|
||||
expect(JSON.parse(String(request?.body))).toEqual({
|
||||
pricing_mode: "per_token",
|
||||
price_input_per_1m: 0.003972,
|
||||
price_output_per_1m: 0.007944,
|
||||
cap_daily_usd: 1,
|
||||
});
|
||||
const headers = new Headers(request?.headers);
|
||||
expect(headers.get("idempotency-key")).toBe("mutation-1");
|
||||
});
|
||||
});
|
||||
283
tests/unit/surplus-controller.test.ts
Normal file
283
tests/unit/surplus-controller.test.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { SurplusManagerConfig } from "../../supplier/src/surplus/config.js";
|
||||
import {
|
||||
SurplusSellerController,
|
||||
type SurplusControllerClient,
|
||||
} from "../../supplier/src/surplus/controller.js";
|
||||
import {
|
||||
SurplusHttpError,
|
||||
type SurplusDiscoveredModel,
|
||||
type SurplusOffer,
|
||||
type SurplusOfferPatch,
|
||||
type SurplusOfferWrite,
|
||||
} from "../../supplier/src/surplus/client.js";
|
||||
import type { OpenRouterKeyAllowance } from "../../supplier/src/surplus/openRouterKey.js";
|
||||
import type {
|
||||
SurplusControllerState,
|
||||
SurplusStateStore,
|
||||
} from "../../supplier/src/surplus/state.js";
|
||||
|
||||
const SELLER_WALLET = "0x1111111111111111111111111111111111111111";
|
||||
|
||||
function config(): SurplusManagerConfig {
|
||||
return {
|
||||
live: true,
|
||||
apiBaseUrl: "https://api.surplusintelligence.ai",
|
||||
sellerApiKey: "si_seller_test",
|
||||
providerApiKey: "sk-or-v1-test",
|
||||
providerBaseUrl: "https://openrouter.ai/api/v1",
|
||||
capacityBaseUrl: "https://openrouter.ai/api",
|
||||
perOfferCapUsd: "1.00",
|
||||
aggregateCapUsd: "1.00",
|
||||
sellerWallet: SELLER_WALLET,
|
||||
payoutAddress: SELLER_WALLET,
|
||||
maxCandidateOrderBooks: 10,
|
||||
reserveUsd: "1.00",
|
||||
maxProviderLimitUsd: "20.00",
|
||||
recoveryBps: 490,
|
||||
undercutBps: 10,
|
||||
pollIntervalMs: 300_000,
|
||||
requestTimeoutMs: 120_000,
|
||||
stopAfterTrades: 1,
|
||||
statePath: "/tmp/surplus-test-state.json",
|
||||
port: 8080,
|
||||
};
|
||||
}
|
||||
|
||||
class MemoryStateStore implements SurplusStateStore {
|
||||
state: SurplusControllerState = { version: 1, phase: "selecting" };
|
||||
|
||||
async load(): Promise<SurplusControllerState> {
|
||||
return structuredClone(this.state);
|
||||
}
|
||||
|
||||
async save(state: SurplusControllerState): Promise<void> {
|
||||
this.state = structuredClone(state);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeSurplusClient implements SurplusControllerClient {
|
||||
offer: SurplusOffer | null = null;
|
||||
trades24h = 0;
|
||||
settled = false;
|
||||
createCalls = 0;
|
||||
pauseCalls = 0;
|
||||
externalCalls = 0;
|
||||
createError: Error | null = null;
|
||||
discoveryError: Error | null = null;
|
||||
createdPayload: SurplusOfferWrite | null = null;
|
||||
patchPayload: SurplusOfferPatch | null = null;
|
||||
|
||||
async listAllOffers(): Promise<SurplusOffer[]> {
|
||||
this.externalCalls += 1;
|
||||
return this.offer ? [{ ...this.offer }] : [];
|
||||
}
|
||||
|
||||
async discoverModels(): Promise<SurplusDiscoveredModel[]> {
|
||||
this.externalCalls += 1;
|
||||
if (this.discoveryError) throw this.discoveryError;
|
||||
return [{
|
||||
model: "beta-model",
|
||||
providerModelId: "vendor/beta-model",
|
||||
supported: true,
|
||||
inputUsdPer1m: 0.07952,
|
||||
outputUsdPer1m: 0.15904,
|
||||
priceUnit: "M",
|
||||
priceVariable: false,
|
||||
modelType: "text",
|
||||
availabilityStatus: "available",
|
||||
}];
|
||||
}
|
||||
|
||||
async getMarkets() {
|
||||
this.externalCalls += 1;
|
||||
return [{
|
||||
model: "beta-model",
|
||||
requests24h: 100,
|
||||
volume24h: 1_000,
|
||||
bestInputMicroUsdPer1m: 3_976,
|
||||
bestOutputMicroUsdPer1m: 7_952,
|
||||
healthySellerCount: 1,
|
||||
}];
|
||||
}
|
||||
|
||||
async getOrderBook(model: string) {
|
||||
this.externalCalls += 1;
|
||||
const offers = [{
|
||||
id: "external",
|
||||
seller: "0x2222222222222222222222222222222222222222",
|
||||
sellerBaseUrl: "https://openrouter.ai/api/v1",
|
||||
inputMicroUsdPer1m: 3_976,
|
||||
outputMicroUsdPer1m: 7_952,
|
||||
available: true,
|
||||
healthy: true,
|
||||
trusted: true,
|
||||
trades24h: 0,
|
||||
}];
|
||||
if (this.offer) {
|
||||
offers.push({
|
||||
id: this.offer.id,
|
||||
seller: SELLER_WALLET,
|
||||
sellerBaseUrl: this.offer.sellerBaseUrl,
|
||||
inputMicroUsdPer1m: this.offer.inputMicroUsdPer1m ?? 3_972,
|
||||
outputMicroUsdPer1m: this.offer.outputMicroUsdPer1m ?? 7_944,
|
||||
available: this.offer.status === "active",
|
||||
healthy: true,
|
||||
trusted: true,
|
||||
trades24h: this.trades24h,
|
||||
});
|
||||
}
|
||||
return { model, offers };
|
||||
}
|
||||
|
||||
async testConnection(): Promise<number> {
|
||||
this.externalCalls += 1;
|
||||
return 10;
|
||||
}
|
||||
|
||||
async createOffer(input: SurplusOfferWrite): Promise<string> {
|
||||
this.externalCalls += 1;
|
||||
this.createCalls += 1;
|
||||
this.createdPayload = input;
|
||||
if (this.createError) throw this.createError;
|
||||
this.offer = {
|
||||
id: "managed-offer",
|
||||
model: input.model,
|
||||
sellerBaseUrl: input.sellerBaseUrl,
|
||||
status: "active",
|
||||
capDailyUsd: input.dailyCapUsd,
|
||||
inputMicroUsdPer1m: Math.round(input.inputUsdPer1m * 1_000_000),
|
||||
outputMicroUsdPer1m: Math.round(input.outputUsdPer1m * 1_000_000),
|
||||
};
|
||||
return this.offer.id;
|
||||
}
|
||||
|
||||
async updateOffer(_id: string, patch: SurplusOfferPatch): Promise<void> {
|
||||
this.externalCalls += 1;
|
||||
this.patchPayload = patch;
|
||||
if (!this.offer) throw new Error("missing fake offer");
|
||||
this.offer.inputMicroUsdPer1m = Math.round(patch.inputUsdPer1m * 1_000_000);
|
||||
this.offer.outputMicroUsdPer1m = Math.round(patch.outputUsdPer1m * 1_000_000);
|
||||
this.offer.capDailyUsd = patch.dailyCapUsd;
|
||||
}
|
||||
|
||||
async pauseOffer(): Promise<void> {
|
||||
this.externalCalls += 1;
|
||||
this.pauseCalls += 1;
|
||||
if (this.offer) this.offer.status = "inactive";
|
||||
}
|
||||
|
||||
async resumeOffer(): Promise<void> {
|
||||
this.externalCalls += 1;
|
||||
if (this.offer) this.offer.status = "active";
|
||||
}
|
||||
|
||||
async getEarnings() {
|
||||
this.externalCalls += 1;
|
||||
return {
|
||||
totalEarnedMicroUsd: this.settled ? 100 : 0,
|
||||
pendingMicroUsd: 0,
|
||||
paidMicroUsd: this.settled ? 100 : 0,
|
||||
recentSales: this.settled ? [{
|
||||
model: "beta-model",
|
||||
offerId: "managed-offer",
|
||||
settlementStatus: "confirmed",
|
||||
createdAt: "2026-08-27T10:00:01.000Z",
|
||||
sellerCostMicroUsd: 100,
|
||||
}] : [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const ALLOWANCE: OpenRouterKeyAllowance = {
|
||||
limitUsdNanos: 20_000_000_000n,
|
||||
remainingUsdNanos: 20_000_000_000n,
|
||||
reset: null,
|
||||
checkedAtMs: Date.parse("2026-08-27T10:00:00.000Z"),
|
||||
};
|
||||
|
||||
function controller(
|
||||
client: FakeSurplusClient,
|
||||
store: MemoryStateStore,
|
||||
): SurplusSellerController {
|
||||
let mutation = 0;
|
||||
return new SurplusSellerController({
|
||||
config: config(),
|
||||
client,
|
||||
allowance: { readAllowance: async () => ALLOWANCE },
|
||||
stateStore: store,
|
||||
now: () => Date.parse("2026-08-27T10:00:00.000Z"),
|
||||
mutationId: () => `mutation-${++mutation}`,
|
||||
});
|
||||
}
|
||||
|
||||
describe("SurplusSellerController", () => {
|
||||
it("selects a discovered model, creates one bounded offer, and stops after settlement", async () => {
|
||||
const client = new FakeSurplusClient();
|
||||
const store = new MemoryStateStore();
|
||||
const activeController = controller(client, store);
|
||||
|
||||
await activeController.runOnce();
|
||||
|
||||
expect(client.createCalls).toBe(1);
|
||||
expect(client.createdPayload).toMatchObject({
|
||||
model: "beta-model",
|
||||
inputUsdPer1m: 0.003972,
|
||||
outputUsdPer1m: 0.007944,
|
||||
dailyCapUsd: 1,
|
||||
payoutAddress: SELLER_WALLET,
|
||||
});
|
||||
expect(store.state.phase).toBe("active");
|
||||
expect(activeController.snapshot()).toMatchObject({
|
||||
ok: true,
|
||||
phase: "active",
|
||||
model: "beta-model",
|
||||
providerModelId: "vendor/beta-model",
|
||||
});
|
||||
|
||||
client.trades24h = 1;
|
||||
client.settled = true;
|
||||
await activeController.runOnce();
|
||||
|
||||
expect(client.pauseCalls).toBeGreaterThan(0);
|
||||
expect(client.offer?.status).toBe("inactive");
|
||||
expect(store.state.phase).toBe("completed");
|
||||
expect(activeController.snapshot()).toMatchObject({ ok: true, phase: "completed" });
|
||||
|
||||
const callsBeforeRestart = client.externalCalls;
|
||||
const restarted = controller(client, store);
|
||||
await restarted.start();
|
||||
expect(client.externalCalls).toBe(callsBeforeRestart);
|
||||
expect(restarted.snapshot()).toMatchObject({ ok: true, phase: "completed" });
|
||||
await restarted.stop();
|
||||
});
|
||||
|
||||
it("never retries an ambiguous create when no matching offer is visible", async () => {
|
||||
const client = new FakeSurplusClient();
|
||||
client.createError = new SurplusHttpError("network lost", null);
|
||||
const store = new MemoryStateStore();
|
||||
const activeController = controller(client, store);
|
||||
|
||||
await activeController.runOnce();
|
||||
expect(client.createCalls).toBe(1);
|
||||
expect(store.state.phase).toBe("create_pending");
|
||||
|
||||
await activeController.runOnce();
|
||||
expect(client.createCalls).toBe(1);
|
||||
expect(activeController.snapshot()).toMatchObject({ ok: false, phase: "error" });
|
||||
});
|
||||
|
||||
it("pauses the managed offer when a required pricing snapshot fails", async () => {
|
||||
const client = new FakeSurplusClient();
|
||||
const store = new MemoryStateStore();
|
||||
const activeController = controller(client, store);
|
||||
await activeController.runOnce();
|
||||
expect(client.offer?.status).toBe("active");
|
||||
|
||||
client.discoveryError = new Error("discovery unavailable");
|
||||
await activeController.runOnce();
|
||||
|
||||
expect(client.offer?.status).toBe("inactive");
|
||||
expect(activeController.snapshot()).toMatchObject({ ok: false, phase: "error" });
|
||||
});
|
||||
});
|
||||
155
tests/unit/surplus-policy.test.ts
Normal file
155
tests/unit/surplus-policy.test.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
quoteSurplusPrice,
|
||||
} from "../../supplier/src/surplus/policy.js";
|
||||
import {
|
||||
eligibleCompetitors,
|
||||
selectSurplusModelCandidates,
|
||||
} from "../../supplier/src/surplus/selection.js";
|
||||
import type {
|
||||
SurplusDiscoveredModel,
|
||||
SurplusMarketSummary,
|
||||
SurplusOrderBookOffer,
|
||||
} from "../../supplier/src/surplus/client.js";
|
||||
|
||||
function discovered(
|
||||
model: string,
|
||||
providerModelId: string,
|
||||
): SurplusDiscoveredModel {
|
||||
return {
|
||||
model,
|
||||
providerModelId,
|
||||
supported: true,
|
||||
inputUsdPer1m: 0.07952,
|
||||
outputUsdPer1m: 0.15904,
|
||||
priceUnit: "M",
|
||||
priceVariable: false,
|
||||
modelType: "text",
|
||||
availabilityStatus: "available",
|
||||
};
|
||||
}
|
||||
|
||||
function market(model: string, requests24h: number): SurplusMarketSummary {
|
||||
return {
|
||||
model,
|
||||
requests24h,
|
||||
volume24h: 1_000,
|
||||
bestInputMicroUsdPer1m: 4_052,
|
||||
bestOutputMicroUsdPer1m: 8_104,
|
||||
healthySellerCount: 1,
|
||||
};
|
||||
}
|
||||
|
||||
describe("Surplus bounded price policy", () => {
|
||||
it("uses exact recovery floors and undercuts in integer micro-USD", () => {
|
||||
const quote = quoteSurplusPrice({
|
||||
upstreamInputMicroUsdPer1m: 79_520,
|
||||
upstreamOutputMicroUsdPer1m: 159_040,
|
||||
recoveryBps: 490,
|
||||
undercutBps: 10,
|
||||
competitors: [{
|
||||
id: "external",
|
||||
inputMicroUsdPer1m: 3_976,
|
||||
outputMicroUsdPer1m: 7_952,
|
||||
}],
|
||||
});
|
||||
|
||||
expect(quote.floorInputMicroUsdPer1m).toBe(3_897);
|
||||
expect(quote.floorOutputMicroUsdPer1m).toBe(7_793);
|
||||
expect(quote.inputMicroUsdPer1m).toBe(3_972);
|
||||
expect(quote.outputMicroUsdPer1m).toBe(7_944);
|
||||
expect(quote.inputUsdPer1m).toBe(0.003972);
|
||||
expect(quote.outputUsdPer1m).toBe(0.007944);
|
||||
expect(quote.competitive).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps the recovery floor when the cheapest offer is too low", () => {
|
||||
const quote = quoteSurplusPrice({
|
||||
upstreamInputMicroUsdPer1m: 79_520,
|
||||
upstreamOutputMicroUsdPer1m: 159_040,
|
||||
recoveryBps: 490,
|
||||
undercutBps: 10,
|
||||
competitors: [{
|
||||
id: "below-floor",
|
||||
inputMicroUsdPer1m: 1_000,
|
||||
outputMicroUsdPer1m: 2_000,
|
||||
}],
|
||||
});
|
||||
|
||||
expect(quote.inputMicroUsdPer1m).toBe(3_897);
|
||||
expect(quote.outputMicroUsdPer1m).toBe(7_793);
|
||||
expect(quote.competitive).toBe(false);
|
||||
});
|
||||
|
||||
it("selects equal-price competitors with a stable total order", () => {
|
||||
const input = {
|
||||
upstreamInputMicroUsdPer1m: 100,
|
||||
upstreamOutputMicroUsdPer1m: 100,
|
||||
recoveryBps: 100,
|
||||
undercutBps: 10,
|
||||
};
|
||||
const left = { id: "left", inputMicroUsdPer1m: 100, outputMicroUsdPer1m: 300 };
|
||||
const right = { id: "right", inputMicroUsdPer1m: 200, outputMicroUsdPer1m: 200 };
|
||||
|
||||
expect(quoteSurplusPrice({ ...input, competitors: [right, left] }).competitorId)
|
||||
.toBe("left");
|
||||
expect(quoteSurplusPrice({ ...input, competitors: [left, right] }).competitorId)
|
||||
.toBe("left");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Surplus multi-model selection", () => {
|
||||
it("selects any eligible OpenRouter model by demand, not a hardcoded model", () => {
|
||||
const discovery = [
|
||||
discovered("beta-model", "vendor/beta"),
|
||||
discovered("alpha-model", "vendor/alpha"),
|
||||
{ ...discovered("deepseek-v4-flash", "deepseek/deepseek-v4-flash"), supported: false },
|
||||
];
|
||||
const markets = [market("alpha-model", 50), market("beta-model", 100)];
|
||||
|
||||
const result = selectSurplusModelCandidates(discovery, markets, 490, 10);
|
||||
|
||||
expect(result.map((candidate) => candidate.model)).toEqual([
|
||||
"beta-model",
|
||||
"alpha-model",
|
||||
]);
|
||||
expect(result[0].providerModelId).toBe("vendor/beta");
|
||||
});
|
||||
|
||||
it("resolves equal demand independently of discovery order", () => {
|
||||
const alpha = discovered("alpha-model", "vendor/alpha");
|
||||
const beta = discovered("beta-model", "vendor/beta");
|
||||
const markets = [market("alpha-model", 100), market("beta-model", 100)];
|
||||
|
||||
expect(selectSurplusModelCandidates([beta, alpha], markets, 490, 10)[0].model)
|
||||
.toBe("alpha-model");
|
||||
expect(selectSurplusModelCandidates([alpha, beta], markets, 490, 10)[0].model)
|
||||
.toBe("alpha-model");
|
||||
});
|
||||
|
||||
it("excludes unhealthy, untrusted, unavailable, and self offers", () => {
|
||||
const base: SurplusOrderBookOffer = {
|
||||
id: "external",
|
||||
seller: "0x2222222222222222222222222222222222222222",
|
||||
sellerBaseUrl: "https://openrouter.ai/api/v1",
|
||||
inputMicroUsdPer1m: 4_000,
|
||||
outputMicroUsdPer1m: 8_000,
|
||||
available: true,
|
||||
healthy: true,
|
||||
trusted: true,
|
||||
trades24h: 0,
|
||||
};
|
||||
const seller = "0x1111111111111111111111111111111111111111";
|
||||
const offers = [
|
||||
base,
|
||||
{ ...base, id: "self-id", seller },
|
||||
{ ...base, id: "managed-id" },
|
||||
{ ...base, id: "unhealthy", healthy: false },
|
||||
{ ...base, id: "untrusted", trusted: false },
|
||||
{ ...base, id: "unavailable", available: false },
|
||||
];
|
||||
|
||||
expect(eligibleCompetitors(offers, seller, new Set(["managed-id"])))
|
||||
.toEqual([{ id: "external", inputMicroUsdPer1m: 4_000, outputMicroUsdPer1m: 8_000 }]);
|
||||
});
|
||||
});
|
||||
77
tests/unit/surplus-state.test.ts
Normal file
77
tests/unit/surplus-state.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
chmod,
|
||||
mkdtemp,
|
||||
rm,
|
||||
stat,
|
||||
symlink,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
FileSurplusStateStore,
|
||||
type SurplusControllerState,
|
||||
} from "../../supplier/src/surplus/state.js";
|
||||
|
||||
const directories: string[] = [];
|
||||
|
||||
async function temporaryDirectory(): Promise<string> {
|
||||
const directory = await mkdtemp(join(tmpdir(), "surplus-state-"));
|
||||
directories.push(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(directories.splice(0).map((path) =>
|
||||
rm(path, { recursive: true, force: true })
|
||||
));
|
||||
});
|
||||
|
||||
describe("FileSurplusStateStore", () => {
|
||||
it("writes a private durable completion record and reloads its sale evidence", async () => {
|
||||
const directory = await temporaryDirectory();
|
||||
const path = join(directory, "state.json");
|
||||
const store = new FileSurplusStateStore(path);
|
||||
const state: SurplusControllerState = {
|
||||
version: 1,
|
||||
phase: "completed",
|
||||
offerId: "offer-1",
|
||||
model: "alpha-model",
|
||||
providerModelId: "vendor/alpha-model",
|
||||
tradeObservedAt: "2026-08-27T10:00:00.000Z",
|
||||
completedAt: "2026-08-27T10:00:05.000Z",
|
||||
settlement: {
|
||||
offerId: "offer-1",
|
||||
createdAt: "2026-08-27T10:00:03.000Z",
|
||||
sellerCostMicroUsd: 100,
|
||||
settlementStatus: "confirmed",
|
||||
},
|
||||
};
|
||||
|
||||
await store.save(state);
|
||||
|
||||
expect((await stat(path)).mode & 0o777).toBe(0o600);
|
||||
await expect(store.load()).resolves.toEqual(state);
|
||||
});
|
||||
|
||||
it("rejects a state symlink instead of following it", async () => {
|
||||
const directory = await temporaryDirectory();
|
||||
const target = join(directory, "target.json");
|
||||
const path = join(directory, "state.json");
|
||||
await writeFile(target, '{"version":1,"phase":"selecting"}\n', { mode: 0o600 });
|
||||
await symlink(target, path);
|
||||
|
||||
await expect(new FileSurplusStateStore(path).load()).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("rejects an existing state file with broad permissions", async () => {
|
||||
const directory = await temporaryDirectory();
|
||||
const path = join(directory, "state.json");
|
||||
await writeFile(path, '{"version":1,"phase":"selecting"}\n', { mode: 0o600 });
|
||||
await chmod(path, 0o644);
|
||||
|
||||
await expect(new FileSurplusStateStore(path).load())
|
||||
.rejects.toThrow("must not allow group or other access");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user