"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractLanguageModel = void 0;
/**
 * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
 * http://github.com/fonoster/fonoster
 *
 * This file is part of Fonoster
 *
 * Licensed under the MIT License (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    https://opensource.org/licenses/MIT
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const logger_1 = require("@fonoster/logger");
const tools_1 = require("../tools");
const chatHistory_1 = require("./chatHistory");
const createChain_1 = require("./createChain");
const createPromptTemplate_1 = require("./createPromptTemplate");
const toolInvocation_1 = require("./toolInvocation");
const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
class AbstractLanguageModel {
    constructor(params, voice, telephonyContext) {
        const { model, firstMessage, transferOptions, systemPrompt, goodbyeMessage, knowledgeBase, tools } = params;
        this.chatHistory = (0, chatHistory_1.createChatHistory)();
        this.toolsCatalog = new tools_1.ToolsCatalog(tools);
        this.voice = voice;
        this.firstMessage = firstMessage;
        this.goodbyeMessage = goodbyeMessage;
        this.transferOptions = transferOptions;
        const promptTemplate = (0, createPromptTemplate_1.createPromptTemplate)({
            systemPrompt,
            telephonyContext
        });
        this.chain = (0, createChain_1.createChain)(model, knowledgeBase, promptTemplate, this.chatHistory);
    }
    async invoke(text) {
        const { chain, chatHistory, toolsCatalog } = this;
        const response = (await chain.invoke({ text }));
        let isFirstTool = true;
        logger.verbose("invoke", {
            text,
            response: response.content,
            hasTools: (response.tool_calls?.length ?? 0) > 0,
            tools: response.tool_calls?.map((tool) => tool.name)
        });
        // Begin the conversation with the first message
        if ((await chatHistory.getMessages()).length === 0 && this.firstMessage) {
            await chatHistory.addAIMessage(this.firstMessage);
        }
        if (response.tool_calls && response.tool_calls.length > 0) {
            // eslint-disable-next-line no-loops/no-loops
            for (const toolCall of response.tool_calls) {
                const { args, name: toolName } = toolCall;
                logger.verbose(`invoking tool: ${toolName} with args: ${JSON.stringify(args)}`, {
                    isFirstTool
                });
                switch (toolName) {
                    case "hangup":
                        await chatHistory.addUserMessage(text);
                        await chatHistory.addAIMessage(this.goodbyeMessage);
                        return {
                            type: "hangup",
                            content: "tool_result: call hangup initiated",
                            toolCalls: response.tool_calls
                        };
                    case "transfer":
                        await chatHistory.addUserMessage(text);
                        await chatHistory.addAIMessage(this.transferOptions.message);
                        return {
                            type: "transfer",
                            content: "tool_result: call transfer initiated",
                            toolCalls: response.tool_calls
                        };
                    default:
                        if (isFirstTool) {
                            const tool = toolsCatalog.getTool(toolName);
                            await this.voice.say(tool?.requestStartMessage ?? "");
                        }
                        await (0, toolInvocation_1.toolInvocation)({
                            args,
                            chatHistory,
                            isFirstTool,
                            toolName,
                            toolsCatalog
                        });
                        isFirstTool = false;
                }
            }
            const finalResponse = (await chain.invoke({
                text: "Write a quick message based on the tools results"
            }));
            logger.verbose("finalResponse by AI", { content: finalResponse.content });
            response.content = finalResponse.content?.toString() ?? "";
        }
        await chatHistory.addUserMessage(text);
        await chatHistory.addAIMessage(response.content?.toString() ?? "");
        logger.verbose("system will say", { content: response.content });
        return {
            type: "say",
            content: response.content.toString(),
            toolCalls: response.tool_calls
        };
    }
    async getChatHistoryMessages() {
        return this.chatHistory.getMessages();
    }
}
exports.AbstractLanguageModel = AbstractLanguageModel;
