"use strict";
// Updated BaseAgent class to also include the ingestResponseAndStream method,
// allowing derived classes to call it, rather than defining their own.
//
// Additionally, we leave the fitHistoryWithinTokenBudget method as is.
//
// We'll remove the local ingestResponseAndStream from PluginAgent in a subsequent step.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAgent = exports.MAX_TOKENS = exports.INSERTED_CODE_PREFIX = void 0;
exports.getColor = getColor;
exports.cycleColor = cycleColor;
exports.narrowLLMProvider = narrowLLMProvider;
exports.narrowGoogleModel = narrowGoogleModel;
exports.narrowAnthropicModel = narrowAnthropicModel;
exports.narrowOpenAIModel = narrowOpenAIModel;
exports.narrowAmazonModel = narrowAmazonModel;
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
const path_1 = __importDefault(require("path"));
const cliconfig_1 = require("../../database/cliconfig");
const promises_1 = require("node:fs/promises");
const projectrootpath_1 = require("../../projectrootpath");
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
const logger_1 = require("../../utils/logger");
const messageparsing_1 = require("../messageparsing");
const openai_1 = __importDefault(require("openai"));
const tiktoken_1 = require("tiktoken");
const chalk_1 = __importDefault(require("chalk"));
const client_bedrock_runtime_1 = require("@aws-sdk/client-bedrock-runtime");
const tools_1 = require("./mcp-servers/tools");
const uuid_1 = require("uuid");
exports.INSERTED_CODE_PREFIX = `This message is added before each call to the agent and contains the code files that exist so far and is not visible in the chat client. This is the current code:`;
// Array of colors you want to cycle through
const colors = ['red', 'yellow', 'blue', 'magenta', 'cyan'];
let currentColor = 0;
function getColor() {
    return colors[currentColor];
}
function cycleColor() {
    currentColor = (currentColor + 1) % colors.length;
    return chalk_1.default.keyword(colors[currentColor]);
}
function narrowLLMProvider(provider) {
    return ["openai", "claude", "google", "amazon"].includes(provider);
}
function narrowGoogleModel(model) {
    return [
        "gemini-2.5-pro",
        "gemini-2.5-flash-preview-05-20"
    ].includes(model);
}
function narrowAnthropicModel(model) {
    return [
        'claude-sonnet-4-20250514',
        'claude-3-7-sonnet-20250219',
        'claude-3-5-sonnet-latest',
        'claude-3-5-haiku-latest'
    ].includes(model);
}
function narrowOpenAIModel(model) {
    return ['gpt-4.1', 'o1', 'o1-pro', 'gpt-4o', 'o4-mini'].includes(model);
}
function narrowAmazonModel(model) {
    return [
        'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
        'us.anthropic.claude-sonnet-4-20250514-v1:0'
    ].includes(model);
}
exports.MAX_TOKENS = {
    'claude-sonnet-4-20250514': 64000,
    'claude-3-7-sonnet-20250219': 64000,
    'claude-3-5-sonnet-latest': 8192,
    'claude-3-5-haiku-latest': 8192,
    'us.anthropic.claude-3-7-sonnet-20250219-v1:0': 64000,
    'us.anthropic.claude-sonnet-4-20250514-v1:0': 30000
};
;
function narrowFormat(format) {
    return ["image/jpeg", "image/png"].includes(format);
}
/**
 * A base Agent class for user prompt handling and chat orchestration.
 * Derived classes may override methods as needed.
 */
class BaseAgent {
    constructor() {
        this.mcpServerPath = "";
        this.tools = [];
        this.mcpClient = null;
        this.mcp = null;
        this.claude = null;
        this.openai = null;
        this.google = null;
        this.amazon = null;
    }
    initialize() {
        var _a, _b;
        if (!this.claude) {
            const rec = (0, cliconfig_1.getAPIKey)("claude");
            if (rec) {
                this.claude = new sdk_1.default({ apiKey: rec.apikey });
            }
        }
        if (!this.openai) {
            const rec = (0, cliconfig_1.getAPIKey)("openai");
            if (rec) {
                this.openai = new openai_1.default({
                    apiKey: rec.apikey,
                });
            }
        }
        if (!this.google) {
            const rec = (0, cliconfig_1.getAPIKey)("google");
            if (rec) {
                this.google = new openai_1.default({
                    apiKey: rec.apikey,
                    baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/"
                });
            }
        }
        if (!this.amazon) {
            const aws_access_key_id = (_a = (0, cliconfig_1.getAPIKey)("aws_access_key_id")) === null || _a === void 0 ? void 0 : _a.apikey; // process.env.AWS_ACCESS_KEY_ID;
            const aws_secret_access_key = (_b = (0, cliconfig_1.getAPIKey)("aws_secret_access_key")) === null || _b === void 0 ? void 0 : _b.apikey; // process.env.AWS_SECRET_ACCESS_KEY;
            if (aws_access_key_id && aws_secret_access_key) {
                this.amazon = new client_bedrock_runtime_1.BedrockRuntimeClient({
                    region: "us-east-1",
                    credentials: {
                        accessKeyId: aws_access_key_id,
                        secretAccessKey: aws_secret_access_key,
                    },
                });
            }
        }
    }
    addToolResultToChat(messages, toolInput, textOfResult, temp_id, chatId) {
        return __awaiter(this, void 0, void 0, function* () {
            messages.push({
                role: "user",
                content_type: "tool_result",
                tool_call_id: toolInput.id,
                tool_name: toolInput.tool,
                content: textOfResult,
                temp_id: temp_id
            });
            if (chatId) {
                yield (0, cliconfig_1.persistChatMessage)(chatId, toolInput.id, null, "tool_result", "user", textOfResult, temp_id);
            }
            else {
                logger_1.logger.error("No chatId found so tool response is not persisted!");
            }
        });
    }
    handleToolRun(toolInput, messages, apptile_context, temp_id, chatId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            let inputVars = {};
            if (toolInput.partialInput) {
                try {
                    inputVars = JSON.parse(toolInput.partialInput);
                }
                catch (err) {
                    console.error("Failed to parse toolinput: ", err);
                }
                inputVars.apptile_context = apptile_context;
            }
            if (!toolInput.id) {
                // force a tooluse id for gemini
                toolInput.id = "toolu-" + Date.now();
            }
            messages.push({
                role: "assistant",
                content_type: "tool_use",
                tool_call_id: toolInput.id,
                tool_name: toolInput.tool,
                content: toolInput.partialInput || "{}",
                temp_id: temp_id
            });
            if (chatId) {
                yield (0, cliconfig_1.persistChatMessage)(chatId, toolInput.id, toolInput.tool, "tool_use", "assistant", toolInput.partialInput || "{}", temp_id);
            }
            if (this.mcp) {
                try {
                    let result = yield this.mcp.client.callTool({
                        name: toolInput.tool,
                        arguments: inputVars,
                    });
                    if (Array.isArray(result.content)) {
                        if (result.content[0].text !== "user_response_required") {
                            const textOfResult = result.content[0].text;
                            yield this.addToolResultToChat(messages, toolInput, textOfResult, temp_id, chatId);
                            return "ContinueChat";
                        }
                        else {
                            logger_1.logger.info("Tool requires user intervention: " + (toolInput === null || toolInput === void 0 ? void 0 : toolInput.tool));
                            return "WaitForUserInput";
                        }
                    }
                    else {
                        logger_1.logger.error("Invalid response from tool. We are only working with one kind of resposne.");
                        yield this.addToolResultToChat(messages, toolInput, JSON.stringify(result), temp_id, chatId);
                        return "WaitForUserInput";
                    }
                }
                catch (err) {
                    logger_1.logger.error("Handled tool error happened", err);
                    const error = ((_a = err === null || err === void 0 ? void 0 : err.toString) === null || _a === void 0 ? void 0 : _a.call(err)) || "There was an unrecognized error during tool execution";
                    yield this.addToolResultToChat(messages, toolInput, error, temp_id, chatId);
                    return "ToolError";
                }
            }
            else {
                logger_1.logger.error("No mcp client found to run the tool! " + toolInput.tool);
                yield this.addToolResultToChat(messages, toolInput, "This tool is not available!", temp_id, chatId);
                return "ToolError";
            }
        });
    }
    /**
     * Creates a minimal text/image prompt from user text input.
     * Derived classes may add custom logic or context if needed.
     */
    prepareUserPrompt(userInput, assetName) {
        let contextInfo = "";
        if (assetName) {
            contextInfo = `The name of the plugin you are working on is: '${assetName}'`;
        }
        let result = [];
        if (typeof userInput === "string") {
            let imgTagStart = userInput.indexOf("<img");
            if (imgTagStart < 0) {
                imgTagStart = userInput.indexOf("&lt;img");
            }
            if (imgTagStart < 0) {
                result.push({ type: "text", text: userInput });
                if (contextInfo) {
                    result.unshift({ type: "text", text: contextInfo });
                }
                return result;
            }
            const format = userInput.match(/img\ssrc="data:(.+);base64,/);
            if (format && format[1]) {
                const originalMessage = userInput;
                const dataStart = userInput.indexOf(";base64,") + ";base64,".length;
                const dataEnd = userInput.indexOf('"', dataStart);
                let imageTagEnd = userInput.indexOf(">", imgTagStart);
                if (imageTagEnd < 0) {
                    imageTagEnd = userInput.indexOf("&gt;", imgTagStart);
                }
                userInput =
                    userInput.slice(0, imgTagStart) +
                        "`image_included_in_next_message`" +
                        userInput.slice(imageTagEnd + 1, dataEnd);
                if (narrowFormat(format[1])) {
                    result.push({ type: "text", text: userInput });
                    result.push({
                        type: "image",
                        source: {
                            type: "base64",
                            media_type: format[1],
                            data: originalMessage.slice(dataStart, dataEnd),
                        },
                    });
                }
                else {
                    result.push({ type: "text", text: userInput });
                }
            }
            else {
                result.push({ type: "text", text: userInput });
            }
            if (contextInfo) {
                result.unshift({ type: "text", text: contextInfo });
            }
        }
        else if (userInput.isToolResponse) {
            result = userInput.response.map(resp => {
                return {
                    type: "tool_result",
                    tool_use_id: resp.id,
                    content: resp.result
                };
            });
        }
        else {
            logger_1.logger.error("Unprocessable user prompt! Stopping. " + JSON.stringify(userInput));
            throw new Error("Invalid prompt!");
        }
        return result;
    }
    countOpenAITokens(messages, model) {
        const encoder = (0, tiktoken_1.encoding_for_model)(model);
        let tokenCount = 0;
        for (const msg of messages) {
            tokenCount += encoder.encode(msg.role || "").length;
            if (msg.role === "assistant") {
                if (typeof msg.content === "string") {
                    tokenCount += encoder.encode(msg.content).length;
                }
                else if (Array.isArray(msg.content)) {
                    for (let block of msg.content) {
                        if (block.type === "text") {
                            tokenCount += encoder.encode(block.text).length;
                        }
                        else {
                            throw new Error("Cannot encode non text tokens yet");
                        }
                    }
                }
                if (msg.tool_calls) {
                    for (let toolCall of msg.tool_calls) {
                        tokenCount += encoder.encode(toolCall.id).length;
                        tokenCount += encoder.encode(toolCall.type).length;
                        tokenCount += encoder.encode(toolCall.function.name).length;
                        tokenCount += encoder.encode(toolCall.function.arguments).length;
                    }
                }
            }
            else if (msg.role === "tool") {
                tokenCount += encoder.encode(msg.tool_call_id).length;
                if (typeof msg.content === "string") {
                    tokenCount += encoder.encode(msg.content).length;
                }
                else {
                    for (let block of msg.content) {
                        if (block.type === "text") {
                            tokenCount += encoder.encode(block.text).length;
                        }
                        else {
                            throw new Error("Cannot encode non text tokens yet");
                        }
                    }
                }
            }
            else if (msg.role === "user") {
                if (typeof msg.content === "string") {
                    tokenCount += encoder.encode(msg.content).length;
                }
                else {
                    for (let block of msg.content) {
                        if (block.type === "text") {
                            tokenCount += encoder.encode(block.text).length;
                        }
                        else {
                            throw new Error("Cannot encode non text tokens yet");
                        }
                    }
                }
            }
        }
        return tokenCount;
    }
    /**
     * Fits chat history within a specified token budget by removing oldest messages if needed.
     */
    fitHistoryWithinTokenBudget(messages, initialPrompt, model, provider, pluginInfo, user) {
        return __awaiter(this, void 0, void 0, function* () {
            logger_1.logger.info(`[BaseAgent][${user}] Start fitting with ` + messages.length + " messages.");
            const MAX_TOKENS_IN_HISTORY = 40000;
            if (provider === "claude") {
                if (!this.claude) {
                    return messages;
                }
                if (pluginInfo === null) {
                    let totalLength = messages.length;
                    if (totalLength > 50) {
                        messages = messages.slice(totalLength - 50);
                    }
                }
                else {
                    let newMessages = [];
                    let startIndex = 0;
                    if (messages.length > 15) {
                        startIndex = messages.length - 15;
                    }
                    logger_1.logger.info("Starting from index: " + startIndex);
                    for (let i = startIndex; i < messages.length; ++i) {
                        const message = messages[i];
                        if (message.tool_name === "apply_file_ops") {
                            message.content = '{"message": "The body of this tool call was removed to save tokens"}';
                        }
                        newMessages.push(message);
                    }
                    messages = (0, cliconfig_1.sequenceToolCallAndResponses)(newMessages);
                    try {
                        logger_1.logger.info(chalk_1.default.green("Adding file contents for: " + pluginInfo.pluginsDir + pluginInfo.pluginName));
                        const formattedFileContents = yield (0, tools_1.readAllPluginFilesByPluginName)(pluginInfo.pluginsDir, pluginInfo.pluginName);
                        const existingCode = exports.INSERTED_CODE_PREFIX + '\n' + formattedFileContents.content[0].text;
                        messages = messages.filter(it => !it.content.startsWith(exports.INSERTED_CODE_PREFIX));
                        messages.unshift({
                            role: "user",
                            content_type: "text",
                            content: existingCode,
                            tool_call_id: null,
                            tool_name: null,
                            temp_id: "none"
                        });
                    }
                    catch (err) {
                        logger_1.logger.error(`[BaseAgent] could not read plugin code`);
                    }
                }
                // let prevTokens = 0;
                // let candidateMessages = messages.slice();
                // do {
                //   try {
                //     const tokenCount = await this.claude.messages.countTokens({
                //       model,
                //       system: initialPrompt,
                //       messages: toAnthropicMessages(candidateMessages),
                //     });
                //     prevTokens = tokenCount.input_tokens;
                //     if (prevTokens > MAX_TOKENS_IN_HISTORY && candidateMessages.length > 0) {
                //       let startIndex = Math.floor(candidateMessages.length / 2);
                //       if (startIndex === 0 && candidateMessages.length > 0) {
                //         startIndex = 1;
                //       }
                //       const messagesToDrop = candidateMessages.length - startIndex;
                //       candidateMessages = candidateMessages.slice(startIndex);
                //       candidateMessages = sequenceToolCallAndResponses(candidateMessages);
                //       logger.info(`[BaseAgent][${user}] prevTokens: `+ prevTokens);
                //       // logger.info(`[BaseAgent][${user}] Dropped message to fit token budget:`+ JSON.stringify(droppedMessage, null, 2));
                //       logger.info(`[BaseAgent][${user}] Dropped ${messagesToDrop} messages to fit token budget`);
                //     }
                //   } catch (err) {
                //     const droppedMessage = candidateMessages.shift();
                //     candidateMessages = sequenceToolCallAndResponses(candidateMessages);
                //     logger.error("An error occurred during fitting. Will drop a message: ");
                //     logger.info(`[BaseAgent][${user}] prevTokens: `+ prevTokens);
                //     // logger.info(`[BaseAgent][${user}] Dropped message to fit token budget:`+ JSON.stringify(droppedMessage, null, 2));
                //     logger.info(`[BaseAgent][${user}] Dropped message to fit token budget`);
                //   }
                // } while (prevTokens > MAX_TOKENS_IN_HISTORY && candidateMessages.length > 0);
                // messages = candidateMessages;
            }
            else if (provider === "openai") {
                if (!this.openai) {
                    return messages;
                }
                let prevTokens = 0;
                do {
                    const openaiMsgs = (0, cliconfig_1.toOpenaiMessages)(messages, initialPrompt);
                    // TODO(gaurav): Handle narrowing the model. Right now its only a few so its fine.
                    const tokenCount = this.countOpenAITokens(openaiMsgs, model);
                    prevTokens = tokenCount;
                    if (prevTokens > MAX_TOKENS_IN_HISTORY && messages.length > 0) {
                        const droppedMessage = messages.shift();
                        logger_1.logger.info(`[BaseAgent][${user}] Dropped message to fit token budget: `, droppedMessage);
                    }
                } while (prevTokens > MAX_TOKENS_IN_HISTORY && messages.length > 0);
            }
            else if (provider === "amazon") {
                if (pluginInfo === null) {
                    let totalLength = messages.length;
                    if (totalLength > 50) {
                        messages = messages.slice(totalLength - 50);
                    }
                }
                else {
                    let newMessages = [];
                    let startIndex = 0;
                    if (messages.length > 15) {
                        startIndex = messages.length - 15;
                    }
                    logger_1.logger.info("Starting from index: " + startIndex);
                    for (let i = startIndex; i < messages.length; ++i) {
                        const message = messages[i];
                        if (message.tool_name === "apply_file_ops") {
                            message.content = '{"message": "The body of this tool call was removed to save tokens"}';
                        }
                        newMessages.push(message);
                    }
                    messages = (0, cliconfig_1.sequenceToolCallAndResponses)(newMessages);
                    try {
                        logger_1.logger.info(chalk_1.default.green("Adding file contents for: " + pluginInfo.pluginsDir + pluginInfo.pluginName));
                        const formattedFileContents = yield (0, tools_1.readAllPluginFilesByPluginName)(pluginInfo.pluginsDir, pluginInfo.pluginName);
                        const existingCode = exports.INSERTED_CODE_PREFIX + '\n' + formattedFileContents.content[0].text;
                        messages = messages.filter(it => !it.content.startsWith(exports.INSERTED_CODE_PREFIX));
                        messages.unshift({
                            role: "user",
                            content_type: "text",
                            content: existingCode,
                            tool_call_id: null,
                            tool_name: null,
                            temp_id: "none"
                        });
                    }
                    catch (err) {
                        logger_1.logger.error(`[BaseAgent] could not read plugin code`);
                    }
                }
            }
            else {
                messages = (0, cliconfig_1.sequenceToolCallAndResponses)(messages);
                ;
                logger_1.logger.info(`[BaseAgent] no token counting available for gemini`);
            }
            return messages;
        });
    }
    retrieveOrCreateChat(anchor, model, type, provider, finalizedPrompt, systemPromptPath, appId, user, temp_id) {
        return __awaiter(this, void 0, void 0, function* () {
            let chat = yield (0, cliconfig_1.getChat)(anchor);
            if (!chat) {
                logger_1.logger.info(`[BaseAgent][${user}] creating chat for anchor because it wasn't found` + anchor);
                chat = yield (0, cliconfig_1.createChat)(anchor, type, provider, model, appId);
            }
            if (chat) {
                logger_1.logger.info(`[BaseAgent][${user}] db chat object found. Finalized prompt that needs to be added to chat history: ` +
                    chalk_1.default.gray(JSON.stringify(finalizedPrompt, null, 2)));
                for (let prompt of finalizedPrompt) {
                    // logger.debug(chalk.yellow("Persisting: " + JSON.stringify(prompt, null, 2)))
                    if (prompt.type === "text") {
                        // logger.debug(chalk.yellow("Persisting as text "))
                        yield (0, cliconfig_1.persistChatMessage)(chat.id, null, null, "text", "user", prompt.text, temp_id);
                    }
                    else if (prompt.type === "image") {
                        // logger.debug(chalk.yellow("Persisting as image "))
                        yield (0, cliconfig_1.persistChatMessage)(chat.id, null, null, prompt.source.media_type, "user", prompt.source.data, temp_id);
                    }
                    else if (prompt.type === "tool_result") {
                        // logger.debug(chalk.yellow("Persisting as toolresult "))
                        yield (0, cliconfig_1.persistChatMessage)(chat.id, prompt.tool_use_id, null, "tool_result", "user", prompt.content, temp_id);
                    }
                    else {
                        logger_1.logger.error("Cannot persist message");
                    }
                }
            }
            else {
                throw new Error("Could not retrieve or create chat");
            }
            const systemPrompt = yield (0, promises_1.readFile)(systemPromptPath, { encoding: "utf8" });
            // build the message array
            let messages;
            // gather chat history (excluding tool calls from user+assistant)
            if (chat) {
                const rawMessages = yield (0, cliconfig_1.getChatMessages)(chat.id, "ASC");
                logger_1.logger.info(`[BaseAgent][${user}] Retrieved ` + rawMessages.length + " messages after persisting prompt");
                const chatMessages = (0, cliconfig_1.sequenceToolCallAndResponses)(rawMessages);
                logger_1.logger.info(`[BaseAgent][${user}] After resequencing ` + chatMessages.length + " remained");
                messages = (0, cliconfig_1.toInMemoryChatMessage)(chatMessages);
            }
            else {
                messages = [];
            }
            return { chat, messages, systemPrompt };
        });
    }
    safeListTools() {
        return __awaiter(this, arguments, void 0, function* (retries = 3) {
            var _a;
            for (let attempt = 0; attempt < retries; attempt++) {
                try {
                    if (this.mcp) {
                        return (_a = this.mcp) === null || _a === void 0 ? void 0 : _a.client.listTools();
                    }
                    else {
                        logger_1.logger.error("[BaseAgent] Cannot list mcp tools as no mcp was found!");
                        return { tools: [] };
                    }
                }
                catch (e) {
                    console.error(`Attempt ${attempt + 1} failed:`, e);
                    yield this.reconnectMCPServer();
                    yield new Promise(r => setTimeout(r, 4000 * (attempt + 1)));
                }
            }
            logger_1.logger.error("[BaseAgent] Failed to list mcp tools");
            return { tools: [] }; // All retries failed
        });
    }
    // Note: I have added the filtering on tools as a hack while the batch tool is evaluated in amazon
    ingestResponseAndStream(llmsdk, systemPrompt, model, messages, res, tokenCounterInstance, isPlanner) {
        return __awaiter(this, void 0, void 0, function* () {
            const uuid = (0, uuid_1.v4)();
            if (llmsdk instanceof sdk_1.default && narrowAnthropicModel(model)) {
                let tools = [];
                if (this.mcp) {
                    const serverTools = yield this.safeListTools();
                    for (let i = 0; i < serverTools.tools.length; ++i) {
                        const tool = serverTools.tools[i];
                        if (isPlanner) {
                            if (![
                                "nocodelayer_create_global_plugin",
                                "nocodelayer_create_screen",
                                "nocodelayer_create_plugin",
                                "nocodelayer_add_plugin_to_screen",
                                "nocodelayer_update_global_plugin_defaultvalue"
                            ].includes(tool.name)) {
                                tools.push({
                                    name: tool.name,
                                    description: tool.description,
                                    input_schema: tool.inputSchema,
                                });
                            }
                        }
                        else {
                            if (tool.name !== "nocodelayer_batch_tools") {
                                tools.push({
                                    name: tool.name,
                                    description: tool.description,
                                    input_schema: tool.inputSchema,
                                });
                            }
                        }
                    }
                }
                tokenCounterInstance.setTools(tools);
                if (tools.length > 0) {
                    let lastTool = tools[tools.length - 1];
                    lastTool.cache_control = { type: "ephemeral" };
                }
                const anthropicMessages = (0, cliconfig_1.toAnthropicMessages)(messages);
                logger_1.logger.info(chalk_1.default.green("Calling anthropic"));
                const responseStream = llmsdk.messages.stream({
                    system: [
                        {
                            type: "text",
                            text: systemPrompt,
                            cache_control: { type: "ephemeral" }
                        }
                    ],
                    model,
                    messages: anthropicMessages,
                    max_tokens: exports.MAX_TOKENS[model],
                    tool_choice: {
                        type: "auto",
                        disable_parallel_tool_use: true,
                    },
                    tools,
                });
                logger_1.logger.info(chalk_1.default.green("Stream started for temp_id" + uuid));
                const result = yield (0, messageparsing_1.ingestClaudeResponseStream)(responseStream, res, uuid);
                logger_1.logger.info(chalk_1.default.green("Stream processed for message: " + result.uuid));
                return result;
            }
            else if (llmsdk instanceof openai_1.default && narrowOpenAIModel(model)) {
                let tools = [];
                if (this.mcp) {
                    const serverTools = yield this.safeListTools();
                    tools = serverTools.tools.map(tool => {
                        return {
                            type: "function",
                            function: {
                                name: tool.name,
                                description: tool.description,
                                parameters: tool.inputSchema
                            }
                        };
                    })
                        .filter(tool => tool.function.name !== "nocodelayer_batch_tools");
                }
                const openaiMessages = (0, cliconfig_1.toOpenaiMessages)(messages, systemPrompt);
                logger_1.logger.info(chalk_1.default.green("Calling openai"));
                const responseStream = llmsdk.chat.completions.create({
                    model,
                    messages: openaiMessages,
                    stream: true,
                    tools,
                    // temperature: 0.9
                });
                logger_1.logger.info(chalk_1.default.green("Stream started"));
                const result = yield (0, messageparsing_1.ingestOpenaiMessageStream)(responseStream, res, uuid);
                logger_1.logger.info(chalk_1.default.green("Stream processed"));
                return result;
            }
            else if (llmsdk instanceof openai_1.default && narrowGoogleModel(model)) {
                let tools = [];
                if (this.mcp) {
                    const serverTools = yield this.safeListTools();
                    tools = serverTools.tools.map(tool => {
                        return {
                            type: "function",
                            function: {
                                name: tool.name,
                                description: tool.description,
                                parameters: tool.inputSchema,
                            }
                        };
                    })
                        .filter(tool => tool.function.name !== "nocodelayer_batch_tools");
                }
                const openaiMessages = (0, cliconfig_1.toOpenaiMessages)(messages, systemPrompt);
                logger_1.logger.info(chalk_1.default.green("Calling openai"));
                const responseStream = llmsdk.chat.completions.create({
                    model,
                    messages: openaiMessages,
                    stream: true,
                    tools,
                    // temperature: 0.9
                });
                logger_1.logger.info(chalk_1.default.green("Stream started"));
                const result = yield (0, messageparsing_1.ingestOpenaiMessageStream)(responseStream, res, uuid);
                logger_1.logger.info(chalk_1.default.green("Stream processed"));
                return result;
            }
            else if (llmsdk instanceof client_bedrock_runtime_1.BedrockRuntimeClient && narrowAmazonModel(model)) {
                const tools = [];
                if (this.mcp) {
                    const serverTools = yield this.safeListTools();
                    for (let i = 0; i < serverTools.tools.length; ++i) {
                        const tool = serverTools.tools[i];
                        if (isPlanner) {
                            if (![
                                "nocodelayer_create_global_plugin",
                                "nocodelayer_create_screen",
                                "nocodelayer_create_plugin",
                                "nocodelayer_add_plugin_to_screen",
                                "nocodelayer_update_global_plugin_defaultvalue"
                            ].includes(tool.name)) {
                                tools.push({
                                    toolSpec: {
                                        name: tool.name,
                                        description: tool.description,
                                        inputSchema: {
                                            json: tool.inputSchema,
                                        },
                                    }
                                });
                            }
                        }
                        else {
                            if (tool.name !== "nocodelayer_batch_tools") {
                                tools.push({
                                    toolSpec: {
                                        name: tool.name,
                                        description: tool.description,
                                        inputSchema: {
                                            json: tool.inputSchema,
                                        },
                                    }
                                });
                            }
                        }
                    }
                }
                const amazonMessages = (0, cliconfig_1.toAmazonMessages)(messages);
                logger_1.logger.info(chalk_1.default.green("Calling amazon: ")); // + messages[0].content);
                const command = new client_bedrock_runtime_1.ConverseStreamCommand({
                    modelId: model,
                    messages: amazonMessages,
                    system: [{ text: systemPrompt }, { cachePoint: { type: "default" } }],
                    inferenceConfig: {
                        maxTokens: 30000,
                        temperature: 0.7,
                        topP: 1,
                    },
                    toolConfig: {
                        tools: tools
                    }
                });
                logger_1.logger.info(chalk_1.default.green("Stream started"));
                const responseStream = yield llmsdk.send(command);
                // console.log(JSON.stringify(response, null, 4));
                const result = yield (0, messageparsing_1.ingestAmazonMessageStream)(responseStream, res, uuid);
                logger_1.logger.info(chalk_1.default.green("Stream processed"));
                if (result.amazonUsage) {
                    tokenCounterInstance.setAmazonUsage(result.amazonUsage);
                }
                return result;
            }
            else {
                throw new Error("This llm provider is not implemented");
            }
        });
    }
    /**
     * Default runPrompt method for Agents that rely on chat-based interactions.
     * Derived classes can override or extend it as needed.
     */
    runPrompt(appId, assetName, userPrompt, req, res, model, provider, user, temp_id) {
        return __awaiter(this, void 0, void 0, function* () {
            throw new Error("You must implement a runPrompt method in your class");
        });
    }
    reconnectMCPServer() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.mcpClient && this.mcpServerPath) {
                return this.connectToMCPServer(this.mcpServerPath, this.mcpClient, this.tools);
            }
            else {
                logger_1.logger.error("Cannot reconnect mcp server before connection happens once!");
            }
        });
    }
    /**
     * Helper method to connect to an MCP server and gather tools from it.
     */
    connectToMCPServer(serverScriptPath_1, mcpClient_1) {
        return __awaiter(this, arguments, void 0, function* (serverScriptPath, mcpClient, tools = []) {
            this.mcpServerPath = serverScriptPath;
            this.mcpClient = mcpClient;
            this.tools = tools;
            logger_1.logger.info(chalk_1.default.red("CONNECTING TO MCP SERVER: " + tools.join(",")));
            try {
                const isJS = serverScriptPath.endsWith(".js");
                const isPy = serverScriptPath.endsWith(".py");
                const isTS = serverScriptPath.endsWith(".ts");
                let transport;
                if (isJS) {
                    transport = new stdio_js_1.StdioClientTransport({
                        command: "node",
                        args: [serverScriptPath, ...tools],
                    });
                }
                else if (isPy) {
                    transport = new stdio_js_1.StdioClientTransport({
                        command: "python3",
                        args: [serverScriptPath, ...tools],
                    });
                }
                else if (isTS) {
                    const tsNodePath = path_1.default.resolve(projectrootpath_1.nodejsRoot, "node_modules", ".bin", "ts-node");
                    transport = new stdio_js_1.StdioClientTransport({
                        command: "node",
                        args: [tsNodePath, serverScriptPath, ...tools],
                    });
                }
                else {
                    transport = new stdio_js_1.StdioClientTransport({
                        command: serverScriptPath,
                        args: tools
                    });
                }
                yield mcpClient.client.connect(transport);
                // const toolResult = await mcpClient.client.listTools();
                // for (let i = 0; i < toolResult.tools.length; i++) {
                //   const tool = toolResult.tools[i];
                //   mcpClient.tools.push(tool.name);
                // }
            }
            catch (err) {
                logger_1.logger.error("Failed to connect to mcp server: " + serverScriptPath, err);
            }
        });
    }
}
exports.BaseAgent = BaseAgent;
