"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }

var _chunkTVQWZE2Bjs = require('./chunk-TVQWZE2B.js');










var _chunkZPVQ5TDQjs = require('./chunk-ZPVQ5TDQ.js');

// src/ai-model/action-executor.ts
var _env = require('@midscene_spp/shared/env');
var _utils = require('@midscene_spp/shared/utils');
var Executor = class {
  constructor(name, options) {
    this.status = _optionalChain([options, 'optionalAccess', _ => _.tasks]) && options.tasks.length > 0 ? "pending" : "init";
    this.name = name;
    this.tasks = (_optionalChain([options, 'optionalAccess', _2 => _2.tasks]) || []).map(
      (item) => this.markTaskAsPending(item)
    );
    this.onTaskStart = _optionalChain([options, 'optionalAccess', _3 => _3.onTaskStart]);
  }
  markTaskAsPending(task) {
    return {
      status: "pending",
      ...task
    };
  }
  async append(task) {
    _utils.assert.call(void 0, 
      this.status !== "error",
      `executor is in error state, cannot append task
error=${_optionalChain([this, 'access', _4 => _4.latestErrorTask, 'call', _5 => _5(), 'optionalAccess', _6 => _6.error])}
${_optionalChain([this, 'access', _7 => _7.latestErrorTask, 'call', _8 => _8(), 'optionalAccess', _9 => _9.errorStack])}`
    );
    if (Array.isArray(task)) {
      this.tasks.push(...task.map((item) => this.markTaskAsPending(item)));
    } else {
      this.tasks.push(this.markTaskAsPending(task));
    }
    if (this.status !== "running") {
      this.status = "pending";
    }
  }
  async flush() {
    if (this.status === "init" && this.tasks.length > 0) {
      console.warn(
        "illegal state for executor, status is init but tasks are not empty"
      );
    }
    _utils.assert.call(void 0, this.status !== "running", "executor is already running");
    _utils.assert.call(void 0, this.status !== "completed", "executor is already completed");
    _utils.assert.call(void 0, this.status !== "error", "executor is in error state");
    const nextPendingIndex = this.tasks.findIndex(
      (task) => task.status === "pending"
    );
    if (nextPendingIndex < 0) {
      return;
    }
    this.status = "running";
    let taskIndex = nextPendingIndex;
    let successfullyCompleted = true;
    let previousFindOutput;
    while (taskIndex < this.tasks.length) {
      const task = this.tasks[taskIndex];
      _utils.assert.call(void 0, 
        task.status === "pending",
        `task status should be pending, but got: ${task.status}`
      );
      task.timing = {
        start: Date.now()
      };
      try {
        task.status = "running";
        try {
          if (this.onTaskStart) {
            await this.onTaskStart(task);
          }
        } catch (e) {
          console.error("error in onTaskStart", e);
        }
        _utils.assert.call(void 0, 
          ["Insight", "Action", "Planning"].indexOf(task.type) >= 0,
          `unsupported task type: ${task.type}`
        );
        const { executor, param } = task;
        _utils.assert.call(void 0, executor, `executor is required for task type: ${task.type}`);
        let returnValue;
        const executorContext = {
          task,
          element: _optionalChain([previousFindOutput, 'optionalAccess', _10 => _10.element])
        };
        if (task.type === "Insight") {
          _utils.assert.call(void 0, 
            task.subType === "Locate" || task.subType === "Query" || task.subType === "Assert" || task.subType === "Boolean" || task.subType === "Number" || task.subType === "String",
            `unsupported insight subType: ${task.subType}`
          );
          returnValue = await task.executor(param, executorContext);
          if (task.subType === "Locate") {
            previousFindOutput = _optionalChain([returnValue, 'optionalAccess', _11 => _11.output]);
          }
        } else if (task.type === "Action" || task.type === "Planning") {
          returnValue = await task.executor(param, executorContext);
        } else {
          console.warn(
            `unsupported task type: ${task.type}, will try to execute it directly`
          );
          returnValue = await task.executor(param, executorContext);
        }
        Object.assign(task, returnValue);
        task.status = "finished";
        task.timing.end = Date.now();
        task.timing.cost = task.timing.end - task.timing.start;
        task.timing.aiCost = _optionalChain([returnValue, 'optionalAccess', _12 => _12.aiCost]) || 0;
        taskIndex++;
      } catch (e) {
        successfullyCompleted = false;
        task.error = _optionalChain([e, 'optionalAccess', _13 => _13.message]) || (typeof e === "string" ? e : "error-without-message");
        task.errorStack = e.stack;
        task.status = "failed";
        task.timing.end = Date.now();
        task.timing.cost = task.timing.end - task.timing.start;
        break;
      }
    }
    for (let i = taskIndex + 1; i < this.tasks.length; i++) {
      this.tasks[i].status = "cancelled";
    }
    if (successfullyCompleted) {
      this.status = "completed";
    } else {
      this.status = "error";
    }
    if (this.tasks.length) {
      const outputIndex = Math.min(taskIndex, this.tasks.length - 1);
      return this.tasks[outputIndex].output;
    }
  }
  isInErrorState() {
    return this.status === "error";
  }
  latestErrorTask() {
    if (this.status !== "error") {
      return null;
    }
    const errorTaskIndex = this.tasks.findIndex(
      (task) => task.status === "failed"
    );
    if (errorTaskIndex >= 0) {
      return this.tasks[errorTaskIndex];
    }
    return null;
  }
  dump() {
    const dumpData = {
      sdkVersion: _chunkTVQWZE2Bjs.getVersion.call(void 0, ),
      model_name: _env.getAIConfig.call(void 0, _env.MIDSCENE_MODEL_NAME) || "",
      logTime: Date.now(),
      name: this.name,
      tasks: this.tasks
    };
    return dumpData;
  }
};

// src/ai-model/prompt/describe.ts

var elementDescriberInstruction = () => {
  return `Tell what is the content of the element wrapped by the read rectangle in the screenshot. Your description is expected to be used to precisely locate the element from other similar elements on screenshot. Use ${_env.getPreferredLanguage.call(void 0, )} in the description.

Please follow the following rules:
1. The description should be start with a brief description, like "a button for confirming the action".

2. Include these information in the description to distinguish the element from its siblings and other similar elements, as much as possible:
- The text of the element, like "with text 'Confirm'"
- What the element looks like if it's an image, like "with image '...'"
- The relative position of the element, like "on the left of ..., around ..."
- How to distinguish the element from its siblings elements, like "it is the icon instead of the text"

3. Do NOT mention the red rectangle in the description.

4. Use the error field to describe the unexpected situations, if any. If not, put null.

Return in JSON:
{
  "description": "[{brief description}]: {text of the element} {image of the element} {relative position of the element} ... ",
  "error"?: "..."
}`;
};

// src/insight/index.ts






var _img = require('@midscene_spp/shared/img');
var _logger = require('@midscene_spp/shared/logger');


// src/insight/utils.ts







function emitInsightDump(data, dumpSubscriber) {
  let modelDescription = "";
  if (_env.vlLocateMode.call(void 0, )) {
    const uiTarsModelVer = _env.uiTarsModelVersion.call(void 0, );
    if (uiTarsModelVer) {
      modelDescription = `UI-TARS=${uiTarsModelVer}`;
    } else {
      modelDescription = `${_env.vlLocateMode.call(void 0, )} mode`;
    }
  }
  const baseData = {
    sdkVersion: _chunkTVQWZE2Bjs.getVersion.call(void 0, ),
    logTime: Date.now(),
    model_name: _env.getAIConfig.call(void 0, _env.MIDSCENE_MODEL_NAME) || "",
    model_description: modelDescription
  };
  const finalData = {
    logId: _utils.uuid.call(void 0, ),
    ...baseData,
    ...data
  };
  _optionalChain([dumpSubscriber, 'optionalCall', _14 => _14(finalData)]);
}

// src/insight/index.ts
var debug = _logger.getDebug.call(void 0, "ai:insight");
var Insight = class {
  constructor(context, opt) {
    this.aiVendorFn = _chunkZPVQ5TDQjs.callAiFn;
    _utils.assert.call(void 0, context, "context is required for Insight");
    if (typeof context === "function") {
      this.contextRetrieverFn = context;
    } else {
      this.contextRetrieverFn = () => Promise.resolve(context);
    }
    if (typeof _optionalChain([opt, 'optionalAccess', _15 => _15.aiVendorFn]) !== "undefined") {
      this.aiVendorFn = opt.aiVendorFn;
    }
    if (typeof _optionalChain([opt, 'optionalAccess', _16 => _16.taskInfo]) !== "undefined") {
      this.taskInfo = opt.taskInfo;
    }
  }
  async locate(query, opt) {
    const { callAI } = opt || {};
    const queryPrompt = typeof query === "string" ? query : query.prompt;
    _utils.assert.call(void 0, queryPrompt, "query is required for locate");
    const dumpSubscriber = this.onceDumpUpdatedFn;
    this.onceDumpUpdatedFn = void 0;
    _utils.assert.call(void 0, typeof query === "object", "query should be an object for locate");
    const globalDeepThinkSwitch = _env.getAIConfigInBoolean.call(void 0, 
      _env.MIDSCENE_FORCE_DEEP_THINK
    );
    if (globalDeepThinkSwitch) {
      debug("globalDeepThinkSwitch", globalDeepThinkSwitch);
    }
    let searchAreaPrompt;
    if (query.deepThink || globalDeepThinkSwitch) {
      searchAreaPrompt = query.prompt;
    }
    if (searchAreaPrompt && !_env.vlLocateMode.call(void 0, )) {
      console.warn(
        'The "deepThink" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model'
      );
      searchAreaPrompt = void 0;
    }
    const context = _optionalChain([opt, 'optionalAccess', _17 => _17.context]) || await this.contextRetrieverFn("locate");
    let searchArea = void 0;
    let searchAreaRawResponse = void 0;
    let searchAreaUsage = void 0;
    let searchAreaResponse = void 0;
    if (searchAreaPrompt) {
      searchAreaResponse = await _chunkZPVQ5TDQjs.AiLocateSection.call(void 0, {
        context,
        sectionDescription: searchAreaPrompt
      });
      _utils.assert.call(void 0, 
        searchAreaResponse.rect,
        `cannot find search area for "${searchAreaPrompt}"${searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ""}`
      );
      searchAreaRawResponse = searchAreaResponse.rawResponse;
      searchAreaUsage = searchAreaResponse.usage;
      searchArea = searchAreaResponse.rect;
    }
    const startTime = Date.now();
    const { parseResult, rect, elementById, rawResponse, usage } = await _chunkZPVQ5TDQjs.AiLocateElement.call(void 0, {
      callAI: callAI || this.aiVendorFn,
      context,
      targetElementDescription: queryPrompt,
      searchConfig: searchAreaResponse
    });
    const timeCost = Date.now() - startTime;
    const taskInfo = {
      ...this.taskInfo ? this.taskInfo : {},
      durationMs: timeCost,
      rawResponse: JSON.stringify(rawResponse),
      formatResponse: JSON.stringify(parseResult),
      usage,
      searchArea,
      searchAreaRawResponse,
      searchAreaUsage
    };
    let errorLog;
    if (_optionalChain([parseResult, 'access', _18 => _18.errors, 'optionalAccess', _19 => _19.length])) {
      errorLog = `AI model failed to locate: 
${parseResult.errors.join("\n")}`;
    }
    const dumpData = {
      type: "locate",
      userQuery: {
        element: queryPrompt
      },
      matchedElement: [],
      matchedRect: rect,
      data: null,
      taskInfo,
      deepThink: !!searchArea,
      error: errorLog
    };
    const elements = [];
    (parseResult.elements || []).forEach((item) => {
      if ("id" in item) {
        const element = elementById(_optionalChain([item, 'optionalAccess', _20 => _20.id]));
        if (!element) {
          console.warn(
            `locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`
          );
          return;
        }
        elements.push(element);
      }
    });
    emitInsightDump(
      {
        ...dumpData,
        matchedElement: elements
      },
      dumpSubscriber
    );
    if (errorLog) {
      throw new Error(errorLog);
    }
    _utils.assert.call(void 0, 
      elements.length <= 1,
      `locate: multiple elements found, length = ${elements.length}`
    );
    if (elements.length === 1) {
      return {
        element: {
          id: elements[0].id,
          indexId: elements[0].indexId,
          center: elements[0].center,
          rect: elements[0].rect,
          xpaths: elements[0].xpaths || [],
          attributes: elements[0].attributes
        },
        rect
      };
    }
    return {
      element: null,
      rect
    };
  }
  async extract(dataDemand) {
    _utils.assert.call(void 0, 
      typeof dataDemand === "object" || typeof dataDemand === "string",
      `dataDemand should be object or string, but get ${typeof dataDemand}`
    );
    const dumpSubscriber = this.onceDumpUpdatedFn;
    this.onceDumpUpdatedFn = void 0;
    const context = await this.contextRetrieverFn("extract");
    const startTime = Date.now();
    const { parseResult, usage } = await _chunkZPVQ5TDQjs.AiExtractElementInfo.call(void 0, {
      context,
      dataQuery: dataDemand
    });
    const timeCost = Date.now() - startTime;
    const taskInfo = {
      ...this.taskInfo ? this.taskInfo : {},
      durationMs: timeCost,
      rawResponse: JSON.stringify(parseResult)
    };
    let errorLog;
    if (_optionalChain([parseResult, 'access', _21 => _21.errors, 'optionalAccess', _22 => _22.length])) {
      errorLog = `AI response error: 
${parseResult.errors.join("\n")}`;
    }
    const dumpData = {
      type: "extract",
      userQuery: {
        dataDemand
      },
      matchedElement: [],
      data: null,
      taskInfo,
      error: errorLog
    };
    const { data } = parseResult || {};
    emitInsightDump(
      {
        ...dumpData,
        data
      },
      dumpSubscriber
    );
    if (errorLog && !data) {
      throw new Error(errorLog);
    }
    return {
      data,
      usage
    };
  }
  async assert(assertion) {
    if (typeof assertion !== "string") {
      throw new Error(
        "This is the assert method for Midscene, the first argument should be a string. If you want to use the assert method from Node.js, please import it from the Node.js assert module."
      );
    }
    const dumpSubscriber = this.onceDumpUpdatedFn;
    this.onceDumpUpdatedFn = void 0;
    const context = await this.contextRetrieverFn("assert");
    const startTime = Date.now();
    const assertResult = await _chunkZPVQ5TDQjs.AiAssert.call(void 0, {
      assertion,
      context
    });
    const timeCost = Date.now() - startTime;
    const taskInfo = {
      ...this.taskInfo ? this.taskInfo : {},
      durationMs: timeCost,
      rawResponse: JSON.stringify(assertResult.content)
    };
    const { thought, pass } = assertResult.content;
    const dumpData = {
      type: "assert",
      userQuery: {
        assertion
      },
      matchedElement: [],
      data: null,
      taskInfo,
      assertionPass: pass,
      assertionThought: thought,
      error: pass ? void 0 : thought
    };
    emitInsightDump(dumpData, dumpSubscriber);
    return {
      pass,
      thought,
      usage: assertResult.usage
    };
  }
  async describe(target, opt) {
    _utils.assert.call(void 0, target, "target is required for insight.describe");
    const context = await this.contextRetrieverFn("describe");
    const { screenshotBase64 } = context;
    _utils.assert.call(void 0, screenshotBase64, "screenshot is required for insight.describe");
    const systemPrompt = elementDescriberInstruction();
    const defaultRectSize = 30;
    const targetRect = Array.isArray(target) ? {
      left: Math.floor(target[0] - defaultRectSize / 2),
      top: Math.floor(target[1] - defaultRectSize / 2),
      width: defaultRectSize,
      height: defaultRectSize
    } : target;
    let imagePayload = await _img.compositeElementInfoImg.call(void 0, {
      inputImgBase64: screenshotBase64,
      elementsPositionInfo: [
        {
          rect: targetRect
        }
      ],
      borderThickness: 3
    });
    if (_optionalChain([opt, 'optionalAccess', _23 => _23.deepThink])) {
      const searchArea = _chunkZPVQ5TDQjs.expandSearchArea.call(void 0, targetRect, context.size);
      debug("describe: set searchArea", searchArea);
      imagePayload = await _img.cropByRect.call(void 0, 
        imagePayload,
        searchArea,
        _env.getAIConfigInBoolean.call(void 0, _env.MIDSCENE_USE_QWEN_VL)
      );
    }
    const msgs = [
      { role: "system", content: systemPrompt },
      {
        role: "user",
        content: [
          {
            type: "image_url",
            image_url: {
              url: imagePayload,
              detail: "high"
            }
          }
        ]
      }
    ];
    const callAIFn = this.aiVendorFn || _chunkZPVQ5TDQjs.callToGetJSONObject;
    const res = await callAIFn(msgs, 4 /* DESCRIBE_ELEMENT */);
    const { content } = res;
    _utils.assert.call(void 0, !content.error, `describe failed: ${content.error}`);
    _utils.assert.call(void 0, content.description, "failed to describe the element");
    return content;
  }
};

// src/index.ts

var src_default = Insight;











exports.AiAssert = _chunkZPVQ5TDQjs.AiAssert; exports.AiLocateElement = _chunkZPVQ5TDQjs.AiLocateElement; exports.Executor = Executor; exports.Insight = Insight; exports.MIDSCENE_MODEL_NAME = _env.MIDSCENE_MODEL_NAME; exports.default = src_default; exports.describeUserPage = _chunkZPVQ5TDQjs.describeUserPage; exports.getAIConfig = _env.getAIConfig; exports.getVersion = _chunkTVQWZE2Bjs.getVersion; exports.plan = _chunkZPVQ5TDQjs.plan;

//# sourceMappingURL=index.js.map