"use strict";
var __webpack_require__ = {};
(()=>{
    __webpack_require__.d = (exports1, definition)=>{
        for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
            enumerable: true,
            get: definition[key]
        });
    };
})();
(()=>{
    __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
    __webpack_require__.r = (exports1)=>{
        if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
            value: 'Module'
        });
        Object.defineProperty(exports1, '__esModule', {
            value: true
        });
    };
})();
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
    locatePlanForLocate: ()=>locatePlanForLocate,
    TaskBuilder: ()=>TaskBuilder
});
const index_js_namespaceObject = require("../ai-model/index.js");
const external_types_js_namespaceObject = require("../types.js");
const external_utils_js_namespaceObject = require("../utils.js");
const extractor_namespaceObject = require("@midscene/shared/extractor");
const logger_namespaceObject = require("@midscene/shared/logger");
const utils_namespaceObject = require("@midscene/shared/utils");
const external_utils_js_namespaceObject_1 = require("./utils.js");
function _define_property(obj, key, value) {
    if (key in obj) Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
    });
    else obj[key] = value;
    return obj;
}
const debug = (0, logger_namespaceObject.getDebug)('agent:task-builder');
function hasNonEmptyCache(cache) {
    return null != cache && 'object' == typeof cache && Object.keys(cache).length > 0;
}
function locatePlanForLocate(param) {
    const locate = 'string' == typeof param ? {
        prompt: param
    } : param;
    const locatePlan = {
        type: 'Locate',
        param: locate,
        thought: ''
    };
    return locatePlan;
}
class TaskBuilder {
    async build(plans, modelConfigForPlanning, modelConfigForDefaultIntent, options) {
        const tasks = [];
        const cacheable = options?.cacheable;
        const context = {
            tasks,
            modelConfigForPlanning,
            modelConfigForDefaultIntent,
            cacheable,
            subTask: !!options?.subTask,
            deepLocate: options?.deepLocate
        };
        const planHandlers = new Map([
            [
                'Locate',
                (plan)=>this.handleLocatePlan(plan, context)
            ],
            [
                'Finished',
                (plan)=>this.handleFinishedPlan(plan, context)
            ]
        ]);
        const defaultHandler = (plan)=>this.handleActionPlan(plan, context);
        for (const plan of plans){
            const handler = planHandlers.get(plan.type) ?? defaultHandler;
            await handler(plan);
        }
        return {
            tasks
        };
    }
    handleFinishedPlan(plan, context) {
        const taskActionFinished = {
            type: 'Action Space',
            subType: 'Finished',
            param: null,
            thought: plan.thought,
            subTask: context.subTask || void 0,
            executor: async ()=>{}
        };
        context.tasks.push(taskActionFinished);
    }
    async handleLocatePlan(plan, context) {
        const taskLocate = this.createLocateTask(plan, plan.param, context);
        context.tasks.push(taskLocate);
    }
    async handleActionPlan(plan, context) {
        const planType = plan.type;
        const actionSpace = this.actionSpace;
        const action = actionSpace.find((item)=>item.name === planType);
        const param = plan.param;
        if (!action) throw new Error(`Action type '${planType}' not found`);
        const locateFields = action ? (0, index_js_namespaceObject.findAllMidsceneLocatorField)(action.paramSchema) : [];
        const requiredLocateFields = action ? (0, index_js_namespaceObject.findAllMidsceneLocatorField)(action.paramSchema, true) : [];
        locateFields.forEach((field)=>{
            if (param[field]) {
                const locatePlan = locatePlanForLocate(param[field]);
                debug('will prepend locate param for field', `action.type=${planType}`, `param=${JSON.stringify(param[field])}`, `locatePlan=${JSON.stringify(locatePlan)}`, `hasBbox=${(0, external_utils_js_namespaceObject_1.ifPlanLocateParamIsBbox)(param[field])}`);
                const locateTask = this.createLocateTask(locatePlan, param[field], context, (result)=>{
                    param[field] = result;
                });
                context.tasks.push(locateTask);
            } else {
                (0, utils_namespaceObject.assert)(!requiredLocateFields.includes(field), `Required locate field '${field}' is not provided for action ${planType}`);
                debug(`field '${field}' is not provided for action ${planType}`);
            }
        });
        const task = {
            type: 'Action Space',
            subType: planType,
            thought: plan.thought,
            param: plan.param,
            subTask: context.subTask || void 0,
            executor: async (param, taskContext)=>{
                debug('executing action', planType, param, `taskContext.element.center: ${taskContext.element?.center}`);
                const uiContext = taskContext.uiContext;
                (0, utils_namespaceObject.assert)(uiContext, 'uiContext is required for Action task');
                requiredLocateFields.forEach((field)=>{
                    (0, utils_namespaceObject.assert)(param[field], `field '${field}' is required for action ${planType} but not provided. Cannot execute action ${planType}.`);
                });
                try {
                    await Promise.all([
                        (async ()=>{
                            if (this.interface.beforeInvokeAction) {
                                debug('will call "beforeInvokeAction" for interface');
                                await this.interface.beforeInvokeAction(action.name, param);
                                debug('called "beforeInvokeAction" for interface');
                            }
                        })(),
                        (0, external_utils_js_namespaceObject.sleep)(200)
                    ]);
                } catch (originalError) {
                    const originalMessage = originalError?.message || String(originalError);
                    throw new Error(`error in running beforeInvokeAction for ${action.name}: ${originalMessage}`, {
                        cause: originalError
                    });
                }
                if (action.paramSchema) try {
                    param = (0, index_js_namespaceObject.parseActionParam)(param, action.paramSchema);
                } catch (error) {
                    throw new Error(`Invalid parameters for action ${action.name}: ${error.message}\nParameters: ${JSON.stringify(param)}`, {
                        cause: error
                    });
                }
                debug('calling action', action.name);
                const actionFn = action.call.bind(this.interface);
                const actionResult = await actionFn(param, taskContext);
                debug('called action', action.name, 'result:', actionResult);
                const delayAfterRunner = action.delayAfterRunner ?? this.waitAfterAction ?? 300;
                if (delayAfterRunner > 0) await (0, external_utils_js_namespaceObject.sleep)(delayAfterRunner);
                try {
                    if (this.interface.afterInvokeAction) {
                        debug('will call "afterInvokeAction" for interface');
                        await this.interface.afterInvokeAction(action.name, param);
                        debug('called "afterInvokeAction" for interface');
                    }
                } catch (originalError) {
                    const originalMessage = originalError?.message || String(originalError);
                    throw new Error(`error in running afterInvokeAction for ${action.name}: ${originalMessage}`, {
                        cause: originalError
                    });
                }
                return {
                    output: actionResult
                };
            }
        };
        context.tasks.push(task);
    }
    createLocateTask(plan, detailedLocateParam, context, onResult) {
        const { cacheable, modelConfigForDefaultIntent, deepLocate } = context;
        let locateParam = detailedLocateParam;
        if ('string' == typeof locateParam) locateParam = {
            prompt: locateParam
        };
        if (void 0 !== cacheable) locateParam = {
            ...locateParam,
            cacheable
        };
        if (deepLocate && !locateParam.deepThink) locateParam = {
            ...locateParam,
            deepThink: true
        };
        const taskLocator = {
            type: 'Planning',
            subType: 'Locate',
            subTask: context.subTask || void 0,
            param: locateParam,
            thought: plan.thought,
            executor: async (param, taskContext)=>{
                const { task } = taskContext;
                let { uiContext } = taskContext;
                (0, utils_namespaceObject.assert)(param?.prompt || param?.bbox, `No prompt or id or position or bbox to locate, param=${JSON.stringify(param)}`);
                if (!uiContext) uiContext = await this.service.contextRetrieverFn();
                (0, utils_namespaceObject.assert)(uiContext, 'uiContext is required for Service task');
                let locateDump;
                let locateResult;
                const applyDump = (dump)=>{
                    if (!dump) return;
                    locateDump = dump;
                    task.log = {
                        dump,
                        rawResponse: dump.taskInfo?.rawResponse
                    };
                    task.usage = dump.taskInfo?.usage;
                    if (dump.taskInfo?.searchAreaUsage) task.searchAreaUsage = dump.taskInfo.searchAreaUsage;
                    if (dump.taskInfo?.reasoning_content) task.reasoning_content = dump.taskInfo.reasoning_content;
                };
                const elementFromBbox = (0, external_utils_js_namespaceObject_1.ifPlanLocateParamIsBbox)(param) ? (0, external_utils_js_namespaceObject_1.matchElementFromPlan)(param) : void 0;
                const isPlanHit = !!elementFromBbox;
                let rectFromXpath;
                if (!isPlanHit && param.xpath && this.interface.rectMatchesCacheFeature) try {
                    rectFromXpath = await this.interface.rectMatchesCacheFeature({
                        xpaths: [
                            param.xpath
                        ]
                    });
                } catch  {}
                const elementFromXpath = rectFromXpath ? (0, extractor_namespaceObject.generateElementByRect)(rectFromXpath, 'string' == typeof param.prompt ? param.prompt : param.prompt?.prompt || '') : void 0;
                const isXpathHit = !!elementFromXpath;
                const cachePrompt = param.prompt;
                const locateCacheRecord = this.taskCache?.matchLocateCache(cachePrompt);
                const cacheEntry = locateCacheRecord?.cacheContent?.cache;
                const elementFromCache = isPlanHit || isXpathHit ? null : await (0, external_utils_js_namespaceObject_1.matchElementFromCache)({
                    taskCache: this.taskCache,
                    interfaceInstance: this.interface
                }, cacheEntry, cachePrompt, param.cacheable);
                const isCacheHit = !!elementFromCache;
                let elementFromAiLocate;
                if (!isXpathHit && !isCacheHit && !isPlanHit) try {
                    locateResult = await this.service.locate(param, {
                        context: uiContext
                    }, modelConfigForDefaultIntent);
                    applyDump(locateResult.dump);
                    elementFromAiLocate = locateResult.element;
                } catch (error) {
                    if (error instanceof external_types_js_namespaceObject.ServiceError) applyDump(error.dump);
                    throw error;
                }
                const element = elementFromBbox || elementFromXpath || elementFromCache || elementFromAiLocate;
                const locateCacheAlreadyExists = hasNonEmptyCache(locateCacheRecord?.cacheContent?.cache);
                let currentCacheEntry;
                if (element && this.taskCache && !isCacheHit && (!isPlanHit || !locateCacheAlreadyExists) && param?.cacheable !== false) if (this.interface.cacheFeatureForPoint) try {
                    const feature = await this.interface.cacheFeatureForPoint(element.center, {
                        targetDescription: 'string' == typeof param.prompt ? param.prompt : param.prompt?.prompt,
                        modelConfig: modelConfigForDefaultIntent
                    });
                    if (hasNonEmptyCache(feature)) {
                        debug('update cache, prompt: %s, cache: %o', cachePrompt, feature);
                        currentCacheEntry = feature;
                        this.taskCache.updateOrAppendCacheRecord({
                            type: 'locate',
                            prompt: cachePrompt,
                            cache: feature
                        }, locateCacheRecord);
                    } else debug('no cache data returned, skip cache update, prompt: %s', cachePrompt);
                } catch (error) {
                    debug('cacheFeatureForPoint failed: %s', error);
                }
                else debug('cacheFeatureForPoint is not supported, skip cache update');
                if (!element) {
                    if (locateDump) throw new external_types_js_namespaceObject.ServiceError(`Element not found : ${param.prompt}`, locateDump);
                    throw new Error(`Element not found: ${param.prompt}`);
                }
                let hitBy;
                if (isPlanHit) hitBy = {
                    from: 'Plan',
                    context: {
                        bbox: param.bbox
                    }
                };
                else if (isXpathHit) hitBy = {
                    from: 'User expected path',
                    context: {
                        xpath: param.xpath
                    }
                };
                else if (isCacheHit) hitBy = {
                    from: 'Cache',
                    context: {
                        cacheEntry,
                        cacheToSave: currentCacheEntry
                    }
                };
                onResult?.(element);
                return {
                    output: {
                        element: {
                            ...element,
                            dpr: uiContext.deprecatedDpr
                        }
                    },
                    hitBy
                };
            }
        };
        return taskLocator;
    }
    constructor({ interfaceInstance, service, taskCache, actionSpace, waitAfterAction }){
        _define_property(this, "interface", void 0);
        _define_property(this, "service", void 0);
        _define_property(this, "taskCache", void 0);
        _define_property(this, "actionSpace", void 0);
        _define_property(this, "waitAfterAction", void 0);
        this.interface = interfaceInstance;
        this.service = service;
        this.taskCache = taskCache;
        this.actionSpace = actionSpace;
        this.waitAfterAction = waitAfterAction;
    }
}
exports.TaskBuilder = __webpack_exports__.TaskBuilder;
exports.locatePlanForLocate = __webpack_exports__.locatePlanForLocate;
for(var __rspack_i in __webpack_exports__)if (-1 === [
    "TaskBuilder",
    "locatePlanForLocate"
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
Object.defineProperty(exports, '__esModule', {
    value: true
});

//# sourceMappingURL=task-builder.js.map