"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReplicateClient = void 0;
/**
 * Minimal Replicate Predictions API adapter. Replicate model schemas vary, so
 * this targets text/chat-like models that accept a `prompt` input and returns
 * the completed prediction output as one assistant message.
 */
class ReplicateClient {
    baseUrl;
    apiKey;
    model;
    constructor(options) {
        if (!options.apiKey.trim())
            throw new Error('Replicate apiKey is required.');
        if (!options.model.trim())
            throw new Error('Replicate model is required.');
        this.apiKey = options.apiKey.trim();
        this.model = options.model.trim();
        this.baseUrl = (options.baseUrl ?? 'https://api.replicate.com/v1').replace(/\/$/, '');
    }
    async chat(messages, tools, abortSignal) {
        if (tools && tools.length > 0) {
            throw new Error('Replicate backend does not support agent tool calls. Use a tool-capable backend for agent loops.');
        }
        const prompt = messagesToPrompt(messages);
        const response = await fetch(this.predictionUrl(), {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.apiKey}`,
                'Content-Type': 'application/json',
                'Prefer': 'wait=60',
            },
            body: JSON.stringify(this.predictionBody(prompt)),
            signal: abortSignal,
        });
        const body = await readJson(response);
        if (!response.ok) {
            const detail = extractErrorDetail(body) || response.statusText;
            throw new Error(`Replicate HTTP ${response.status}: ${detail}`);
        }
        const prediction = body;
        if (prediction.status === 'failed' || prediction.status === 'canceled') {
            throw new Error(`Replicate prediction ${prediction.status}: ${extractErrorDetail(prediction.error) || 'no details'}`);
        }
        const content = outputToText(prediction.output);
        return {
            message: { role: 'assistant', content },
            usage: { promptTokens: 0, completionTokens: 0, totalDurationNs: 0 },
        };
    }
    chatOnce(messages, tools) {
        return this.chat(messages, tools);
    }
    async *chatStream(messages, tools, abortSignal) {
        const result = await this.chat(messages, tools);
        yield { content: result.message.content ?? '', done: true };
    }
    async listModels() {
        return [this.model];
    }
    async getContextWindow() {
        return null;
    }
    async healthCheck() {
        return { ok: true };
    }
    getModel() {
        return this.model;
    }
    predictionUrl() {
        const parts = this.model.split('/');
        if (parts.length === 2 && !this.model.includes(':')) {
            const [owner, name] = parts.map(encodeURIComponent);
            return `${this.baseUrl}/models/${owner}/${name}/predictions`;
        }
        return `${this.baseUrl}/predictions`;
    }
    predictionBody(prompt) {
        if (this.model.includes('/') && !this.model.includes(':')) {
            return { input: { prompt } };
        }
        return { version: this.model, input: { prompt } };
    }
}
exports.ReplicateClient = ReplicateClient;
function messagesToPrompt(messages) {
    return messages
        .map((m) => `${m.role.toUpperCase()}: ${m.content ?? ''}`)
        .join('\n\n')
        .trim();
}
async function readJson(response) {
    const text = await response.text();
    if (!text.trim())
        return {};
    try {
        return JSON.parse(text);
    }
    catch {
        return { detail: text };
    }
}
function outputToText(output) {
    if (typeof output === 'string')
        return output;
    if (Array.isArray(output))
        return output.map(outputToText).join('');
    if (output && typeof output === 'object') {
        const record = output;
        if (typeof record.text === 'string')
            return record.text;
        if (typeof record.output === 'string')
            return record.output;
        return JSON.stringify(record);
    }
    return output == null ? '' : String(output);
}
function extractErrorDetail(value) {
    if (typeof value === 'string')
        return value;
    if (Array.isArray(value))
        return value.map(extractErrorDetail).filter(Boolean).join('; ');
    if (value && typeof value === 'object') {
        const record = value;
        return extractErrorDetail(record.detail ?? record.error ?? record.message ?? JSON.stringify(record));
    }
    return '';
}
//# sourceMappingURL=replicateClient.js.map