"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var AlibabaLlmProvider_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlibabaLlmProvider = void 0;
const common_1 = require("@nestjs/common");
const application_state_service_1 = require("../application-state/application-state.service");
const llm_call_logs_service_1 = require("../llm-call-logs/llm-call-logs.service");
let AlibabaLlmProvider = AlibabaLlmProvider_1 = class AlibabaLlmProvider {
    constructor(applicationStateService, llmCallLogsService) {
        this.applicationStateService = applicationStateService;
        this.llmCallLogsService = llmCallLogsService;
        this.logger = new common_1.Logger(AlibabaLlmProvider_1.name);
        this.baseUrl = 'https://coding-intl.dashscope.aliyuncs.com/v1';
    }
    mapHistory(history) {
        return history.map((turn) => {
            if (turn.role === 'tool') {
                return {
                    role: 'tool',
                    tool_call_id: turn.tool_call_id,
                    content: turn.parts.map((p) => p.text).join(''),
                };
            }
            const mappedTurn = {
                role: turn.role === 'model' ? 'assistant' : 'user',
                content: turn.parts.map((p) => p.text).join(''),
            };
            if (turn.thoughts) {
                mappedTurn.thoughts = turn.thoughts;
            }
            if (turn.tool_calls) {
                mappedTurn.tool_calls = turn.tool_calls.map((tc) => ({
                    id: tc.id,
                    type: tc.type,
                    function: {
                        name: tc.function.name,
                        arguments: typeof tc.function.arguments === 'string'
                            ? tc.function.arguments
                            : JSON.stringify(tc.function.arguments),
                    },
                }));
            }
            return mappedTurn;
        });
    }
    mapTools(tools) {
        if (!tools || tools.length === 0)
            return undefined;
        return tools.map((tool) => ({
            type: tool.type,
            function: {
                name: tool.function.name,
                description: tool.function.description,
                parameters: tool.function.parameters,
            },
        }));
    }
    async getModels() {
        const apiKey = await this.applicationStateService.getAlibabaApiKey();
        if (!apiKey)
            return [];
        const models = [
            { id: 'alibaba/qwen3.6-plus', name: 'Qwen3.6 Plus (Vision)' },
            { id: 'alibaba/qwen3.5-plus', name: 'Qwen3.5 Plus (Vision)' },
            { id: 'alibaba/kimi-k2.5', name: 'Kimi K2.5 (Vision)' },
            { id: 'alibaba/glm-5', name: 'GLM-5' },
            { id: 'alibaba/MiniMax-M2.5', name: 'MiniMax M2.5' },
            { id: 'alibaba/qwen3-max-2026-01-23', name: 'Qwen3 Max' },
            { id: 'alibaba/qwen3-coder-next', name: 'Qwen3 Coder Next' },
            { id: 'alibaba/qwen3-coder-plus', name: 'Qwen3 Coder Plus' },
            { id: 'alibaba/glm-4.7', name: 'GLM-4.7' },
        ];
        return models.map((m) => ({ ...m, provider: 'alibaba' }));
    }
    async generateContent(request) {
        const apiKey = await this.applicationStateService.getAlibabaApiKey();
        if (!apiKey) {
            throw new Error('Alibaba API Key is not configured in settings.');
        }
        const { prompt, systemInstruction, history, modelId, generationConfig, tools, tool_choice, onToken, abortController, } = request;
        const alibabaModelId = modelId
            ? modelId.replace(/^alibaba\//, '')
            : 'qwen3.5-plus';
        const messages = [];
        if (systemInstruction) {
            messages.push({ role: 'system', content: systemInstruction });
        }
        if (history && history.length > 0) {
            messages.push(...this.mapHistory(history));
        }
        else {
            messages.push({ role: 'user', content: prompt });
        }
        await this.applicationStateService.trackUsedModel(modelId);
        this.logger.log(`Calling Alibaba API with model: ${alibabaModelId}`);
        const startTime = Date.now();
        let llmCallLogId = null;
        try {
            llmCallLogId = (await this.llmCallLogsService.createLog({
                session_input_id: 'pending',
                provider: 'alibaba',
                model_id: alibabaModelId,
                request_body: JSON.stringify({
                    model: alibabaModelId,
                    messages,
                    tools,
                    tool_choice,
                    stream: !!onToken,
                    temperature: generationConfig?.temperature,
                    max_tokens: generationConfig?.maxOutputTokens,
                    top_p: generationConfig?.topP,
                }),
            })).id;
        }
        catch (logError) {
            this.logger.warn(`Failed to create LLM call log: ${logError.message}`);
        }
        try {
            const body = {
                model: alibabaModelId,
                messages,
                extra_body: { enable_thinking: true },
                parallel_tool_calls: true,
            };
            if (tools && tools.length > 0) {
                body.tools = this.mapTools(tools);
                if (tool_choice) {
                    body.tool_choice = tool_choice;
                }
            }
            if (onToken) {
                body.stream = true;
                body.stream_options = { include_usage: true };
            }
            if (generationConfig) {
                if (generationConfig.temperature !== undefined)
                    body.temperature = generationConfig.temperature;
                if (generationConfig.maxOutputTokens !== undefined)
                    body.max_tokens = generationConfig.maxOutputTokens;
                if (generationConfig.topP !== undefined)
                    body.top_p = generationConfig.topP;
                if (generationConfig.reasoning) {
                    body.enable_thinking = true;
                }
            }
            const response = await fetch(`${this.baseUrl}/chat/completions`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${apiKey}`,
                },
                body: JSON.stringify(body),
                signal: abortController?.signal,
            });
            if (!response.ok) {
                const errorText = await response.text();
                const errorData = this.tryParseJson(errorText);
                const errorMessage = errorData?.message || `Alibaba API error: ${response.statusText}`;
                if (llmCallLogId) {
                    try {
                        await this.llmCallLogsService.updateLog(llmCallLogId, {
                            status_code: response.status,
                            latency_ms: Date.now() - startTime,
                            error_message: errorMessage,
                            response_body: errorText,
                        });
                    }
                    catch (updateError) {
                        this.logger.warn(`Failed to update LLM call log: ${updateError.message}`);
                    }
                }
                const error = new Error(errorMessage);
                error.status = response.status;
                throw error;
            }
            let accumulatedResponseBody = '';
            if (onToken && response.body) {
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let buffer = '';
                let accumulatedResponse = '';
                let accumulatedReasoning = '';
                let isFirst = true;
                let usageData = null;
                const accumulatedToolCalls = new Map();
                while (true) {
                    if (abortController?.signal?.aborted) {
                        throw new DOMException('The operation was aborted', 'AbortError');
                    }
                    const { done, value } = await reader.read();
                    if (done) {
                        break;
                    }
                    buffer += decoder.decode(value, { stream: true });
                    const lines = buffer.split('\n');
                    buffer = lines.pop() || '';
                    for (const line of lines) {
                        if (line.startsWith('data: ')) {
                            const dataStr = line.substring(6);
                            if (dataStr.trim() === '[DONE]') {
                                break;
                            }
                            try {
                                const parsed = JSON.parse(dataStr);
                                const chunk = parsed.choices?.[0]?.delta?.content;
                                if (chunk) {
                                    accumulatedResponse += chunk;
                                    onToken(chunk, isFirst);
                                    if (isFirst) {
                                        isFirst = false;
                                    }
                                }
                                const reasoningChunk = parsed.choices?.[0]?.delta?.reasoning_content ||
                                    parsed.choices?.[0]?.delta?.reasoning;
                                if (reasoningChunk) {
                                    accumulatedReasoning += reasoningChunk;
                                    onToken?.('', false, reasoningChunk);
                                }
                                const deltaToolCalls = parsed.choices?.[0]?.delta?.tool_calls;
                                if (deltaToolCalls) {
                                    for (const deltaCall of deltaToolCalls) {
                                        const index = deltaCall.index;
                                        if (!accumulatedToolCalls.has(index)) {
                                            accumulatedToolCalls.set(index, {
                                                id: deltaCall.id,
                                                type: deltaCall.type,
                                                function: {
                                                    name: deltaCall.function?.name || '',
                                                    arguments: '',
                                                },
                                            });
                                        }
                                        const existing = accumulatedToolCalls.get(index);
                                        if (deltaCall.function?.arguments) {
                                            existing.function.arguments +=
                                                deltaCall.function.arguments;
                                        }
                                    }
                                }
                                if (parsed.usage) {
                                    usageData = parsed.usage;
                                    accumulatedResponseBody += dataStr + '\n';
                                }
                            }
                            catch (e) {
                                this.logger.warn(`Error parsing stream chunk: ${dataStr}`, e);
                            }
                        }
                    }
                }
                const finalToolCalls = [];
                for (const toolCall of accumulatedToolCalls.values()) {
                    try {
                        finalToolCalls.push({
                            ...toolCall,
                            function: {
                                ...toolCall.function,
                                arguments: typeof toolCall.function.arguments === 'string'
                                    ? JSON.parse(toolCall.function.arguments)
                                    : toolCall.function.arguments,
                            },
                        });
                    }
                    catch (e) {
                        this.logger.warn(`Failed to parse tool call arguments: ${toolCall.function.arguments}`, e);
                    }
                }
                if (usageData) {
                    this.logger.log(`Alibaba stream finished. Usage: ${usageData.prompt_tokens} prompt, ${usageData.completion_tokens} completion tokens.`);
                    if (llmCallLogId) {
                        try {
                            await this.llmCallLogsService.updateLog(llmCallLogId, {
                                status_code: response.status,
                                latency_ms: Date.now() - startTime,
                                response_body: accumulatedResponseBody ||
                                    JSON.stringify({ usage: usageData, stream_chunks: '...' }),
                                input_tokens: usageData.prompt_tokens,
                                output_tokens: usageData.completion_tokens,
                                cached_tokens: usageData.prompt_tokens_details?.cached_tokens,
                            });
                        }
                        catch (updateError) {
                            this.logger.warn(`Failed to update LLM call log: ${updateError.message}`);
                        }
                    }
                    return {
                        text: accumulatedResponse,
                        usage: {
                            inputTokens: usageData.prompt_tokens,
                            outputTokens: usageData.completion_tokens,
                            cachedTokens: usageData.prompt_tokens_details?.cached_tokens,
                        },
                        tool_calls: finalToolCalls.length > 0 ? finalToolCalls : undefined,
                        thoughts: accumulatedReasoning || undefined,
                    };
                }
                if (llmCallLogId) {
                    try {
                        await this.llmCallLogsService.updateLog(llmCallLogId, {
                            status_code: response.status,
                            latency_ms: Date.now() - startTime,
                            response_body: accumulatedResponseBody ||
                                JSON.stringify({ stream_chunks: '...' }),
                        });
                    }
                    catch (updateError) {
                        this.logger.warn(`Failed to update LLM call log: ${updateError.message}`);
                    }
                }
                return {
                    text: accumulatedResponse,
                    tool_calls: finalToolCalls.length > 0 ? finalToolCalls : undefined,
                    thoughts: accumulatedReasoning || undefined,
                };
            }
            const data = await response.json();
            const content = data.choices?.[0]?.message?.content;
            const rawToolCalls = data.choices?.[0]?.message?.tool_calls;
            const reasoningContent = data.choices?.[0]?.message?.reasoning_content ||
                data.choices?.[0]?.message?.reasoning;
            const usage = data.usage;
            let parsedToolCalls;
            if (rawToolCalls && rawToolCalls.length > 0) {
                parsedToolCalls = rawToolCalls.map((tc) => ({
                    id: tc.id,
                    type: tc.type,
                    function: {
                        name: tc.function.name,
                        arguments: typeof tc.function.arguments === 'string'
                            ? JSON.parse(tc.function.arguments)
                            : tc.function.arguments,
                    },
                }));
            }
            if (!content && !parsedToolCalls) {
                const error = new Error('Alibaba returned an empty response.');
                error.status = response.status || 0;
                throw error;
            }
            if (usage) {
                this.logger.log(`Alibaba response. Usage: ${usage.prompt_tokens} prompt, ${usage.completion_tokens} completion tokens`);
                if (llmCallLogId) {
                    try {
                        await this.llmCallLogsService.updateLog(llmCallLogId, {
                            status_code: response.status,
                            latency_ms: Date.now() - startTime,
                            response_body: JSON.stringify(data),
                            input_tokens: usage.prompt_tokens,
                            output_tokens: usage.completion_tokens,
                            cached_tokens: usage.prompt_tokens_details?.cached_tokens,
                        });
                    }
                    catch (updateError) {
                        this.logger.warn(`Failed to update LLM call log: ${updateError.message}`);
                    }
                }
                return {
                    text: content || '',
                    usage: {
                        inputTokens: usage.prompt_tokens,
                        outputTokens: usage.completion_tokens,
                        cachedTokens: usage.prompt_tokens_details?.cached_tokens,
                    },
                    tool_calls: parsedToolCalls,
                    thoughts: reasoningContent || undefined,
                };
            }
            if (llmCallLogId) {
                try {
                    await this.llmCallLogsService.updateLog(llmCallLogId, {
                        status_code: response.status,
                        latency_ms: Date.now() - startTime,
                        response_body: JSON.stringify(data),
                    });
                }
                catch (updateError) {
                    this.logger.warn(`Failed to update LLM call log: ${updateError.message}`);
                }
            }
            return {
                text: content || '',
                tool_calls: parsedToolCalls,
                thoughts: reasoningContent || undefined,
            };
        }
        catch (error) {
            this.logger.error(`Alibaba generation failed: ${error.message}`);
            if (llmCallLogId) {
                try {
                    await this.llmCallLogsService.updateLog(llmCallLogId, {
                        status_code: null,
                        latency_ms: Date.now() - startTime,
                        error_message: error.message,
                    });
                }
                catch (updateError) {
                    this.logger.warn(`Failed to update LLM call log: ${updateError.message}`);
                }
            }
            throw error;
        }
    }
    tryParseJson(text) {
        try {
            return JSON.parse(text);
        }
        catch {
            return null;
        }
    }
};
exports.AlibabaLlmProvider = AlibabaLlmProvider;
exports.AlibabaLlmProvider = AlibabaLlmProvider = AlibabaLlmProvider_1 = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [application_state_service_1.ApplicationStateService,
        llm_call_logs_service_1.LlmCallLogsService])
], AlibabaLlmProvider);
//# sourceMappingURL=alibaba-llm.provider.js.map