/**
 * Non-streaming Shortcut LLM provider.
 *
 * Calls /api/llm/invoke (JSON request/response) instead of /api/llm/stream (SSE).
 * Returns an AssistantMessageEventStream for compatibility with owned AI's StreamFn interface,
 * but emits only start → done (no deltas).
 */
import { createAssistantMessageEventStream } from '../../ai/utils/event-stream.js';
import { APP_NAME } from '../../config.js';
import { SHORTCUT_LLM_PROXY_ENDPOINTS } from '../../endpoints.js';
import { SHORTCUT_PROVIDER_ID } from '../../model-ids.js';
import { buildUsage, mapStopReason } from './llm-usage.js';
import { convertMessages, convertTools } from './message-converter.js';
import { THINKING_TO_EFFORT } from './sse-protocol.js';
/**
 * Create a non-streaming invoke function for the Shortcut LLM proxy.
 * Returns a owned AI StreamFn that calls /api/llm/invoke and emits start+done.
 */
export function createShortcutInvoke(baseUrl, getExtraHeaders, recoverAuth) {
    return function shortcutInvoke(model, context, options) {
        const stream = createAssistantMessageEventStream();
        const shortcutOptions = options;
        const body = {
            model: model.id,
            messages: convertMessages(context),
            tools: convertTools(context.tools),
            effort_level: options?.reasoning
                ? (THINKING_TO_EFFORT[options.reasoning] ?? 'low')
                : undefined,
            thinking_type: options?.reasoning ? 'adaptive' : 'off',
            ...(shortcutOptions?.userMessageId ? { user_message_id: shortcutOptions.userMessageId } : {}),
            max_tokens: options?.maxTokens
        };
        (async () => {
            try {
                const requestInvoke = async (apiKey) => await fetch(`${baseUrl}${SHORTCUT_LLM_PROXY_ENDPOINTS.invoke}`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        ...getExtraHeaders?.(),
                        Authorization: `Bearer ${apiKey}`,
                        'User-AgentController': `Mozilla/5.0 (compatible; ${APP_NAME}-coding-agent/1.0)`
                    },
                    body: JSON.stringify(body),
                    signal: options?.signal
                });
                let apiKey = options?.apiKey ?? '';
                let response = await requestInvoke(apiKey);
                if (response.status === 401 && recoverAuth) {
                    try {
                        const recoveredApiKey = await recoverAuth(apiKey);
                        if (recoveredApiKey) {
                            apiKey = recoveredApiKey;
                            response = await requestInvoke(apiKey);
                        }
                    }
                    catch {
                        // Keep the original 401 response path below.
                    }
                }
                if (!response.ok) {
                    const raw = await response.text();
                    const text = raw.split('\n').slice(0, 20).join('\n');
                    if (response.status === 401) {
                        throw new Error(`Session expired. Run /login to re-authenticate. Raw error: LLM proxy error 401: ${text}`);
                    }
                    throw new Error(`LLM proxy error ${response.status}: ${text}`);
                }
                const data = await response.json();
                // Build content array
                const content = [];
                for (const tb of data.thinking) {
                    content.push({
                        type: 'thinking',
                        thinking: tb.thinking,
                        redacted: tb.redacted,
                        thinkingSignature: tb.signature
                    });
                }
                if (data.text) {
                    content.push({ type: 'text', text: data.text });
                }
                for (const tc of data.tool_calls) {
                    let args = {};
                    try {
                        args = JSON.parse(tc.arguments);
                    }
                    catch {
                        // keep empty
                    }
                    content.push({
                        type: 'toolCall',
                        id: tc.id,
                        name: tc.name,
                        arguments: args
                    });
                }
                const stopReason = mapStopReason(data.stop_reason);
                const message = {
                    role: 'assistant',
                    content,
                    api: 'shortcut-llm',
                    provider: SHORTCUT_PROVIDER_ID,
                    model: model.id,
                    usage: buildUsage(data.usage, model),
                    stopReason,
                    timestamp: Date.now()
                };
                stream.push({ type: 'start', partial: message });
                stream.push({
                    type: 'done',
                    reason: stopReason,
                    message
                });
            }
            catch (err) {
                const isAbort = options?.signal?.aborted || (err instanceof Error && err.name === 'AbortError');
                const errMsg = err instanceof Error ? err.message : 'Request failed';
                const errorMessage = {
                    role: 'assistant',
                    content: [],
                    api: 'shortcut-llm',
                    provider: SHORTCUT_PROVIDER_ID,
                    model: model.id,
                    usage: {
                        input: 0,
                        output: 0,
                        cacheRead: 0,
                        cacheWrite: 0,
                        totalTokens: 0,
                        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
                    },
                    stopReason: isAbort ? 'aborted' : 'error',
                    errorMessage: isAbort ? 'Request was aborted' : errMsg,
                    timestamp: Date.now()
                };
                stream.push({ type: 'error', reason: isAbort ? 'aborted' : 'error', error: errorMessage });
            }
        })();
        return stream;
    };
}
//# sourceMappingURL=shortcut-invoke.js.map