misoai-web 1.0.6 → 1.5.6

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 (47) hide show
  1. package/README.md +5 -349
  2. package/dist/es/agent.js +43 -409
  3. package/dist/es/agent.js.map +1 -1
  4. package/dist/es/bridge-mode-browser.js +3 -3
  5. package/dist/es/bridge-mode.js +45 -411
  6. package/dist/es/bridge-mode.js.map +1 -1
  7. package/dist/es/chrome-extension.js +44 -410
  8. package/dist/es/chrome-extension.js.map +1 -1
  9. package/dist/es/index.js +47 -413
  10. package/dist/es/index.js.map +1 -1
  11. package/dist/es/midscene-playground.js +43 -409
  12. package/dist/es/midscene-playground.js.map +1 -1
  13. package/dist/es/playground.js +43 -409
  14. package/dist/es/playground.js.map +1 -1
  15. package/dist/es/playwright.js +44 -410
  16. package/dist/es/playwright.js.map +1 -1
  17. package/dist/es/puppeteer-agent-launcher.js +47 -413
  18. package/dist/es/puppeteer-agent-launcher.js.map +1 -1
  19. package/dist/es/puppeteer.js +47 -413
  20. package/dist/es/puppeteer.js.map +1 -1
  21. package/dist/es/yaml.js +5 -3
  22. package/dist/es/yaml.js.map +1 -1
  23. package/dist/lib/agent.js +43 -409
  24. package/dist/lib/agent.js.map +1 -1
  25. package/dist/lib/bridge-mode-browser.js +3 -3
  26. package/dist/lib/bridge-mode.js +45 -411
  27. package/dist/lib/bridge-mode.js.map +1 -1
  28. package/dist/lib/chrome-extension.js +44 -410
  29. package/dist/lib/chrome-extension.js.map +1 -1
  30. package/dist/lib/index.js +47 -413
  31. package/dist/lib/index.js.map +1 -1
  32. package/dist/lib/midscene-playground.js +43 -409
  33. package/dist/lib/midscene-playground.js.map +1 -1
  34. package/dist/lib/playground.js +43 -409
  35. package/dist/lib/playground.js.map +1 -1
  36. package/dist/lib/playwright.js +44 -410
  37. package/dist/lib/playwright.js.map +1 -1
  38. package/dist/lib/puppeteer-agent-launcher.js +47 -413
  39. package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
  40. package/dist/lib/puppeteer.js +47 -413
  41. package/dist/lib/puppeteer.js.map +1 -1
  42. package/dist/lib/yaml.js +5 -3
  43. package/dist/lib/yaml.js.map +1 -1
  44. package/dist/types/agent.d.ts +3 -44
  45. package/iife-script/htmlElement.js +2 -2
  46. package/iife-script/htmlElementDebug.js +2 -2
  47. package/package.json +4 -4
@@ -137,10 +137,11 @@ var ScriptPlayer = class {
137
137
  this.unnamedResultIndex = 0;
138
138
  this.pageAgent = null;
139
139
  this.result = {};
140
+ const target = script.target || script.web || script.android;
140
141
  if (ifInBrowser) {
141
142
  this.output = void 0;
142
- } else if (script.target?.output) {
143
- this.output = resolve(process.cwd(), script.target.output);
143
+ } else if (target?.output) {
144
+ this.output = resolve(process.cwd(), target.output);
144
145
  } else {
145
146
  this.output = join(getMidsceneRunSubDir("output"), `${process.pid}.json`);
146
147
  }
@@ -214,12 +215,13 @@ var ScriptPlayer = class {
214
215
  } else if ("aiAssert" in flowItem) {
215
216
  const assertTask = flowItem;
216
217
  const prompt = assertTask.aiAssert;
218
+ const msg = assertTask.errorMessage;
217
219
  assert2(prompt, "missing prompt for aiAssert");
218
220
  assert2(
219
221
  typeof prompt === "string",
220
222
  "prompt for aiAssert must be a string"
221
223
  );
222
- await agent.aiAssert(prompt);
224
+ await agent.aiAssert(prompt, msg);
223
225
  } else if ("aiQuery" in flowItem) {
224
226
  const queryTask = flowItem;
225
227
  const prompt = queryTask.aiQuery;
@@ -1661,7 +1663,7 @@ import yaml3 from "js-yaml";
1661
1663
  import semver from "semver";
1662
1664
 
1663
1665
  // package.json
1664
- var version = "1.0.5";
1666
+ var version = "1.5.6";
1665
1667
 
1666
1668
  // src/common/task-cache.ts
1667
1669
  var debug3 = getDebug3("cache");
@@ -1689,70 +1691,44 @@ var TaskCache = class {
1689
1691
  this.cache = cacheContent;
1690
1692
  this.cacheOriginalLength = this.cache.caches.length;
1691
1693
  }
1692
- matchCache(prompt, type, contextData) {
1693
- const contextHash = contextData ? this.generateContextHash(contextData) : void 0;
1694
+ matchCache(prompt, type) {
1694
1695
  for (let i = 0; i < this.cacheOriginalLength; i++) {
1695
1696
  const item = this.cache.caches[i];
1696
1697
  const key = `${type}:${prompt}:${i}`;
1697
- if (item.type !== type || item.prompt !== prompt || this.matchedCacheIndices.has(key)) {
1698
- continue;
1699
- }
1700
- if (type === "plan" && item.type === "plan") {
1701
- const planItem = item;
1702
- if (contextHash && planItem.contextHash) {
1703
- if (contextHash !== planItem.contextHash) {
1704
- debug3("cache context mismatch, type: %s, prompt: %s, index: %d", type, prompt, i);
1705
- continue;
1698
+ if (item.type === type && item.prompt === prompt && !this.matchedCacheIndices.has(key)) {
1699
+ this.matchedCacheIndices.add(key);
1700
+ debug3(
1701
+ "cache found and marked as used, type: %s, prompt: %s, index: %d",
1702
+ type,
1703
+ prompt,
1704
+ i
1705
+ );
1706
+ return {
1707
+ cacheContent: item,
1708
+ updateFn: (cb) => {
1709
+ debug3(
1710
+ "will call updateFn to update cache, type: %s, prompt: %s, index: %d",
1711
+ type,
1712
+ prompt,
1713
+ i
1714
+ );
1715
+ cb(item);
1716
+ debug3(
1717
+ "cache updated, will flush to file, type: %s, prompt: %s, index: %d",
1718
+ type,
1719
+ prompt,
1720
+ i
1721
+ );
1722
+ this.flushCacheToFile();
1706
1723
  }
1707
- } else if (contextHash || planItem.contextHash) {
1708
- debug3("cache context availability mismatch, type: %s, prompt: %s, index: %d", type, prompt, i);
1709
- continue;
1710
- }
1724
+ };
1711
1725
  }
1712
- this.matchedCacheIndices.add(key);
1713
- debug3(
1714
- "cache found and marked as used, type: %s, prompt: %s, index: %d, contextMatch: %s",
1715
- type,
1716
- prompt,
1717
- i,
1718
- contextHash ? "yes" : "no-context"
1719
- );
1720
- return {
1721
- cacheContent: item,
1722
- updateFn: (cb) => {
1723
- debug3(
1724
- "will call updateFn to update cache, type: %s, prompt: %s, index: %d",
1725
- type,
1726
- prompt,
1727
- i
1728
- );
1729
- cb(item);
1730
- debug3(
1731
- "cache updated, will flush to file, type: %s, prompt: %s, index: %d",
1732
- type,
1733
- prompt,
1734
- i
1735
- );
1736
- this.flushCacheToFile();
1737
- }
1738
- };
1739
1726
  }
1740
- debug3("no unused cache found, type: %s, prompt: %s, contextHash: %s", type, prompt, contextHash);
1727
+ debug3("no unused cache found, type: %s, prompt: %s", type, prompt);
1741
1728
  return void 0;
1742
1729
  }
1743
- generateContextHash(contextData) {
1744
- const sortedKeys = Object.keys(contextData).sort();
1745
- const stableString = sortedKeys.map((key) => `${key}:${JSON.stringify(contextData[key])}`).join("|");
1746
- let hash = 0;
1747
- for (let i = 0; i < stableString.length; i++) {
1748
- const char = stableString.charCodeAt(i);
1749
- hash = (hash << 5) - hash + char;
1750
- hash = hash & hash;
1751
- }
1752
- return hash.toString(36);
1753
- }
1754
- matchPlanCache(prompt, contextData) {
1755
- return this.matchCache(prompt, "plan", contextData);
1730
+ matchPlanCache(prompt) {
1731
+ return this.matchCache(prompt, "plan");
1756
1732
  }
1757
1733
  matchLocateCache(prompt) {
1758
1734
  return this.matchCache(prompt, "locate");
@@ -1828,16 +1804,11 @@ cache file: ${cacheFile}`
1828
1804
  );
1829
1805
  }
1830
1806
  }
1831
- updateOrAppendCacheRecord(newRecord, cachedRecord, contextData) {
1807
+ updateOrAppendCacheRecord(newRecord, cachedRecord) {
1832
1808
  if (cachedRecord) {
1833
1809
  if (newRecord.type === "plan") {
1834
1810
  cachedRecord.updateFn((cache) => {
1835
- const planCache = cache;
1836
- planCache.yamlWorkflow = newRecord.yamlWorkflow;
1837
- if (contextData) {
1838
- planCache.contextHash = this.generateContextHash(contextData);
1839
- planCache.contextData = { ...contextData };
1840
- }
1811
+ cache.yamlWorkflow = newRecord.yamlWorkflow;
1841
1812
  });
1842
1813
  } else {
1843
1814
  cachedRecord.updateFn((cache) => {
@@ -1845,11 +1816,6 @@ cache file: ${cacheFile}`
1845
1816
  });
1846
1817
  }
1847
1818
  } else {
1848
- if (newRecord.type === "plan" && contextData) {
1849
- const planRecord = newRecord;
1850
- planRecord.contextHash = this.generateContextHash(contextData);
1851
- planRecord.contextData = { ...contextData };
1852
- }
1853
1819
  this.appendCache(newRecord);
1854
1820
  }
1855
1821
  }
@@ -1879,13 +1845,10 @@ var PageAgent = class {
1879
1845
  generateReport: true,
1880
1846
  autoPrintReportMsg: true,
1881
1847
  groupName: "Midscene Report",
1882
- groupDescription: "",
1883
- enableCumulativeContext: true,
1884
- autoClearContext: false
1848
+ groupDescription: ""
1885
1849
  },
1886
1850
  opts || {}
1887
1851
  );
1888
- this.initializeContextStore();
1889
1852
  if (this.page.pageType === "puppeteer" || this.page.pageType === "playwright") {
1890
1853
  this.page.waitForNavigationTimeout = this.opts.waitForNavigationTimeout || DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT;
1891
1854
  this.page.waitForNetworkIdleTimeout = this.opts.waitForNetworkIdleTimeout || DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;
@@ -1912,69 +1875,6 @@ var PageAgent = class {
1912
1875
  opts?.testId || this.page.pageType || "web"
1913
1876
  );
1914
1877
  }
1915
- /**
1916
- * Initialize context store for cumulative context functionality
1917
- */
1918
- async initializeContextStore() {
1919
- if (!this.opts.enableCumulativeContext) {
1920
- debug4("Cumulative context disabled via options");
1921
- return;
1922
- }
1923
- try {
1924
- const aiModel = await import("misoai-core/ai-model");
1925
- this.contextStore = aiModel.getContextStore();
1926
- debug4("Context store initialized successfully", {
1927
- autoClearContext: this.opts.autoClearContext,
1928
- testId: this.opts.testId
1929
- });
1930
- if (this.opts.autoClearContext) {
1931
- this.contextStore.clear();
1932
- debug4("Context store cleared due to autoClearContext option");
1933
- } else {
1934
- const existingData = this.contextStore.getAllData();
1935
- const existingSteps = this.contextStore.getRecentSteps(100).length;
1936
- debug4("Context store preserving existing data", {
1937
- existingDataKeys: Object.keys(existingData),
1938
- existingStepsCount: existingSteps
1939
- });
1940
- }
1941
- } catch (error) {
1942
- debug4("Failed to initialize context store:", error);
1943
- console.warn("⚠️ Could not initialize context store:", error);
1944
- }
1945
- }
1946
- /**
1947
- * Get the context store instance
1948
- */
1949
- getContextStore() {
1950
- return this.contextStore;
1951
- }
1952
- /**
1953
- * Clear the context store
1954
- */
1955
- clearContext() {
1956
- if (this.contextStore) {
1957
- this.contextStore.clear();
1958
- }
1959
- }
1960
- /**
1961
- * Get all stored data from context store
1962
- */
1963
- getStoredData() {
1964
- if (this.contextStore) {
1965
- return this.contextStore.getAllData();
1966
- }
1967
- return {};
1968
- }
1969
- /**
1970
- * Get step summary from context store
1971
- */
1972
- getStepSummary() {
1973
- if (this.contextStore) {
1974
- return this.contextStore.getStepSummary();
1975
- }
1976
- return "";
1977
- }
1978
1878
  async getUIContext(action) {
1979
1879
  if (action && (action === "extract" || action === "assert" || action === "captcha")) {
1980
1880
  return await parseContextFromWebPage(this.page, {
@@ -2210,35 +2110,9 @@ var PageAgent = class {
2210
2110
  };
2211
2111
  }
2212
2112
  async aiAction(taskPrompt, opt) {
2213
- const originalPrompt = taskPrompt;
2214
- let processedPrompt = taskPrompt;
2215
- if (this.opts.enableCumulativeContext && this.contextStore) {
2216
- try {
2217
- const storedData = this.contextStore.getAllData();
2218
- if (Object.keys(storedData).length > 0) {
2219
- debug4("Available data for aiAction:", {
2220
- prompt: taskPrompt,
2221
- availableData: storedData
2222
- });
2223
- }
2224
- } catch (error) {
2225
- debug4("Context store operation failed:", error);
2226
- }
2227
- }
2228
2113
  const cacheable = opt?.cacheable;
2229
2114
  const isVlmUiTars = vlLocateMode() === "vlm-ui-tars";
2230
- let contextData;
2231
- if (this.opts.enableCumulativeContext && this.contextStore) {
2232
- try {
2233
- contextData = this.contextStore.getAllData();
2234
- if (contextData && Object.keys(contextData).length === 0) {
2235
- contextData = void 0;
2236
- }
2237
- } catch (error) {
2238
- debug4("Failed to get context data for cache:", error);
2239
- }
2240
- }
2241
- const matchedCache = isVlmUiTars || cacheable === false ? void 0 : this.taskCache?.matchPlanCache(taskPrompt, contextData);
2115
+ const matchedCache = isVlmUiTars || cacheable === false ? void 0 : this.taskCache?.matchPlanCache(taskPrompt);
2242
2116
  if (matchedCache && this.taskCache?.isCacheResultUsed) {
2243
2117
  const { executor: executor2 } = await this.taskExecutor.loadYamlFlowAsPlanning(
2244
2118
  taskPrompt,
@@ -2248,28 +2122,6 @@ var PageAgent = class {
2248
2122
  debug4("matched cache, will call .runYaml to run the action");
2249
2123
  const yaml5 = matchedCache.cacheContent?.yamlWorkflow;
2250
2124
  const result = await this.runYaml(yaml5);
2251
- if (this.opts.enableCumulativeContext && this.contextStore) {
2252
- try {
2253
- const executionResult = {
2254
- success: true,
2255
- actionType: "cached",
2256
- description: `Executed cached action: ${processedPrompt}`,
2257
- timing: result.metadata?.totalTime
2258
- };
2259
- this.contextStore.addStep({
2260
- type: "action",
2261
- summary: `Action: ${processedPrompt} (cached)`,
2262
- prompt: processedPrompt,
2263
- executionResult
2264
- });
2265
- debug4("Added cached action step to context store:", {
2266
- stepNumber: this.contextStore.getRecentSteps(1)[0]?.stepNumber,
2267
- totalSteps: this.contextStore.getRecentSteps(100).length
2268
- });
2269
- } catch (error) {
2270
- debug4("Failed to add cached action step:", error);
2271
- }
2272
- }
2273
2125
  return {
2274
2126
  result: result.result,
2275
2127
  metadata: metadata2
@@ -2294,114 +2146,17 @@ var PageAgent = class {
2294
2146
  prompt: taskPrompt,
2295
2147
  yamlWorkflow: yamlFlowStr
2296
2148
  },
2297
- matchedCache,
2298
- contextData
2299
- // Pass context data for cache creation
2149
+ matchedCache
2300
2150
  );
2301
2151
  }
2302
2152
  const metadata = this.afterTaskRunning(executor);
2303
- if (this.opts.enableCumulativeContext && this.contextStore) {
2304
- try {
2305
- const executionResult = this.analyzeExecutionResults(executor, originalPrompt);
2306
- this.contextStore.addStep({
2307
- type: "action",
2308
- summary: `Action: ${processedPrompt}`,
2309
- prompt: processedPrompt,
2310
- executionResult
2311
- });
2312
- debug4("Added action step with execution result to context store:", {
2313
- stepNumber: this.contextStore.getRecentSteps(1)[0]?.stepNumber,
2314
- totalSteps: this.contextStore.getRecentSteps(100).length,
2315
- executionResult
2316
- });
2317
- } catch (error) {
2318
- debug4("Failed to analyze execution results, adding step without execution result:", error);
2319
- try {
2320
- this.contextStore.addStep({
2321
- type: "action",
2322
- summary: `Action: ${processedPrompt}`,
2323
- prompt: processedPrompt
2324
- });
2325
- } catch (stepError) {
2326
- debug4("Failed to add action step:", stepError);
2327
- }
2328
- }
2329
- }
2330
2153
  return {
2331
2154
  result: output,
2332
2155
  metadata
2333
2156
  };
2334
2157
  }
2335
2158
  async aiQuery(demand) {
2336
- let processedDemand = demand;
2337
- let storageKey;
2338
- try {
2339
- const aiModel = await import("misoai-core/ai-model");
2340
- const contextStore = aiModel.getContextStore();
2341
- if (typeof demand === "string") {
2342
- const storageInstruction = contextStore.parseStorageInstruction(demand);
2343
- if (storageInstruction) {
2344
- storageKey = storageInstruction.key;
2345
- processedDemand = storageInstruction.cleanText;
2346
- contextStore._pendingAliases = storageInstruction.aliases;
2347
- } else {
2348
- const storageMatch = demand.match(/store\s+(?:as\s+)?(\w+)/i);
2349
- if (storageMatch) {
2350
- storageKey = storageMatch[1];
2351
- processedDemand = demand.replace(/,?\s*store\s+(?:as\s+)?\w+/i, "").trim();
2352
- }
2353
- }
2354
- }
2355
- } catch (error) {
2356
- debug4("Context store not available:", error);
2357
- }
2358
- const { output, executor } = await this.taskExecutor.query(processedDemand);
2359
- if (this.opts.enableCumulativeContext && this.contextStore) {
2360
- if (storageKey && output) {
2361
- try {
2362
- const pendingAliases = this.contextStore._pendingAliases;
2363
- if (pendingAliases) {
2364
- this.contextStore.storeDataWithAliases(storageKey, output, pendingAliases, typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand));
2365
- delete this.contextStore._pendingAliases;
2366
- debug4("Stored query result with aliases:", {
2367
- key: storageKey,
2368
- value: output,
2369
- aliases: pendingAliases
2370
- });
2371
- } else {
2372
- this.contextStore.storeData(storageKey, output);
2373
- debug4("Stored query result:", {
2374
- key: storageKey,
2375
- value: output
2376
- });
2377
- }
2378
- this.contextStore.addStep({
2379
- type: "query",
2380
- summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)} (stored as ${storageKey})`,
2381
- data: output,
2382
- prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
2383
- });
2384
- debug4("Added query step to context store:", {
2385
- storageKey,
2386
- totalStoredItems: Object.keys(this.contextStore.getAllData()).length,
2387
- totalSteps: this.contextStore.getRecentSteps(100).length
2388
- });
2389
- } catch (error) {
2390
- debug4("Failed to store query result:", error);
2391
- }
2392
- } else {
2393
- try {
2394
- this.contextStore.addStep({
2395
- type: "query",
2396
- summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)}`,
2397
- data: output,
2398
- prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
2399
- });
2400
- } catch (error) {
2401
- debug4("Failed to add query step:", error);
2402
- }
2403
- }
2404
- }
2159
+ const { output, executor } = await this.taskExecutor.query(demand);
2405
2160
  const metadata = this.afterTaskRunning(executor);
2406
2161
  return {
2407
2162
  result: output,
@@ -2511,48 +2266,6 @@ var PageAgent = class {
2511
2266
  };
2512
2267
  }
2513
2268
  async aiAssert(assertion, msg, opt) {
2514
- let executionContext = "";
2515
- if (this.opts.enableCumulativeContext && this.contextStore) {
2516
- try {
2517
- const recentSteps = this.contextStore.getRecentSteps(3);
2518
- const stepsWithExecutionResults = recentSteps.filter((step) => step.executionResult);
2519
- const storedData = this.contextStore.getAllData();
2520
- if (stepsWithExecutionResults.length > 0) {
2521
- const recentActions = stepsWithExecutionResults.map((step) => {
2522
- const result = step.executionResult;
2523
- return `- ${result.description}${result.success ? "" : " (FAILED)"}`;
2524
- }).join("\n");
2525
- executionContext = `
2526
-
2527
- Recent actions performed:
2528
- ${recentActions}
2529
-
2530
- This context may help verify the assertion.`;
2531
- }
2532
- if (storedData && Object.keys(storedData).length > 0) {
2533
- executionContext += `
2534
-
2535
- Available data for reference:
2536
- ${JSON.stringify(storedData, null, 2)}
2537
-
2538
- Note: If the assertion references any data keys or natural language equivalents, consider the stored values when verifying.`;
2539
- debug4("Available data for aiAssert:", {
2540
- assertion,
2541
- availableData: storedData
2542
- });
2543
- }
2544
- this.contextStore.addStep({
2545
- type: "assertion",
2546
- summary: `Assertion: ${assertion}`,
2547
- prompt: assertion
2548
- });
2549
- debug4("Added assertion step to context store:", {
2550
- totalSteps: this.contextStore.getRecentSteps(100).length
2551
- });
2552
- } catch (error) {
2553
- debug4("Context store operation failed:", error);
2554
- }
2555
- }
2556
2269
  let currentUrl = "";
2557
2270
  if (this.page.url) {
2558
2271
  try {
@@ -2560,13 +2273,7 @@ Note: If the assertion references any data keys or natural language equivalents,
2560
2273
  } catch (e) {
2561
2274
  }
2562
2275
  }
2563
- let assertionWithContext = assertion;
2564
- if (currentUrl) {
2565
- assertionWithContext = `For the page at URL "${currentUrl}", ${assertion}`;
2566
- }
2567
- if (executionContext) {
2568
- assertionWithContext += executionContext;
2569
- }
2276
+ const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
2570
2277
  const { output, executor } = await this.taskExecutor.assert(assertionWithContext);
2571
2278
  const metadata = this.afterTaskRunning(executor, true);
2572
2279
  if (output && opt?.keepRawResponse) {
@@ -2780,79 +2487,6 @@ ${errors}`);
2780
2487
  async destroy() {
2781
2488
  await this.page.destroy();
2782
2489
  }
2783
- /**
2784
- * Analyze execution results from executor to generate meaningful descriptions
2785
- */
2786
- analyzeExecutionResults(executor, originalPrompt) {
2787
- const tasks = executor.tasks;
2788
- const success = !executor.isInErrorState();
2789
- if (!success) {
2790
- const errorTask = executor.latestErrorTask();
2791
- return {
2792
- success: false,
2793
- actionType: "error",
2794
- description: `Failed to execute: ${originalPrompt}`,
2795
- error: errorTask?.error
2796
- };
2797
- }
2798
- const actionTasks = tasks.filter((t) => t.type === "Action" && t.status === "finished");
2799
- const locateTasks = tasks.filter((t) => t.type === "Insight" && t.subType === "Locate");
2800
- const lastAction = actionTasks[actionTasks.length - 1];
2801
- const lastLocate = locateTasks[locateTasks.length - 1];
2802
- if (!lastAction) {
2803
- return {
2804
- success: true,
2805
- actionType: "unknown",
2806
- description: `Completed: ${originalPrompt}`
2807
- };
2808
- }
2809
- const actionType = lastAction.subType || "unknown";
2810
- const elementInfo = this.extractElementInfo(lastLocate, lastAction);
2811
- const description = this.generateActionDescription(actionType, lastAction.param, elementInfo);
2812
- return {
2813
- success: true,
2814
- actionType,
2815
- description,
2816
- elementInfo,
2817
- timing: lastAction.timing?.cost
2818
- };
2819
- }
2820
- /**
2821
- * Extract element information from locate task
2822
- */
2823
- extractElementInfo(locateTask, _actionTask) {
2824
- if (!locateTask?.output?.element)
2825
- return void 0;
2826
- const element = locateTask.output.element;
2827
- return {
2828
- type: element.attributes?.nodeType || "unknown",
2829
- text: element.content || element.attributes?.placeholder || element.attributes?.title || "",
2830
- location: `(${element.center[0]}, ${element.center[1]})`
2831
- };
2832
- }
2833
- /**
2834
- * Generate natural language description for actions
2835
- */
2836
- generateActionDescription(actionType, param, elementInfo) {
2837
- const elementDesc = elementInfo ? `'${elementInfo.text || elementInfo.type}' element` : "element";
2838
- switch (actionType) {
2839
- case "Tap":
2840
- return `Clicked on ${elementDesc}`;
2841
- case "Input":
2842
- const inputValue = param?.value || "";
2843
- return `Entered "${inputValue}" into ${elementDesc}`;
2844
- case "KeyboardPress":
2845
- return `Pressed ${param?.value || "key"}`;
2846
- case "Scroll":
2847
- return `Scrolled ${param?.direction || "on page"}`;
2848
- case "Hover":
2849
- return `Hovered over ${elementDesc}`;
2850
- case "Drag":
2851
- return `Dragged ${elementDesc}`;
2852
- default:
2853
- return `Performed ${actionType} action on ${elementDesc}`;
2854
- }
2855
- }
2856
2490
  };
2857
2491
 
2858
2492
  // src/playground/agent.ts