@aiscene/core 1.1.1

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 (299) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/es/agent/agent.mjs +753 -0
  4. package/dist/es/agent/agent.mjs.map +1 -0
  5. package/dist/es/agent/common.mjs +0 -0
  6. package/dist/es/agent/execution-session.mjs +41 -0
  7. package/dist/es/agent/execution-session.mjs.map +1 -0
  8. package/dist/es/agent/index.mjs +6 -0
  9. package/dist/es/agent/task-builder.mjs +332 -0
  10. package/dist/es/agent/task-builder.mjs.map +1 -0
  11. package/dist/es/agent/task-cache.mjs +214 -0
  12. package/dist/es/agent/task-cache.mjs.map +1 -0
  13. package/dist/es/agent/tasks.mjs +423 -0
  14. package/dist/es/agent/tasks.mjs.map +1 -0
  15. package/dist/es/agent/ui-utils.mjs +91 -0
  16. package/dist/es/agent/ui-utils.mjs.map +1 -0
  17. package/dist/es/agent/utils.mjs +169 -0
  18. package/dist/es/agent/utils.mjs.map +1 -0
  19. package/dist/es/ai-model/auto-glm/actions.mjs +239 -0
  20. package/dist/es/ai-model/auto-glm/actions.mjs.map +1 -0
  21. package/dist/es/ai-model/auto-glm/index.mjs +6 -0
  22. package/dist/es/ai-model/auto-glm/parser.mjs +239 -0
  23. package/dist/es/ai-model/auto-glm/parser.mjs.map +1 -0
  24. package/dist/es/ai-model/auto-glm/planning.mjs +71 -0
  25. package/dist/es/ai-model/auto-glm/planning.mjs.map +1 -0
  26. package/dist/es/ai-model/auto-glm/prompt.mjs +222 -0
  27. package/dist/es/ai-model/auto-glm/prompt.mjs.map +1 -0
  28. package/dist/es/ai-model/auto-glm/util.mjs +9 -0
  29. package/dist/es/ai-model/auto-glm/util.mjs.map +1 -0
  30. package/dist/es/ai-model/connectivity.mjs +138 -0
  31. package/dist/es/ai-model/connectivity.mjs.map +1 -0
  32. package/dist/es/ai-model/conversation-history.mjs +195 -0
  33. package/dist/es/ai-model/conversation-history.mjs.map +1 -0
  34. package/dist/es/ai-model/index.mjs +12 -0
  35. package/dist/es/ai-model/inspect.mjs +397 -0
  36. package/dist/es/ai-model/inspect.mjs.map +1 -0
  37. package/dist/es/ai-model/llm-planning.mjs +233 -0
  38. package/dist/es/ai-model/llm-planning.mjs.map +1 -0
  39. package/dist/es/ai-model/prompt/common.mjs +7 -0
  40. package/dist/es/ai-model/prompt/common.mjs.map +1 -0
  41. package/dist/es/ai-model/prompt/describe.mjs +66 -0
  42. package/dist/es/ai-model/prompt/describe.mjs.map +1 -0
  43. package/dist/es/ai-model/prompt/extraction.mjs +131 -0
  44. package/dist/es/ai-model/prompt/extraction.mjs.map +1 -0
  45. package/dist/es/ai-model/prompt/llm-locator.mjs +51 -0
  46. package/dist/es/ai-model/prompt/llm-locator.mjs.map +1 -0
  47. package/dist/es/ai-model/prompt/llm-planning.mjs +568 -0
  48. package/dist/es/ai-model/prompt/llm-planning.mjs.map +1 -0
  49. package/dist/es/ai-model/prompt/llm-section-locator.mjs +44 -0
  50. package/dist/es/ai-model/prompt/llm-section-locator.mjs.map +1 -0
  51. package/dist/es/ai-model/prompt/order-sensitive-judge.mjs +35 -0
  52. package/dist/es/ai-model/prompt/order-sensitive-judge.mjs.map +1 -0
  53. package/dist/es/ai-model/prompt/playwright-generator.mjs +117 -0
  54. package/dist/es/ai-model/prompt/playwright-generator.mjs.map +1 -0
  55. package/dist/es/ai-model/prompt/ui-tars-planning.mjs +36 -0
  56. package/dist/es/ai-model/prompt/ui-tars-planning.mjs.map +1 -0
  57. package/dist/es/ai-model/prompt/util.mjs +59 -0
  58. package/dist/es/ai-model/prompt/util.mjs.map +1 -0
  59. package/dist/es/ai-model/prompt/yaml-generator.mjs +203 -0
  60. package/dist/es/ai-model/prompt/yaml-generator.mjs.map +1 -0
  61. package/dist/es/ai-model/service-caller/codex-app-server.mjs +575 -0
  62. package/dist/es/ai-model/service-caller/codex-app-server.mjs.map +1 -0
  63. package/dist/es/ai-model/service-caller/image-detail.mjs +6 -0
  64. package/dist/es/ai-model/service-caller/image-detail.mjs.map +1 -0
  65. package/dist/es/ai-model/service-caller/index.mjs +475 -0
  66. package/dist/es/ai-model/service-caller/index.mjs.map +1 -0
  67. package/dist/es/ai-model/ui-tars-planning.mjs +249 -0
  68. package/dist/es/ai-model/ui-tars-planning.mjs.map +1 -0
  69. package/dist/es/common.mjs +371 -0
  70. package/dist/es/common.mjs.map +1 -0
  71. package/dist/es/device/device-options.mjs +0 -0
  72. package/dist/es/device/index.mjs +341 -0
  73. package/dist/es/device/index.mjs.map +1 -0
  74. package/dist/es/dump/html-utils.mjs +292 -0
  75. package/dist/es/dump/html-utils.mjs.map +1 -0
  76. package/dist/es/dump/index.mjs +3 -0
  77. package/dist/es/dump/screenshot-restoration.mjs +32 -0
  78. package/dist/es/dump/screenshot-restoration.mjs.map +1 -0
  79. package/dist/es/dump/screenshot-store.mjs +126 -0
  80. package/dist/es/dump/screenshot-store.mjs.map +1 -0
  81. package/dist/es/index.mjs +19 -0
  82. package/dist/es/index.mjs.map +1 -0
  83. package/dist/es/report-cli.mjs +151 -0
  84. package/dist/es/report-cli.mjs.map +1 -0
  85. package/dist/es/report-generator.mjs +205 -0
  86. package/dist/es/report-generator.mjs.map +1 -0
  87. package/dist/es/report-markdown.mjs +218 -0
  88. package/dist/es/report-markdown.mjs.map +1 -0
  89. package/dist/es/report.mjs +270 -0
  90. package/dist/es/report.mjs.map +1 -0
  91. package/dist/es/screenshot-item.mjs +122 -0
  92. package/dist/es/screenshot-item.mjs.map +1 -0
  93. package/dist/es/service/index.mjs +274 -0
  94. package/dist/es/service/index.mjs.map +1 -0
  95. package/dist/es/service/utils.mjs +15 -0
  96. package/dist/es/service/utils.mjs.map +1 -0
  97. package/dist/es/skill/index.mjs +38 -0
  98. package/dist/es/skill/index.mjs.map +1 -0
  99. package/dist/es/task-runner.mjs +263 -0
  100. package/dist/es/task-runner.mjs.map +1 -0
  101. package/dist/es/task-timing.mjs +12 -0
  102. package/dist/es/task-timing.mjs.map +1 -0
  103. package/dist/es/tree.mjs +13 -0
  104. package/dist/es/tree.mjs.map +1 -0
  105. package/dist/es/types.mjs +204 -0
  106. package/dist/es/types.mjs.map +1 -0
  107. package/dist/es/utils.mjs +234 -0
  108. package/dist/es/utils.mjs.map +1 -0
  109. package/dist/es/yaml/builder.mjs +13 -0
  110. package/dist/es/yaml/builder.mjs.map +1 -0
  111. package/dist/es/yaml/index.mjs +4 -0
  112. package/dist/es/yaml/player.mjs +442 -0
  113. package/dist/es/yaml/player.mjs.map +1 -0
  114. package/dist/es/yaml/utils.mjs +102 -0
  115. package/dist/es/yaml/utils.mjs.map +1 -0
  116. package/dist/es/yaml.mjs +0 -0
  117. package/dist/lib/agent/agent.js +801 -0
  118. package/dist/lib/agent/agent.js.map +1 -0
  119. package/dist/lib/agent/common.js +5 -0
  120. package/dist/lib/agent/execution-session.js +75 -0
  121. package/dist/lib/agent/execution-session.js.map +1 -0
  122. package/dist/lib/agent/index.js +78 -0
  123. package/dist/lib/agent/index.js.map +1 -0
  124. package/dist/lib/agent/task-builder.js +369 -0
  125. package/dist/lib/agent/task-builder.js.map +1 -0
  126. package/dist/lib/agent/task-cache.js +266 -0
  127. package/dist/lib/agent/task-cache.js.map +1 -0
  128. package/dist/lib/agent/tasks.js +466 -0
  129. package/dist/lib/agent/tasks.js.map +1 -0
  130. package/dist/lib/agent/ui-utils.js +143 -0
  131. package/dist/lib/agent/ui-utils.js.map +1 -0
  132. package/dist/lib/agent/utils.js +240 -0
  133. package/dist/lib/agent/utils.js.map +1 -0
  134. package/dist/lib/ai-model/auto-glm/actions.js +273 -0
  135. package/dist/lib/ai-model/auto-glm/actions.js.map +1 -0
  136. package/dist/lib/ai-model/auto-glm/index.js +66 -0
  137. package/dist/lib/ai-model/auto-glm/index.js.map +1 -0
  138. package/dist/lib/ai-model/auto-glm/parser.js +282 -0
  139. package/dist/lib/ai-model/auto-glm/parser.js.map +1 -0
  140. package/dist/lib/ai-model/auto-glm/planning.js +105 -0
  141. package/dist/lib/ai-model/auto-glm/planning.js.map +1 -0
  142. package/dist/lib/ai-model/auto-glm/prompt.js +259 -0
  143. package/dist/lib/ai-model/auto-glm/prompt.js.map +1 -0
  144. package/dist/lib/ai-model/auto-glm/util.js +46 -0
  145. package/dist/lib/ai-model/auto-glm/util.js.map +1 -0
  146. package/dist/lib/ai-model/connectivity.js +182 -0
  147. package/dist/lib/ai-model/connectivity.js.map +1 -0
  148. package/dist/lib/ai-model/conversation-history.js +229 -0
  149. package/dist/lib/ai-model/conversation-history.js.map +1 -0
  150. package/dist/lib/ai-model/index.js +129 -0
  151. package/dist/lib/ai-model/index.js.map +1 -0
  152. package/dist/lib/ai-model/inspect.js +443 -0
  153. package/dist/lib/ai-model/inspect.js.map +1 -0
  154. package/dist/lib/ai-model/llm-planning.js +270 -0
  155. package/dist/lib/ai-model/llm-planning.js.map +1 -0
  156. package/dist/lib/ai-model/prompt/common.js +41 -0
  157. package/dist/lib/ai-model/prompt/common.js.map +1 -0
  158. package/dist/lib/ai-model/prompt/describe.js +100 -0
  159. package/dist/lib/ai-model/prompt/describe.js.map +1 -0
  160. package/dist/lib/ai-model/prompt/extraction.js +171 -0
  161. package/dist/lib/ai-model/prompt/extraction.js.map +1 -0
  162. package/dist/lib/ai-model/prompt/llm-locator.js +88 -0
  163. package/dist/lib/ai-model/prompt/llm-locator.js.map +1 -0
  164. package/dist/lib/ai-model/prompt/llm-planning.js +605 -0
  165. package/dist/lib/ai-model/prompt/llm-planning.js.map +1 -0
  166. package/dist/lib/ai-model/prompt/llm-section-locator.js +81 -0
  167. package/dist/lib/ai-model/prompt/llm-section-locator.js.map +1 -0
  168. package/dist/lib/ai-model/prompt/order-sensitive-judge.js +72 -0
  169. package/dist/lib/ai-model/prompt/order-sensitive-judge.js.map +1 -0
  170. package/dist/lib/ai-model/prompt/playwright-generator.js +178 -0
  171. package/dist/lib/ai-model/prompt/playwright-generator.js.map +1 -0
  172. package/dist/lib/ai-model/prompt/ui-tars-planning.js +73 -0
  173. package/dist/lib/ai-model/prompt/ui-tars-planning.js.map +1 -0
  174. package/dist/lib/ai-model/prompt/util.js +105 -0
  175. package/dist/lib/ai-model/prompt/util.js.map +1 -0
  176. package/dist/lib/ai-model/prompt/yaml-generator.js +264 -0
  177. package/dist/lib/ai-model/prompt/yaml-generator.js.map +1 -0
  178. package/dist/lib/ai-model/service-caller/codex-app-server.js +624 -0
  179. package/dist/lib/ai-model/service-caller/codex-app-server.js.map +1 -0
  180. package/dist/lib/ai-model/service-caller/image-detail.js +40 -0
  181. package/dist/lib/ai-model/service-caller/image-detail.js.map +1 -0
  182. package/dist/lib/ai-model/service-caller/index.js +540 -0
  183. package/dist/lib/ai-model/service-caller/index.js.map +1 -0
  184. package/dist/lib/ai-model/ui-tars-planning.js +283 -0
  185. package/dist/lib/ai-model/ui-tars-planning.js.map +1 -0
  186. package/dist/lib/common.js +480 -0
  187. package/dist/lib/common.js.map +1 -0
  188. package/dist/lib/device/device-options.js +20 -0
  189. package/dist/lib/device/device-options.js.map +1 -0
  190. package/dist/lib/device/index.js +468 -0
  191. package/dist/lib/device/index.js.map +1 -0
  192. package/dist/lib/dump/html-utils.js +368 -0
  193. package/dist/lib/dump/html-utils.js.map +1 -0
  194. package/dist/lib/dump/index.js +60 -0
  195. package/dist/lib/dump/index.js.map +1 -0
  196. package/dist/lib/dump/screenshot-restoration.js +66 -0
  197. package/dist/lib/dump/screenshot-restoration.js.map +1 -0
  198. package/dist/lib/dump/screenshot-store.js +166 -0
  199. package/dist/lib/dump/screenshot-store.js.map +1 -0
  200. package/dist/lib/index.js +186 -0
  201. package/dist/lib/index.js.map +1 -0
  202. package/dist/lib/report-cli.js +191 -0
  203. package/dist/lib/report-cli.js.map +1 -0
  204. package/dist/lib/report-generator.js +246 -0
  205. package/dist/lib/report-generator.js.map +1 -0
  206. package/dist/lib/report-markdown.js +255 -0
  207. package/dist/lib/report-markdown.js.map +1 -0
  208. package/dist/lib/report.js +316 -0
  209. package/dist/lib/report.js.map +1 -0
  210. package/dist/lib/screenshot-item.js +156 -0
  211. package/dist/lib/screenshot-item.js.map +1 -0
  212. package/dist/lib/service/index.js +308 -0
  213. package/dist/lib/service/index.js.map +1 -0
  214. package/dist/lib/service/utils.js +49 -0
  215. package/dist/lib/service/utils.js.map +1 -0
  216. package/dist/lib/skill/index.js +72 -0
  217. package/dist/lib/skill/index.js.map +1 -0
  218. package/dist/lib/task-runner.js +300 -0
  219. package/dist/lib/task-runner.js.map +1 -0
  220. package/dist/lib/task-timing.js +46 -0
  221. package/dist/lib/task-timing.js.map +1 -0
  222. package/dist/lib/tree.js +53 -0
  223. package/dist/lib/tree.js.map +1 -0
  224. package/dist/lib/types.js +300 -0
  225. package/dist/lib/types.js.map +1 -0
  226. package/dist/lib/utils.js +316 -0
  227. package/dist/lib/utils.js.map +1 -0
  228. package/dist/lib/yaml/builder.js +57 -0
  229. package/dist/lib/yaml/builder.js.map +1 -0
  230. package/dist/lib/yaml/index.js +81 -0
  231. package/dist/lib/yaml/index.js.map +1 -0
  232. package/dist/lib/yaml/player.js +476 -0
  233. package/dist/lib/yaml/player.js.map +1 -0
  234. package/dist/lib/yaml/utils.js +155 -0
  235. package/dist/lib/yaml/utils.js.map +1 -0
  236. package/dist/lib/yaml.js +20 -0
  237. package/dist/lib/yaml.js.map +1 -0
  238. package/dist/types/agent/agent.d.ts +216 -0
  239. package/dist/types/agent/common.d.ts +0 -0
  240. package/dist/types/agent/execution-session.d.ts +36 -0
  241. package/dist/types/agent/index.d.ts +9 -0
  242. package/dist/types/agent/task-builder.d.ts +34 -0
  243. package/dist/types/agent/task-cache.d.ts +49 -0
  244. package/dist/types/agent/tasks.d.ts +69 -0
  245. package/dist/types/agent/ui-utils.d.ts +14 -0
  246. package/dist/types/agent/utils.d.ts +25 -0
  247. package/dist/types/ai-model/auto-glm/actions.d.ts +78 -0
  248. package/dist/types/ai-model/auto-glm/index.d.ts +6 -0
  249. package/dist/types/ai-model/auto-glm/parser.d.ts +18 -0
  250. package/dist/types/ai-model/auto-glm/planning.d.ts +12 -0
  251. package/dist/types/ai-model/auto-glm/prompt.d.ts +27 -0
  252. package/dist/types/ai-model/auto-glm/util.d.ts +13 -0
  253. package/dist/types/ai-model/connectivity.d.ts +20 -0
  254. package/dist/types/ai-model/conversation-history.d.ts +105 -0
  255. package/dist/types/ai-model/index.d.ts +16 -0
  256. package/dist/types/ai-model/inspect.d.ts +67 -0
  257. package/dist/types/ai-model/llm-planning.d.ts +19 -0
  258. package/dist/types/ai-model/prompt/common.d.ts +2 -0
  259. package/dist/types/ai-model/prompt/describe.d.ts +1 -0
  260. package/dist/types/ai-model/prompt/extraction.d.ts +7 -0
  261. package/dist/types/ai-model/prompt/llm-locator.d.ts +3 -0
  262. package/dist/types/ai-model/prompt/llm-planning.d.ts +10 -0
  263. package/dist/types/ai-model/prompt/llm-section-locator.d.ts +3 -0
  264. package/dist/types/ai-model/prompt/order-sensitive-judge.d.ts +2 -0
  265. package/dist/types/ai-model/prompt/playwright-generator.d.ts +26 -0
  266. package/dist/types/ai-model/prompt/ui-tars-planning.d.ts +2 -0
  267. package/dist/types/ai-model/prompt/util.d.ts +33 -0
  268. package/dist/types/ai-model/prompt/yaml-generator.d.ts +102 -0
  269. package/dist/types/ai-model/service-caller/codex-app-server.d.ts +42 -0
  270. package/dist/types/ai-model/service-caller/image-detail.d.ts +2 -0
  271. package/dist/types/ai-model/service-caller/index.d.ts +49 -0
  272. package/dist/types/ai-model/ui-tars-planning.d.ts +72 -0
  273. package/dist/types/common.d.ts +288 -0
  274. package/dist/types/device/device-options.d.ts +145 -0
  275. package/dist/types/device/index.d.ts +2528 -0
  276. package/dist/types/dump/html-utils.d.ts +75 -0
  277. package/dist/types/dump/index.d.ts +5 -0
  278. package/dist/types/dump/screenshot-restoration.d.ts +8 -0
  279. package/dist/types/dump/screenshot-store.d.ts +49 -0
  280. package/dist/types/index.d.ts +21 -0
  281. package/dist/types/report-cli.d.ts +36 -0
  282. package/dist/types/report-generator.d.ts +81 -0
  283. package/dist/types/report-markdown.d.ts +24 -0
  284. package/dist/types/report.d.ts +52 -0
  285. package/dist/types/screenshot-item.d.ts +67 -0
  286. package/dist/types/service/index.d.ts +24 -0
  287. package/dist/types/service/utils.d.ts +2 -0
  288. package/dist/types/skill/index.d.ts +25 -0
  289. package/dist/types/task-runner.d.ts +50 -0
  290. package/dist/types/task-timing.d.ts +8 -0
  291. package/dist/types/tree.d.ts +4 -0
  292. package/dist/types/types.d.ts +681 -0
  293. package/dist/types/utils.d.ts +45 -0
  294. package/dist/types/yaml/builder.d.ts +2 -0
  295. package/dist/types/yaml/index.d.ts +4 -0
  296. package/dist/types/yaml/player.d.ts +34 -0
  297. package/dist/types/yaml/utils.d.ts +9 -0
  298. package/dist/types/yaml.d.ts +215 -0
  299. package/package.json +111 -0
@@ -0,0 +1,274 @@
1
+ import { isAutoGLM } from "../ai-model/auto-glm/util.mjs";
2
+ import { AIResponseParseError, AiExtractElementInfo, AiLocateElement, callAIWithObjectResponse } from "../ai-model/index.mjs";
3
+ import { AiLocateSection, buildSearchAreaConfig } from "../ai-model/inspect.mjs";
4
+ import { elementDescriberInstruction } from "../ai-model/prompt/describe.mjs";
5
+ import { expandSearchArea } from "../common.mjs";
6
+ import { ServiceError } from "../types.mjs";
7
+ import { compositeElementInfoImg, cropByRect } from "@midscene/shared/img";
8
+ import { getDebug } from "@midscene/shared/logger";
9
+ import { assert } from "@midscene/shared/utils";
10
+ import { createServiceDump } from "./utils.mjs";
11
+ function _define_property(obj, key, value) {
12
+ if (key in obj) Object.defineProperty(obj, key, {
13
+ value: value,
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true
17
+ });
18
+ else obj[key] = value;
19
+ return obj;
20
+ }
21
+ const debug = getDebug('ai:service');
22
+ class Service {
23
+ async locate(query, opt, modelConfig, abortSignal) {
24
+ const queryPrompt = 'string' == typeof query ? query : query.prompt;
25
+ assert(queryPrompt, 'query is required for locate');
26
+ assert('object' == typeof query, 'query should be an object for locate');
27
+ const hasPlanLocatedElement = !!opt?.planLocatedElement?.rect;
28
+ let searchAreaPrompt;
29
+ if (query.deepLocate && !hasPlanLocatedElement) searchAreaPrompt = query.prompt;
30
+ const { modelFamily } = modelConfig;
31
+ if (searchAreaPrompt && !modelFamily) {
32
+ console.warn('The "deepLocate" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/model-config');
33
+ searchAreaPrompt = void 0;
34
+ }
35
+ if (searchAreaPrompt && isAutoGLM(modelFamily)) {
36
+ console.warn('The "deepLocate" feature is not supported with AutoGLM.');
37
+ searchAreaPrompt = void 0;
38
+ }
39
+ const context = opt?.context || await this.contextRetrieverFn();
40
+ let searchArea;
41
+ let searchAreaRawResponse;
42
+ let searchAreaUsage;
43
+ let searchAreaResponse;
44
+ if (query.deepLocate && hasPlanLocatedElement) {
45
+ const searchAreaConfig = await buildSearchAreaConfig({
46
+ context,
47
+ baseRect: opt.planLocatedElement.rect,
48
+ modelFamily
49
+ });
50
+ searchArea = searchAreaConfig.rect;
51
+ searchAreaRawResponse = JSON.stringify({
52
+ source: 'plan-located-element',
53
+ rect: opt.planLocatedElement.rect
54
+ });
55
+ searchAreaResponse = {
56
+ rect: searchArea,
57
+ imageBase64: searchAreaConfig.imageBase64,
58
+ scale: searchAreaConfig.scale,
59
+ rawResponse: searchAreaRawResponse
60
+ };
61
+ } else if (searchAreaPrompt) {
62
+ searchAreaResponse = await AiLocateSection({
63
+ context,
64
+ sectionDescription: searchAreaPrompt,
65
+ modelConfig,
66
+ abortSignal
67
+ });
68
+ assert(searchAreaResponse.rect, `cannot find search area for "${searchAreaPrompt}"${searchAreaResponse.error ? `: ${searchAreaResponse.error}` : ''}`);
69
+ searchAreaRawResponse = searchAreaResponse.rawResponse;
70
+ searchAreaUsage = searchAreaResponse.usage;
71
+ searchArea = searchAreaResponse.rect;
72
+ }
73
+ const startTime = Date.now();
74
+ const { parseResult, rect, rawResponse, usage, reasoning_content } = await AiLocateElement({
75
+ context,
76
+ targetElementDescription: queryPrompt,
77
+ searchConfig: searchAreaResponse,
78
+ modelConfig,
79
+ abortSignal
80
+ });
81
+ const timeCost = Date.now() - startTime;
82
+ const taskInfo = {
83
+ ...this.taskInfo ? this.taskInfo : {},
84
+ durationMs: timeCost,
85
+ rawResponse: JSON.stringify(rawResponse),
86
+ formatResponse: JSON.stringify(parseResult),
87
+ usage,
88
+ searchArea,
89
+ searchAreaRawResponse,
90
+ searchAreaUsage,
91
+ reasoning_content
92
+ };
93
+ let errorLog;
94
+ if (parseResult.errors?.length) errorLog = `failed to locate element: \n${parseResult.errors.join('\n')}`;
95
+ const dumpData = {
96
+ type: 'locate',
97
+ userQuery: {
98
+ element: queryPrompt
99
+ },
100
+ matchedElement: [],
101
+ matchedRect: rect,
102
+ data: null,
103
+ taskInfo,
104
+ deepLocate: !!searchArea,
105
+ error: errorLog
106
+ };
107
+ const elements = parseResult.elements || [];
108
+ const dump = createServiceDump({
109
+ ...dumpData,
110
+ matchedElement: elements
111
+ });
112
+ if (errorLog) throw new ServiceError(errorLog, dump);
113
+ if (elements.length > 1) throw new ServiceError(`locate: multiple elements found, length = ${elements.length}`, dump);
114
+ if (1 === elements.length) return {
115
+ element: {
116
+ center: elements[0].center,
117
+ rect: elements[0].rect,
118
+ description: elements[0].description
119
+ },
120
+ rect,
121
+ dump
122
+ };
123
+ return {
124
+ element: null,
125
+ rect,
126
+ dump
127
+ };
128
+ }
129
+ async extract(dataDemand, modelConfig, opt, pageDescription, multimodalPrompt, context) {
130
+ assert(context, 'context is required for extract');
131
+ assert('object' == typeof dataDemand || 'string' == typeof dataDemand, `dataDemand should be object or string, but get ${typeof dataDemand}`);
132
+ const startTime = Date.now();
133
+ let parseResult;
134
+ let rawResponse;
135
+ let usage;
136
+ let reasoning_content;
137
+ try {
138
+ const result = await AiExtractElementInfo({
139
+ context,
140
+ dataQuery: dataDemand,
141
+ multimodalPrompt,
142
+ extractOption: opt,
143
+ modelConfig,
144
+ pageDescription
145
+ });
146
+ parseResult = result.parseResult;
147
+ rawResponse = result.rawResponse;
148
+ usage = result.usage;
149
+ reasoning_content = result.reasoning_content;
150
+ } catch (error) {
151
+ if (error instanceof AIResponseParseError) {
152
+ const timeCost = Date.now() - startTime;
153
+ const taskInfo = {
154
+ ...this.taskInfo ? this.taskInfo : {},
155
+ durationMs: timeCost,
156
+ rawResponse: error.rawResponse,
157
+ usage: error.usage
158
+ };
159
+ const dump = createServiceDump({
160
+ type: 'extract',
161
+ userQuery: {
162
+ dataDemand
163
+ },
164
+ matchedElement: [],
165
+ data: null,
166
+ taskInfo,
167
+ error: error.message
168
+ });
169
+ throw new ServiceError(error.message, dump);
170
+ }
171
+ throw error;
172
+ }
173
+ const timeCost = Date.now() - startTime;
174
+ const taskInfo = {
175
+ ...this.taskInfo ? this.taskInfo : {},
176
+ durationMs: timeCost,
177
+ rawResponse,
178
+ formatResponse: JSON.stringify(parseResult),
179
+ usage,
180
+ reasoning_content
181
+ };
182
+ let errorLog;
183
+ if (parseResult.errors?.length) errorLog = `AI response error: \n${parseResult.errors.join('\n')}`;
184
+ const dumpData = {
185
+ type: 'extract',
186
+ userQuery: {
187
+ dataDemand
188
+ },
189
+ matchedElement: [],
190
+ data: null,
191
+ taskInfo,
192
+ error: errorLog
193
+ };
194
+ const { data, thought } = parseResult || {};
195
+ const dump = createServiceDump({
196
+ ...dumpData,
197
+ data
198
+ });
199
+ if (errorLog && !data) throw new ServiceError(errorLog, dump);
200
+ return {
201
+ data,
202
+ thought,
203
+ usage,
204
+ reasoning_content,
205
+ dump
206
+ };
207
+ }
208
+ async describe(target, modelConfig, opt) {
209
+ assert(target, 'target is required for service.describe');
210
+ const context = await this.contextRetrieverFn();
211
+ const { shotSize } = context;
212
+ const screenshotBase64 = context.screenshot.base64;
213
+ assert(screenshotBase64, 'screenshot is required for service.describe');
214
+ const { modelFamily } = modelConfig;
215
+ const systemPrompt = elementDescriberInstruction();
216
+ const defaultRectSize = 30;
217
+ const targetRect = Array.isArray(target) ? {
218
+ left: Math.floor(target[0] - defaultRectSize / 2),
219
+ top: Math.floor(target[1] - defaultRectSize / 2),
220
+ width: defaultRectSize,
221
+ height: defaultRectSize
222
+ } : target;
223
+ let imagePayload = await compositeElementInfoImg({
224
+ inputImgBase64: screenshotBase64,
225
+ size: shotSize,
226
+ elementsPositionInfo: [
227
+ {
228
+ rect: targetRect
229
+ }
230
+ ],
231
+ borderThickness: 3
232
+ });
233
+ if (opt?.deepLocate) {
234
+ const searchArea = expandSearchArea(targetRect, shotSize);
235
+ debug('describe: cropping to searchArea', searchArea);
236
+ const croppedResult = await cropByRect(imagePayload, searchArea, 'qwen2.5-vl' === modelFamily);
237
+ imagePayload = croppedResult.imageBase64;
238
+ }
239
+ const msgs = [
240
+ {
241
+ role: 'system',
242
+ content: systemPrompt
243
+ },
244
+ {
245
+ role: 'user',
246
+ content: [
247
+ {
248
+ type: 'image_url',
249
+ image_url: {
250
+ url: imagePayload,
251
+ detail: 'high'
252
+ }
253
+ }
254
+ ]
255
+ }
256
+ ];
257
+ const res = await callAIWithObjectResponse(msgs, modelConfig);
258
+ const { content } = res;
259
+ assert(!content.error, `describe failed: ${content.error}`);
260
+ assert(content.description, 'failed to describe the element');
261
+ return content;
262
+ }
263
+ constructor(context, opt){
264
+ _define_property(this, "contextRetrieverFn", void 0);
265
+ _define_property(this, "taskInfo", void 0);
266
+ assert(context, 'context is required for Service');
267
+ if ('function' == typeof context) this.contextRetrieverFn = context;
268
+ else this.contextRetrieverFn = ()=>Promise.resolve(context);
269
+ if (void 0 !== opt?.taskInfo) this.taskInfo = opt.taskInfo;
270
+ }
271
+ }
272
+ export { Service as default };
273
+
274
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service/index.mjs","sources":["../../../src/service/index.ts"],"sourcesContent":["import { isAutoGLM, isUITars } from '@/ai-model/auto-glm/util';\nimport {\n AIResponseParseError,\n AiExtractElementInfo,\n AiLocateElement,\n callAIWithObjectResponse,\n} from '@/ai-model/index';\nimport { AiLocateSection, buildSearchAreaConfig } from '@/ai-model/inspect';\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\nimport { type AIArgs, expandSearchArea } from '@/common';\nimport type {\n AIDescribeElementResponse,\n AIUsageInfo,\n DetailedLocateParam,\n LocateResultElement,\n LocateResultWithDump,\n PartialServiceDumpFromSDK,\n PlanningLocateParam,\n Rect,\n ServiceExtractOption,\n ServiceExtractParam,\n ServiceExtractResult,\n ServiceTaskInfo,\n UIContext,\n} from '@/types';\nimport { ServiceError } from '@/types';\nimport type { IModelConfig } 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 '../common';\nimport { createServiceDump } from './utils';\n\nexport interface LocateOpts {\n context?: UIContext;\n planLocatedElement?: LocateResultElement;\n}\n\nexport type AnyValue<T> = {\n [K in keyof T]: unknown extends T[K] ? any : T[K];\n};\n\ninterface ServiceOptions {\n taskInfo?: Omit<ServiceTaskInfo, 'durationMs'>;\n}\n\nconst debug = getDebug('ai:service');\nexport default class Service {\n contextRetrieverFn: () => Promise<UIContext> | UIContext;\n\n taskInfo?: Omit<ServiceTaskInfo, 'durationMs'>;\n\n constructor(\n context: UIContext | (() => Promise<UIContext> | UIContext),\n opt?: ServiceOptions,\n ) {\n assert(context, 'context is required for Service');\n if (typeof context === 'function') {\n this.contextRetrieverFn = context;\n } else {\n this.contextRetrieverFn = () => Promise.resolve(context);\n }\n\n if (typeof opt?.taskInfo !== 'undefined') {\n this.taskInfo = opt.taskInfo;\n }\n }\n\n async locate(\n query: PlanningLocateParam,\n opt: LocateOpts,\n modelConfig: IModelConfig,\n abortSignal?: AbortSignal,\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 hasPlanLocatedElement = !!opt?.planLocatedElement?.rect;\n\n let searchAreaPrompt;\n if (query.deepLocate && !hasPlanLocatedElement) {\n searchAreaPrompt = query.prompt;\n }\n\n const { modelFamily } = modelConfig;\n\n if (searchAreaPrompt && !modelFamily) {\n console.warn(\n 'The \"deepLocate\" feature is not supported with multimodal LLM. Please config VL model for Midscene. https://midscenejs.com/model-config',\n );\n searchAreaPrompt = undefined;\n }\n\n if (searchAreaPrompt && isAutoGLM(modelFamily)) {\n console.warn('The \"deepLocate\" feature is not supported with AutoGLM.');\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 (query.deepLocate && hasPlanLocatedElement) {\n const searchAreaConfig = await buildSearchAreaConfig({\n context,\n baseRect: opt.planLocatedElement!.rect,\n modelFamily,\n });\n searchArea = searchAreaConfig.rect;\n\n searchAreaRawResponse = JSON.stringify({\n source: 'plan-located-element',\n rect: opt.planLocatedElement!.rect,\n });\n searchAreaResponse = {\n rect: searchArea,\n imageBase64: searchAreaConfig.imageBase64,\n scale: searchAreaConfig.scale,\n rawResponse: searchAreaRawResponse,\n };\n } else if (searchAreaPrompt) {\n searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: searchAreaPrompt,\n modelConfig,\n abortSignal,\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 { parseResult, rect, rawResponse, usage, reasoning_content } =\n await AiLocateElement({\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchAreaResponse,\n modelConfig,\n abortSignal,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\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 reasoning_content,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `failed to locate element: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialServiceDumpFromSDK = {\n type: 'locate',\n userQuery: {\n element: queryPrompt,\n },\n matchedElement: [],\n matchedRect: rect,\n data: null,\n taskInfo,\n deepLocate: !!searchArea,\n error: errorLog,\n };\n\n const elements = parseResult.elements || [];\n\n const dump = createServiceDump({\n ...dumpData,\n matchedElement: elements,\n });\n\n if (errorLog) {\n throw new ServiceError(errorLog, dump);\n }\n\n if (elements.length > 1) {\n throw new ServiceError(\n `locate: multiple elements found, length = ${elements.length}`,\n dump,\n );\n }\n\n if (elements.length === 1) {\n return {\n element: {\n center: elements[0]!.center,\n rect: elements[0]!.rect,\n description: elements[0]!.description,\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: ServiceExtractParam,\n modelConfig: IModelConfig,\n opt?: ServiceExtractOption,\n pageDescription?: string,\n multimodalPrompt?: TMultimodalPrompt,\n context?: UIContext,\n ): Promise<ServiceExtractResult<T>> {\n assert(context, 'context is required for extract');\n assert(\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\n );\n\n const startTime = Date.now();\n\n let parseResult: Awaited<\n ReturnType<typeof AiExtractElementInfo<T>>\n >['parseResult'];\n let rawResponse: string;\n let usage: Awaited<ReturnType<typeof AiExtractElementInfo<T>>>['usage'];\n let reasoning_content: string | undefined;\n\n try {\n const result = await AiExtractElementInfo<T>({\n context,\n dataQuery: dataDemand,\n multimodalPrompt,\n extractOption: opt,\n modelConfig,\n pageDescription,\n });\n parseResult = result.parseResult;\n rawResponse = result.rawResponse;\n usage = result.usage;\n reasoning_content = result.reasoning_content;\n } catch (error) {\n if (error instanceof AIResponseParseError) {\n // Create dump with usage and rawResponse from the error\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: error.rawResponse,\n usage: error.usage,\n };\n const dump = createServiceDump({\n type: 'extract',\n userQuery: { dataDemand },\n matchedElement: [],\n data: null,\n taskInfo,\n error: error.message,\n });\n throw new ServiceError(error.message, dump);\n }\n throw error;\n }\n\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse,\n formatResponse: JSON.stringify(parseResult),\n usage,\n reasoning_content,\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: PartialServiceDumpFromSDK = {\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 const dump = createServiceDump({\n ...dumpData,\n data,\n });\n\n if (errorLog && !data) {\n throw new ServiceError(errorLog, dump);\n }\n\n return {\n data,\n thought,\n usage,\n reasoning_content,\n dump,\n };\n }\n\n async describe(\n target: Rect | [number, number],\n modelConfig: IModelConfig,\n opt?: {\n deepLocate?: boolean;\n },\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\n assert(target, 'target is required for service.describe');\n const context = await this.contextRetrieverFn();\n const { shotSize } = context;\n const screenshotBase64 = context.screenshot.base64;\n assert(screenshotBase64, 'screenshot is required for service.describe');\n // The result of the \"describe\" function will be used for positioning, so essentially it is a form of grounding.\n const { modelFamily } = 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: shotSize,\n elementsPositionInfo: [\n {\n rect: targetRect,\n },\n ],\n borderThickness: 3,\n });\n\n if (opt?.deepLocate) {\n const searchArea = expandSearchArea(targetRect, shotSize);\n // Always crop in describe mode. Unlike locate's deepLocate (where\n // cropping too small loses context for finding elements), describe's\n // deepLocate intentionally zooms in so the model produces a more\n // precise description from a focused view. expandSearchArea already\n // guarantees a minimum 400x400 area with surrounding context.\n debug('describe: cropping to searchArea', searchArea);\n const croppedResult = await cropByRect(\n imagePayload,\n searchArea,\n modelFamily === 'qwen2.5-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 res = await callAIWithObjectResponse<AIDescribeElementResponse>(\n msgs,\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","Service","query","opt","modelConfig","abortSignal","queryPrompt","assert","hasPlanLocatedElement","searchAreaPrompt","modelFamily","console","undefined","isAutoGLM","context","searchArea","searchAreaRawResponse","searchAreaUsage","searchAreaResponse","searchAreaConfig","buildSearchAreaConfig","JSON","AiLocateSection","startTime","Date","parseResult","rect","rawResponse","usage","reasoning_content","AiLocateElement","timeCost","taskInfo","errorLog","dumpData","elements","dump","createServiceDump","ServiceError","dataDemand","pageDescription","multimodalPrompt","result","AiExtractElementInfo","error","AIResponseParseError","data","thought","target","shotSize","screenshotBase64","systemPrompt","elementDescriberInstruction","defaultRectSize","targetRect","Array","Math","imagePayload","compositeElementInfoImg","expandSearchArea","croppedResult","cropByRect","msgs","res","callAIWithObjectResponse","content","Promise"],"mappings":";;;;;;;;;;;;;;;;;;;;AA8CA,MAAMA,QAAQC,SAAS;AACR,MAAMC;IAqBnB,MAAM,OACJC,KAA0B,EAC1BC,GAAe,EACfC,WAAyB,EACzBC,WAAyB,EACM;QAC/B,MAAMC,cAAc,AAAiB,YAAjB,OAAOJ,QAAqBA,QAAQA,MAAM,MAAM;QACpEK,OAAOD,aAAa;QAEpBC,OAAO,AAAiB,YAAjB,OAAOL,OAAoB;QAElC,MAAMM,wBAAwB,CAAC,CAACL,KAAK,oBAAoB;QAEzD,IAAIM;QACJ,IAAIP,MAAM,UAAU,IAAI,CAACM,uBACvBC,mBAAmBP,MAAM,MAAM;QAGjC,MAAM,EAAEQ,WAAW,EAAE,GAAGN;QAExB,IAAIK,oBAAoB,CAACC,aAAa;YACpCC,QAAQ,IAAI,CACV;YAEFF,mBAAmBG;QACrB;QAEA,IAAIH,oBAAoBI,UAAUH,cAAc;YAC9CC,QAAQ,IAAI,CAAC;YACbF,mBAAmBG;QACrB;QAEA,MAAME,UAAUX,KAAK,WAAY,MAAM,IAAI,CAAC,kBAAkB;QAE9D,IAAIY;QACJ,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QAGJ,IAAIhB,MAAM,UAAU,IAAIM,uBAAuB;YAC7C,MAAMW,mBAAmB,MAAMC,sBAAsB;gBACnDN;gBACA,UAAUX,IAAI,kBAAkB,CAAE,IAAI;gBACtCO;YACF;YACAK,aAAaI,iBAAiB,IAAI;YAElCH,wBAAwBK,KAAK,SAAS,CAAC;gBACrC,QAAQ;gBACR,MAAMlB,IAAI,kBAAkB,CAAE,IAAI;YACpC;YACAe,qBAAqB;gBACnB,MAAMH;gBACN,aAAaI,iBAAiB,WAAW;gBACzC,OAAOA,iBAAiB,KAAK;gBAC7B,aAAaH;YACf;QACF,OAAO,IAAIP,kBAAkB;YAC3BS,qBAAqB,MAAMI,gBAAgB;gBACzCR;gBACA,oBAAoBL;gBACpBL;gBACAC;YACF;YACAE,OACEW,mBAAmB,IAAI,EACvB,CAAC,6BAA6B,EAAET,iBAAiB,CAAC,EAChDS,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,MAAMK,YAAYC,KAAK,GAAG;QAC1B,MAAM,EAAEC,WAAW,EAAEC,IAAI,EAAEC,WAAW,EAAEC,KAAK,EAAEC,iBAAiB,EAAE,GAChE,MAAMC,gBAAgB;YACpBhB;YACA,0BAA0BR;YAC1B,cAAcY;YACdd;YACAC;QACF;QAEF,MAAM0B,WAAWP,KAAK,GAAG,KAAKD;QAC9B,MAAMS,WAA4B;YAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YACtC,YAAYD;YACZ,aAAaV,KAAK,SAAS,CAACM;YAC5B,gBAAgBN,KAAK,SAAS,CAACI;YAC/BG;YACAb;YACAC;YACAC;YACAY;QACF;QAEA,IAAII;QACJ,IAAIR,YAAY,MAAM,EAAE,QACtBQ,WAAW,CAAC,4BAA4B,EAAER,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO;QAG3E,MAAMS,WAAsC;YAC1C,MAAM;YACN,WAAW;gBACT,SAAS5B;YACX;YACA,gBAAgB,EAAE;YAClB,aAAaoB;YACb,MAAM;YACNM;YACA,YAAY,CAAC,CAACjB;YACd,OAAOkB;QACT;QAEA,MAAME,WAAWV,YAAY,QAAQ,IAAI,EAAE;QAE3C,MAAMW,OAAOC,kBAAkB;YAC7B,GAAGH,QAAQ;YACX,gBAAgBC;QAClB;QAEA,IAAIF,UACF,MAAM,IAAIK,aAAaL,UAAUG;QAGnC,IAAID,SAAS,MAAM,GAAG,GACpB,MAAM,IAAIG,aACR,CAAC,0CAA0C,EAAEH,SAAS,MAAM,EAAE,EAC9DC;QAIJ,IAAID,AAAoB,MAApBA,SAAS,MAAM,EACjB,OAAO;YACL,SAAS;gBACP,QAAQA,QAAQ,CAAC,EAAE,CAAE,MAAM;gBAC3B,MAAMA,QAAQ,CAAC,EAAE,CAAE,IAAI;gBACvB,aAAaA,QAAQ,CAAC,EAAE,CAAE,WAAW;YACvC;YACAT;YACAU;QACF;QAGF,OAAO;YACL,SAAS;YACTV;YACAU;QACF;IACF;IAEA,MAAM,QACJG,UAA+B,EAC/BnC,WAAyB,EACzBD,GAA0B,EAC1BqC,eAAwB,EACxBC,gBAAoC,EACpC3B,OAAmB,EACe;QAClCP,OAAOO,SAAS;QAChBP,OACE,AAAsB,YAAtB,OAAOgC,cAA2B,AAAsB,YAAtB,OAAOA,YACzC,CAAC,+CAA+C,EAAE,OAAOA,YAAY;QAGvE,MAAMhB,YAAYC,KAAK,GAAG;QAE1B,IAAIC;QAGJ,IAAIE;QACJ,IAAIC;QACJ,IAAIC;QAEJ,IAAI;YACF,MAAMa,SAAS,MAAMC,qBAAwB;gBAC3C7B;gBACA,WAAWyB;gBACXE;gBACA,eAAetC;gBACfC;gBACAoC;YACF;YACAf,cAAciB,OAAO,WAAW;YAChCf,cAAce,OAAO,WAAW;YAChCd,QAAQc,OAAO,KAAK;YACpBb,oBAAoBa,OAAO,iBAAiB;QAC9C,EAAE,OAAOE,OAAO;YACd,IAAIA,iBAAiBC,sBAAsB;gBAEzC,MAAMd,WAAWP,KAAK,GAAG,KAAKD;gBAC9B,MAAMS,WAA4B;oBAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;oBACtC,YAAYD;oBACZ,aAAaa,MAAM,WAAW;oBAC9B,OAAOA,MAAM,KAAK;gBACpB;gBACA,MAAMR,OAAOC,kBAAkB;oBAC7B,MAAM;oBACN,WAAW;wBAAEE;oBAAW;oBACxB,gBAAgB,EAAE;oBAClB,MAAM;oBACNP;oBACA,OAAOY,MAAM,OAAO;gBACtB;gBACA,MAAM,IAAIN,aAAaM,MAAM,OAAO,EAAER;YACxC;YACA,MAAMQ;QACR;QAEA,MAAMb,WAAWP,KAAK,GAAG,KAAKD;QAC9B,MAAMS,WAA4B;YAChC,GAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YACtC,YAAYD;YACZJ;YACA,gBAAgBN,KAAK,SAAS,CAACI;YAC/BG;YACAC;QACF;QAEA,IAAII;QACJ,IAAIR,YAAY,MAAM,EAAE,QACtBQ,WAAW,CAAC,qBAAqB,EAAER,YAAY,MAAM,CAAC,IAAI,CAAC,OAAO;QAGpE,MAAMS,WAAsC;YAC1C,MAAM;YACN,WAAW;gBACTK;YACF;YACA,gBAAgB,EAAE;YAClB,MAAM;YACNP;YACA,OAAOC;QACT;QAEA,MAAM,EAAEa,IAAI,EAAEC,OAAO,EAAE,GAAGtB,eAAe,CAAC;QAE1C,MAAMW,OAAOC,kBAAkB;YAC7B,GAAGH,QAAQ;YACXY;QACF;QAEA,IAAIb,YAAY,CAACa,MACf,MAAM,IAAIR,aAAaL,UAAUG;QAGnC,OAAO;YACLU;YACAC;YACAnB;YACAC;YACAO;QACF;IACF;IAEA,MAAM,SACJY,MAA+B,EAC/B5C,WAAyB,EACzBD,GAEC,EACwD;QACzDI,OAAOyC,QAAQ;QACf,MAAMlC,UAAU,MAAM,IAAI,CAAC,kBAAkB;QAC7C,MAAM,EAAEmC,QAAQ,EAAE,GAAGnC;QACrB,MAAMoC,mBAAmBpC,QAAQ,UAAU,CAAC,MAAM;QAClDP,OAAO2C,kBAAkB;QAEzB,MAAM,EAAExC,WAAW,EAAE,GAAGN;QACxB,MAAM+C,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,gBAAgBR;YAChB,MAAMD;YACN,sBAAsB;gBACpB;oBACE,MAAMK;gBACR;aACD;YACD,iBAAiB;QACnB;QAEA,IAAInD,KAAK,YAAY;YACnB,MAAMY,aAAa4C,iBAAiBL,YAAYL;YAMhDlD,MAAM,oCAAoCgB;YAC1C,MAAM6C,gBAAgB,MAAMC,WAC1BJ,cACA1C,YACAL,AAAgB,iBAAhBA;YAEF+C,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,MAAM,MAAMC,yBAChBF,MACA1D;QAGF,MAAM,EAAE6D,OAAO,EAAE,GAAGF;QACpBxD,OAAO,CAAC0D,QAAQ,KAAK,EAAE,CAAC,iBAAiB,EAAEA,QAAQ,KAAK,EAAE;QAC1D1D,OAAO0D,QAAQ,WAAW,EAAE;QAC5B,OAAOA;IACT;IAlWA,YACEnD,OAA2D,EAC3DX,GAAoB,CACpB;QAPF;QAEA;QAMEI,OAAOO,SAAS;QAChB,IAAI,AAAmB,cAAnB,OAAOA,SACT,IAAI,CAAC,kBAAkB,GAAGA;aAE1B,IAAI,CAAC,kBAAkB,GAAG,IAAMoD,QAAQ,OAAO,CAACpD;QAGlD,IAAI,AAAyB,WAAlBX,KAAK,UACd,IAAI,CAAC,QAAQ,GAAGA,IAAI,QAAQ;IAEhC;AAqVF"}
@@ -0,0 +1,15 @@
1
+ import { uuid } from "@midscene/shared/utils";
2
+ function createServiceDump(data) {
3
+ const baseData = {
4
+ logTime: Date.now()
5
+ };
6
+ const finalData = {
7
+ logId: uuid(),
8
+ ...baseData,
9
+ ...data
10
+ };
11
+ return finalData;
12
+ }
13
+ export { createServiceDump };
14
+
15
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service/utils.mjs","sources":["../../../src/service/utils.ts"],"sourcesContent":["import type { DumpMeta, PartialServiceDumpFromSDK, ServiceDump } from '@/types';\nimport { uuid } from '@midscene/shared/utils';\n\nexport function createServiceDump(\n data: PartialServiceDumpFromSDK,\n): ServiceDump {\n const baseData: DumpMeta = {\n logTime: Date.now(),\n };\n const finalData: ServiceDump = {\n logId: uuid(),\n ...baseData,\n ...data,\n };\n\n return finalData;\n}\n"],"names":["createServiceDump","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"}
@@ -0,0 +1,38 @@
1
+ import { CLIError, runToolsCLI } from "@midscene/shared/cli";
2
+ import { BaseMidsceneTools } from "@midscene/shared/mcp";
3
+ import { Agent } from "../agent/agent.mjs";
4
+ function _define_property(obj, key, value) {
5
+ if (key in obj) Object.defineProperty(obj, key, {
6
+ value: value,
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true
10
+ });
11
+ else obj[key] = value;
12
+ return obj;
13
+ }
14
+ class SkillMidsceneTools extends BaseMidsceneTools {
15
+ createTemporaryDevice() {
16
+ return new this.DeviceClass();
17
+ }
18
+ async ensureAgent() {
19
+ if (!this.agent) {
20
+ const device = new this.DeviceClass();
21
+ this.agent = new Agent(device);
22
+ }
23
+ return this.agent;
24
+ }
25
+ constructor(DeviceClass){
26
+ super(), _define_property(this, "DeviceClass", void 0), this.DeviceClass = DeviceClass;
27
+ }
28
+ }
29
+ function runSkillCLI(options) {
30
+ const tools = new SkillMidsceneTools(options.DeviceClass);
31
+ return runToolsCLI(tools, options.scriptName).catch((e)=>{
32
+ if (!(e instanceof CLIError)) console.error(e);
33
+ process.exit(e instanceof CLIError ? e.exitCode : 1);
34
+ });
35
+ }
36
+ export { runSkillCLI };
37
+
38
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill/index.mjs","sources":["../../../src/skill/index.ts"],"sourcesContent":["import { CLIError, runToolsCLI } from '@midscene/shared/cli';\nimport { BaseMidsceneTools } from '@midscene/shared/mcp';\nimport type { BaseAgent, BaseDevice } from '@midscene/shared/mcp';\nimport { Agent } from '../agent/agent';\nimport type { AbstractInterface } from '../device';\n\ntype DeviceClass = new (...args: any[]) => AbstractInterface;\n\n/**\n * Skill tools manager that lazily creates Agent from a Device class.\n * Used by runSkillCLI for CLI / Agent Skills scenarios where no agent exists at startup.\n */\nclass SkillMidsceneTools extends BaseMidsceneTools<BaseAgent> {\n constructor(private DeviceClass: DeviceClass) {\n super();\n }\n\n protected createTemporaryDevice(): BaseDevice {\n return new this.DeviceClass() as unknown as BaseDevice;\n }\n\n protected async ensureAgent(): Promise<BaseAgent> {\n if (!this.agent) {\n const device = new this.DeviceClass();\n this.agent = new Agent(device) as unknown as BaseAgent;\n }\n return this.agent;\n }\n}\n\nexport interface SkillCLIOptions {\n scriptName: string;\n DeviceClass: DeviceClass;\n}\n\n/**\n * Launch a Skill CLI for a custom interface Device class.\n * This enables AI coding assistants (Claude Code, Cline, etc.) to control\n * your custom interface through CLI commands.\n *\n * @example\n * ```typescript\n * #!/usr/bin/env node\n * import { runSkillCLI } from '@midscene/core/skill';\n * import { SampleDevice } from './sample-device';\n *\n * runSkillCLI({\n * DeviceClass: SampleDevice,\n * scriptName: 'my-device',\n * });\n * ```\n */\nexport function runSkillCLI(options: SkillCLIOptions): Promise<void> {\n const tools = new SkillMidsceneTools(options.DeviceClass);\n return runToolsCLI(tools, options.scriptName).catch((e) => {\n if (!(e instanceof CLIError)) console.error(e);\n process.exit(e instanceof CLIError ? e.exitCode : 1);\n });\n}\n"],"names":["SkillMidsceneTools","BaseMidsceneTools","device","Agent","DeviceClass","runSkillCLI","options","tools","runToolsCLI","e","CLIError","console","process"],"mappings":";;;;;;;;;;;;;AAYA,MAAMA,2BAA2BC;IAKrB,wBAAoC;QAC5C,OAAO,IAAI,IAAI,CAAC,WAAW;IAC7B;IAEA,MAAgB,cAAkC;QAChD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YACf,MAAMC,SAAS,IAAI,IAAI,CAAC,WAAW;YACnC,IAAI,CAAC,KAAK,GAAG,IAAIC,MAAMD;QACzB;QACA,OAAO,IAAI,CAAC,KAAK;IACnB;IAdA,YAAoBE,WAAwB,CAAE;QAC5C,KAAK,wDADaA,WAAW,GAAXA;IAEpB;AAaF;AAwBO,SAASC,YAAYC,OAAwB;IAClD,MAAMC,QAAQ,IAAIP,mBAAmBM,QAAQ,WAAW;IACxD,OAAOE,YAAYD,OAAOD,QAAQ,UAAU,EAAE,KAAK,CAAC,CAACG;QACnD,IAAI,CAAEA,CAAAA,aAAaC,QAAO,GAAIC,QAAQ,KAAK,CAACF;QAC5CG,QAAQ,IAAI,CAACH,aAAaC,WAAWD,EAAE,QAAQ,GAAG;IACpD;AACF"}
@@ -0,0 +1,263 @@
1
+ import { setTimingFieldOnce } from "./task-timing.mjs";
2
+ import { ExecutionDump } from "./types.mjs";
3
+ import { getDebug } from "@midscene/shared/logger";
4
+ import { assert, uuid } from "@midscene/shared/utils";
5
+ function _define_property(obj, key, value) {
6
+ if (key in obj) Object.defineProperty(obj, key, {
7
+ value: value,
8
+ enumerable: true,
9
+ configurable: true,
10
+ writable: true
11
+ });
12
+ else obj[key] = value;
13
+ return obj;
14
+ }
15
+ const debug = getDebug('task-runner');
16
+ const UI_CONTEXT_CACHE_TTL_MS = 300;
17
+ class TaskRunner {
18
+ async emitOnTaskUpdate(error) {
19
+ if (!this.onTaskUpdate) return;
20
+ await this.onTaskUpdate(this, error);
21
+ }
22
+ async getUiContext(options) {
23
+ const now = Date.now();
24
+ const shouldReuse = !options?.forceRefresh && this.lastUiContext && now - this.lastUiContext.capturedAt <= UI_CONTEXT_CACHE_TTL_MS;
25
+ if (shouldReuse && this.lastUiContext?.context) {
26
+ debug(`reuse cached uiContext captured ${now - this.lastUiContext.capturedAt}ms ago`);
27
+ return this.lastUiContext?.context;
28
+ }
29
+ try {
30
+ const uiContext = await this.uiContextBuilder();
31
+ if (uiContext) this.lastUiContext = {
32
+ context: uiContext,
33
+ capturedAt: Date.now()
34
+ };
35
+ else this.lastUiContext = void 0;
36
+ return uiContext;
37
+ } catch (error) {
38
+ this.lastUiContext = void 0;
39
+ throw error;
40
+ }
41
+ }
42
+ async captureScreenshot() {
43
+ try {
44
+ const uiContext = await this.getUiContext({
45
+ forceRefresh: true
46
+ });
47
+ return uiContext?.screenshot;
48
+ } catch (error) {
49
+ console.error('error while capturing screenshot', error);
50
+ }
51
+ }
52
+ attachRecorderItem(task, screenshot, phase) {
53
+ if (!phase || !screenshot) return;
54
+ const recorderItem = {
55
+ type: 'screenshot',
56
+ ts: Date.now(),
57
+ screenshot,
58
+ timing: phase
59
+ };
60
+ if (!task.recorder) {
61
+ task.recorder = [
62
+ recorderItem
63
+ ];
64
+ return;
65
+ }
66
+ task.recorder.push(recorderItem);
67
+ }
68
+ markTaskAsPending(task) {
69
+ return {
70
+ taskId: uuid(),
71
+ status: 'pending',
72
+ ...task
73
+ };
74
+ }
75
+ normalizeStatusFromError(options, errorMessage) {
76
+ if ('error' !== this.status) return;
77
+ assert(options?.allowWhenError, errorMessage || `task runner is in error state, cannot proceed\nerror=${this.latestErrorTask()?.error}\n${this.latestErrorTask()?.errorStack}`);
78
+ this.status = this.tasks.length > 0 ? 'pending' : 'init';
79
+ }
80
+ async append(task, options) {
81
+ this.normalizeStatusFromError(options, `task runner is in error state, cannot append task\nerror=${this.latestErrorTask()?.error}\n${this.latestErrorTask()?.errorStack}`);
82
+ if (Array.isArray(task)) this.tasks.push(...task.map((item)=>this.markTaskAsPending(item)));
83
+ else this.tasks.push(this.markTaskAsPending(task));
84
+ if ('running' !== this.status) this.status = 'pending';
85
+ await this.emitOnTaskUpdate();
86
+ }
87
+ async appendAndFlush(task, options) {
88
+ await this.append(task, options);
89
+ return this.flush(options);
90
+ }
91
+ async flush(options) {
92
+ if ('init' === this.status && this.tasks.length > 0) console.warn('illegal state for task runner, status is init but tasks are not empty');
93
+ this.normalizeStatusFromError(options, 'task runner is in error state');
94
+ assert('running' !== this.status, 'task runner is already running');
95
+ assert('completed' !== this.status, 'task runner is already completed');
96
+ const nextPendingIndex = this.tasks.findIndex((task)=>'pending' === task.status);
97
+ if (nextPendingIndex < 0) return;
98
+ this.status = 'running';
99
+ await this.emitOnTaskUpdate();
100
+ let taskIndex = nextPendingIndex;
101
+ let successfullyCompleted = true;
102
+ let previousFindOutput;
103
+ while(taskIndex < this.tasks.length){
104
+ const task = this.tasks[taskIndex];
105
+ assert('pending' === task.status, `task status should be pending, but got: ${task.status}`);
106
+ task.timing = {
107
+ start: Date.now()
108
+ };
109
+ try {
110
+ task.status = 'running';
111
+ await this.emitOnTaskUpdate();
112
+ try {
113
+ if (this.onTaskStart) await this.onTaskStart(task);
114
+ } catch (e) {
115
+ console.error('error in onTaskStart', e);
116
+ }
117
+ assert([
118
+ 'Insight',
119
+ 'Action Space',
120
+ 'Planning'
121
+ ].indexOf(task.type) >= 0, `unsupported task type: ${task.type}`);
122
+ const { executor, param } = task;
123
+ assert(executor, `executor is required for task type: ${task.type}`);
124
+ let returnValue;
125
+ const forceRefresh = 'Insight' === task.type;
126
+ setTimingFieldOnce(task.timing, 'getUiContextStart');
127
+ const uiContext = await this.getUiContext({
128
+ forceRefresh
129
+ });
130
+ setTimingFieldOnce(task.timing, 'getUiContextEnd');
131
+ task.uiContext = uiContext;
132
+ const executorContext = {
133
+ task,
134
+ element: previousFindOutput?.element,
135
+ uiContext
136
+ };
137
+ if ('Insight' === task.type) {
138
+ assert('Query' === task.subType || 'Assert' === task.subType || 'WaitFor' === task.subType || 'Boolean' === task.subType || 'Number' === task.subType || 'String' === task.subType, `unsupported service subType: ${task.subType}`);
139
+ returnValue = await task.executor(param, executorContext);
140
+ } else if ('Planning' === task.type) {
141
+ returnValue = await task.executor(param, executorContext);
142
+ if ('Locate' === task.subType) previousFindOutput = returnValue?.output;
143
+ } else if ('Action Space' === task.type) returnValue = await task.executor(param, executorContext);
144
+ else {
145
+ console.warn(`unsupported task type: ${task.type}, will try to execute it directly`);
146
+ returnValue = await task.executor(param, executorContext);
147
+ }
148
+ const isLastTask = taskIndex === this.tasks.length - 1;
149
+ if (isLastTask) {
150
+ setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotStart');
151
+ const screenshot = await this.captureScreenshot();
152
+ this.attachRecorderItem(task, screenshot, 'after-calling');
153
+ setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotEnd');
154
+ }
155
+ Object.assign(task, returnValue);
156
+ task.status = 'finished';
157
+ task.timing.end = Date.now();
158
+ task.timing.cost = task.timing.end - task.timing.start;
159
+ await this.emitOnTaskUpdate();
160
+ taskIndex++;
161
+ } catch (e) {
162
+ successfullyCompleted = false;
163
+ task.error = e;
164
+ task.errorMessage = e?.message || ('string' == typeof e ? e : 'error-without-message');
165
+ task.errorStack = e.stack;
166
+ task.status = 'failed';
167
+ task.timing.end = Date.now();
168
+ task.timing.cost = task.timing.end - task.timing.start;
169
+ await this.emitOnTaskUpdate();
170
+ break;
171
+ }
172
+ }
173
+ for(let i = taskIndex + 1; i < this.tasks.length; i++)this.tasks[i].status = 'cancelled';
174
+ if (taskIndex + 1 < this.tasks.length) await this.emitOnTaskUpdate();
175
+ let finalizeError;
176
+ if (successfullyCompleted) {
177
+ this.status = 'completed';
178
+ await this.emitOnTaskUpdate();
179
+ } else {
180
+ this.status = 'error';
181
+ const errorTask = this.latestErrorTask();
182
+ const messageBase = errorTask?.errorMessage || (errorTask?.error ? String(errorTask.error) : 'Task execution failed');
183
+ const stack = errorTask?.errorStack;
184
+ const message = stack ? `${messageBase}\n${stack}` : messageBase;
185
+ finalizeError = new TaskExecutionError(message, this, errorTask, {
186
+ cause: errorTask?.error
187
+ });
188
+ await this.emitOnTaskUpdate(finalizeError);
189
+ }
190
+ if (finalizeError) throw finalizeError;
191
+ if (this.tasks.length) {
192
+ const outputIndex = Math.min(taskIndex, this.tasks.length - 1);
193
+ const { thought, output } = this.tasks[outputIndex];
194
+ return {
195
+ thought,
196
+ output
197
+ };
198
+ }
199
+ }
200
+ isInErrorState() {
201
+ return 'error' === this.status;
202
+ }
203
+ latestErrorTask() {
204
+ if ('error' !== this.status) return null;
205
+ for(let i = this.tasks.length - 1; i >= 0; i--)if ('failed' === this.tasks[i].status) return this.tasks[i];
206
+ return null;
207
+ }
208
+ dump() {
209
+ return new ExecutionDump({
210
+ id: this.id,
211
+ logTime: this.executionLogTime,
212
+ name: this.name,
213
+ tasks: this.tasks
214
+ });
215
+ }
216
+ async appendErrorPlan(errorMsg) {
217
+ const errorTask = {
218
+ type: 'Action Space',
219
+ subType: 'Error',
220
+ param: {
221
+ thought: errorMsg
222
+ },
223
+ thought: errorMsg,
224
+ executor: async ()=>{
225
+ throw new Error(errorMsg || 'error without thought');
226
+ }
227
+ };
228
+ await this.appendAndFlush(errorTask);
229
+ return {
230
+ output: void 0,
231
+ runner: this
232
+ };
233
+ }
234
+ constructor(name, uiContextBuilder, options){
235
+ _define_property(this, "id", void 0);
236
+ _define_property(this, "name", void 0);
237
+ _define_property(this, "tasks", void 0);
238
+ _define_property(this, "status", void 0);
239
+ _define_property(this, "onTaskStart", void 0);
240
+ _define_property(this, "uiContextBuilder", void 0);
241
+ _define_property(this, "onTaskUpdate", void 0);
242
+ _define_property(this, "executionLogTime", void 0);
243
+ _define_property(this, "lastUiContext", void 0);
244
+ this.id = uuid();
245
+ this.status = options?.tasks && options.tasks.length > 0 ? 'pending' : 'init';
246
+ this.name = name;
247
+ this.tasks = (options?.tasks || []).map((item)=>this.markTaskAsPending(item));
248
+ this.onTaskStart = options?.onTaskStart;
249
+ this.uiContextBuilder = uiContextBuilder;
250
+ this.onTaskUpdate = options?.onTaskUpdate;
251
+ this.executionLogTime = Date.now();
252
+ }
253
+ }
254
+ class TaskExecutionError extends Error {
255
+ constructor(message, runner, errorTask, options){
256
+ super(message, options), _define_property(this, "runner", void 0), _define_property(this, "errorTask", void 0);
257
+ this.runner = runner;
258
+ this.errorTask = errorTask;
259
+ }
260
+ }
261
+ export { TaskExecutionError, TaskRunner };
262
+
263
+ //# sourceMappingURL=task-runner.mjs.map