Ctrl K
ComunidadGuías…

test/byok-transport.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";

const scratch = await mkdtemp(path.join(tmpdir(), "forge-byok-transport-"));
process.env.FORGE_CONFIG_DIR = path.join(scratch, "config");
process.env.FORGE_DB_PATH = path.join(scratch, "forge.db");
process.env.FORGE_KEY_PEPPER = "test-only-byok-budget-pepper-32-chars";
await mkdir(process.env.FORGE_CONFIG_DIR, { recursive: true });
await writeFile(path.join(process.env.FORGE_CONFIG_DIR, "models.yaml"), `
host: http://127.0.0.1:1
providers:
  paid:
    type: openai-compatible
    session_header: true
    responses_models: [paid-model]
    baseURL: https://paid.invalid/v1
    apiKey: env:PAID_API_KEY
    models: [paid-model]
roles:
  author:
    model: local-model
    num_predict: 24000
    transports:
      cloud:
        num_predict: 24000
defaults:
  max_retries: 2
  request_timeout_ms: 1000
`);

const auth = await import("../src/auth.js");
const { runAsAccount } = await import("../src/account.js");
const { setUserApiKey, testCloudConnection } = await import("../src/cloud.js");
const { setHostedForTest } = await import("../src/cloud.js");
const { BYOK_OUTPUT_CAP, byokUsage, clearByokUsage, setByokBudget } = await import("../src/byok-budget.js");
const { chat } = await import("../src/ai/ollama.js");

await auth.register({ name: "Key owner", email: "owner@example.test", password: "test-password-123" });
const userId = auth.getUserId("owner@example.test");
await setUserApiKey(userId, "paid", "sk-test-key-12345678");

const originalFetch = global.fetch;
test.after(() => {
  global.fetch = originalFetch;
  setHostedForTest(null);
  return rm(scratch, { recursive: true, force: true });
});
test.beforeEach(() => {
  clearByokUsage(userId);
  setByokBudget(userId, 180000);
  setHostedForTest(false);
});

const asOwner = (fn) => runAsAccount({ userId, email: "owner@example.test" }, fn);

test("a draft key is tested without persistence through the provider's Responses model", async () => {
  let request;
  global.fetch = async (url, init) => {
    request = { url: String(url), headers: init.headers, body: JSON.parse(init.body) };
    return new Response(JSON.stringify({
      status: "completed",
      output_text: "ok",
      usage: { input_tokens: 3, output_tokens: 1 },
    }), { status: 200, headers: { "Content-Type": "application/json" } });
  };

  const result = await asOwner(() => testCloudConnection({ key: "sk-draft-key-87654321" }));

  assert.equal(result.ok, true);
  assert.equal(result.model, "paid-model");
  assert.equal(request.url, "https://paid.invalid/v1/responses");
  assert.equal(request.body.model, "paid-model");
  assert.equal(request.body.max_output_tokens, 1);
  assert.equal(request.headers.Authorization, "Bearer sk-draft-key-87654321");
  assert.match(request.headers["x-opencode-session"], /^[0-9a-f-]{36}$/);
});

test("BYOK uses the conservative output ceiling in local and hosted mode", async () => {
  const caps = [];
  const sessions = [];
  global.fetch = async (url, init) => {
    const body = JSON.parse(init.body);
    assert.equal(String(url), "https://paid.invalid/v1/responses");
    caps.push(body.max_output_tokens);
    sessions.push(init.headers["x-opencode-session"]);
    return new Response(JSON.stringify({
      status: "completed",
      output: [{ type: "message", content: [{ type: "output_text", text: "ok" }] }],
      usage: { input_tokens: 8, output_tokens: 2 },
    }), { status: 200, headers: { "Content-Type": "application/json" } });
  };

  await asOwner(() => chat({ role: "author", model: "paid-model", messages: [{ role: "user", content: "local" }] }));
  setHostedForTest(true);
  await asOwner(() => chat({ role: "author", model: "paid-model", messages: [{ role: "user", content: "hosted" }] }));

  assert.deepEqual(caps, [BYOK_OUTPUT_CAP, BYOK_OUTPUT_CAP]);
  assert.match(sessions[0], /^[0-9a-f-]{36}$/);
  assert.notEqual(sessions[0], sessions[1]);
  assert.equal(byokUsage(userId).tokens, 20);
});

test("a failed provider attempt keeps its reserve and the next call is refused", async () => {
  setByokBudget(userId, 13000);
  let calls = 0;
  global.fetch = async () => {
    calls++;
    throw new Error("provider disconnected after accepting the request");
  };

  await assert.rejects(
    asOwner(() => chat({ role: "author", model: "paid-model", messages: [{ role: "user", content: "spend once" }] })),
    /BYOK safety budget reached/,
  );
  assert.equal(calls, 1, "the second transport attempt must be refused before fetch");
  assert.ok(byokUsage(userId).tokens >= BYOK_OUTPUT_CAP);
});

test("BYOK retries at most once even when the provider keeps failing", async () => {
  let calls = 0;
  global.fetch = async () => {
    calls++;
    throw new Error("temporary provider failure");
  };
  await assert.rejects(
    asOwner(() => chat({ role: "author", model: "paid-model", messages: [{ role: "user", content: "retry" }] })),
    /failed after 2 attempts/,
  );
  assert.equal(calls, 2);
  assert.equal(byokUsage(userId).calls, 2);
});

test("missing usage metadata is estimated instead of becoming free", async () => {
  global.fetch = async () => new Response(JSON.stringify({
    status: "completed",
    output: [{ type: "message", content: [{ type: "output_text", text: "answer without usage metadata" }] }],
  }), { status: 200, headers: { "Content-Type": "application/json" } });

  await asOwner(() => chat({ role: "author", model: "paid-model", messages: [{ role: "user", content: "hello" }] }));
  const usage = byokUsage(userId);
  assert.ok(usage.tokens > 1);
  assert.ok(usage.tokens < BYOK_OUTPUT_CAP, "a success settles below its worst-case reservation");
});