/**
 * `api + openai` strategy: direct provider HTTP API call via the official
 * OpenAI SDK using the user's API key.
 *
 * Model neutrality (per `feedback_stop_haiku_drift`): NO vendor model
 * identifier appears in this file. `cfg.model` is the user-supplied id
 * passed through to the SDK; opensquid treats it as opaque. If the user
 * leaves `cfg.model` unset, we throw — the source code never picks a
 * default.
 *
 * Auth: API key resolved via `SecretResolver`. Default URI is
 * `env:OPENAI_API_KEY`.
 *
 * Rate-limit retry: same shape as api_anthropic.ts — exponential backoff
 * (1s, 2s, 4s) on HTTP 429, max 3 retries.
 *
 * Lazy load: `openai` is an OPTIONAL peer dep.
 *
 * Test seam (`opts.sdkModule`): injects a stub OpenAI constructor module.
 *
 * Imports from: ../types.js, ../../secrets/types.js.
 * Imported by: models/dispatcher.ts.
 */
const RETRY_DELAYS_MS = [1000, 2000, 4000];
async function loadSdk() {
    const moduleName = 'openai';
    try {
        const mod = (await import(/* @vite-ignore */ moduleName));
        return mod;
    }
    catch (e) {
        throw new Error(`api/openai strategy: failed to load "${moduleName}". ` +
            `Install it (\`pnpm add ${moduleName}\`) or pick a different mode. ` +
            `Cause: ${String(e)}`);
    }
}
function isRateLimitError(e) {
    if (typeof e !== 'object' || e === null)
        return false;
    const obj = e;
    if (obj.status === 429)
        return true;
    if (obj.response?.status === 429)
        return true;
    return false;
}
function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}
export function apiOpenAIStrategy(cfg, secrets, opts = {}) {
    return {
        async call(prompt) {
            const apiKey = await secrets.resolve('env:OPENAI_API_KEY');
            if (!apiKey) {
                throw new Error('OPENAI_API_KEY not configured (api/openai strategy)');
            }
            if (!cfg.model) {
                throw new Error('api/openai strategy: `model` is required in alias config');
            }
            const sdkModule = opts.sdkModule ?? (await loadSdk());
            const client = new sdkModule.default({ apiKey });
            let lastErr;
            for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt += 1) {
                try {
                    const res = await client.chat.completions.create({
                        model: cfg.model,
                        messages: [{ role: 'user', content: prompt }],
                    });
                    return res.choices[0]?.message?.content ?? '';
                }
                catch (e) {
                    lastErr = e;
                    if (!isRateLimitError(e) || attempt === RETRY_DELAYS_MS.length) {
                        throw e;
                    }
                    await sleep(RETRY_DELAYS_MS[attempt] ?? 0);
                }
            }
            throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
        },
    };
}
//# sourceMappingURL=api_openai.js.map