"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: ()=>external_task_builder_js_namespaceObject.locatePlanForLocate,
    TaskExecutionError: ()=>external_task_runner_js_namespaceObject.TaskExecutionError,
    TaskExecutor: ()=>TaskExecutor,
    withFileChooser: ()=>withFileChooser
});
const index_js_namespaceObject = require("../ai-model/index.js");
const util_js_namespaceObject = require("../ai-model/auto-glm/util.js");
const external_common_js_namespaceObject = require("../common.js");
const external_task_runner_js_namespaceObject = require("../task-runner.js");
const external_types_js_namespaceObject = require("../types.js");
const env_namespaceObject = require("@midscene/shared/env");
const logger_namespaceObject = require("@midscene/shared/logger");
const utils_namespaceObject = require("@midscene/shared/utils");
const external_execution_session_js_namespaceObject = require("./execution-session.js");
const external_task_builder_js_namespaceObject = require("./task-builder.js");
const extractor_namespaceObject = require("@midscene/shared/extractor");
const external_ui_utils_js_namespaceObject = require("./ui-utils.js");
const external_utils_js_namespaceObject = 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)('device-task-executor');
const maxErrorCountAllowedInOnePlanningLoop = 5;
class TaskExecutor {
    get page() {
        return this.interface;
    }
    createExecutionSession(title, options) {
        return new external_execution_session_js_namespaceObject.ExecutionSession(title, ()=>Promise.resolve(this.service.contextRetrieverFn()), {
            onTaskStart: this.onTaskStartCallback,
            tasks: options?.tasks,
            onTaskUpdate: this.hooks?.onTaskUpdate
        });
    }
    getActionSpace() {
        return this.providedActionSpace;
    }
    async getTimeString(format) {
        const timestamp = await (0, env_namespaceObject.getCurrentTime)(this.interface, this.useDeviceTimestamp);
        return (0, external_common_js_namespaceObject.getReadableTimeString)(format, timestamp);
    }
    async convertPlanToExecutable(plans, modelConfigForPlanning, modelConfigForDefaultIntent, options) {
        return this.taskBuilder.build(plans, modelConfigForPlanning, modelConfigForDefaultIntent, options);
    }
    async loadYamlFlowAsPlanning(userInstruction, yamlString) {
        const session = this.createExecutionSession((0, external_ui_utils_js_namespaceObject.taskTitleStr)('Act', userInstruction));
        const task = {
            type: 'Planning',
            subType: 'LoadYaml',
            param: {
                userInstruction
            },
            executor: async (param, executorContext)=>{
                const { uiContext } = executorContext;
                (0, utils_namespaceObject.assert)(uiContext, 'uiContext is required for Planning task');
                return {
                    output: {
                        actions: [],
                        shouldContinuePlanning: false,
                        log: '',
                        yamlString
                    },
                    cache: {
                        hit: true
                    },
                    hitBy: {
                        from: 'Cache',
                        context: {
                            yamlString
                        }
                    }
                };
            }
        };
        const runner = session.getRunner();
        await session.appendAndRun(task);
        return {
            runner
        };
    }
    async runPlans(title, plans, modelConfigForPlanning, modelConfigForDefaultIntent) {
        const session = this.createExecutionSession(title);
        const { tasks } = await this.convertPlanToExecutable(plans, modelConfigForPlanning, modelConfigForDefaultIntent);
        const runner = session.getRunner();
        const result = await session.appendAndRun(tasks);
        const { output } = result ?? {};
        return {
            output,
            runner
        };
    }
    async action(userPrompt, modelConfigForPlanning, modelConfigForDefaultIntent, includeBboxInPlanning, aiActContext, cacheable, replanningCycleLimitOverride, imagesIncludeCount, deepThink, fileChooserAccept, deepLocate) {
        return withFileChooser(this.interface, fileChooserAccept, async ()=>this.runAction(userPrompt, modelConfigForPlanning, modelConfigForDefaultIntent, includeBboxInPlanning, aiActContext, cacheable, replanningCycleLimitOverride, imagesIncludeCount, deepThink, deepLocate));
    }
    async runAction(userPrompt, modelConfigForPlanning, modelConfigForDefaultIntent, includeBboxInPlanning, aiActContext, cacheable, replanningCycleLimitOverride, imagesIncludeCount, deepThink, deepLocate) {
        this.conversationHistory.reset();
        const session = this.createExecutionSession((0, external_ui_utils_js_namespaceObject.taskTitleStr)('Act', userPrompt));
        const runner = session.getRunner();
        let replanCount = 0;
        const yamlFlow = [];
        const replanningCycleLimit = replanningCycleLimitOverride ?? this.replanningCycleLimit;
        (0, utils_namespaceObject.assert)(void 0 !== replanningCycleLimit, 'replanningCycleLimit is required for TaskExecutor.action');
        let errorCountInOnePlanningLoop = 0;
        let outputString;
        while(true){
            const subGoalStatus = this.conversationHistory.subGoalsToText() || void 0;
            const memoriesStatus = this.conversationHistory.memoriesToText() || void 0;
            const result = await session.appendAndRun({
                type: 'Planning',
                subType: 'Plan',
                param: {
                    userInstruction: userPrompt,
                    aiActContext,
                    imagesIncludeCount,
                    deepThink,
                    ...subGoalStatus ? {
                        subGoalStatus
                    } : {},
                    ...memoriesStatus ? {
                        memoriesStatus
                    } : {}
                },
                executor: async (param, executorContext)=>{
                    const { uiContext } = executorContext;
                    (0, utils_namespaceObject.assert)(uiContext, 'uiContext is required for Planning task');
                    const { modelFamily } = modelConfigForPlanning;
                    const actionSpace = this.getActionSpace();
                    debug('actionSpace for this interface is:', actionSpace.map((action)=>action.name).join(', '));
                    (0, utils_namespaceObject.assert)(Array.isArray(actionSpace), 'actionSpace must be an array');
                    if (0 === actionSpace.length) console.warn(`ActionSpace for ${this.interface.interfaceType} is empty. This may lead to unexpected behavior.`);
                    const planImpl = (0, util_js_namespaceObject.isUITars)(modelFamily) ? index_js_namespaceObject.uiTarsPlanning : (0, util_js_namespaceObject.isAutoGLM)(modelFamily) ? index_js_namespaceObject.autoGLMPlanning : index_js_namespaceObject.plan;
                    let planResult;
                    try {
                        planResult = await planImpl(param.userInstruction, {
                            context: uiContext,
                            actionContext: param.aiActContext,
                            interfaceType: this.interface.interfaceType,
                            actionSpace,
                            modelConfig: modelConfigForPlanning,
                            conversationHistory: this.conversationHistory,
                            includeBbox: includeBboxInPlanning,
                            imagesIncludeCount,
                            deepThink
                        });
                    } catch (planError) {
                        if (planError instanceof index_js_namespaceObject.AIResponseParseError) {
                            executorContext.task.usage = planError.usage;
                            executorContext.task.log = {
                                ...executorContext.task.log || {},
                                rawResponse: planError.rawResponse
                            };
                        }
                        throw planError;
                    }
                    debug('planResult', JSON.stringify(planResult, null, 2));
                    const { actions, thought, log, memory, error, usage, rawResponse, reasoning_content, finalizeSuccess, finalizeMessage, updateSubGoals, markFinishedIndexes } = planResult;
                    outputString = finalizeMessage;
                    executorContext.task.log = {
                        ...executorContext.task.log || {},
                        rawResponse
                    };
                    executorContext.task.usage = usage;
                    executorContext.task.reasoning_content = reasoning_content;
                    executorContext.task.output = {
                        actions: actions || [],
                        log,
                        thought,
                        memory,
                        yamlFlow: planResult.yamlFlow,
                        output: finalizeMessage,
                        shouldContinuePlanning: planResult.shouldContinuePlanning,
                        updateSubGoals,
                        markFinishedIndexes
                    };
                    executorContext.uiContext = uiContext;
                    (0, utils_namespaceObject.assert)(!error, `Failed to continue: ${error}\n${log || ''}`);
                    if (false === finalizeSuccess) (0, utils_namespaceObject.assert)(false, `Task failed: ${finalizeMessage || 'No error message provided'}\n${log || ''}`);
                    return {
                        cache: {
                            hit: false
                        }
                    };
                }
            }, {
                allowWhenError: true
            });
            const planResult = result?.output;
            const plans = planResult?.actions || [];
            yamlFlow.push(...planResult?.yamlFlow || []);
            let executables;
            try {
                executables = await this.convertPlanToExecutable(plans, modelConfigForPlanning, modelConfigForDefaultIntent, {
                    cacheable,
                    subTask: true,
                    deepLocate
                });
            } catch (error) {
                return session.appendErrorPlan(`Error converting plans to executable tasks: ${error}, plans: ${JSON.stringify(plans)}`);
            }
            if (this.conversationHistory.pendingFeedbackMessage) console.warn('unconsumed pending feedback message detected, this may lead to unexpected planning result:', this.conversationHistory.pendingFeedbackMessage);
            const initialTimeString = await this.getTimeString();
            this.conversationHistory.pendingFeedbackMessage += `Current time: ${initialTimeString}`;
            try {
                await session.appendAndRun(executables.tasks);
            } catch (error) {
                errorCountInOnePlanningLoop++;
                const timeString = await this.getTimeString();
                this.conversationHistory.pendingFeedbackMessage = `Time: ${timeString}, Error executing running tasks: ${error?.message || String(error)}`;
                debug('error when executing running tasks, but continue to run if it is not too many errors:', error instanceof Error ? error.message : String(error), 'current error count in one planning loop:', errorCountInOnePlanningLoop);
            }
            if (errorCountInOnePlanningLoop > maxErrorCountAllowedInOnePlanningLoop) return session.appendErrorPlan('Too many errors in one planning loop');
            if (!planResult?.shouldContinuePlanning) break;
            ++replanCount;
            if (replanCount > replanningCycleLimit) {
                const errorMsg = `Replanned ${replanningCycleLimit} times, exceeding the limit. Please configure a larger value for replanningCycleLimit (or use MIDSCENE_REPLANNING_CYCLE_LIMIT) to handle more complex tasks.`;
                return session.appendErrorPlan(errorMsg);
            }
            if (!this.conversationHistory.pendingFeedbackMessage) {
                const timeString = await this.getTimeString();
                this.conversationHistory.pendingFeedbackMessage = `Time: ${timeString}, I have finished the action previously planned.`;
            }
        }
        return {
            output: {
                yamlFlow,
                output: outputString
            },
            runner
        };
    }
    createTypeQueryTask(type, demand, modelConfig, opt, multimodalPrompt) {
        const queryTask = {
            type: 'Insight',
            subType: type,
            param: {
                dataDemand: multimodalPrompt ? {
                    demand,
                    multimodalPrompt
                } : demand
            },
            executor: async (param, taskContext)=>{
                const { task } = taskContext;
                let queryDump;
                const applyDump = (dump)=>{
                    queryDump = dump;
                    task.log = {
                        dump,
                        rawResponse: dump.taskInfo?.rawResponse
                    };
                    task.usage = dump.taskInfo?.usage;
                    if (dump.taskInfo?.reasoning_content) task.reasoning_content = dump.taskInfo.reasoning_content;
                };
                const uiContext = taskContext.uiContext;
                (0, utils_namespaceObject.assert)(uiContext, 'uiContext is required for Query task');
                const ifTypeRestricted = 'Query' !== type;
                let demandInput = demand;
                let keyOfResult = 'result';
                if (ifTypeRestricted && ('Assert' === type || 'WaitFor' === type)) {
                    keyOfResult = 'StatementIsTruthy';
                    const booleanPrompt = 'Assert' === type ? `Boolean, whether the following statement is true: ${demand}` : `Boolean, the user wants to do some 'wait for' operation, please check whether the following statement is true: ${demand}`;
                    demandInput = {
                        [keyOfResult]: booleanPrompt
                    };
                } else if (ifTypeRestricted) demandInput = {
                    [keyOfResult]: `${type}, ${demand}`
                };
                let extractResult;
                let extraPageDescription = '';
                if (opt?.domIncluded && this.interface.getElementsNodeTree) {
                    debug('appending tree info for page');
                    const tree = await this.interface.getElementsNodeTree();
                    extraPageDescription = await (0, extractor_namespaceObject.descriptionOfTree)(tree, 200, false, opt?.domIncluded === 'visible-only');
                }
                try {
                    extractResult = await this.service.extract(demandInput, modelConfig, opt, extraPageDescription, multimodalPrompt, uiContext);
                } catch (error) {
                    if (error instanceof external_types_js_namespaceObject.ServiceError) applyDump(error.dump);
                    throw error;
                }
                const { data, thought, dump } = extractResult;
                applyDump(dump);
                let outputResult = data;
                if (ifTypeRestricted) if ('string' == typeof data) outputResult = data;
                else if ('WaitFor' === type) outputResult = null == data ? false : data[keyOfResult];
                else if (null == data) outputResult = null;
                else {
                    (0, utils_namespaceObject.assert)(data?.[keyOfResult] !== void 0, 'No result in query data');
                    outputResult = data[keyOfResult];
                }
                if ('Assert' === type && !outputResult) {
                    task.thought = thought;
                    throw new Error(`Assertion failed: ${thought}`);
                }
                return {
                    output: outputResult,
                    log: queryDump,
                    thought
                };
            }
        };
        return queryTask;
    }
    async createTypeQueryExecution(type, demand, modelConfig, opt, multimodalPrompt) {
        const session = this.createExecutionSession((0, external_ui_utils_js_namespaceObject.taskTitleStr)(type, 'string' == typeof demand ? demand : JSON.stringify(demand)));
        const queryTask = await this.createTypeQueryTask(type, demand, modelConfig, opt, multimodalPrompt);
        const runner = session.getRunner();
        const result = await session.appendAndRun(queryTask);
        if (!result) throw new Error('result of taskExecutor.flush() is undefined in function createTypeQueryTask');
        const { output, thought } = result;
        return {
            output,
            thought,
            runner
        };
    }
    async waitFor(assertion, opt, modelConfig) {
        const { textPrompt, multimodalPrompt } = (0, external_utils_js_namespaceObject.parsePrompt)(assertion);
        const description = `waitFor: ${textPrompt}`;
        const session = this.createExecutionSession((0, external_ui_utils_js_namespaceObject.taskTitleStr)('WaitFor', description));
        const runner = session.getRunner();
        const { timeoutMs, checkIntervalMs, domIncluded, screenshotIncluded, ...restOpt } = opt;
        const serviceExtractOpt = {
            domIncluded,
            screenshotIncluded,
            ...restOpt
        };
        (0, utils_namespaceObject.assert)(assertion, 'No assertion for waitFor');
        (0, utils_namespaceObject.assert)(timeoutMs, 'No timeoutMs for waitFor');
        (0, utils_namespaceObject.assert)(checkIntervalMs, 'No checkIntervalMs for waitFor');
        (0, utils_namespaceObject.assert)(checkIntervalMs <= timeoutMs, `wrong config for waitFor: checkIntervalMs must be less than timeoutMs, config: {checkIntervalMs: ${checkIntervalMs}, timeoutMs: ${timeoutMs}}`);
        const overallStartTime = Date.now();
        let lastCheckStart = overallStartTime;
        let errorThought = '';
        while(lastCheckStart - overallStartTime <= timeoutMs){
            const currentCheckStart = Date.now();
            lastCheckStart = currentCheckStart;
            const queryTask = await this.createTypeQueryTask('WaitFor', textPrompt, modelConfig, serviceExtractOpt, multimodalPrompt);
            const result = await session.appendAndRun(queryTask);
            if (result?.output) return {
                output: void 0,
                runner
            };
            errorThought = result?.thought || !result && `No result from assertion: ${textPrompt}` || `unknown error when waiting for assertion: ${textPrompt}`;
            const now = Date.now();
            if (now - currentCheckStart < checkIntervalMs) {
                const elapsed = now - currentCheckStart;
                const timeRemaining = checkIntervalMs - elapsed;
                const thought = `Check interval is ${checkIntervalMs}ms, ${elapsed}ms elapsed since last check, sleeping for ${timeRemaining}ms`;
                const { tasks: sleepTasks } = await this.convertPlanToExecutable([
                    {
                        type: 'Sleep',
                        param: {
                            timeMs: timeRemaining
                        },
                        thought
                    }
                ], modelConfig, modelConfig);
                if (sleepTasks[0]) await session.appendAndRun(sleepTasks[0]);
            }
        }
        return session.appendErrorPlan(`waitFor timeout: ${errorThought}`);
    }
    constructor(interfaceInstance, service, opts){
        _define_property(this, "interface", void 0);
        _define_property(this, "service", void 0);
        _define_property(this, "taskCache", void 0);
        _define_property(this, "providedActionSpace", void 0);
        _define_property(this, "taskBuilder", void 0);
        _define_property(this, "conversationHistory", void 0);
        _define_property(this, "onTaskStartCallback", void 0);
        _define_property(this, "hooks", void 0);
        _define_property(this, "replanningCycleLimit", void 0);
        _define_property(this, "waitAfterAction", void 0);
        _define_property(this, "useDeviceTimestamp", void 0);
        this.interface = interfaceInstance;
        this.service = service;
        this.taskCache = opts.taskCache;
        this.onTaskStartCallback = opts?.onTaskStart;
        this.replanningCycleLimit = opts.replanningCycleLimit;
        this.waitAfterAction = opts.waitAfterAction;
        this.useDeviceTimestamp = opts.useDeviceTimestamp;
        this.hooks = opts.hooks;
        this.conversationHistory = new index_js_namespaceObject.ConversationHistory();
        this.providedActionSpace = opts.actionSpace;
        this.taskBuilder = new external_task_builder_js_namespaceObject.TaskBuilder({
            interfaceInstance,
            service,
            taskCache: opts.taskCache,
            actionSpace: this.getActionSpace(),
            waitAfterAction: opts.waitAfterAction
        });
    }
}
async function withFileChooser(interfaceInstance, fileChooserAccept, action) {
    if (!fileChooserAccept?.length) return action();
    if (!interfaceInstance.registerFileChooserListener) throw new Error(`File upload is not supported on ${interfaceInstance.interfaceType}`);
    const handler = async (chooser)=>{
        await chooser.accept(fileChooserAccept);
    };
    const { dispose, getError } = await interfaceInstance.registerFileChooserListener(handler);
    try {
        const result = await action();
        const error = getError();
        if (error) throw error;
        return result;
    } finally{
        dispose();
    }
}
exports.TaskExecutionError = __webpack_exports__.TaskExecutionError;
exports.TaskExecutor = __webpack_exports__.TaskExecutor;
exports.locatePlanForLocate = __webpack_exports__.locatePlanForLocate;
exports.withFileChooser = __webpack_exports__.withFileChooser;
for(var __rspack_i in __webpack_exports__)if (-1 === [
    "TaskExecutionError",
    "TaskExecutor",
    "locatePlanForLocate",
    "withFileChooser"
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
Object.defineProperty(exports, '__esModule', {
    value: true
});

//# sourceMappingURL=tasks.js.map