@midscene/core 0.30.5 → 1.0.1-beta-20251021060907.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/es/agent/agent.mjs +41 -33
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/execution-session.mjs +41 -0
  4. package/dist/es/agent/execution-session.mjs.map +1 -0
  5. package/dist/es/agent/task-builder.mjs +303 -0
  6. package/dist/es/agent/task-builder.mjs.map +1 -0
  7. package/dist/es/agent/tasks.mjs +68 -391
  8. package/dist/es/agent/tasks.mjs.map +1 -1
  9. package/dist/es/agent/ui-utils.mjs.map +1 -1
  10. package/dist/es/agent/utils.mjs +6 -6
  11. package/dist/es/agent/utils.mjs.map +1 -1
  12. package/dist/es/ai-model/common.mjs +1 -15
  13. package/dist/es/ai-model/common.mjs.map +1 -1
  14. package/dist/es/ai-model/inspect.mjs +2 -3
  15. package/dist/es/ai-model/inspect.mjs.map +1 -1
  16. package/dist/es/ai-model/llm-planning.mjs +6 -24
  17. package/dist/es/ai-model/llm-planning.mjs.map +1 -1
  18. package/dist/es/ai-model/prompt/llm-locator.mjs +3 -204
  19. package/dist/es/ai-model/prompt/llm-locator.mjs.map +1 -1
  20. package/dist/es/ai-model/service-caller/index.mjs +101 -231
  21. package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
  22. package/dist/es/index.mjs +3 -2
  23. package/dist/es/index.mjs.map +1 -1
  24. package/dist/es/insight/index.mjs +18 -19
  25. package/dist/es/insight/index.mjs.map +1 -1
  26. package/dist/es/insight/utils.mjs +3 -3
  27. package/dist/es/insight/utils.mjs.map +1 -1
  28. package/dist/es/report.mjs.map +1 -1
  29. package/dist/es/{ai-model/action-executor.mjs → task-runner.mjs} +69 -10
  30. package/dist/es/task-runner.mjs.map +1 -0
  31. package/dist/es/types.mjs +18 -1
  32. package/dist/es/types.mjs.map +1 -1
  33. package/dist/es/utils.mjs +2 -2
  34. package/dist/es/yaml/player.mjs +18 -14
  35. package/dist/es/yaml/player.mjs.map +1 -1
  36. package/dist/lib/agent/agent.js +41 -33
  37. package/dist/lib/agent/agent.js.map +1 -1
  38. package/dist/lib/agent/execution-session.js +75 -0
  39. package/dist/lib/agent/execution-session.js.map +1 -0
  40. package/dist/lib/agent/task-builder.js +340 -0
  41. package/dist/lib/agent/task-builder.js.map +1 -0
  42. package/dist/lib/agent/tasks.js +68 -391
  43. package/dist/lib/agent/tasks.js.map +1 -1
  44. package/dist/lib/agent/ui-utils.js.map +1 -1
  45. package/dist/lib/agent/utils.js +6 -6
  46. package/dist/lib/agent/utils.js.map +1 -1
  47. package/dist/lib/ai-model/common.js +2 -19
  48. package/dist/lib/ai-model/common.js.map +1 -1
  49. package/dist/lib/ai-model/inspect.js +1 -2
  50. package/dist/lib/ai-model/inspect.js.map +1 -1
  51. package/dist/lib/ai-model/llm-planning.js +5 -23
  52. package/dist/lib/ai-model/llm-planning.js.map +1 -1
  53. package/dist/lib/ai-model/prompt/llm-locator.js +2 -206
  54. package/dist/lib/ai-model/prompt/llm-locator.js.map +1 -1
  55. package/dist/lib/ai-model/service-caller/index.js +236 -384
  56. package/dist/lib/ai-model/service-caller/index.js.map +1 -1
  57. package/dist/lib/index.js +9 -5
  58. package/dist/lib/index.js.map +1 -1
  59. package/dist/lib/insight/index.js +17 -18
  60. package/dist/lib/insight/index.js.map +1 -1
  61. package/dist/lib/insight/utils.js +5 -5
  62. package/dist/lib/insight/utils.js.map +1 -1
  63. package/dist/lib/report.js.map +1 -1
  64. package/dist/lib/{ai-model/action-executor.js → task-runner.js} +71 -12
  65. package/dist/lib/task-runner.js.map +1 -0
  66. package/dist/lib/types.js +22 -1
  67. package/dist/lib/types.js.map +1 -1
  68. package/dist/lib/utils.js +2 -2
  69. package/dist/lib/yaml/player.js +18 -14
  70. package/dist/lib/yaml/player.js.map +1 -1
  71. package/dist/types/agent/agent.d.ts +16 -0
  72. package/dist/types/agent/execution-session.d.ts +27 -0
  73. package/dist/types/agent/task-builder.d.ts +24 -0
  74. package/dist/types/agent/tasks.d.ts +8 -11
  75. package/dist/types/agent/ui-utils.d.ts +2 -2
  76. package/dist/types/agent/utils.d.ts +5 -2
  77. package/dist/types/ai-model/common.d.ts +0 -1
  78. package/dist/types/ai-model/prompt/llm-locator.d.ts +0 -2
  79. package/dist/types/index.d.ts +4 -3
  80. package/dist/types/insight/index.d.ts +5 -10
  81. package/dist/types/insight/utils.d.ts +2 -2
  82. package/dist/types/{ai-model/action-executor.d.ts → task-runner.d.ts} +14 -3
  83. package/dist/types/types.d.ts +47 -4
  84. package/dist/types/yaml.d.ts +3 -1
  85. package/package.json +4 -7
  86. package/dist/es/ai-model/action-executor.mjs.map +0 -1
  87. package/dist/lib/ai-model/action-executor.js.map +0 -1
@@ -2,11 +2,12 @@ import { AIActionType, expandSearchArea } from "../ai-model/common.mjs";
2
2
  import { AiExtractElementInfo, AiLocateElement, callAIWithObjectResponse } from "../ai-model/index.mjs";
3
3
  import { AiLocateSection } from "../ai-model/inspect.mjs";
4
4
  import { elementDescriberInstruction } from "../ai-model/prompt/describe.mjs";
5
+ import { InsightError } from "../types.mjs";
5
6
  import { MIDSCENE_FORCE_DEEP_THINK, globalConfigManager } from "@midscene/shared/env";
6
7
  import { compositeElementInfoImg, cropByRect } from "@midscene/shared/img";
7
8
  import { getDebug } from "@midscene/shared/logger";
8
9
  import { assert } from "@midscene/shared/utils";
9
- import { emitInsightDump } from "./utils.mjs";
10
+ import { createInsightDump } from "./utils.mjs";
10
11
  function _define_property(obj, key, value) {
11
12
  if (key in obj) Object.defineProperty(obj, key, {
12
13
  value: value,
@@ -23,8 +24,6 @@ class Insight {
23
24
  var _parseResult_errors;
24
25
  const queryPrompt = 'string' == typeof query ? query : query.prompt;
25
26
  assert(queryPrompt, 'query is required for locate');
26
- const dumpSubscriber = this.onceDumpUpdatedFn;
27
- this.onceDumpUpdatedFn = void 0;
28
27
  assert('object' == typeof query, 'query should be an object for locate');
29
28
  const globalDeepThinkSwitch = globalConfigManager.getEnvConfigInBoolean(MIDSCENE_FORCE_DEEP_THINK);
30
29
  if (globalDeepThinkSwitch) debug('globalDeepThinkSwitch', globalDeepThinkSwitch);
@@ -35,7 +34,7 @@ class Insight {
35
34
  console.warn('The "deepThink" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model');
36
35
  searchAreaPrompt = void 0;
37
36
  }
38
- const context = (null == opt ? void 0 : opt.context) || await this.contextRetrieverFn('locate');
37
+ const context = (null == opt ? void 0 : opt.context) || await this.contextRetrieverFn();
39
38
  let searchArea;
40
39
  let searchAreaRawResponse;
41
40
  let searchAreaUsage;
@@ -92,12 +91,12 @@ class Insight {
92
91
  elements.push(element);
93
92
  }
94
93
  });
95
- emitInsightDump({
94
+ const dump = createInsightDump({
96
95
  ...dumpData,
97
96
  matchedElement: elements
98
- }, dumpSubscriber);
99
- if (errorLog) throw new Error(errorLog);
100
- assert(elements.length <= 1, `locate: multiple elements found, length = ${elements.length}`);
97
+ });
98
+ if (errorLog) throw new InsightError(errorLog, dump);
99
+ if (elements.length > 1) throw new InsightError(`locate: multiple elements found, length = ${elements.length}`, dump);
101
100
  if (1 === elements.length) return {
102
101
  element: {
103
102
  id: elements[0].id,
@@ -108,19 +107,19 @@ class Insight {
108
107
  attributes: elements[0].attributes,
109
108
  isOrderSensitive
110
109
  },
111
- rect
110
+ rect,
111
+ dump
112
112
  };
113
113
  return {
114
114
  element: null,
115
- rect
115
+ rect,
116
+ dump
116
117
  };
117
118
  }
118
119
  async extract(dataDemand, modelConfig, opt, multimodalPrompt) {
119
120
  var _parseResult_errors;
120
121
  assert('object' == typeof dataDemand || 'string' == typeof dataDemand, `dataDemand should be object or string, but get ${typeof dataDemand}`);
121
- const dumpSubscriber = this.onceDumpUpdatedFn;
122
- this.onceDumpUpdatedFn = void 0;
123
- const context = await this.contextRetrieverFn('extract');
122
+ const context = await this.contextRetrieverFn();
124
123
  const startTime = Date.now();
125
124
  const { parseResult, usage } = await AiExtractElementInfo({
126
125
  context,
@@ -148,20 +147,21 @@ class Insight {
148
147
  error: errorLog
149
148
  };
150
149
  const { data, thought } = parseResult || {};
151
- emitInsightDump({
150
+ const dump = createInsightDump({
152
151
  ...dumpData,
153
152
  data
154
- }, dumpSubscriber);
155
- if (errorLog && !data && !(null == opt ? void 0 : opt.doNotThrowError)) throw new Error(errorLog);
153
+ });
154
+ if (errorLog && !data && !(null == opt ? void 0 : opt.doNotThrowError)) throw new InsightError(errorLog, dump);
156
155
  return {
157
156
  data,
158
157
  thought,
159
- usage
158
+ usage,
159
+ dump
160
160
  };
161
161
  }
162
162
  async describe(target, modelConfig, opt) {
163
163
  assert(target, 'target is required for insight.describe');
164
- const context = await this.contextRetrieverFn('describe');
164
+ const context = await this.contextRetrieverFn();
165
165
  const { screenshotBase64, size } = context;
166
166
  assert(screenshotBase64, 'screenshot is required for insight.describe');
167
167
  const { vlMode } = modelConfig;
@@ -217,7 +217,6 @@ class Insight {
217
217
  constructor(context, opt){
218
218
  _define_property(this, "contextRetrieverFn", void 0);
219
219
  _define_property(this, "aiVendorFn", callAIWithObjectResponse);
220
- _define_property(this, "onceDumpUpdatedFn", void 0);
221
220
  _define_property(this, "taskInfo", void 0);
222
221
  assert(context, 'context is required for Insight');
223
222
  if ('function' == typeof context) this.contextRetrieverFn = context;
@@ -1 +1 @@
1
- {"version":3,"file":"insight/index.mjs","sources":["webpack://@midscene/core/./src/insight/index.ts"],"sourcesContent":["import { AIActionType, type AIArgs, expandSearchArea } from '@/ai-model/common';\nimport {\n AiExtractElementInfo,\n AiLocateElement,\n callAIWithObjectResponse,\n} from '@/ai-model/index';\nimport { AiLocateSection } from '@/ai-model/inspect';\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\nimport type {\n AIDescribeElementResponse,\n AIUsageInfo,\n BaseElement,\n DetailedLocateParam,\n DumpSubscriber,\n InsightAction,\n InsightExtractOption,\n InsightExtractParam,\n InsightTaskInfo,\n LocateResult,\n PartialInsightDumpFromSDK,\n Rect,\n UIContext,\n} from '@/types';\nimport {\n type IModelConfig,\n MIDSCENE_FORCE_DEEP_THINK,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { compositeElementInfoImg, cropByRect } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { TMultimodalPrompt } from '../ai-model/common';\nimport { emitInsightDump } from './utils';\n\nexport interface LocateOpts {\n context?: UIContext<BaseElement>;\n}\n\nexport type AnyValue<T> = {\n [K in keyof T]: unknown extends T[K] ? any : T[K];\n};\n\ninterface InsightOptions {\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\n aiVendorFn?: typeof callAIWithObjectResponse;\n}\n\nconst debug = getDebug('ai:insight');\nexport default class Insight<\n ElementType extends BaseElement = BaseElement,\n ContextType extends UIContext<ElementType> = UIContext<ElementType>,\n> {\n contextRetrieverFn: (\n action: InsightAction,\n ) => Promise<ContextType> | ContextType;\n\n aiVendorFn: Exclude<InsightOptions['aiVendorFn'], undefined> =\n callAIWithObjectResponse;\n\n onceDumpUpdatedFn?: DumpSubscriber;\n\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\n\n constructor(\n context:\n | ContextType\n | ((action: InsightAction) => Promise<ContextType> | ContextType),\n opt?: InsightOptions,\n ) {\n assert(context, 'context is required for Insight');\n if (typeof context === 'function') {\n this.contextRetrieverFn = context;\n } else {\n this.contextRetrieverFn = () => Promise.resolve(context);\n }\n\n // just for unit test, aiVendorFn is callAIWithObjectResponse by default\n if (typeof opt?.aiVendorFn !== 'undefined') {\n this.aiVendorFn = opt.aiVendorFn;\n }\n if (typeof opt?.taskInfo !== 'undefined') {\n this.taskInfo = opt.taskInfo;\n }\n }\n\n async locate(\n query: DetailedLocateParam,\n opt: LocateOpts,\n modelConfig: IModelConfig,\n ): Promise<LocateResult> {\n const queryPrompt = typeof query === 'string' ? query : query.prompt;\n assert(queryPrompt, 'query is required for locate');\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = undefined;\n\n assert(typeof query === 'object', 'query should be an object for locate');\n\n const globalDeepThinkSwitch = globalConfigManager.getEnvConfigInBoolean(\n MIDSCENE_FORCE_DEEP_THINK,\n );\n if (globalDeepThinkSwitch) {\n debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\n }\n let searchAreaPrompt;\n if (query.deepThink || globalDeepThinkSwitch) {\n searchAreaPrompt = query.prompt;\n }\n\n const { vlMode } = modelConfig;\n\n if (searchAreaPrompt && !vlMode) {\n console.warn(\n 'The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model',\n );\n searchAreaPrompt = undefined;\n }\n\n const context = opt?.context || (await this.contextRetrieverFn('locate'));\n\n let searchArea: Rect | undefined = undefined;\n let searchAreaRawResponse: string | undefined = undefined;\n let searchAreaUsage: AIUsageInfo | undefined = undefined;\n let searchAreaResponse:\n | Awaited<ReturnType<typeof AiLocateSection>>\n | undefined = undefined;\n if (searchAreaPrompt) {\n searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: searchAreaPrompt,\n modelConfig,\n });\n assert(\n searchAreaResponse.rect,\n `cannot find search area for \"${searchAreaPrompt}\"${\n searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''\n }`,\n );\n searchAreaRawResponse = searchAreaResponse.rawResponse;\n searchAreaUsage = searchAreaResponse.usage;\n searchArea = searchAreaResponse.rect;\n }\n\n const startTime = Date.now();\n const {\n parseResult,\n rect,\n elementById,\n rawResponse,\n usage,\n isOrderSensitive,\n } = await AiLocateElement({\n callAIFn: this.aiVendorFn,\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchAreaResponse,\n modelConfig,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: JSON.stringify(rawResponse),\n formatResponse: JSON.stringify(parseResult),\n usage,\n searchArea,\n searchAreaRawResponse,\n searchAreaUsage,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialInsightDumpFromSDK = {\n type: 'locate',\n userQuery: {\n element: queryPrompt,\n },\n matchedElement: [],\n matchedRect: rect,\n data: null,\n taskInfo,\n deepThink: !!searchArea,\n error: errorLog,\n };\n\n const elements: BaseElement[] = [];\n (parseResult.elements || []).forEach((item) => {\n if ('id' in item) {\n const element = elementById(item?.id);\n\n if (!element) {\n console.warn(\n `locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`,\n );\n return;\n }\n elements.push(element);\n }\n });\n\n emitInsightDump(\n {\n ...dumpData,\n matchedElement: elements,\n },\n dumpSubscriber,\n );\n\n if (errorLog) {\n throw new Error(errorLog);\n }\n\n assert(\n elements.length <= 1,\n `locate: multiple elements found, length = ${elements.length}`,\n );\n\n if (elements.length === 1) {\n return {\n element: {\n id: elements[0]!.id,\n indexId: elements[0]!.indexId,\n center: elements[0]!.center,\n rect: elements[0]!.rect,\n xpaths: elements[0]!.xpaths || [],\n attributes: elements[0]!.attributes,\n isOrderSensitive,\n },\n rect,\n };\n }\n return {\n element: null,\n rect,\n };\n }\n\n async extract<T>(\n dataDemand: InsightExtractParam,\n modelConfig: IModelConfig,\n opt?: InsightExtractOption,\n multimodalPrompt?: TMultimodalPrompt,\n ): Promise<{\n data: T;\n thought?: string;\n usage?: AIUsageInfo;\n }> {\n assert(\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\n );\n const dumpSubscriber = this.onceDumpUpdatedFn;\n this.onceDumpUpdatedFn = undefined;\n\n const context = await this.contextRetrieverFn('extract');\n\n const startTime = Date.now();\n\n const { parseResult, usage } = await AiExtractElementInfo<T>({\n context,\n dataQuery: dataDemand,\n multimodalPrompt,\n extractOption: opt,\n modelConfig,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: JSON.stringify(parseResult),\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialInsightDumpFromSDK = {\n type: 'extract',\n userQuery: {\n dataDemand,\n },\n matchedElement: [],\n data: null,\n taskInfo,\n error: errorLog,\n };\n\n const { data, thought } = parseResult || {};\n\n // 4\n emitInsightDump(\n {\n ...dumpData,\n data,\n },\n dumpSubscriber,\n );\n\n if (errorLog && !data && !opt?.doNotThrowError) {\n throw new Error(errorLog);\n }\n\n return {\n data,\n thought,\n usage,\n };\n }\n\n async describe(\n target: Rect | [number, number],\n modelConfig: IModelConfig,\n opt?: {\n deepThink?: boolean;\n },\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\n assert(target, 'target is required for insight.describe');\n const context = await this.contextRetrieverFn('describe');\n const { screenshotBase64, size } = context;\n assert(screenshotBase64, 'screenshot is required for insight.describe');\n // The result of the \"describe\" function will be used for positioning, so essentially it is a form of grounding.\n const { vlMode } = modelConfig;\n const systemPrompt = elementDescriberInstruction();\n\n // Convert [x,y] center point to Rect if needed\n const defaultRectSize = 30;\n const targetRect: Rect = Array.isArray(target)\n ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize,\n }\n : target;\n\n let imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size,\n elementsPositionInfo: [\n {\n rect: targetRect,\n },\n ],\n borderThickness: 3,\n });\n\n if (opt?.deepThink) {\n const searchArea = expandSearchArea(targetRect, context.size, vlMode);\n debug('describe: set searchArea', searchArea);\n const croppedResult = await cropByRect(\n imagePayload,\n searchArea,\n vlMode === 'qwen-vl',\n );\n imagePayload = croppedResult.imageBase64;\n }\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high',\n },\n },\n ],\n },\n ];\n\n const callAIFn = this\n .aiVendorFn as typeof callAIWithObjectResponse<AIDescribeElementResponse>;\n\n const res = await callAIFn(\n msgs,\n AIActionType.DESCRIBE_ELEMENT,\n modelConfig,\n );\n\n const { content } = res;\n assert(!content.error, `describe failed: ${content.error}`);\n assert(content.description, 'failed to describe the element');\n return content;\n }\n}\n"],"names":["debug","getDebug","Insight","query","opt","modelConfig","_parseResult_errors","queryPrompt","assert","dumpSubscriber","undefined","globalDeepThinkSwitch","globalConfigManager","MIDSCENE_FORCE_DEEP_THINK","searchAreaPrompt","vlMode","console","context","searchArea","searchAreaRawResponse","searchAreaUsage","searchAreaResponse","AiLocateSection","startTime","Date","parseResult","rect","elementById","rawResponse","usage","isOrderSensitive","AiLocateElement","timeCost","taskInfo","JSON","errorLog","dumpData","elements","item","element","emitInsightDump","Error","dataDemand","multimodalPrompt","AiExtractElementInfo","data","thought","target","screenshotBase64","size","systemPrompt","elementDescriberInstruction","defaultRectSize","targetRect","Array","Math","imagePayload","compositeElementInfoImg","expandSearchArea","croppedResult","cropByRect","msgs","callAIFn","res","AIActionType","content","callAIWithObjectResponse","Promise"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,MAAMA,QAAQC,SAAS;AACR,MAAMC;IAqCnB,MAAM,OACJC,KAA0B,EAC1BC,GAAe,EACfC,WAAyB,EACF;YAkFnBC;QAjFJ,MAAMC,cAAc,AAAiB,YAAjB,OAAOJ,QAAqBA,QAAQA,MAAM,MAAM;QACpEK,OAAOD,aAAa;QACpB,MAAME,iBAAiB,IAAI,CAAC,iBAAiB;QAC7C,IAAI,CAAC,iBAAiB,GAAGC;QAEzBF,OAAO,AAAiB,YAAjB,OAAOL,OAAoB;QAElC,MAAMQ,wBAAwBC,oBAAoB,qBAAqB,CACrEC;QAEF,IAAIF,uBACFX,MAAM,yBAAyBW;QAEjC,IAAIG;QACJ,IAAIX,MAAM,SAAS,IAAIQ,uBACrBG,mBAAmBX,MAAM,MAAM;QAGjC,MAAM,EAAEY,MAAM,EAAE,GAAGV;QAEnB,IAAIS,oBAAoB,CAACC,QAAQ;YAC/BC,QAAQ,IAAI,CACV;YAEFF,mBAAmBJ;QACrB;QAEA,MAAMO,UAAUb,AAAAA,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,OAAO,AAAD,KAAM,MAAM,IAAI,CAAC,kBAAkB,CAAC;QAE/D,IAAIc;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QAGJ,IAAIP,kBAAkB;YACpBO,qBAAqB,MAAMC,gBAAgB;gBACzCL;gBACA,oBAAoBH;gBACpBT;YACF;YACAG,OACEa,mBAAmB,IAAI,EACvB,CAAC,6BAA6B,EAAEP,iBAAiB,CAAC,EAChDO,mBAAmB,KAAK,GAAG,CAAC,EAAE,EAAEA,mBAAmB,KAAK,EAAE,GAAG,IAC7D;YAEJF,wBAAwBE,mBAAmB,WAAW;YACtDD,kBAAkBC,mBAAmB,KAAK;YAC1CH,aAAaG,mBAAmB,IAAI;QACtC;QAEA,MAAME,YAAYC,KAAK,GAAG;QAC1B,MAAM,EACJC,WAAW,EACXC,IAAI,EACJC,WAAW,EACXC,WAAW,EACXC,KAAK,EACLC,gBAAgB,EACjB,GAAG,MAAMC,gBAAgB;YACxB,UAAU,IAAI,CAAC,UAAU;YACzBd;YACA,0BAA0BV;YAC1B,cAAcc;YACdhB;QACF;QAEA,MAAM2B,WAAWR,KAAK,GAAG,KAAKD;QAC9B,MAAMU,WAA4B;YAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YACtC,YAAYD;YACZ,aAAaE,KAAK,SAAS,CAACN;YAC5B,gBAAgBM,KAAK,SAAS,CAACT;YAC/BI;YACAX;YACAC;YACAC;QACF;QAEA,IAAIe;QACJ,IAAI,QAAA7B,CAAAA,sBAAAA,YAAY,MAAM,AAAD,IAAjBA,KAAAA,IAAAA,oBAAoB,MAAM,EAC5B6B,WAAW,CAAC,6BAA6B,EAAEV,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO;QAG5E,MAAMW,WAAsC;YAC1C,MAAM;YACN,WAAW;gBACT,SAAS7B;YACX;YACA,gBAAgB,EAAE;YAClB,aAAamB;YACb,MAAM;YACNO;YACA,WAAW,CAAC,CAACf;YACb,OAAOiB;QACT;QAEA,MAAME,WAA0B,EAAE;QACjCZ,CAAAA,YAAY,QAAQ,IAAI,EAAC,EAAG,OAAO,CAAC,CAACa;YACpC,IAAI,QAAQA,MAAM;gBAChB,MAAMC,UAAUZ,YAAYW,QAAAA,OAAAA,KAAAA,IAAAA,KAAM,EAAE;gBAEpC,IAAI,CAACC,SAAS,YACZvB,QAAQ,IAAI,CACV,CAAC,+BAA+B,EAAEsB,KAAK,EAAE,CAAC,0CAA0C,CAAC;gBAIzFD,SAAS,IAAI,CAACE;YAChB;QACF;QAEAC,gBACE;YACE,GAAGJ,QAAQ;YACX,gBAAgBC;QAClB,GACA5B;QAGF,IAAI0B,UACF,MAAM,IAAIM,MAAMN;QAGlB3B,OACE6B,SAAS,MAAM,IAAI,GACnB,CAAC,0CAA0C,EAAEA,SAAS,MAAM,EAAE;QAGhE,IAAIA,AAAoB,MAApBA,SAAS,MAAM,EACjB,OAAO;YACL,SAAS;gBACP,IAAIA,QAAQ,CAAC,EAAE,CAAE,EAAE;gBACnB,SAASA,QAAQ,CAAC,EAAE,CAAE,OAAO;gBAC7B,QAAQA,QAAQ,CAAC,EAAE,CAAE,MAAM;gBAC3B,MAAMA,QAAQ,CAAC,EAAE,CAAE,IAAI;gBACvB,QAAQA,QAAQ,CAAC,EAAE,CAAE,MAAM,IAAI,EAAE;gBACjC,YAAYA,QAAQ,CAAC,EAAE,CAAE,UAAU;gBACnCP;YACF;YACAJ;QACF;QAEF,OAAO;YACL,SAAS;YACTA;QACF;IACF;IAEA,MAAM,QACJgB,UAA+B,EAC/BrC,WAAyB,EACzBD,GAA0B,EAC1BuC,gBAAoC,EAKnC;YA4BGrC;QA3BJE,OACE,AAAsB,YAAtB,OAAOkC,cAA2B,AAAsB,YAAtB,OAAOA,YACzC,CAAC,+CAA+C,EAAE,OAAOA,YAAY;QAEvE,MAAMjC,iBAAiB,IAAI,CAAC,iBAAiB;QAC7C,IAAI,CAAC,iBAAiB,GAAGC;QAEzB,MAAMO,UAAU,MAAM,IAAI,CAAC,kBAAkB,CAAC;QAE9C,MAAMM,YAAYC,KAAK,GAAG;QAE1B,MAAM,EAAEC,WAAW,EAAEI,KAAK,EAAE,GAAG,MAAMe,qBAAwB;YAC3D3B;YACA,WAAWyB;YACXC;YACA,eAAevC;YACfC;QACF;QAEA,MAAM2B,WAAWR,KAAK,GAAG,KAAKD;QAC9B,MAAMU,WAA4B;YAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YACtC,YAAYD;YACZ,aAAaE,KAAK,SAAS,CAACT;QAC9B;QAEA,IAAIU;QACJ,IAAI,QAAA7B,CAAAA,sBAAAA,YAAY,MAAM,AAAD,IAAjBA,KAAAA,IAAAA,oBAAoB,MAAM,EAC5B6B,WAAW,CAAC,qBAAqB,EAAEV,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO;QAGpE,MAAMW,WAAsC;YAC1C,MAAM;YACN,WAAW;gBACTM;YACF;YACA,gBAAgB,EAAE;YAClB,MAAM;YACNT;YACA,OAAOE;QACT;QAEA,MAAM,EAAEU,IAAI,EAAEC,OAAO,EAAE,GAAGrB,eAAe,CAAC;QAG1Ce,gBACE;YACE,GAAGJ,QAAQ;YACXS;QACF,GACApC;QAGF,IAAI0B,YAAY,CAACU,QAAQ,CAACzC,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,eAAe,AAAD,GAC3C,MAAM,IAAIqC,MAAMN;QAGlB,OAAO;YACLU;YACAC;YACAjB;QACF;IACF;IAEA,MAAM,SACJkB,MAA+B,EAC/B1C,WAAyB,EACzBD,GAEC,EACwD;QACzDI,OAAOuC,QAAQ;QACf,MAAM9B,UAAU,MAAM,IAAI,CAAC,kBAAkB,CAAC;QAC9C,MAAM,EAAE+B,gBAAgB,EAAEC,IAAI,EAAE,GAAGhC;QACnCT,OAAOwC,kBAAkB;QAEzB,MAAM,EAAEjC,MAAM,EAAE,GAAGV;QACnB,MAAM6C,eAAeC;QAGrB,MAAMC,kBAAkB;QACxB,MAAMC,aAAmBC,MAAM,OAAO,CAACP,UACnC;YACE,MAAMQ,KAAK,KAAK,CAACR,MAAM,CAAC,EAAE,GAAGK,kBAAkB;YAC/C,KAAKG,KAAK,KAAK,CAACR,MAAM,CAAC,EAAE,GAAGK,kBAAkB;YAC9C,OAAOA;YACP,QAAQA;QACV,IACAL;QAEJ,IAAIS,eAAe,MAAMC,wBAAwB;YAC/C,gBAAgBT;YAChBC;YACA,sBAAsB;gBACpB;oBACE,MAAMI;gBACR;aACD;YACD,iBAAiB;QACnB;QAEA,IAAIjD,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,SAAS,EAAE;YAClB,MAAMc,aAAawC,iBAAiBL,YAAYpC,QAAQ,IAAI,EAAEF;YAC9Df,MAAM,4BAA4BkB;YAClC,MAAMyC,gBAAgB,MAAMC,WAC1BJ,cACAtC,YACAH,AAAW,cAAXA;YAEFyC,eAAeG,cAAc,WAAW;QAC1C;QAEA,MAAME,OAAe;YACnB;gBAAE,MAAM;gBAAU,SAASX;YAAa;YACxC;gBACE,MAAM;gBACN,SAAS;oBACP;wBACE,MAAM;wBACN,WAAW;4BACT,KAAKM;4BACL,QAAQ;wBACV;oBACF;iBACD;YACH;SACD;QAED,MAAMM,WAAW,IAAI,CAClB,UAAU;QAEb,MAAMC,MAAM,MAAMD,SAChBD,MACAG,aAAa,gBAAgB,EAC7B3D;QAGF,MAAM,EAAE4D,OAAO,EAAE,GAAGF;QACpBvD,OAAO,CAACyD,QAAQ,KAAK,EAAE,CAAC,iBAAiB,EAAEA,QAAQ,KAAK,EAAE;QAC1DzD,OAAOyD,QAAQ,WAAW,EAAE;QAC5B,OAAOA;IACT;IAxUA,YACEhD,OAEmE,EACnEb,GAAoB,CACpB;QAhBF;QAIA,qCACE8D;QAEF;QAEA;QAQE1D,OAAOS,SAAS;QAChB,IAAI,AAAmB,cAAnB,OAAOA,SACT,IAAI,CAAC,kBAAkB,GAAGA;aAE1B,IAAI,CAAC,kBAAkB,GAAG,IAAMkD,QAAQ,OAAO,CAAClD;QAIlD,IAAI,AAA2B,WAApBb,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,UAAU,AAAD,GACvB,IAAI,CAAC,UAAU,GAAGA,IAAI,UAAU;QAElC,IAAI,AAAyB,WAAlBA,CAAAA,QAAAA,MAAAA,KAAAA,IAAAA,IAAK,QAAQ,AAAD,GACrB,IAAI,CAAC,QAAQ,GAAGA,IAAI,QAAQ;IAEhC;AAqTF"}
1
+ {"version":3,"file":"insight/index.mjs","sources":["webpack://@midscene/core/./src/insight/index.ts"],"sourcesContent":["import { AIActionType, type AIArgs, expandSearchArea } from '@/ai-model/common';\nimport {\n AiExtractElementInfo,\n AiLocateElement,\n callAIWithObjectResponse,\n} from '@/ai-model/index';\nimport { AiLocateSection } from '@/ai-model/inspect';\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\nimport type {\n AIDescribeElementResponse,\n AIUsageInfo,\n BaseElement,\n DetailedLocateParam,\n InsightAction,\n InsightExtractOption,\n InsightExtractParam,\n InsightExtractResult,\n InsightTaskInfo,\n LocateResultWithDump,\n PartialInsightDumpFromSDK,\n Rect,\n UIContext,\n} from '@/types';\nimport { InsightError } from '@/types';\nimport {\n type IModelConfig,\n MIDSCENE_FORCE_DEEP_THINK,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { compositeElementInfoImg, cropByRect } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { TMultimodalPrompt } from '../ai-model/common';\nimport { createInsightDump } from './utils';\n\nexport interface LocateOpts {\n context?: UIContext<BaseElement>;\n}\n\nexport type AnyValue<T> = {\n [K in keyof T]: unknown extends T[K] ? any : T[K];\n};\n\ninterface InsightOptions {\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\n aiVendorFn?: typeof callAIWithObjectResponse;\n}\n\nconst debug = getDebug('ai:insight');\nexport default class Insight<\n ElementType extends BaseElement = BaseElement,\n ContextType extends UIContext<ElementType> = UIContext<ElementType>,\n> {\n contextRetrieverFn: () => Promise<ContextType> | ContextType;\n\n aiVendorFn: Exclude<InsightOptions['aiVendorFn'], undefined> =\n callAIWithObjectResponse;\n\n taskInfo?: Omit<InsightTaskInfo, 'durationMs'>;\n\n constructor(\n context: ContextType | (() => Promise<ContextType> | ContextType),\n opt?: InsightOptions,\n ) {\n assert(context, 'context is required for Insight');\n if (typeof context === 'function') {\n this.contextRetrieverFn = context;\n } else {\n this.contextRetrieverFn = () => Promise.resolve(context);\n }\n\n // just for unit test, aiVendorFn is callAIWithObjectResponse by default\n if (typeof opt?.aiVendorFn !== 'undefined') {\n this.aiVendorFn = opt.aiVendorFn;\n }\n if (typeof opt?.taskInfo !== 'undefined') {\n this.taskInfo = opt.taskInfo;\n }\n }\n\n async locate(\n query: DetailedLocateParam,\n opt: LocateOpts,\n modelConfig: IModelConfig,\n ): Promise<LocateResultWithDump> {\n const queryPrompt = typeof query === 'string' ? query : query.prompt;\n assert(queryPrompt, 'query is required for locate');\n\n assert(typeof query === 'object', 'query should be an object for locate');\n\n const globalDeepThinkSwitch = globalConfigManager.getEnvConfigInBoolean(\n MIDSCENE_FORCE_DEEP_THINK,\n );\n if (globalDeepThinkSwitch) {\n debug('globalDeepThinkSwitch', globalDeepThinkSwitch);\n }\n let searchAreaPrompt;\n if (query.deepThink || globalDeepThinkSwitch) {\n searchAreaPrompt = query.prompt;\n }\n\n const { vlMode } = modelConfig;\n\n if (searchAreaPrompt && !vlMode) {\n console.warn(\n 'The \"deepThink\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/choose-a-model',\n );\n searchAreaPrompt = undefined;\n }\n\n const context = opt?.context || (await this.contextRetrieverFn());\n\n let searchArea: Rect | undefined = undefined;\n let searchAreaRawResponse: string | undefined = undefined;\n let searchAreaUsage: AIUsageInfo | undefined = undefined;\n let searchAreaResponse:\n | Awaited<ReturnType<typeof AiLocateSection>>\n | undefined = undefined;\n if (searchAreaPrompt) {\n searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: searchAreaPrompt,\n modelConfig,\n });\n assert(\n searchAreaResponse.rect,\n `cannot find search area for \"${searchAreaPrompt}\"${\n searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''\n }`,\n );\n searchAreaRawResponse = searchAreaResponse.rawResponse;\n searchAreaUsage = searchAreaResponse.usage;\n searchArea = searchAreaResponse.rect;\n }\n\n const startTime = Date.now();\n const {\n parseResult,\n rect,\n elementById,\n rawResponse,\n usage,\n isOrderSensitive,\n } = await AiLocateElement({\n callAIFn: this.aiVendorFn,\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchAreaResponse,\n modelConfig,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: JSON.stringify(rawResponse),\n formatResponse: JSON.stringify(parseResult),\n usage,\n searchArea,\n searchAreaRawResponse,\n searchAreaUsage,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI model failed to locate: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialInsightDumpFromSDK = {\n type: 'locate',\n userQuery: {\n element: queryPrompt,\n },\n matchedElement: [],\n matchedRect: rect,\n data: null,\n taskInfo,\n deepThink: !!searchArea,\n error: errorLog,\n };\n\n const elements: BaseElement[] = [];\n (parseResult.elements || []).forEach((item) => {\n if ('id' in item) {\n const element = elementById(item?.id);\n\n if (!element) {\n console.warn(\n `locate: cannot find element id=${item.id}. Maybe an unstable response from AI model`,\n );\n return;\n }\n elements.push(element);\n }\n });\n\n const dump = createInsightDump({\n ...dumpData,\n matchedElement: elements,\n });\n\n if (errorLog) {\n throw new InsightError(errorLog, dump);\n }\n\n if (elements.length > 1) {\n throw new InsightError(\n `locate: multiple elements found, length = ${elements.length}`,\n dump,\n );\n }\n\n if (elements.length === 1) {\n return {\n element: {\n id: elements[0]!.id,\n indexId: elements[0]!.indexId,\n center: elements[0]!.center,\n rect: elements[0]!.rect,\n xpaths: elements[0]!.xpaths || [],\n attributes: elements[0]!.attributes,\n isOrderSensitive,\n },\n rect,\n dump,\n };\n }\n\n return {\n element: null,\n rect,\n dump,\n };\n }\n\n async extract<T>(\n dataDemand: InsightExtractParam,\n modelConfig: IModelConfig,\n opt?: InsightExtractOption,\n multimodalPrompt?: TMultimodalPrompt,\n ): Promise<InsightExtractResult<T>> {\n assert(\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\n );\n const context = await this.contextRetrieverFn();\n\n const startTime = Date.now();\n\n const { parseResult, usage } = await AiExtractElementInfo<T>({\n context,\n dataQuery: dataDemand,\n multimodalPrompt,\n extractOption: opt,\n modelConfig,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: InsightTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: JSON.stringify(parseResult),\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialInsightDumpFromSDK = {\n type: 'extract',\n userQuery: {\n dataDemand,\n },\n matchedElement: [],\n data: null,\n taskInfo,\n error: errorLog,\n };\n\n const { data, thought } = parseResult || {};\n\n // 4\n const dump = createInsightDump({\n ...dumpData,\n data,\n });\n\n if (errorLog && !data && !opt?.doNotThrowError) {\n throw new InsightError(errorLog, dump);\n }\n\n return {\n data,\n thought,\n usage,\n dump,\n };\n }\n\n async describe(\n target: Rect | [number, number],\n modelConfig: IModelConfig,\n opt?: {\n deepThink?: boolean;\n },\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\n assert(target, 'target is required for insight.describe');\n const context = await this.contextRetrieverFn();\n const { screenshotBase64, size } = context;\n assert(screenshotBase64, 'screenshot is required for insight.describe');\n // The result of the \"describe\" function will be used for positioning, so essentially it is a form of grounding.\n const { vlMode } = modelConfig;\n const systemPrompt = elementDescriberInstruction();\n\n // Convert [x,y] center point to Rect if needed\n const defaultRectSize = 30;\n const targetRect: Rect = Array.isArray(target)\n ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize,\n }\n : target;\n\n let imagePayload = await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size,\n elementsPositionInfo: [\n {\n rect: targetRect,\n },\n ],\n borderThickness: 3,\n });\n\n if (opt?.deepThink) {\n const searchArea = expandSearchArea(targetRect, context.size, vlMode);\n debug('describe: set searchArea', searchArea);\n const croppedResult = await cropByRect(\n imagePayload,\n searchArea,\n vlMode === 'qwen-vl',\n );\n imagePayload = croppedResult.imageBase64;\n }\n\n const msgs: AIArgs = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high',\n },\n },\n ],\n },\n ];\n\n const callAIFn = this\n .aiVendorFn as typeof callAIWithObjectResponse<AIDescribeElementResponse>;\n\n const res = await callAIFn(\n msgs,\n AIActionType.DESCRIBE_ELEMENT,\n modelConfig,\n );\n\n const { content } = res;\n assert(!content.error, `describe failed: ${content.error}`);\n assert(content.description, 'failed to describe the element');\n return content;\n }\n}\n"],"names":["debug","getDebug","Insight","query","opt","modelConfig","_parseResult_errors","queryPrompt","assert","globalDeepThinkSwitch","globalConfigManager","MIDSCENE_FORCE_DEEP_THINK","searchAreaPrompt","vlMode","console","undefined","context","searchArea","searchAreaRawResponse","searchAreaUsage","searchAreaResponse","AiLocateSection","startTime","Date","parseResult","rect","elementById","rawResponse","usage","isOrderSensitive","AiLocateElement","timeCost","taskInfo","JSON","errorLog","dumpData","elements","item","element","dump","createInsightDump","InsightError","dataDemand","multimodalPrompt","AiExtractElementInfo","data","thought","target","screenshotBase64","size","systemPrompt","elementDescriberInstruction","defaultRectSize","targetRect","Array","Math","imagePayload","compositeElementInfoImg","expandSearchArea","croppedResult","cropByRect","msgs","callAIFn","res","AIActionType","content","callAIWithObjectResponse","Promise"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { uuid } from "@midscene/shared/utils";
2
- function emitInsightDump(data, dumpSubscriber) {
2
+ function createInsightDump(data) {
3
3
  const baseData = {
4
4
  logTime: Date.now()
5
5
  };
@@ -8,8 +8,8 @@ function emitInsightDump(data, dumpSubscriber) {
8
8
  ...baseData,
9
9
  ...data
10
10
  };
11
- null == dumpSubscriber || dumpSubscriber(finalData);
11
+ return finalData;
12
12
  }
13
- export { emitInsightDump };
13
+ export { createInsightDump };
14
14
 
15
15
  //# sourceMappingURL=utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"insight/utils.mjs","sources":["webpack://@midscene/core/./src/insight/utils.ts"],"sourcesContent":["import type {\n DumpMeta,\n DumpSubscriber,\n InsightDump,\n PartialInsightDumpFromSDK,\n} from '@/types';\nimport { uuid } from '@midscene/shared/utils';\n\nexport function emitInsightDump(\n data: PartialInsightDumpFromSDK,\n dumpSubscriber?: DumpSubscriber,\n) {\n const baseData: DumpMeta = {\n logTime: Date.now(),\n };\n const finalData: InsightDump = {\n logId: uuid(),\n ...baseData,\n ...data,\n };\n\n dumpSubscriber?.(finalData);\n}\n"],"names":["emitInsightDump","data","dumpSubscriber","baseData","Date","finalData","uuid"],"mappings":";AAQO,SAASA,gBACdC,IAA+B,EAC/BC,cAA+B;IAE/B,MAAMC,WAAqB;QACzB,SAASC,KAAK,GAAG;IACnB;IACA,MAAMC,YAAyB;QAC7B,OAAOC;QACP,GAAGH,QAAQ;QACX,GAAGF,IAAI;IACT;IAEAC,QAAAA,kBAAAA,eAAiBG;AACnB"}
1
+ {"version":3,"file":"insight/utils.mjs","sources":["webpack://@midscene/core/./src/insight/utils.ts"],"sourcesContent":["import type { DumpMeta, InsightDump, PartialInsightDumpFromSDK } from '@/types';\nimport { uuid } from '@midscene/shared/utils';\n\nexport function createInsightDump(\n data: PartialInsightDumpFromSDK,\n): InsightDump {\n const baseData: DumpMeta = {\n logTime: Date.now(),\n };\n const finalData: InsightDump = {\n logId: uuid(),\n ...baseData,\n ...data,\n };\n\n return finalData;\n}\n"],"names":["createInsightDump","data","baseData","Date","finalData","uuid"],"mappings":";AAGO,SAASA,kBACdC,IAA+B;IAE/B,MAAMC,WAAqB;QACzB,SAASC,KAAK,GAAG;IACnB;IACA,MAAMC,YAAyB;QAC7B,OAAOC;QACP,GAAGH,QAAQ;QACX,GAAGD,IAAI;IACT;IAEA,OAAOG;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"report.mjs","sources":["webpack://@midscene/core/./src/report.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { getReportFileName } from './agent';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, reportHTMLContent } from './utils';\n\nexport class ReportMergingTool {\n private reportInfos: ReportFileWithAttributes[] = [];\n public append(reportInfo: ReportFileWithAttributes) {\n this.reportInfos.push(reportInfo);\n }\n public clear() {\n this.reportInfos = [];\n }\n private extractScriptContent(filePath: string): string {\n // Regular expression to match content between script tags\n // Requires newline before <script and </script>\n const scriptRegex =\n /\\n<script type=\"midscene_web_dump\" type=\"application\\/json\"[^>]*>([\\s\\S]*?)\\n<\\/script>/;\n\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n const match = scriptRegex.exec(fileContent);\n\n return match ? match[1].trim() : '';\n }\n\n public mergeReports(\n reportFileName: 'AUTO' | string = 'AUTO', // user custom report filename, save into midscene report dir if undefined\n opts?: {\n rmOriginalReports?: boolean; // whether to remove origin report files\n overwrite?: boolean; // if outfilepath specified, throw an error when overwrite = true, otherwise overwrite the file\n },\n ): string | null {\n if (this.reportInfos.length <= 1) {\n console.log('Not enough report to merge');\n return null;\n }\n opts = Object.assign(\n {\n rmOriginalReports: false,\n overwrite: false,\n },\n opts || {},\n );\n const { rmOriginalReports, overwrite } = opts;\n let outputFilePath;\n const targetDir = `${getMidsceneRunSubDir('report')}`;\n if (reportFileName === 'AUTO') {\n outputFilePath = path.resolve(\n targetDir,\n `${getReportFileName('merged-report')}.html`,\n );\n } else {\n // user specified a outfilepath\n outputFilePath = path.resolve(targetDir, `${reportFileName}.html`);\n if (fs.existsSync(outputFilePath) && !overwrite) {\n throw Error(\n `report file already existed: ${outputFilePath}\\nset override to true to overwrite this file.`,\n );\n } else if (fs.existsSync(outputFilePath) && overwrite) {\n fs.unlinkSync(outputFilePath);\n }\n }\n\n console.log(\n `Start merging ${this.reportInfos.length} reports...\\nCreating template file...`,\n );\n\n try {\n // Write template\n fs.appendFileSync(outputFilePath, getReportTpl());\n\n // Process all reports one by one\n for (let i = 0; i < this.reportInfos.length; i++) {\n const reportInfo = this.reportInfos[i];\n console.log(`Processing report ${i + 1}/${this.reportInfos.length}`);\n\n const dumpString = this.extractScriptContent(reportInfo.reportFilePath);\n const reportAttributes = reportInfo.reportAttributes;\n\n const reportHtmlStr = `${reportHTMLContent(\n {\n dumpString,\n attributes: {\n playwright_test_duration: reportAttributes.testDuration,\n playwright_test_status: reportAttributes.testStatus,\n playwright_test_title: reportAttributes.testTitle,\n playwright_test_id: reportAttributes.testId,\n playwright_test_description: reportAttributes.testDescription,\n },\n },\n undefined,\n undefined,\n false,\n )}\\n`; // use existed function to achieve report script content\n\n fs.appendFileSync(outputFilePath, reportHtmlStr);\n }\n\n console.log(`Successfully merged new report: ${outputFilePath}`);\n\n // Remove original reports if needed\n if (rmOriginalReports) {\n for (const info of this.reportInfos) {\n try {\n fs.unlinkSync(info.reportFilePath);\n } catch (error) {\n console.error(\n `Error deleting report ${info.reportFilePath}:`,\n error,\n );\n }\n }\n console.log(`Removed ${this.reportInfos.length} original reports`);\n }\n return outputFilePath;\n } catch (error) {\n console.error('Error in mergeReports:', error);\n throw error;\n }\n }\n}\n"],"names":["ReportMergingTool","reportInfo","filePath","scriptRegex","fileContent","fs","match","reportFileName","opts","console","Object","rmOriginalReports","overwrite","outputFilePath","targetDir","getMidsceneRunSubDir","path","getReportFileName","Error","getReportTpl","i","dumpString","reportAttributes","reportHtmlStr","reportHTMLContent","undefined","info","error"],"mappings":";;;;;;;;;;;;;;;AAOO,MAAMA;IAEJ,OAAOC,UAAoC,EAAE;QAClD,IAAI,CAAC,WAAW,CAAC,IAAI,CAACA;IACxB;IACO,QAAQ;QACb,IAAI,CAAC,WAAW,GAAG,EAAE;IACvB;IACQ,qBAAqBC,QAAgB,EAAU;QAGrD,MAAMC,cACJ;QAEF,MAAMC,cAAcC,aAAgBH,UAAU;QAC9C,MAAMI,QAAQH,YAAY,IAAI,CAACC;QAE/B,OAAOE,QAAQA,KAAK,CAAC,EAAE,CAAC,IAAI,KAAK;IACnC;IAEO,aACLC,iBAAkC,MAAM,EACxCC,IAGC,EACc;QACf,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,GAAG;YAChCC,QAAQ,GAAG,CAAC;YACZ,OAAO;QACT;QACAD,OAAOE,OAAO,MAAM,CAClB;YACE,mBAAmB;YACnB,WAAW;QACb,GACAF,QAAQ,CAAC;QAEX,MAAM,EAAEG,iBAAiB,EAAEC,SAAS,EAAE,GAAGJ;QACzC,IAAIK;QACJ,MAAMC,YAAY,GAAGC,qBAAqB,WAAW;QACrD,IAAIR,AAAmB,WAAnBA,gBACFM,iBAAiBG,QACfF,WACA,GAAGG,kBAAkB,iBAAiB,KAAK,CAAC;aAEzC;YAELJ,iBAAiBG,QAAaF,WAAW,GAAGP,eAAe,KAAK,CAAC;YACjE,IAAIF,WAAcQ,mBAAmB,CAACD,WACpC,MAAMM,MACJ,CAAC,6BAA6B,EAAEL,eAAe,8CAA8C,CAAC;YAE3F,IAAIR,WAAcQ,mBAAmBD,WAC1CP,WAAcQ;QAElB;QAEAJ,QAAQ,GAAG,CACT,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,sCAAsC,CAAC;QAGlF,IAAI;YAEFJ,eAAkBQ,gBAAgBM;YAGlC,IAAK,IAAIC,IAAI,GAAGA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAEA,IAAK;gBAChD,MAAMnB,aAAa,IAAI,CAAC,WAAW,CAACmB,EAAE;gBACtCX,QAAQ,GAAG,CAAC,CAAC,kBAAkB,EAAEW,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;gBAEnE,MAAMC,aAAa,IAAI,CAAC,oBAAoB,CAACpB,WAAW,cAAc;gBACtE,MAAMqB,mBAAmBrB,WAAW,gBAAgB;gBAEpD,MAAMsB,gBAAgB,GAAGC,kBACvB;oBACEH;oBACA,YAAY;wBACV,0BAA0BC,iBAAiB,YAAY;wBACvD,wBAAwBA,iBAAiB,UAAU;wBACnD,uBAAuBA,iBAAiB,SAAS;wBACjD,oBAAoBA,iBAAiB,MAAM;wBAC3C,6BAA6BA,iBAAiB,eAAe;oBAC/D;gBACF,GACAG,QACAA,QACA,OACA,EAAE,CAAC;gBAELpB,eAAkBQ,gBAAgBU;YACpC;YAEAd,QAAQ,GAAG,CAAC,CAAC,gCAAgC,EAAEI,gBAAgB;YAG/D,IAAIF,mBAAmB;gBACrB,KAAK,MAAMe,QAAQ,IAAI,CAAC,WAAW,CACjC,IAAI;oBACFrB,WAAcqB,KAAK,cAAc;gBACnC,EAAE,OAAOC,OAAO;oBACdlB,QAAQ,KAAK,CACX,CAAC,sBAAsB,EAAEiB,KAAK,cAAc,CAAC,CAAC,CAAC,EAC/CC;gBAEJ;gBAEFlB,QAAQ,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC;YACnE;YACA,OAAOI;QACT,EAAE,OAAOc,OAAO;YACdlB,QAAQ,KAAK,CAAC,0BAA0BkB;YACxC,MAAMA;QACR;IACF;;QAjHA,uBAAQ,eAA0C,EAAE;;AAkHtD"}
1
+ {"version":3,"file":"report.mjs","sources":["webpack://@midscene/core/./src/report.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { getReportFileName } from './agent';\nimport type { ReportFileWithAttributes } from './types';\nimport { getReportTpl, reportHTMLContent } from './utils';\n\nexport class ReportMergingTool {\n private reportInfos: ReportFileWithAttributes[] = [];\n public append(reportInfo: ReportFileWithAttributes) {\n this.reportInfos.push(reportInfo);\n }\n public clear() {\n this.reportInfos = [];\n }\n private extractScriptContent(filePath: string): string {\n // Regular expression to match content between script tags\n // Requires newline before <script and </script>\n const scriptRegex =\n /\\n<script type=\"midscene_web_dump\" type=\"application\\/json\"[^>]*>([\\s\\S]*?)\\n<\\/script>/;\n\n const fileContent = fs.readFileSync(filePath, 'utf-8');\n const match = scriptRegex.exec(fileContent);\n\n return match ? match[1].trim() : '';\n }\n\n public mergeReports(\n reportFileName: 'AUTO' | string = 'AUTO', // user custom report filename, save into midscene report dir if undefined\n opts?: {\n rmOriginalReports?: boolean; // whether to remove origin report files\n overwrite?: boolean; // if output filepath specified, throw an error when overwrite = true, otherwise overwrite the file\n },\n ): string | null {\n if (this.reportInfos.length <= 1) {\n console.log('Not enough report to merge');\n return null;\n }\n opts = Object.assign(\n {\n rmOriginalReports: false,\n overwrite: false,\n },\n opts || {},\n );\n const { rmOriginalReports, overwrite } = opts;\n let outputFilePath;\n const targetDir = `${getMidsceneRunSubDir('report')}`;\n if (reportFileName === 'AUTO') {\n outputFilePath = path.resolve(\n targetDir,\n `${getReportFileName('merged-report')}.html`,\n );\n } else {\n // user specified a output filepath\n outputFilePath = path.resolve(targetDir, `${reportFileName}.html`);\n if (fs.existsSync(outputFilePath) && !overwrite) {\n throw Error(\n `report file already existed: ${outputFilePath}\\nset override to true to overwrite this file.`,\n );\n } else if (fs.existsSync(outputFilePath) && overwrite) {\n fs.unlinkSync(outputFilePath);\n }\n }\n\n console.log(\n `Start merging ${this.reportInfos.length} reports...\\nCreating template file...`,\n );\n\n try {\n // Write template\n fs.appendFileSync(outputFilePath, getReportTpl());\n\n // Process all reports one by one\n for (let i = 0; i < this.reportInfos.length; i++) {\n const reportInfo = this.reportInfos[i];\n console.log(`Processing report ${i + 1}/${this.reportInfos.length}`);\n\n const dumpString = this.extractScriptContent(reportInfo.reportFilePath);\n const reportAttributes = reportInfo.reportAttributes;\n\n const reportHtmlStr = `${reportHTMLContent(\n {\n dumpString,\n attributes: {\n playwright_test_duration: reportAttributes.testDuration,\n playwright_test_status: reportAttributes.testStatus,\n playwright_test_title: reportAttributes.testTitle,\n playwright_test_id: reportAttributes.testId,\n playwright_test_description: reportAttributes.testDescription,\n },\n },\n undefined,\n undefined,\n false,\n )}\\n`; // use existed function to achieve report script content\n\n fs.appendFileSync(outputFilePath, reportHtmlStr);\n }\n\n console.log(`Successfully merged new report: ${outputFilePath}`);\n\n // Remove original reports if needed\n if (rmOriginalReports) {\n for (const info of this.reportInfos) {\n try {\n fs.unlinkSync(info.reportFilePath);\n } catch (error) {\n console.error(\n `Error deleting report ${info.reportFilePath}:`,\n error,\n );\n }\n }\n console.log(`Removed ${this.reportInfos.length} original reports`);\n }\n return outputFilePath;\n } catch (error) {\n console.error('Error in mergeReports:', error);\n throw error;\n }\n }\n}\n"],"names":["ReportMergingTool","reportInfo","filePath","scriptRegex","fileContent","fs","match","reportFileName","opts","console","Object","rmOriginalReports","overwrite","outputFilePath","targetDir","getMidsceneRunSubDir","path","getReportFileName","Error","getReportTpl","i","dumpString","reportAttributes","reportHtmlStr","reportHTMLContent","undefined","info","error"],"mappings":";;;;;;;;;;;;;;;AAOO,MAAMA;IAEJ,OAAOC,UAAoC,EAAE;QAClD,IAAI,CAAC,WAAW,CAAC,IAAI,CAACA;IACxB;IACO,QAAQ;QACb,IAAI,CAAC,WAAW,GAAG,EAAE;IACvB;IACQ,qBAAqBC,QAAgB,EAAU;QAGrD,MAAMC,cACJ;QAEF,MAAMC,cAAcC,aAAgBH,UAAU;QAC9C,MAAMI,QAAQH,YAAY,IAAI,CAACC;QAE/B,OAAOE,QAAQA,KAAK,CAAC,EAAE,CAAC,IAAI,KAAK;IACnC;IAEO,aACLC,iBAAkC,MAAM,EACxCC,IAGC,EACc;QACf,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,GAAG;YAChCC,QAAQ,GAAG,CAAC;YACZ,OAAO;QACT;QACAD,OAAOE,OAAO,MAAM,CAClB;YACE,mBAAmB;YACnB,WAAW;QACb,GACAF,QAAQ,CAAC;QAEX,MAAM,EAAEG,iBAAiB,EAAEC,SAAS,EAAE,GAAGJ;QACzC,IAAIK;QACJ,MAAMC,YAAY,GAAGC,qBAAqB,WAAW;QACrD,IAAIR,AAAmB,WAAnBA,gBACFM,iBAAiBG,QACfF,WACA,GAAGG,kBAAkB,iBAAiB,KAAK,CAAC;aAEzC;YAELJ,iBAAiBG,QAAaF,WAAW,GAAGP,eAAe,KAAK,CAAC;YACjE,IAAIF,WAAcQ,mBAAmB,CAACD,WACpC,MAAMM,MACJ,CAAC,6BAA6B,EAAEL,eAAe,8CAA8C,CAAC;YAE3F,IAAIR,WAAcQ,mBAAmBD,WAC1CP,WAAcQ;QAElB;QAEAJ,QAAQ,GAAG,CACT,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,sCAAsC,CAAC;QAGlF,IAAI;YAEFJ,eAAkBQ,gBAAgBM;YAGlC,IAAK,IAAIC,IAAI,GAAGA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAEA,IAAK;gBAChD,MAAMnB,aAAa,IAAI,CAAC,WAAW,CAACmB,EAAE;gBACtCX,QAAQ,GAAG,CAAC,CAAC,kBAAkB,EAAEW,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;gBAEnE,MAAMC,aAAa,IAAI,CAAC,oBAAoB,CAACpB,WAAW,cAAc;gBACtE,MAAMqB,mBAAmBrB,WAAW,gBAAgB;gBAEpD,MAAMsB,gBAAgB,GAAGC,kBACvB;oBACEH;oBACA,YAAY;wBACV,0BAA0BC,iBAAiB,YAAY;wBACvD,wBAAwBA,iBAAiB,UAAU;wBACnD,uBAAuBA,iBAAiB,SAAS;wBACjD,oBAAoBA,iBAAiB,MAAM;wBAC3C,6BAA6BA,iBAAiB,eAAe;oBAC/D;gBACF,GACAG,QACAA,QACA,OACA,EAAE,CAAC;gBAELpB,eAAkBQ,gBAAgBU;YACpC;YAEAd,QAAQ,GAAG,CAAC,CAAC,gCAAgC,EAAEI,gBAAgB;YAG/D,IAAIF,mBAAmB;gBACrB,KAAK,MAAMe,QAAQ,IAAI,CAAC,WAAW,CACjC,IAAI;oBACFrB,WAAcqB,KAAK,cAAc;gBACnC,EAAE,OAAOC,OAAO;oBACdlB,QAAQ,KAAK,CACX,CAAC,sBAAsB,EAAEiB,KAAK,cAAc,CAAC,CAAC,CAAC,EAC/CC;gBAEJ;gBAEFlB,QAAQ,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC;YACnE;YACA,OAAOI;QACT,EAAE,OAAOc,OAAO;YACdlB,QAAQ,KAAK,CAAC,0BAA0BkB;YACxC,MAAMA;QACR;IACF;;QAjHA,uBAAQ,eAA0C,EAAE;;AAkHtD"}
@@ -9,7 +9,33 @@ function _define_property(obj, key, value) {
9
9
  else obj[key] = value;
10
10
  return obj;
11
11
  }
12
- class Executor {
12
+ class TaskRunner {
13
+ async captureScreenshot() {
14
+ try {
15
+ const uiContext = await this.uiContextBuilder();
16
+ return null == uiContext ? void 0 : uiContext.screenshotBase64;
17
+ } catch (error) {
18
+ console.error('error while capturing screenshot', error);
19
+ }
20
+ }
21
+ attachRecorderItem(task, contextOrScreenshot, phase) {
22
+ const timing = phase;
23
+ const screenshot = 'string' == typeof contextOrScreenshot ? contextOrScreenshot : null == contextOrScreenshot ? void 0 : contextOrScreenshot.screenshotBase64;
24
+ if (!timing || !screenshot) return;
25
+ const recorderItem = {
26
+ type: 'screenshot',
27
+ ts: Date.now(),
28
+ screenshot,
29
+ timing
30
+ };
31
+ if (!task.recorder) {
32
+ task.recorder = [
33
+ recorderItem
34
+ ];
35
+ return;
36
+ }
37
+ task.recorder.push(recorderItem);
38
+ }
13
39
  markTaskAsPending(task) {
14
40
  return {
15
41
  status: 'pending',
@@ -18,16 +44,20 @@ class Executor {
18
44
  }
19
45
  async append(task) {
20
46
  var _this_latestErrorTask, _this_latestErrorTask1;
21
- assert('error' !== this.status, `executor is in error state, cannot append task\nerror=${null == (_this_latestErrorTask = this.latestErrorTask()) ? void 0 : _this_latestErrorTask.error}\n${null == (_this_latestErrorTask1 = this.latestErrorTask()) ? void 0 : _this_latestErrorTask1.errorStack}`);
47
+ assert('error' !== this.status, `task runner is in error state, cannot append task\nerror=${null == (_this_latestErrorTask = this.latestErrorTask()) ? void 0 : _this_latestErrorTask.error}\n${null == (_this_latestErrorTask1 = this.latestErrorTask()) ? void 0 : _this_latestErrorTask1.errorStack}`);
22
48
  if (Array.isArray(task)) this.tasks.push(...task.map((item)=>this.markTaskAsPending(item)));
23
49
  else this.tasks.push(this.markTaskAsPending(task));
24
50
  if ('running' !== this.status) this.status = 'pending';
25
51
  }
52
+ async appendAndFlush(task) {
53
+ await this.append(task);
54
+ return this.flush();
55
+ }
26
56
  async flush() {
27
- if ('init' === this.status && this.tasks.length > 0) console.warn('illegal state for executor, status is init but tasks are not empty');
28
- assert('running' !== this.status, 'executor is already running');
29
- assert('completed' !== this.status, 'executor is already completed');
30
- assert('error' !== this.status, 'executor is in error state');
57
+ if ('init' === this.status && this.tasks.length > 0) console.warn('illegal state for task runner, status is init but tasks are not empty');
58
+ assert('running' !== this.status, 'task runner is already running');
59
+ assert('completed' !== this.status, 'task runner is already completed');
60
+ assert('error' !== this.status, 'task runner is in error state');
31
61
  const nextPendingIndex = this.tasks.findIndex((task)=>'pending' === task.status);
32
62
  if (nextPendingIndex < 0) return;
33
63
  this.status = 'running';
@@ -55,9 +85,12 @@ class Executor {
55
85
  const { executor, param } = task;
56
86
  assert(executor, `executor is required for task type: ${task.type}`);
57
87
  let returnValue;
88
+ const uiContext = await this.uiContextBuilder();
89
+ task.uiContext = uiContext;
58
90
  const executorContext = {
59
91
  task,
60
- element: null == previousFindOutput ? void 0 : previousFindOutput.element
92
+ element: null == previousFindOutput ? void 0 : previousFindOutput.element,
93
+ uiContext
61
94
  };
62
95
  if ('Insight' === task.type) {
63
96
  assert('Locate' === task.subType || 'Query' === task.subType || 'Assert' === task.subType || 'WaitFor' === task.subType || 'Boolean' === task.subType || 'Number' === task.subType || 'String' === task.subType, `unsupported insight subType: ${task.subType}`);
@@ -68,6 +101,11 @@ class Executor {
68
101
  console.warn(`unsupported task type: ${task.type}, will try to execute it directly`);
69
102
  returnValue = await task.executor(param, executorContext);
70
103
  }
104
+ const isLastTask = taskIndex === this.tasks.length - 1;
105
+ if (isLastTask) {
106
+ const screenshot = await this.captureScreenshot();
107
+ this.attachRecorderItem(task, screenshot, 'after');
108
+ }
71
109
  Object.assign(task, returnValue);
72
110
  task.status = 'finished';
73
111
  task.timing.end = Date.now();
@@ -113,17 +151,38 @@ class Executor {
113
151
  };
114
152
  return dumpData;
115
153
  }
116
- constructor(name, options){
154
+ async appendErrorPlan(errorMsg) {
155
+ const errorTask = {
156
+ type: 'Action',
157
+ subType: 'Error',
158
+ param: {
159
+ thought: errorMsg
160
+ },
161
+ thought: errorMsg,
162
+ locate: null,
163
+ executor: async ()=>{
164
+ throw new Error(errorMsg || 'error without thought');
165
+ }
166
+ };
167
+ await this.appendAndFlush(errorTask);
168
+ return {
169
+ output: void 0,
170
+ runner: this
171
+ };
172
+ }
173
+ constructor(name, uiContextBuilder, options){
117
174
  _define_property(this, "name", void 0);
118
175
  _define_property(this, "tasks", void 0);
119
176
  _define_property(this, "status", void 0);
120
177
  _define_property(this, "onTaskStart", void 0);
178
+ _define_property(this, "uiContextBuilder", void 0);
121
179
  this.status = (null == options ? void 0 : options.tasks) && options.tasks.length > 0 ? 'pending' : 'init';
122
180
  this.name = name;
123
181
  this.tasks = ((null == options ? void 0 : options.tasks) || []).map((item)=>this.markTaskAsPending(item));
124
182
  this.onTaskStart = null == options ? void 0 : options.onTaskStart;
183
+ this.uiContextBuilder = uiContextBuilder;
125
184
  }
126
185
  }
127
- export { Executor };
186
+ export { TaskRunner };
128
187
 
129
- //# sourceMappingURL=action-executor.mjs.map
188
+ //# sourceMappingURL=task-runner.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-runner.mjs","sources":["webpack://@midscene/core/./src/task-runner.ts"],"sourcesContent":["import type {\n ExecutionDump,\n ExecutionRecorderItem,\n ExecutionTask,\n ExecutionTaskActionApply,\n ExecutionTaskApply,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskProgressOptions,\n ExecutionTaskReturn,\n ExecutorContext,\n PlanningActionParamError,\n UIContext,\n} from '@/types';\nimport { assert } from '@midscene/shared/utils';\n\nexport class TaskRunner {\n name: string;\n\n tasks: ExecutionTask[];\n\n // status of runner\n status: 'init' | 'pending' | 'running' | 'completed' | 'error';\n\n onTaskStart?: ExecutionTaskProgressOptions['onTaskStart'];\n\n private readonly uiContextBuilder: () => Promise<UIContext>;\n\n constructor(\n name: string,\n uiContextBuilder: () => Promise<UIContext>,\n options?: ExecutionTaskProgressOptions & {\n tasks?: ExecutionTaskApply[];\n },\n ) {\n this.status =\n options?.tasks && options.tasks.length > 0 ? 'pending' : 'init';\n this.name = name;\n this.tasks = (options?.tasks || []).map((item) =>\n this.markTaskAsPending(item),\n );\n this.onTaskStart = options?.onTaskStart;\n this.uiContextBuilder = uiContextBuilder;\n }\n\n private async captureScreenshot(): Promise<string | undefined> {\n try {\n const uiContext = await this.uiContextBuilder();\n return uiContext?.screenshotBase64;\n } catch (error) {\n console.error('error while capturing screenshot', error);\n }\n return undefined;\n }\n\n private attachRecorderItem(\n task: ExecutionTask,\n contextOrScreenshot: UIContext | string | undefined,\n phase: 'before' | 'after',\n ): void {\n const timing = phase;\n const screenshot =\n typeof contextOrScreenshot === 'string'\n ? contextOrScreenshot\n : contextOrScreenshot?.screenshotBase64;\n if (!timing || !screenshot) {\n return;\n }\n\n const recorderItem: ExecutionRecorderItem = {\n type: 'screenshot',\n ts: Date.now(),\n screenshot,\n timing,\n };\n\n if (!task.recorder) {\n task.recorder = [recorderItem];\n return;\n }\n task.recorder.push(recorderItem);\n }\n\n private markTaskAsPending(task: ExecutionTaskApply): ExecutionTask {\n return {\n status: 'pending',\n ...task,\n };\n }\n\n async append(task: ExecutionTaskApply[] | ExecutionTaskApply): Promise<void> {\n assert(\n this.status !== 'error',\n `task runner is in error state, cannot append task\\nerror=${this.latestErrorTask()?.error}\\n${this.latestErrorTask()?.errorStack}`,\n );\n if (Array.isArray(task)) {\n this.tasks.push(...task.map((item) => this.markTaskAsPending(item)));\n } else {\n this.tasks.push(this.markTaskAsPending(task));\n }\n if (this.status !== 'running') {\n this.status = 'pending';\n }\n }\n\n async appendAndFlush(\n task: ExecutionTaskApply[] | ExecutionTaskApply,\n ): Promise<{ output: any; thought?: string } | undefined> {\n await this.append(task);\n return this.flush();\n }\n\n async flush(): Promise<{ output: any; thought?: string } | undefined> {\n if (this.status === 'init' && this.tasks.length > 0) {\n console.warn(\n 'illegal state for task runner, status is init but tasks are not empty',\n );\n }\n\n assert(this.status !== 'running', 'task runner is already running');\n assert(this.status !== 'completed', 'task runner is already completed');\n assert(this.status !== 'error', 'task runner is in error state');\n\n const nextPendingIndex = this.tasks.findIndex(\n (task) => task.status === 'pending',\n );\n if (nextPendingIndex < 0) {\n // all tasks are completed\n return;\n }\n\n this.status = 'running';\n let taskIndex = nextPendingIndex;\n let successfullyCompleted = true;\n\n let previousFindOutput: ExecutionTaskInsightLocateOutput | undefined;\n\n while (taskIndex < this.tasks.length) {\n const task = this.tasks[taskIndex];\n assert(\n task.status === 'pending',\n `task status should be pending, but got: ${task.status}`,\n );\n task.timing = {\n start: Date.now(),\n };\n try {\n task.status = 'running';\n try {\n if (this.onTaskStart) {\n await this.onTaskStart(task);\n }\n } catch (e) {\n console.error('error in onTaskStart', e);\n }\n assert(\n ['Insight', 'Action', 'Planning'].indexOf(task.type) >= 0,\n `unsupported task type: ${task.type}`,\n );\n\n const { executor, param } = task;\n assert(executor, `executor is required for task type: ${task.type}`);\n\n let returnValue;\n const uiContext = await this.uiContextBuilder();\n task.uiContext = uiContext;\n const executorContext: ExecutorContext = {\n task,\n element: previousFindOutput?.element,\n uiContext,\n };\n\n if (task.type === 'Insight') {\n assert(\n task.subType === 'Locate' ||\n task.subType === 'Query' ||\n task.subType === 'Assert' ||\n task.subType === 'WaitFor' ||\n task.subType === 'Boolean' ||\n task.subType === 'Number' ||\n task.subType === 'String',\n `unsupported insight subType: ${task.subType}`,\n );\n returnValue = await task.executor(param, executorContext);\n if (task.subType === 'Locate') {\n previousFindOutput = (\n returnValue as ExecutionTaskReturn<ExecutionTaskInsightLocateOutput>\n )?.output;\n }\n } else if (task.type === 'Action' || task.type === 'Planning') {\n returnValue = await task.executor(param, executorContext);\n } else {\n console.warn(\n `unsupported task type: ${task.type}, will try to execute it directly`,\n );\n returnValue = await task.executor(param, executorContext);\n }\n\n const isLastTask = taskIndex === this.tasks.length - 1;\n\n if (isLastTask) {\n const screenshot = await this.captureScreenshot();\n this.attachRecorderItem(task, screenshot, 'after');\n }\n\n Object.assign(task, returnValue);\n task.status = 'finished';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n taskIndex++;\n } catch (e: any) {\n successfullyCompleted = false;\n task.error = e;\n task.errorMessage =\n e?.message || (typeof e === 'string' ? e : 'error-without-message');\n task.errorStack = e.stack;\n\n task.status = 'failed';\n task.timing.end = Date.now();\n task.timing.cost = task.timing.end - task.timing.start;\n break;\n }\n }\n\n // set all remaining tasks as cancelled\n for (let i = taskIndex + 1; i < this.tasks.length; i++) {\n this.tasks[i].status = 'cancelled';\n }\n\n if (successfullyCompleted) {\n this.status = 'completed';\n } else {\n this.status = 'error';\n }\n\n if (this.tasks.length) {\n // return the last output\n const outputIndex = Math.min(taskIndex, this.tasks.length - 1);\n const { thought, output } = this.tasks[outputIndex];\n return {\n thought,\n output,\n };\n }\n }\n\n isInErrorState(): boolean {\n return this.status === 'error';\n }\n\n latestErrorTask(): ExecutionTask | null {\n if (this.status !== 'error') {\n return null;\n }\n const errorTaskIndex = this.tasks.findIndex(\n (task) => task.status === 'failed',\n );\n if (errorTaskIndex >= 0) {\n return this.tasks[errorTaskIndex];\n }\n return null;\n }\n\n dump(): ExecutionDump {\n const dumpData: ExecutionDump = {\n logTime: Date.now(),\n name: this.name,\n tasks: this.tasks,\n };\n return dumpData;\n }\n\n async appendErrorPlan(errorMsg: string): Promise<{\n output: undefined;\n runner: TaskRunner;\n }> {\n const errorTask: ExecutionTaskActionApply<PlanningActionParamError> = {\n type: 'Action',\n subType: 'Error',\n param: {\n thought: errorMsg,\n },\n thought: errorMsg,\n locate: null,\n executor: async () => {\n throw new Error(errorMsg || 'error without thought');\n },\n };\n await this.appendAndFlush(errorTask);\n\n return {\n output: undefined,\n runner: this,\n };\n }\n}\n"],"names":["TaskRunner","uiContext","error","console","task","contextOrScreenshot","phase","timing","screenshot","recorderItem","Date","_this_latestErrorTask","_this_latestErrorTask1","assert","Array","item","nextPendingIndex","taskIndex","successfullyCompleted","previousFindOutput","e","executor","param","returnValue","executorContext","isLastTask","Object","i","outputIndex","Math","thought","output","errorTaskIndex","dumpData","errorMsg","errorTask","Error","undefined","name","uiContextBuilder","options"],"mappings":"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"}
package/dist/es/types.mjs CHANGED
@@ -1,4 +1,14 @@
1
1
  export * from "./yaml.mjs";
2
+ function _define_property(obj, key, value) {
3
+ if (key in obj) Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ else obj[key] = value;
10
+ return obj;
11
+ }
2
12
  var types_AIResponseFormat = /*#__PURE__*/ function(AIResponseFormat) {
3
13
  AIResponseFormat["JSON"] = "json_object";
4
14
  AIResponseFormat["TEXT"] = "text";
@@ -6,6 +16,13 @@ var types_AIResponseFormat = /*#__PURE__*/ function(AIResponseFormat) {
6
16
  }({});
7
17
  class UIContext {
8
18
  }
9
- export { types_AIResponseFormat as AIResponseFormat, UIContext };
19
+ class InsightError extends Error {
20
+ constructor(message, dump){
21
+ super(message), _define_property(this, "dump", void 0);
22
+ this.name = 'InsightError';
23
+ this.dump = dump;
24
+ }
25
+ }
26
+ export { types_AIResponseFormat as AIResponseFormat, InsightError, UIContext };
10
27
 
11
28
  //# sourceMappingURL=types.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","sources":["webpack://@midscene/core/./src/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { NodeType } from '@midscene/shared/constants';\nimport type { TModelConfigFn } from '@midscene/shared/env';\nimport type {\n BaseElement,\n ElementTreeNode,\n Rect,\n Size,\n} from '@midscene/shared/types';\nimport type { z } from 'zod';\nimport type { TUserPrompt } from './ai-model/common';\nimport type { DetailedLocateParam, MidsceneYamlFlowItem } from './yaml';\n\nexport type {\n ElementTreeNode,\n BaseElement,\n Rect,\n Size,\n Point,\n} from '@midscene/shared/types';\nexport * from './yaml';\n\nexport type AIUsageInfo = Record<string, any> & {\n prompt_tokens: number | undefined;\n completion_tokens: number | undefined;\n total_tokens: number | undefined;\n time_cost: number | undefined;\n model_name: string | undefined;\n model_description: string | undefined;\n intent: string | undefined;\n};\n\n/**\n * openai\n *\n */\nexport enum AIResponseFormat {\n JSON = 'json_object',\n TEXT = 'text',\n}\n\nexport type AISingleElementResponseById = {\n id: string;\n reason?: string;\n text?: string;\n xpaths?: string[];\n};\n\nexport type AISingleElementResponseByPosition = {\n position?: {\n x: number;\n y: number;\n };\n bbox?: [number, number, number, number];\n reason: string;\n text: string;\n};\n\nexport type AISingleElementResponse = AISingleElementResponseById;\nexport interface AIElementLocatorResponse {\n elements: {\n id: string;\n reason?: string;\n text?: string;\n xpaths?: string[];\n }[];\n bbox?: [number, number, number, number];\n isOrderSensitive?: boolean;\n errors?: string[];\n}\n\nexport interface AIElementCoordinatesResponse {\n bbox: [number, number, number, number];\n isOrderSensitive?: boolean;\n errors?: string[];\n}\n\nexport type AIElementResponse =\n | AIElementLocatorResponse\n | AIElementCoordinatesResponse;\n\nexport interface AIDataExtractionResponse<DataDemand> {\n data: DataDemand;\n errors?: string[];\n thought?: string;\n}\n\nexport interface AISectionLocatorResponse {\n bbox: [number, number, number, number];\n references_bbox?: [number, number, number, number][];\n error?: string;\n}\n\nexport interface AIAssertionResponse {\n pass: boolean;\n thought: string;\n}\n\nexport interface AIDescribeElementResponse {\n description: string;\n error?: string;\n}\n\nexport interface LocatorValidatorOption {\n centerDistanceThreshold?: number;\n}\n\nexport interface LocateValidatorResult {\n pass: boolean;\n rect: Rect;\n center: [number, number];\n centerDistance?: number;\n}\n\nexport interface AgentDescribeElementAtPointResult {\n prompt: string;\n deepThink: boolean;\n verifyResult?: LocateValidatorResult;\n}\n\n/**\n * context\n */\n\nexport abstract class UIContext<ElementType extends BaseElement = BaseElement> {\n abstract screenshotBase64: string;\n\n abstract tree: ElementTreeNode<ElementType>;\n\n abstract size: Size;\n\n abstract _isFrozen?: boolean;\n}\n\nexport type EnsureObject<T> = { [K in keyof T]: any };\n\nexport type InsightAction = 'locate' | 'extract' | 'assert' | 'describe';\n\nexport type InsightExtractParam = string | Record<string, string>;\n\nexport type ElementCacheFeature = Record<string, unknown>;\n\nexport type LocateResultElement = {\n center: [number, number];\n rect: Rect;\n id: string;\n indexId?: number;\n xpaths: string[];\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n isOrderSensitive?: boolean;\n};\n\nexport interface LocateResult {\n element: LocateResultElement | null;\n rect?: Rect;\n}\n\nexport interface InsightTaskInfo {\n durationMs: number;\n formatResponse?: string;\n rawResponse?: string;\n usage?: AIUsageInfo;\n searchArea?: Rect;\n searchAreaRawResponse?: string;\n searchAreaUsage?: AIUsageInfo;\n}\n\nexport interface DumpMeta {\n logTime: number;\n}\n\nexport interface ReportDumpWithAttributes {\n dumpString: string;\n attributes?: Record<string, any>;\n}\n\nexport interface InsightDump extends DumpMeta {\n type: 'locate' | 'extract' | 'assert';\n logId: string;\n userQuery: {\n element?: TUserPrompt;\n dataDemand?: InsightExtractParam;\n assertion?: TUserPrompt;\n };\n matchedElement: BaseElement[];\n matchedRect?: Rect;\n deepThink?: boolean;\n data: any;\n assertionPass?: boolean;\n assertionThought?: string;\n taskInfo: InsightTaskInfo;\n error?: string;\n output?: any;\n}\n\nexport type PartialInsightDumpFromSDK = Omit<\n InsightDump,\n 'logTime' | 'logId' | 'model_name'\n>;\n\nexport type DumpSubscriber = (dump: InsightDump) => Promise<void> | void;\n\n// intermediate variables to optimize the return value by AI\nexport interface LiteUISection {\n name: string;\n description: string;\n sectionCharacteristics: string;\n textIds: string[];\n}\n\nexport type ElementById = (id: string) => BaseElement | null;\n\nexport type InsightAssertionResponse = AIAssertionResponse & {\n usage?: AIUsageInfo;\n};\n\n/**\n * agent\n */\n\nexport type OnTaskStartTip = (tip: string) => Promise<void> | void;\n\nexport interface AgentWaitForOpt {\n checkIntervalMs?: number;\n timeoutMs?: number;\n}\n\nexport interface AgentAssertOpt {\n keepRawResponse?: boolean;\n}\n\n/**\n * planning\n *\n */\n\nexport interface PlanningLocateParam extends DetailedLocateParam {\n id?: string;\n bbox?: [number, number, number, number];\n}\n\nexport interface PlanningAction<ParamType = any> {\n thought?: string;\n type: string;\n param: ParamType;\n locate?: PlanningLocateParam | null;\n}\n\nexport interface PlanningAIResponse {\n action?: PlanningAction; // this is the qwen mode\n actions?: PlanningAction[];\n more_actions_needed_by_instruction: boolean;\n log: string;\n sleep?: number;\n error?: string;\n usage?: AIUsageInfo;\n rawResponse?: string;\n yamlFlow?: MidsceneYamlFlowItem[];\n yamlString?: string;\n}\n\nexport type PlanningActionParamTap = null;\nexport type PlanningActionParamHover = null;\nexport type PlanningActionParamRightClick = null;\n\nexport interface PlanningActionParamInputOrKeyPress {\n value: string;\n autoDismissKeyboard?: boolean;\n}\n\nexport interface PlanningActionParamSleep {\n timeMs: number;\n}\n\nexport interface PlanningActionParamError {\n thought: string;\n}\n\nexport type PlanningActionParamWaitFor = AgentWaitForOpt & {};\n\nexport interface AndroidLongPressParam {\n duration?: number;\n}\n\nexport interface AndroidPullParam {\n direction: 'up' | 'down';\n distance?: number;\n duration?: number;\n}\n/**\n * misc\n */\n\nexport interface Color {\n name: string;\n hex: string;\n}\n\nexport interface BaseAgentParserOpt {\n selector?: string;\n}\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PuppeteerParserOpt extends BaseAgentParserOpt {}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PlaywrightParserOpt extends BaseAgentParserOpt {}\n\n/*\naction\n*/\nexport interface ExecutionTaskProgressOptions {\n onTaskStart?: (task: ExecutionTask) => Promise<void> | void;\n}\n\nexport interface ExecutionRecorderItem {\n type: 'screenshot';\n ts: number;\n screenshot?: string;\n timing?: string;\n}\n\nexport type ExecutionTaskType =\n | 'Planning'\n | 'Insight'\n | 'Action'\n | 'Assertion'\n | 'Log';\n\nexport interface ExecutorContext {\n task: ExecutionTask;\n element?: LocateResultElement | null;\n}\n\nexport interface ExecutionTaskApply<\n Type extends ExecutionTaskType = any,\n TaskParam = any,\n TaskOutput = any,\n TaskLog = any,\n> {\n type: Type;\n subType?: string;\n param?: TaskParam;\n thought?: string;\n locate?: PlanningLocateParam | null;\n uiContext?: UIContext;\n executor: (\n param: TaskParam,\n context: ExecutorContext,\n ) => // biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\n | Promise<ExecutionTaskReturn<TaskOutput, TaskLog> | undefined | void>\n | undefined\n | void;\n}\n\nexport interface ExecutionTaskHitBy {\n from: string;\n context: Record<string, any>;\n}\n\nexport interface ExecutionTaskReturn<TaskOutput = unknown, TaskLog = unknown> {\n output?: TaskOutput;\n log?: TaskLog;\n recorder?: ExecutionRecorderItem[];\n hitBy?: ExecutionTaskHitBy;\n}\n\nexport type ExecutionTask<\n E extends ExecutionTaskApply<any, any, any> = ExecutionTaskApply<\n any,\n any,\n any\n >,\n> = E &\n ExecutionTaskReturn<\n E extends ExecutionTaskApply<any, any, infer TaskOutput, any>\n ? TaskOutput\n : unknown,\n E extends ExecutionTaskApply<any, any, any, infer TaskLog>\n ? TaskLog\n : unknown\n > & {\n status: 'pending' | 'running' | 'finished' | 'failed' | 'cancelled';\n error?: Error;\n errorMessage?: string;\n errorStack?: string;\n timing?: {\n start: number;\n end?: number;\n cost?: number;\n };\n usage?: AIUsageInfo;\n searchAreaUsage?: AIUsageInfo;\n };\n\nexport interface ExecutionDump extends DumpMeta {\n name: string;\n description?: string;\n tasks: ExecutionTask[];\n aiActionContext?: string;\n}\n\n/*\ntask - insight-locate\n*/\nexport type ExecutionTaskInsightLocateParam = PlanningLocateParam;\n\nexport interface ExecutionTaskInsightLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport type ExecutionTaskInsightDump = InsightDump;\n\nexport type ExecutionTaskInsightLocateApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightLocateParam,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightLocate =\n ExecutionTask<ExecutionTaskInsightLocateApply>;\n\n/*\ntask - insight-query\n*/\nexport interface ExecutionTaskInsightQueryParam {\n dataDemand: InsightExtractParam;\n}\n\nexport interface ExecutionTaskInsightQueryOutput {\n data: any;\n}\n\nexport type ExecutionTaskInsightQueryApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightQueryParam,\n any,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightQuery =\n ExecutionTask<ExecutionTaskInsightQueryApply>;\n\n/*\ntask - assertion\n*/\nexport interface ExecutionTaskInsightAssertionParam {\n assertion: string;\n}\n\nexport type ExecutionTaskInsightAssertionApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightAssertionParam,\n InsightAssertionResponse,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightAssertion =\n ExecutionTask<ExecutionTaskInsightAssertionApply>;\n\n/*\ntask - action (i.e. interact) \n*/\nexport type ExecutionTaskActionApply<ActionParam = any> = ExecutionTaskApply<\n 'Action',\n ActionParam,\n void,\n void\n>;\n\nexport type ExecutionTaskAction = ExecutionTask<ExecutionTaskActionApply>;\n\n/*\ntask - Log\n*/\n\nexport type ExecutionTaskLogApply<\n LogParam = {\n content: string;\n },\n> = ExecutionTaskApply<'Log', LogParam, void, void>;\n\nexport type ExecutionTaskLog = ExecutionTask<ExecutionTaskLogApply>;\n\n/*\ntask - planning\n*/\n\nexport type ExecutionTaskPlanningApply = ExecutionTaskApply<\n 'Planning',\n {\n userInstruction: string;\n },\n PlanningAIResponse\n>;\n\nexport type ExecutionTaskPlanning = ExecutionTask<ExecutionTaskPlanningApply>;\n\n/*\nGrouped dump\n*/\nexport interface GroupedActionDump {\n sdkVersion: string;\n groupName: string;\n groupDescription?: string;\n modelBriefs: string[];\n executions: ExecutionDump[];\n}\n\nexport type InterfaceType =\n | 'puppeteer'\n | 'playwright'\n | 'static'\n | 'chrome-extension-proxy'\n | 'android'\n | string;\n\nexport interface StreamingCodeGenerationOptions {\n /** Whether to enable streaming output */\n stream?: boolean;\n /** Callback function to handle streaming chunks */\n onChunk?: StreamingCallback;\n /** Callback function to handle streaming completion */\n onComplete?: (finalCode: string) => void;\n /** Callback function to handle streaming errors */\n onError?: (error: Error) => void;\n}\n\nexport type StreamingCallback = (chunk: CodeGenerationChunk) => void;\n\nexport interface CodeGenerationChunk {\n /** The incremental content chunk */\n content: string;\n /** The reasoning content */\n reasoning_content: string;\n /** The accumulated content so far */\n accumulated: string;\n /** Whether this is the final chunk */\n isComplete: boolean;\n /** Token usage information if available */\n usage?: AIUsageInfo;\n}\n\nexport interface StreamingAIResponse {\n /** The final accumulated content */\n content: string;\n /** Token usage information */\n usage?: AIUsageInfo;\n /** Whether the response was streamed */\n isStreamed: boolean;\n}\n\nexport interface DeviceAction<T = any> {\n name: string;\n description?: string;\n interfaceAlias?: string;\n paramSchema?: z.ZodType<T>;\n call: (param: T, context: ExecutorContext) => Promise<void> | void;\n}\n\n/**\n * Web-specific types\n */\nexport interface WebElementInfo extends BaseElement {\n id: string;\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n}\n\nexport type WebUIContext = UIContext<WebElementInfo>;\n\n/**\n * Agent\n */\n\nexport type CacheConfig = {\n strategy?: 'read-only' | 'read-write' | 'write-only';\n id: string;\n};\n\nexport type Cache =\n | false // No read, no write\n | true // Will throw error at runtime - deprecated\n | CacheConfig; // Object configuration (requires explicit id)\n\nexport interface AgentOpt {\n testId?: string;\n // @deprecated\n cacheId?: string; // Keep backward compatibility, but marked as deprecated\n groupName?: string;\n groupDescription?: string;\n /* if auto generate report, default true */\n generateReport?: boolean;\n /* if auto print report msg, default true */\n autoPrintReportMsg?: boolean;\n onTaskStartTip?: OnTaskStartTip;\n aiActionContext?: string;\n /* custom report file name */\n reportFileName?: string;\n modelConfig?: TModelConfigFn;\n cache?: Cache;\n replanningCycleLimit?: number;\n}\n\nexport type TestStatus =\n | 'passed'\n | 'failed'\n | 'timedOut'\n | 'skipped'\n | 'interrupted';\n\nexport interface ReportFileWithAttributes {\n reportFilePath: string;\n reportAttributes: {\n testDuration: number;\n testStatus: TestStatus;\n testTitle: string;\n testId: string;\n testDescription: string;\n };\n}\n"],"names":["AIResponseFormat","UIContext"],"mappings":";AAqCO,IAAKA,yBAAgBA,WAAAA,GAAAA,SAAhBA,gBAAgB;;;WAAhBA;;AAwFL,MAAeC;AAQtB"}
1
+ {"version":3,"file":"types.mjs","sources":["webpack://@midscene/core/./src/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { NodeType } from '@midscene/shared/constants';\nimport type {\n CreateOpenAIClientFn,\n TModelConfigFn,\n} from '@midscene/shared/env';\nimport type {\n BaseElement,\n ElementTreeNode,\n Rect,\n Size,\n} from '@midscene/shared/types';\nimport type { z } from 'zod';\nimport type { TUserPrompt } from './ai-model/common';\nimport type { DetailedLocateParam, MidsceneYamlFlowItem } from './yaml';\n\nexport type {\n ElementTreeNode,\n BaseElement,\n Rect,\n Size,\n Point,\n} from '@midscene/shared/types';\nexport * from './yaml';\n\nexport type AIUsageInfo = Record<string, any> & {\n prompt_tokens: number | undefined;\n completion_tokens: number | undefined;\n total_tokens: number | undefined;\n time_cost: number | undefined;\n model_name: string | undefined;\n model_description: string | undefined;\n intent: string | undefined;\n};\n\n/**\n * openai\n *\n */\nexport enum AIResponseFormat {\n JSON = 'json_object',\n TEXT = 'text',\n}\n\nexport type AISingleElementResponseById = {\n id: string;\n reason?: string;\n text?: string;\n xpaths?: string[];\n};\n\nexport type AISingleElementResponseByPosition = {\n position?: {\n x: number;\n y: number;\n };\n bbox?: [number, number, number, number];\n reason: string;\n text: string;\n};\n\nexport type AISingleElementResponse = AISingleElementResponseById;\nexport interface AIElementLocatorResponse {\n elements: {\n id: string;\n reason?: string;\n text?: string;\n xpaths?: string[];\n }[];\n bbox?: [number, number, number, number];\n isOrderSensitive?: boolean;\n errors?: string[];\n}\n\nexport interface AIElementCoordinatesResponse {\n bbox: [number, number, number, number];\n isOrderSensitive?: boolean;\n errors?: string[];\n}\n\nexport type AIElementResponse =\n | AIElementLocatorResponse\n | AIElementCoordinatesResponse;\n\nexport interface AIDataExtractionResponse<DataDemand> {\n data: DataDemand;\n errors?: string[];\n thought?: string;\n}\n\nexport interface AISectionLocatorResponse {\n bbox: [number, number, number, number];\n references_bbox?: [number, number, number, number][];\n error?: string;\n}\n\nexport interface AIAssertionResponse {\n pass: boolean;\n thought: string;\n}\n\nexport interface AIDescribeElementResponse {\n description: string;\n error?: string;\n}\n\nexport interface LocatorValidatorOption {\n centerDistanceThreshold?: number;\n}\n\nexport interface LocateValidatorResult {\n pass: boolean;\n rect: Rect;\n center: [number, number];\n centerDistance?: number;\n}\n\nexport interface AgentDescribeElementAtPointResult {\n prompt: string;\n deepThink: boolean;\n verifyResult?: LocateValidatorResult;\n}\n\n/**\n * context\n */\n\nexport abstract class UIContext<ElementType extends BaseElement = BaseElement> {\n abstract screenshotBase64: string;\n\n abstract tree: ElementTreeNode<ElementType>;\n\n abstract size: Size;\n\n abstract _isFrozen?: boolean;\n}\n\nexport type EnsureObject<T> = { [K in keyof T]: any };\n\nexport type InsightAction = 'locate' | 'extract' | 'assert' | 'describe';\n\nexport type InsightExtractParam = string | Record<string, string>;\n\nexport type ElementCacheFeature = Record<string, unknown>;\n\nexport type LocateResultElement = {\n center: [number, number];\n rect: Rect;\n id: string;\n indexId?: number;\n xpaths: string[];\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n isOrderSensitive?: boolean;\n};\n\nexport interface LocateResult {\n element: LocateResultElement | null;\n rect?: Rect;\n}\n\nexport interface InsightTaskInfo {\n durationMs: number;\n formatResponse?: string;\n rawResponse?: string;\n usage?: AIUsageInfo;\n searchArea?: Rect;\n searchAreaRawResponse?: string;\n searchAreaUsage?: AIUsageInfo;\n}\n\nexport interface DumpMeta {\n logTime: number;\n}\n\nexport interface ReportDumpWithAttributes {\n dumpString: string;\n attributes?: Record<string, any>;\n}\n\nexport interface InsightDump extends DumpMeta {\n type: 'locate' | 'extract' | 'assert';\n logId: string;\n userQuery: {\n element?: TUserPrompt;\n dataDemand?: InsightExtractParam;\n assertion?: TUserPrompt;\n };\n matchedElement: BaseElement[];\n matchedRect?: Rect;\n deepThink?: boolean;\n data: any;\n assertionPass?: boolean;\n assertionThought?: string;\n taskInfo: InsightTaskInfo;\n error?: string;\n output?: any;\n}\n\nexport type PartialInsightDumpFromSDK = Omit<\n InsightDump,\n 'logTime' | 'logId' | 'model_name'\n>;\n\nexport interface InsightResultBase {\n dump: InsightDump;\n}\n\nexport type LocateResultWithDump = LocateResult & InsightResultBase;\n\nexport interface InsightExtractResult<T> extends InsightResultBase {\n data: T;\n thought?: string;\n usage?: AIUsageInfo;\n}\n\nexport class InsightError extends Error {\n dump: InsightDump;\n\n constructor(message: string, dump: InsightDump) {\n super(message);\n this.name = 'InsightError';\n this.dump = dump;\n }\n}\n\n// intermediate variables to optimize the return value by AI\nexport interface LiteUISection {\n name: string;\n description: string;\n sectionCharacteristics: string;\n textIds: string[];\n}\n\nexport type ElementById = (id: string) => BaseElement | null;\n\nexport type InsightAssertionResponse = AIAssertionResponse & {\n usage?: AIUsageInfo;\n};\n\n/**\n * agent\n */\n\nexport type OnTaskStartTip = (tip: string) => Promise<void> | void;\n\nexport interface AgentWaitForOpt {\n checkIntervalMs?: number;\n timeoutMs?: number;\n}\n\nexport interface AgentAssertOpt {\n keepRawResponse?: boolean;\n}\n\n/**\n * planning\n *\n */\n\nexport interface PlanningLocateParam extends DetailedLocateParam {\n id?: string;\n bbox?: [number, number, number, number];\n}\n\nexport interface PlanningAction<ParamType = any> {\n thought?: string;\n type: string;\n param: ParamType;\n locate?: PlanningLocateParam | null;\n}\n\nexport interface PlanningAIResponse {\n action?: PlanningAction; // this is the qwen mode\n actions?: PlanningAction[];\n more_actions_needed_by_instruction: boolean;\n log: string;\n sleep?: number;\n error?: string;\n usage?: AIUsageInfo;\n rawResponse?: string;\n yamlFlow?: MidsceneYamlFlowItem[];\n yamlString?: string;\n}\n\nexport type PlanningActionParamTap = null;\nexport type PlanningActionParamHover = null;\nexport type PlanningActionParamRightClick = null;\n\nexport interface PlanningActionParamInputOrKeyPress {\n value: string;\n autoDismissKeyboard?: boolean;\n}\n\nexport interface PlanningActionParamSleep {\n timeMs: number;\n}\n\nexport interface PlanningActionParamError {\n thought: string;\n}\n\nexport type PlanningActionParamWaitFor = AgentWaitForOpt & {};\n\nexport interface LongPressParam {\n duration?: number;\n}\n\nexport interface PullParam {\n direction: 'up' | 'down';\n distance?: number;\n duration?: number;\n}\n/**\n * misc\n */\n\nexport interface Color {\n name: string;\n hex: string;\n}\n\nexport interface BaseAgentParserOpt {\n selector?: string;\n}\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PuppeteerParserOpt extends BaseAgentParserOpt {}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PlaywrightParserOpt extends BaseAgentParserOpt {}\n\n/*\naction\n*/\nexport interface ExecutionTaskProgressOptions {\n onTaskStart?: (task: ExecutionTask) => Promise<void> | void;\n}\n\nexport interface ExecutionRecorderItem {\n type: 'screenshot';\n ts: number;\n screenshot?: string;\n timing?: string;\n}\n\nexport type ExecutionTaskType =\n | 'Planning'\n | 'Insight'\n | 'Action'\n | 'Assertion'\n | 'Log';\n\nexport interface ExecutorContext {\n task: ExecutionTask;\n element?: LocateResultElement | null;\n uiContext?: UIContext;\n}\n\nexport interface ExecutionTaskApply<\n Type extends ExecutionTaskType = any,\n TaskParam = any,\n TaskOutput = any,\n TaskLog = any,\n> {\n type: Type;\n subType?: string;\n param?: TaskParam;\n thought?: string;\n locate?: PlanningLocateParam | null;\n uiContext?: UIContext;\n executor: (\n param: TaskParam,\n context: ExecutorContext,\n ) => // biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\n | Promise<ExecutionTaskReturn<TaskOutput, TaskLog> | undefined | void>\n | undefined\n | void;\n}\n\nexport interface ExecutionTaskHitBy {\n from: string;\n context: Record<string, any>;\n}\n\nexport interface ExecutionTaskReturn<TaskOutput = unknown, TaskLog = unknown> {\n output?: TaskOutput;\n log?: TaskLog;\n recorder?: ExecutionRecorderItem[];\n hitBy?: ExecutionTaskHitBy;\n}\n\nexport type ExecutionTask<\n E extends ExecutionTaskApply<any, any, any> = ExecutionTaskApply<\n any,\n any,\n any\n >,\n> = E &\n ExecutionTaskReturn<\n E extends ExecutionTaskApply<any, any, infer TaskOutput, any>\n ? TaskOutput\n : unknown,\n E extends ExecutionTaskApply<any, any, any, infer TaskLog>\n ? TaskLog\n : unknown\n > & {\n status: 'pending' | 'running' | 'finished' | 'failed' | 'cancelled';\n error?: Error;\n errorMessage?: string;\n errorStack?: string;\n timing?: {\n start: number;\n end?: number;\n cost?: number;\n };\n usage?: AIUsageInfo;\n searchAreaUsage?: AIUsageInfo;\n };\n\nexport interface ExecutionDump extends DumpMeta {\n name: string;\n description?: string;\n tasks: ExecutionTask[];\n aiActionContext?: string;\n}\n\n/*\ntask - insight-locate\n*/\nexport type ExecutionTaskInsightLocateParam = PlanningLocateParam;\n\nexport interface ExecutionTaskInsightLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport type ExecutionTaskInsightDump = InsightDump;\n\nexport type ExecutionTaskInsightLocateApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightLocateParam,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightLocate =\n ExecutionTask<ExecutionTaskInsightLocateApply>;\n\n/*\ntask - insight-query\n*/\nexport interface ExecutionTaskInsightQueryParam {\n dataDemand: InsightExtractParam;\n}\n\nexport interface ExecutionTaskInsightQueryOutput {\n data: any;\n}\n\nexport type ExecutionTaskInsightQueryApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightQueryParam,\n any,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightQuery =\n ExecutionTask<ExecutionTaskInsightQueryApply>;\n\n/*\ntask - assertion\n*/\nexport interface ExecutionTaskInsightAssertionParam {\n assertion: string;\n}\n\nexport type ExecutionTaskInsightAssertionApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightAssertionParam,\n InsightAssertionResponse,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightAssertion =\n ExecutionTask<ExecutionTaskInsightAssertionApply>;\n\n/*\ntask - action (i.e. interact) \n*/\nexport type ExecutionTaskActionApply<ActionParam = any> = ExecutionTaskApply<\n 'Action',\n ActionParam,\n void,\n void\n>;\n\nexport type ExecutionTaskAction = ExecutionTask<ExecutionTaskActionApply>;\n\n/*\ntask - Log\n*/\n\nexport type ExecutionTaskLogApply<\n LogParam = {\n content: string;\n },\n> = ExecutionTaskApply<'Log', LogParam, void, void>;\n\nexport type ExecutionTaskLog = ExecutionTask<ExecutionTaskLogApply>;\n\n/*\ntask - planning\n*/\n\nexport type ExecutionTaskPlanningApply = ExecutionTaskApply<\n 'Planning',\n {\n userInstruction: string;\n },\n PlanningAIResponse\n>;\n\nexport type ExecutionTaskPlanning = ExecutionTask<ExecutionTaskPlanningApply>;\n\n/*\nGrouped dump\n*/\nexport interface GroupedActionDump {\n sdkVersion: string;\n groupName: string;\n groupDescription?: string;\n modelBriefs: string[];\n executions: ExecutionDump[];\n}\n\nexport type InterfaceType =\n | 'puppeteer'\n | 'playwright'\n | 'static'\n | 'chrome-extension-proxy'\n | 'android'\n | string;\n\nexport interface StreamingCodeGenerationOptions {\n /** Whether to enable streaming output */\n stream?: boolean;\n /** Callback function to handle streaming chunks */\n onChunk?: StreamingCallback;\n /** Callback function to handle streaming completion */\n onComplete?: (finalCode: string) => void;\n /** Callback function to handle streaming errors */\n onError?: (error: Error) => void;\n}\n\nexport type StreamingCallback = (chunk: CodeGenerationChunk) => void;\n\nexport interface CodeGenerationChunk {\n /** The incremental content chunk */\n content: string;\n /** The reasoning content */\n reasoning_content: string;\n /** The accumulated content so far */\n accumulated: string;\n /** Whether this is the final chunk */\n isComplete: boolean;\n /** Token usage information if available */\n usage?: AIUsageInfo;\n}\n\nexport interface StreamingAIResponse {\n /** The final accumulated content */\n content: string;\n /** Token usage information */\n usage?: AIUsageInfo;\n /** Whether the response was streamed */\n isStreamed: boolean;\n}\n\nexport interface DeviceAction<T = any> {\n name: string;\n description?: string;\n interfaceAlias?: string;\n paramSchema?: z.ZodType<T>;\n call: (param: T, context: ExecutorContext) => Promise<void> | void;\n}\n\n/**\n * Web-specific types\n */\nexport interface WebElementInfo extends BaseElement {\n id: string;\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n}\n\nexport type WebUIContext = UIContext<WebElementInfo>;\n\n/**\n * Agent\n */\n\nexport type CacheConfig = {\n strategy?: 'read-only' | 'read-write' | 'write-only';\n id: string;\n};\n\nexport type Cache =\n | false // No read, no write\n | true // Will throw error at runtime - deprecated\n | CacheConfig; // Object configuration (requires explicit id)\n\nexport interface AgentOpt {\n testId?: string;\n // @deprecated\n cacheId?: string; // Keep backward compatibility, but marked as deprecated\n groupName?: string;\n groupDescription?: string;\n /* if auto generate report, default true */\n generateReport?: boolean;\n /* if auto print report msg, default true */\n autoPrintReportMsg?: boolean;\n onTaskStartTip?: OnTaskStartTip;\n aiActionContext?: string;\n /* custom report file name */\n reportFileName?: string;\n modelConfig?: TModelConfigFn;\n cache?: Cache;\n replanningCycleLimit?: number;\n\n /**\n * Custom OpenAI client factory function\n *\n * If provided, this function will be called to create OpenAI client instances\n * for each AI call, allowing you to:\n * - Wrap clients with observability tools (langsmith, langfuse)\n * - Use custom OpenAI-compatible clients\n * - Apply different configurations based on intent\n *\n * @param config - Resolved model configuration\n * @returns OpenAI client instance (original or wrapped)\n *\n * @example\n * ```typescript\n * createOpenAIClient: (config) => {\n * const openai = new OpenAI({\n * apiKey: config.openaiApiKey,\n * baseURL: config.openaiBaseURL,\n * });\n *\n * // Wrap with langsmith for planning tasks\n * if (config.intent === 'planning') {\n * return wrapOpenAI(openai, { metadata: { task: 'planning' } });\n * }\n *\n * return openai;\n * }\n * ```\n */\n createOpenAIClient?: CreateOpenAIClientFn;\n}\n\nexport type TestStatus =\n | 'passed'\n | 'failed'\n | 'timedOut'\n | 'skipped'\n | 'interrupted';\n\nexport interface ReportFileWithAttributes {\n reportFilePath: string;\n reportAttributes: {\n testDuration: number;\n testStatus: TestStatus;\n testTitle: string;\n testId: string;\n testDescription: string;\n };\n}\n"],"names":["AIResponseFormat","UIContext","InsightError","Error","message","dump"],"mappings":";AAAqD;;;;;;;;;;AAwC9C,IAAKA,yBAAgBA,WAAAA,GAAAA,SAAhBA,gBAAgB;;;WAAhBA;;AAwFL,MAAeC;AAQtB;AAmFO,MAAMC,qBAAqBC;IAGhC,YAAYC,OAAe,EAAEC,IAAiB,CAAE;QAC9C,KAAK,CAACD,UAHR;QAIE,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,IAAI,GAAGC;IACd;AACF"}