mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
76 lines
3.2 KiB
TypeScript
76 lines
3.2 KiB
TypeScript
import { completeSimple, type Model } from "openclaw/plugin-sdk/llm";
|
|
import { extractNonEmptyAssistantText, isLiveTestEnabled } from "openclaw/plugin-sdk/test-live";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
buildOpencodeGoLiveProviderConfig,
|
|
listOpencodeGoModelCatalogEntries,
|
|
} from "./provider-catalog.js";
|
|
|
|
const OPENCODE_GO_MODELS_URL = "https://opencode.ai/zen/go/v1/models";
|
|
const OPENCODE_API_KEY =
|
|
process.env.OPENCODE_API_KEY?.trim() || process.env.OPENCODE_ZEN_API_KEY?.trim() || "";
|
|
const LIVE = isLiveTestEnabled(["OPENCODE_GO_LIVE_TEST"]) && OPENCODE_API_KEY.length > 0;
|
|
const describeLive = LIVE ? describe : describe.skip;
|
|
|
|
type ModelsResponse = { data?: Array<{ id?: unknown; object?: unknown }> };
|
|
|
|
describeLive("OpenCode Go live dynamic catalog", () => {
|
|
it("discovers the active advertised models with trusted upstream metadata", async () => {
|
|
const response = await fetch(OPENCODE_GO_MODELS_URL, {
|
|
headers: {
|
|
accept: "application/json",
|
|
authorization: `Bearer ${OPENCODE_API_KEY}`,
|
|
"accept-encoding": "identity",
|
|
},
|
|
});
|
|
expect(response.ok).toBe(true);
|
|
const body = (await response.json()) as ModelsResponse;
|
|
const liveIds = (body.data ?? [])
|
|
.filter((row) => row.object === undefined || row.object === "model")
|
|
.map((row) => row.id)
|
|
.filter((id): id is string => typeof id === "string" && id.trim().length > 0)
|
|
.map((id) => id.trim().toLowerCase())
|
|
.toSorted();
|
|
const live = await buildOpencodeGoLiveProviderConfig({
|
|
apiKey: OPENCODE_API_KEY,
|
|
discoveryApiKey: OPENCODE_API_KEY,
|
|
});
|
|
const discoveredIds = live.models.map((model) => model.id).toSorted();
|
|
const trustedRows = listOpencodeGoModelCatalogEntries();
|
|
const activeIds = new Set(
|
|
trustedRows.filter((row) => !row.status).map((row) => row.id.toLowerCase()),
|
|
);
|
|
|
|
expect(discoveredIds.length).toBeGreaterThan(0);
|
|
expect(new Set(discoveredIds).size).toBe(discoveredIds.length);
|
|
expect(discoveredIds).toEqual([...new Set(liveIds)].filter((id) => activeIds.has(id)));
|
|
}, 30_000);
|
|
|
|
it("runs a discovered Go model with the account credential", async () => {
|
|
const provider = await buildOpencodeGoLiveProviderConfig({ apiKey: OPENCODE_API_KEY });
|
|
const row = provider.models.find((model) => model.id === "gpt-5.6-luna");
|
|
if (!row || row.api !== "openai-responses" || !row.contextWindow) {
|
|
throw new Error("OpenCode Go catalog lacks the GPT 5.6 Luna Responses route");
|
|
}
|
|
const input = row.input.filter((kind) => kind === "text" || kind === "image");
|
|
expect(input).toEqual(row.input);
|
|
const model: Model<"openai-responses"> = {
|
|
...row,
|
|
api: row.api,
|
|
contextWindow: row.contextWindow,
|
|
provider: "opencode-go",
|
|
baseUrl: row.baseUrl ?? provider.baseUrl,
|
|
input,
|
|
};
|
|
const result = await completeSimple(
|
|
model,
|
|
{ messages: [{ role: "user", content: "Reply with exactly: ok", timestamp: Date.now() }] },
|
|
{ apiKey: OPENCODE_API_KEY, maxTokens: 128 },
|
|
);
|
|
if (result.stopReason === "error") {
|
|
throw new Error(result.errorMessage || "OpenCode Go inference returned an error");
|
|
}
|
|
expect(extractNonEmptyAssistantText(result.content)).toMatch(/^ok[.!]?$/i);
|
|
}, 120_000);
|
|
});
|