fix(POSTV1-02): 接通真实AI生成链路
Dada P0-A isolated Windows CI / validate-and-package (push) Waiting to run
Dada P0-A isolated Windows CI / validate-and-package (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { createRequire } from "node:module";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
ModelConfigurationService,
|
||||
portableRuntimeModelCandidates,
|
||||
} from "../../apps/api/src/model-configuration.js";
|
||||
|
||||
const requireFromApi = createRequire(new URL("../../apps/api/package.json", import.meta.url));
|
||||
const Database = requireFromApi("better-sqlite3") as new (path: string) => {
|
||||
close(): void;
|
||||
};
|
||||
|
||||
describe("POSTV1-02 portable runtime model seed", () => {
|
||||
it("enables only models backed by the real OneAPI contract", () => {
|
||||
const database = new Database(":memory:");
|
||||
try {
|
||||
const models = new ModelConfigurationService({ database, seedCandidates: portableRuntimeModelCandidates }).read();
|
||||
const flash = models.models.find((model) => model.model_id === "gemini-3.1-flash-image-preview");
|
||||
const pro = models.models.find((model) => model.model_id === "gemini-3-pro-image-preview");
|
||||
const gpt = models.models.find((model) => model.model_id === "gpt-image-2");
|
||||
|
||||
expect(models.configured_default_model_id).toBe("gemini-3.1-flash-image-preview");
|
||||
expect(flash).toMatchObject({
|
||||
contract_validation_status: "verified",
|
||||
enabled: true,
|
||||
runtime_availability: { available_for_new_jobs: true, reason: "available" },
|
||||
});
|
||||
expect(flash?.route_profile).toMatchObject({ endpoint: "https://oneapi.intelligrow.cn/v1/chat/completions" });
|
||||
expect(pro).toMatchObject({
|
||||
contract_validation_status: "unverified",
|
||||
enabled: false,
|
||||
runtime_availability: { available_for_new_jobs: false, reason: "configured_disabled" },
|
||||
});
|
||||
expect(gpt).toMatchObject({
|
||||
contract_validation_status: "verified",
|
||||
enabled: true,
|
||||
runtime_availability: { available_for_new_jobs: true, reason: "available" },
|
||||
});
|
||||
} finally {
|
||||
database.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -46,7 +46,10 @@ async function stop(child) {
|
||||
test("portable package serves the product and keeps SQLite data across API restart", async () => {
|
||||
assert.ok(existsSync(join(packageRoot, "Dada.exe")));
|
||||
assert.ok(existsSync(join(packageRoot, "web", "index.html")));
|
||||
assert.match(await readFile(join(packageRoot, "server", "worker", "dist", "worker.js"), "utf8"), /GenerationProcessor/);
|
||||
const packagedWorker = await readFile(join(packageRoot, "server", "worker", "dist", "worker.js"), "utf8");
|
||||
assert.match(packagedWorker, /GenerationProcessor/);
|
||||
assert.match(packagedWorker, /oneapi\.intelligrow\.cn/);
|
||||
assert.doesNotMatch(packagedWorker, /portable-mock-worker/);
|
||||
const root = await mkdtemp(join(tmpdir(), "dada-postv1-"));
|
||||
const dataRoot = join(root, "data");
|
||||
const configPath = join(root, "instance.json");
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { GenerationAdapterRequest } from "../../apps/worker/src/ai-adapter-contract.js";
|
||||
import { OneApiGenerationAdapter } from "../../apps/worker/src/oneapi-generation-adapter.js";
|
||||
|
||||
function request(overrides: Partial<GenerationAdapterRequest> = {}): GenerationAdapterRequest {
|
||||
return {
|
||||
configSnapshot: {},
|
||||
generationId: "00000000-0000-4000-8000-000000000001",
|
||||
modelId: "gemini-3.1-flash-image-preview",
|
||||
prompt: "一张用于本机验收的抽象色彩图",
|
||||
ratio: "1:1",
|
||||
referenceAssetIds: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("POSTV1-02 OneAPI runtime adapter", () => {
|
||||
it("uses the fixed Gemini gateway and normalizes one real-shaped response", async () => {
|
||||
const source = Buffer.from(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
|
||||
"base64",
|
||||
);
|
||||
const gateway = vi.fn(async (_url: string | URL | Request, init?: RequestInit) => {
|
||||
const headers = new Headers(init?.headers);
|
||||
expect(headers.get("authorization")).toBe("Bearer synthetic-runtime-token");
|
||||
expect(init?.redirect).toBe("error");
|
||||
return new Response(JSON.stringify({
|
||||
choices: [{ message: { content: `})` } }],
|
||||
}), { headers: { "content-type": "application/json" }, status: 200 });
|
||||
});
|
||||
const credential = Buffer.from("synthetic-runtime-token");
|
||||
const adapter = new OneApiGenerationAdapter({ credential, fetch: gateway as typeof fetch });
|
||||
const result = await adapter.start(request());
|
||||
|
||||
expect(gateway).toHaveBeenCalledOnce();
|
||||
expect(gateway.mock.calls[0]?.[0]).toBe("https://oneapi.intelligrow.cn/v1/chat/completions");
|
||||
expect(result.status === "failed" ? result.sourceCategory : "completed").toBe("completed");
|
||||
if (result.status === "completed") {
|
||||
expect(result.outputs).toHaveLength(1);
|
||||
expect(result.outputs[0]).toMatchObject({ mimeType: "image/png", pixelHeight: 1080, pixelWidth: 1080 });
|
||||
expect(result.outputs[0]?.bytes.length).toBeGreaterThan(0);
|
||||
}
|
||||
expect(JSON.stringify(result)).not.toContain("synthetic-runtime-token");
|
||||
adapter.dispose();
|
||||
credential.fill(0);
|
||||
});
|
||||
|
||||
it("fails closed instead of returning a mock image", async () => {
|
||||
const adapter = new OneApiGenerationAdapter({
|
||||
credential: Buffer.from("synthetic-runtime-token"),
|
||||
fetch: vi.fn(async () => new Response(null, { status: 503 })) as typeof fetch,
|
||||
});
|
||||
await expect(adapter.start(request())).resolves.toEqual({
|
||||
category: "upstream_failed",
|
||||
sourceCategory: "upstream_http_503",
|
||||
status: "failed",
|
||||
});
|
||||
adapter.dispose();
|
||||
await expect(adapter.start(request())).resolves.toEqual({
|
||||
category: "upstream_failed",
|
||||
sourceCategory: "adapter_disposed",
|
||||
status: "failed",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user