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());
    });
};
import { ToolMessage } from "@langchain/core/messages";
import { createMiddleware } from "langchain";
import { logger } from "adminforth";
import { formatApiBasedToolCall, } from "../../apiBasedTools.js";
import { createToolCallTracker, } from "../toolCallEvents.js";
import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../tools/index.js";
import { createApiTool } from "../tools/apiTool.js";
function getEnabledApiToolNames(messages) {
    const enabledToolNames = new Set();
    for (const message of messages) {
        if (!ToolMessage.isInstance(message) || message.name !== "fetch_tool_schema") {
            continue;
        }
        const content = typeof message.content === "string"
            ? message.content
            : Array.isArray(message.content)
                ? message.content
                    .map((block) => typeof block === "string"
                    ? block
                    : "text" in block
                        ? block.text
                        : "")
                    .join("")
                : "";
        try {
            const parsed = JSON.parse(content);
            if (parsed.status === 200 && parsed.name) {
                enabledToolNames.add(parsed.name);
            }
        }
        catch (_a) { }
    }
    return enabledToolNames;
}
export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
    const alwaysAvailableApiToolNames = new Set(ALWAYS_AVAILABLE_API_TOOL_NAMES);
    const dynamicTools = Object.fromEntries(Object.entries(apiBasedTools).map(([toolName, apiBasedTool]) => [
        toolName,
        createApiTool(toolName, apiBasedTool),
    ]));
    return createMiddleware({
        name: "ApiBasedToolsMiddleware",
        wrapModelCall(request, handler) {
            return __awaiter(this, void 0, void 0, function* () {
                const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
                const tools = [...enabledApiToolNames]
                    .filter((toolName) => !alwaysAvailableApiToolNames.has(toolName))
                    .map((toolName) => dynamicTools[toolName]);
                const availableTools = [...request.tools, ...tools];
                logger.info(`AdminForth Agent callable tools: ${availableTools.map((tool) => tool.name).join(", ")}`);
                return handler(Object.assign(Object.assign({}, request), { tools: availableTools }));
            });
        },
        wrapToolCall(request, handler) {
            return __awaiter(this, void 0, void 0, function* () {
                var _a, _b, _c, _d;
                const startedAt = Date.now();
                const toolInput = JSON.stringify((_a = request.toolCall.args) !== null && _a !== void 0 ? _a : {});
                const { adminUser, emit, sequenceDebugSink, userTimeZone } = request.runtime.context;
                const emitToolCall = (event) => {
                    sequenceDebugSink.handleToolCallEvent(event);
                    void (emit === null || emit === void 0 ? void 0 : emit({
                        type: "tool-call",
                        data: event,
                    }));
                };
                const toolArgs = ((_b = request.toolCall.args) !== null && _b !== void 0 ? _b : {});
                let toolInfo;
                if (request.toolCall.name === "fetch_skill") {
                    toolInfo = `Load ${toolArgs.skillName.split("_").join(" ")} skill`;
                }
                else if (request.toolCall.name === "fetch_tool_schema") {
                    toolInfo = `Load ${toolArgs.toolName.split("_").join(" ")} tool `;
                }
                else {
                    toolInfo = yield formatApiBasedToolCall({
                        adminforth,
                        adminUser,
                        inputs: toolArgs,
                        toolName: request.toolCall.name,
                        userTimeZone,
                    });
                }
                const toolCallTracker = createToolCallTracker({
                    emit: emitToolCall,
                    toolCallId: request.toolCall.id,
                    toolName: request.toolCall.name,
                    toolInfo,
                    input: toolArgs,
                    startedAt,
                });
                toolCallTracker.start();
                logger.info(`Invoking tool "${request.toolCall.name}" with input: ${toolInput}`);
                try {
                    let result;
                    if (request.tool) {
                        result = yield handler(request);
                    }
                    else {
                        const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
                        if (enabledApiToolNames.has(request.toolCall.name)) {
                            result = yield handler(Object.assign(Object.assign({}, request), { tool: dynamicTools[request.toolCall.name] }));
                        }
                        else {
                            result = new ToolMessage({
                                content: `Tool "${request.toolCall.name}" is not loaded. Call fetch_tool_schema first.`,
                                tool_call_id: (_c = request.toolCall.id) !== null && _c !== void 0 ? _c : "",
                                name: request.toolCall.name,
                                status: "error",
                            });
                        }
                    }
                    toolCallTracker.finishSuccess(result);
                    return result;
                }
                catch (error) {
                    const errorDetails = error instanceof Error ? (_d = error.stack) !== null && _d !== void 0 ? _d : error.message : String(error);
                    logger.error(`Tool "${request.toolCall.name}" failed after ${Date.now() - startedAt}ms with input: ${toolInput}\n${errorDetails}`);
                    toolCallTracker.finishError(error);
                    throw error;
                }
                finally {
                    logger.info(`Tool "${request.toolCall.name}" finished in ${Date.now() - startedAt}ms`);
                }
            });
        },
    });
}
