import fs from "node:fs/promises" ;
import path from "node:path" ;
import { buildQaImageGenerationConfigPatch } from "./providers/image-generation.js" ;
import {
fetchJson,
patchConfig,
readConfigSnapshot,
waitForGatewayHealthy,
waitForTransportReady,
} from "./suite-runtime-gateway.js" ;
import type { QaSuiteRuntimeEnv } from "./suite-runtime-types.js" ;
function extractMediaPathFromText(text: string | undefined): string | undefined {
return /MEDIA:([^\n]+)/.exec(text ?? "" )?.[1 ]?.trim();
}
function readPluginAllow(config: Record<string, unknown>) {
const plugins = config.plugins;
if (typeof plugins !== "object" || plugins === null || Array.isArray(plugins)) {
return [];
}
const allow = (plugins as { allow?: unknown }).allow;
return Array.isArray(allow)
? allow.filter(
(pluginId): pluginId is string => typeof pluginId === "string" && pluginId.length > 0 ,
)
: [];
}
async function resolveGeneratedImagePath(params: {
env: Pick<QaSuiteRuntimeEnv, "mock" | "gateway" >;
promptSnippet: string;
startedAtMs: number;
timeoutMs: number;
}) {
const startedAt = Date.now();
while (Date.now() - startedAt < params.timeoutMs) {
if (params.env.mock) {
const requests = await fetchJson<Array<{ allInputText?: string; toolOutput?: string }>>(
`${params.env.mock.baseUrl}/debug/requests`,
);
for (let index = requests.length - 1 ; index >= 0 ; index -= 1 ) {
const request = requests[index];
if (!(request.allInputText ?? "" ).includes(params.promptSnippet)) {
continue ;
}
const mediaPath = extractMediaPathFromText(request.toolOutput);
if (mediaPath) {
return mediaPath;
}
}
}
const mediaDir = path.join(
params.env.gateway.tempRoot,
"state" ,
"media" ,
"tool-image-generation" ,
);
const entries = await fs.readdir(mediaDir).catch (() => []);
const candidates = await Promise.all(
entries.map(async (entry) => {
const fullPath = path.join(mediaDir, entry);
const stat = await fs.stat(fullPath).catch (() => null );
if (!stat?.isFile()) {
return null ;
}
return {
fullPath,
mtimeMs: stat.mtimeMs,
};
}),
);
const match = candidates
.filter((entry): entry is NonNullable<typeof entry> => Boolean (entry))
.filter((entry) => entry.mtimeMs >= params.startedAtMs - 1 _000 )
.toSorted((left, right) => right.mtimeMs - left.mtimeMs)
.at(0 )?.fullPath;
if (match) {
return match;
}
await new Promise((resolve) => setTimeout(resolve, 250 ));
}
throw new Error(`timed out after ${params.timeoutMs}ms`);
}
async function ensureImageGenerationConfigured(env: QaSuiteRuntimeEnv) {
const snapshot = await readConfigSnapshot(env);
await patchConfig({
env,
patch: buildQaImageGenerationConfigPatch({
providerMode: env.providerMode,
providerBaseUrl: env.mock ? `${env.mock.baseUrl}/v1` : undefined,
requiredPluginIds: env.transport.requiredPluginIds,
existingPluginIds: readPluginAllow(snapshot.config),
}),
});
await waitForGatewayHealthy(env);
await waitForTransportReady(env, 60 _000 );
}
export { ensureImageGenerationConfigured, extractMediaPathFromText, resolveGeneratedImagePath };
Messung V0.5 in Prozent C=100 H=92 G=95
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland