feat: add autonomous Surplus seller

This commit is contained in:
david
2026-08-27 12:48:18 +02:00
parent 2b8409a499
commit 732de817aa
17 changed files with 3074 additions and 2 deletions

View 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");
});
});

View 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" });
});
});

View 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 }]);
});
});

View 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");
});
});