import type { GenerationProvider, GenerationRequest, } from "@wrnexus/design-studio"; export const APIMART_MODEL = "gpt-6-luna"; export const AI_TIMEOUT_MS = 60_000; export const AI_OUTPUT_TOKENS = 8192; type FailureKind = | "auth" | "quota" | "model" | "rate" | "unavailable" | "network" | "truncated" | "filtered" | "response" | "request"; const failureMessages: Record = { auth: "APIMart rejected the server API key. Check APIMART_API_KEY and its permissions, then restart the app.", quota: "APIMart reports insufficient credit or quota. Check the provider account balance and limits.", model: "APIMart could not access gpt-6-luna. Check that this model is enabled for the server API key.", rate: "APIMart is rate limiting requests. Wait a minute and generate again.", unavailable: "APIMart is temporarily unavailable. Try generating again shortly.", network: "The server could not reach APIMart. Check the VM's outbound HTTPS connection and try again.", truncated: "APIMart stopped before completing all design alternatives. Try a shorter brief or generate again.", filtered: "APIMart declined this generation. Revise the brief and try again.", response: "APIMart returned an empty or unreadable completion. Try generating again.", request: "APIMart rejected the completion request. Check the provider's model configuration.", }; class APIMartFailure extends Error { constructor( readonly kind: FailureKind, readonly status?: number, ) { super(failureMessages[kind]); } get retryable() { return ["rate", "unavailable", "network", "truncated", "response"].includes( this.kind, ); } } function failureFor(status: number, code?: unknown) { // Only recognized codes influence the category; upstream text never leaves this adapter. const known = typeof code === "string" ? code.toLowerCase() : ""; const kind: FailureKind = status === 401 || status === 403 || known === "invalid_api_key" ? "auth" : status === 402 || ["insufficient_quota", "insufficient_balance"].includes(known) ? "quota" : status === 404 || known === "model_not_found" ? "model" : status === 429 || known === "rate_limit_exceeded" ? "rate" : status >= 500 ? "unavailable" : "request"; return new APIMartFailure(kind, status); } export function apimartProvider( apiKey: string, transport: typeof fetch = fetch, ): GenerationProvider { return { name: "APIMart", async generate(prompt, options = {}) { let response: Response; try { response = await transport( "https://api.apimart.ai/v1/chat/completions", { method: "POST", signal: options.signal, redirect: "error", headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json", }, body: JSON.stringify({ model: APIMART_MODEL, stream: false, max_tokens: options.maxTokens ?? AI_OUTPUT_TOKENS, messages: [ { role: "system", content: options.system ?? "Return valid design proposal JSON only.", }, { role: "user", content: prompt }, ], }), }, ); } catch { options.signal?.throwIfAborted(); throw new APIMartFailure("network"); } // Never forward upstream bodies: they may echo credentials or submitted context. if (!response.ok) { // Read a bounded envelope only to recognize documented machine codes. let code: unknown; try { code = JSON.parse(await readBounded(response, 200_000)).error?.code; } catch { /* Ignore raw error text. */ } throw failureFor(response.status, code); } let result; try { result = JSON.parse(await readBounded(response, 200_000)); } catch { options.signal?.throwIfAborted(); throw new APIMartFailure("response"); } if (result?.error) throw failureFor(400, result.error.code); const choice = result?.choices?.[0]; if (choice?.finish_reason === "length") throw new APIMartFailure("truncated"); if (choice?.finish_reason === "content_filter") throw new APIMartFailure("filtered"); if ( typeof choice?.message?.content !== "string" || !choice.message.content.trim() ) throw new APIMartFailure("response"); return { value: choice.message.content, provider: "APIMart", model: APIMART_MODEL, }; }, }; } async function readBounded(source: Request | Response, limit: number) { const reader = source.body?.getReader(); const decoder = new TextDecoder(); let text = "", bytes = 0; if (!reader) return text; try { while (true) { const chunk = await reader.read(); if (chunk.done) break; bytes += chunk.value.byteLength; if (bytes > limit) { await reader.cancel(); throw Error("Request or response is too large."); } text += decoder.decode(chunk.value, { stream: true }); } return text + decoder.decode(); } finally { reader.releaseLock(); } } export function studioAI(apiKey?: string, transport: typeof fetch = fetch) { let active = 0, windowStart = Date.now(), count = 0; const json = (value: unknown, status = 200) => new Response(JSON.stringify(value), { status, headers: { "content-type": "application/json", "cache-control": "no-store", }, }); return async (request: Request): Promise => { const url = new URL(request.url); if ( !apiKey || ![ "/design-studio/api/generation", "/design-studio/api/generate", ].includes(url.pathname) ) return; const scheme = request.headers.get("x-forwarded-proto"); if (scheme === "https" || scheme === "http") url.protocol = scheme + ":"; if ( request.headers.get("origin") && request.headers.get("origin") !== url.origin ) return json({ error: "Same-origin requests only." }, 403); if (url.pathname.endsWith("/generation") && request.method === "GET") return json({ provider: "APIMart", model: APIMART_MODEL, templateVersion: 1, maxAttempts: 2, maxOutputTokens: AI_OUTPUT_TOKENS, timeoutMs: AI_TIMEOUT_MS, }); if (!url.pathname.endsWith("/generate") || request.method !== "POST") return json({ error: "Method not allowed." }, 405); if ( !(request.headers.get("content-type") ?? "").startsWith( "application/json", ) ) return json({ error: "JSON required." }, 415); if (Date.now() - windowStart >= 60000) { windowStart = Date.now(); count = 0; } if (active >= 2 || count >= 10) return json( { error: "AI generation is busy. Try again in a minute." }, 429, ); active++; try { const input = JSON.parse( await readBounded(request, 2_000_000), ) as GenerationRequest; count++; // Preserve the installed engine's validation, locks, revision checks and repair budget. const module = import.meta.resolve("@wrnexus/design-studio"); const { generateDesigns } = (await import( module )) as typeof import("@wrnexus/design-studio"); let calls = 0; let exhausted = false; let failure: APIMartFailure | undefined; const upstream = apimartProvider(apiKey, transport); const provider: GenerationProvider = { name: upstream.name, async generate(prompt, options) { // The repair pass and transport retry share one two-call budget. if (calls >= 2) { exhausted = true; throw failure ?? new APIMartFailure("response"); } calls++; failure = undefined; try { return await upstream.generate(prompt, options); } catch (error) { options?.signal?.throwIfAborted(); failure = error instanceof APIMartFailure ? error : new APIMartFailure("response"); throw failure; } }, }; const deadline = AbortSignal.any([ request.signal, AbortSignal.timeout(AI_TIMEOUT_MS), ]); const generate = () => generateDesigns(input, { provider, model: APIMART_MODEL, signal: deadline, timeoutMs: AI_TIMEOUT_MS, maxOutputTokens: AI_OUTPUT_TOKENS, }); let result = await generate(); if ( !result.alternatives.length && failure?.retryable && calls < 2 && !deadline.aborted ) result = await generate(); result.provenance.attempts = calls; if (exhausted && !failure && !result.alternatives.length) { result.diagnostics = [ { code: "WRN-STUDIO-PROPOSAL", path: "$", message: "APIMart returned a design that did not meet the schema after both provider requests were used. Generate again. Your draft and previous alternatives are unchanged.", }, ]; } if ( failure && result.diagnostics.some((d) => d.code === "WRN-STUDIO-PROVIDER") ) { const reference = crypto.randomUUID(); console.warn( JSON.stringify({ event: "studio-ai-provider-failure", reference, category: failure.kind, status: failure.status, attempts: calls, }), ); result.diagnostics = [ { code: "WRN-STUDIO-PROVIDER", path: "$", message: `${failure.message} Your draft and previous alternatives are unchanged. Reference: ${reference}`, }, ]; } return json(result); } catch (error) { const message = error instanceof Error ? error.message : "Invalid generation request."; if (message.includes("WRN-STUDIO-CONFLICT")) return json( { error: "Your draft changed. Generate again from the current draft.", }, 409, ); if (message.includes("too large")) return json({ error: "Request is too large." }, 413); if ( request.signal.aborted || (error instanceof Error && ["AbortError", "TimeoutError"].includes(error.name)) ) return json( { error: "AI generation timed out or was cancelled. Your draft is unchanged.", }, 408, ); return json( { error: "Could not generate a design. Check the brief and server AI configuration. Your draft is unchanged.", }, 400, ); } finally { active--; } }; }