misoai-web 1.0.2 → 1.0.4

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -8
  3. package/bin/midscene-playground +2 -2
  4. package/dist/es/agent.js +167 -44
  5. package/dist/es/agent.js.map +1 -1
  6. package/dist/es/bridge-mode-browser.js +64 -17
  7. package/dist/es/bridge-mode-browser.js.map +1 -1
  8. package/dist/es/bridge-mode.js +169 -46
  9. package/dist/es/bridge-mode.js.map +1 -1
  10. package/dist/es/chrome-extension.js +229 -59
  11. package/dist/es/chrome-extension.js.map +1 -1
  12. package/dist/es/index.js +183 -45
  13. package/dist/es/index.js.map +1 -1
  14. package/dist/es/midscene-playground.js +173 -44
  15. package/dist/es/midscene-playground.js.map +1 -1
  16. package/dist/es/midscene-server.js.map +1 -1
  17. package/dist/es/playground.js +173 -44
  18. package/dist/es/playground.js.map +1 -1
  19. package/dist/es/playwright-report.js.map +1 -1
  20. package/dist/es/playwright.js +183 -45
  21. package/dist/es/playwright.js.map +1 -1
  22. package/dist/es/puppeteer-agent-launcher.js +183 -45
  23. package/dist/es/puppeteer-agent-launcher.js.map +1 -1
  24. package/dist/es/puppeteer.js +183 -45
  25. package/dist/es/puppeteer.js.map +1 -1
  26. package/dist/es/ui-utils.js.map +1 -1
  27. package/dist/es/utils.js.map +1 -1
  28. package/dist/es/yaml.js +21 -3
  29. package/dist/es/yaml.js.map +1 -1
  30. package/dist/lib/agent.js +167 -44
  31. package/dist/lib/agent.js.map +1 -1
  32. package/dist/lib/bridge-mode-browser.js +64 -17
  33. package/dist/lib/bridge-mode-browser.js.map +1 -1
  34. package/dist/lib/bridge-mode.js +169 -46
  35. package/dist/lib/bridge-mode.js.map +1 -1
  36. package/dist/lib/chrome-extension.js +229 -59
  37. package/dist/lib/chrome-extension.js.map +1 -1
  38. package/dist/lib/index.js +181 -46
  39. package/dist/lib/index.js.map +1 -1
  40. package/dist/lib/midscene-playground.js +173 -44
  41. package/dist/lib/midscene-playground.js.map +1 -1
  42. package/dist/lib/midscene-server.js.map +1 -1
  43. package/dist/lib/playground.js +173 -44
  44. package/dist/lib/playground.js.map +1 -1
  45. package/dist/lib/playwright-report.js.map +1 -1
  46. package/dist/lib/playwright.js +181 -46
  47. package/dist/lib/playwright.js.map +1 -1
  48. package/dist/lib/puppeteer-agent-launcher.js +181 -46
  49. package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
  50. package/dist/lib/puppeteer.js +181 -46
  51. package/dist/lib/puppeteer.js.map +1 -1
  52. package/dist/lib/ui-utils.js.map +1 -1
  53. package/dist/lib/utils.js.map +1 -1
  54. package/dist/lib/yaml.js +21 -3
  55. package/dist/lib/yaml.js.map +1 -1
  56. package/dist/types/agent.d.ts +16 -6
  57. package/dist/types/bridge-mode-browser.d.ts +2 -2
  58. package/dist/types/bridge-mode.d.ts +2 -2
  59. package/dist/types/{browser-d447695b.d.ts → browser-a1877d18.d.ts} +1 -1
  60. package/dist/types/chrome-extension.d.ts +2 -2
  61. package/dist/types/index.d.ts +1 -1
  62. package/dist/types/midscene-server.d.ts +1 -1
  63. package/dist/types/{page-b8ada1f3.d.ts → page-663ece08.d.ts} +41 -30
  64. package/dist/types/playground.d.ts +2 -2
  65. package/dist/types/playwright.d.ts +1 -1
  66. package/dist/types/puppeteer-agent-launcher.d.ts +1 -1
  67. package/dist/types/puppeteer.d.ts +1 -1
  68. package/dist/types/utils.d.ts +1 -1
  69. package/dist/types/yaml.d.ts +1 -1
  70. package/iife-script/htmlElement.js +99 -37
  71. package/iife-script/htmlElementDebug.js +92 -9
  72. package/package.json +23 -24
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Bytedance, Inc. and its affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- ## Documentation
2
-
3
- Automate UI actions, extract data, and perform assertions using AI. It offers JavaScript SDK, Chrome extension, and support for scripting in YAML.
4
-
5
- See https://midscenejs.com/ for details.
6
-
7
- ## License
8
-
1
+ ## Documentation
2
+
3
+ Automate UI actions, extract data, and perform assertions using AI. It offers JavaScript SDK, Chrome extension, and support for scripting in YAML.
4
+
5
+ See https://midscenejs.com/ for details.
6
+
7
+ ## License
8
+
9
9
  Midscene is MIT licensed.
@@ -1,3 +1,3 @@
1
- #!/usr/bin/env node
2
-
1
+ #!/usr/bin/env node
2
+
3
3
  require('../dist/lib/midscene-playground.js');
package/dist/es/agent.js CHANGED
@@ -88,7 +88,9 @@ var ScriptPlayer = class {
88
88
  typeof prompt === "string",
89
89
  "prompt for aiAction must be a string"
90
90
  );
91
- await agent.aiAction(prompt);
91
+ await agent.aiAction(prompt, {
92
+ cacheable: actionTask.cacheable
93
+ });
92
94
  } else if ("aiAssert" in flowItem) {
93
95
  const assertTask = flowItem;
94
96
  const prompt = assertTask.aiAssert;
@@ -290,8 +292,24 @@ function interpolateEnvVars(content) {
290
292
  });
291
293
  }
292
294
  function parseYamlScript(content, filePath, ignoreCheckingTarget) {
293
- const interpolatedContent = interpolateEnvVars(content);
294
- const obj = yaml2.load(interpolatedContent);
295
+ let processedContent = content;
296
+ if (content.indexOf("android") !== -1 && content.match(/deviceId:\s*(\d+)/)) {
297
+ let matchedDeviceId;
298
+ processedContent = content.replace(
299
+ /deviceId:\s*(\d+)/g,
300
+ (match, deviceId) => {
301
+ matchedDeviceId = deviceId;
302
+ return `deviceId: '${deviceId}'`;
303
+ }
304
+ );
305
+ console.warn(
306
+ `please use string-style deviceId in yaml script, for example: deviceId: "${matchedDeviceId}"`
307
+ );
308
+ }
309
+ const interpolatedContent = interpolateEnvVars(processedContent);
310
+ const obj = yaml2.load(interpolatedContent, {
311
+ schema: yaml2.JSON_SCHEMA
312
+ });
295
313
  const pathTip = filePath ? `, failed to load ${filePath}` : "";
296
314
  const android = typeof obj.android !== "undefined" ? Object.assign({}, obj.android || {}) : void 0;
297
315
  const webConfig = obj.web || obj.target;
@@ -347,7 +365,6 @@ import {
347
365
  } from "misoai-core/ai-model";
348
366
  import { sleep } from "misoai-core/utils";
349
367
  import { NodeType } from "misoai-shared/constants";
350
- import { getElementInfosScriptContent } from "misoai-shared/fs";
351
368
  import { getDebug } from "misoai-shared/logger";
352
369
  import { assert as assert4 } from "misoai-shared/utils";
353
370
 
@@ -584,16 +601,18 @@ var PageTaskExecutor = class {
584
601
  );
585
602
  if (info?.id) {
586
603
  elementId = info.id;
604
+ } else {
605
+ debug(
606
+ "no element id found for position node, will not update cache",
607
+ element
608
+ );
587
609
  }
588
610
  }
589
611
  if (!elementId) {
590
612
  return void 0;
591
613
  }
592
614
  try {
593
- const elementInfosScriptContent = getElementInfosScriptContent();
594
- const result = await this.page.evaluateJavaScript?.(
595
- `${elementInfosScriptContent}midscene_element_inspector.getXpathsById('${elementId}')`
596
- );
615
+ const result = await this.page.getXpathsById(elementId);
597
616
  return result;
598
617
  } catch (error) {
599
618
  debug("getXpathsById error: ", error);
@@ -632,7 +651,7 @@ var PageTaskExecutor = class {
632
651
  };
633
652
  return taskWithScreenshot;
634
653
  }
635
- async convertPlanToExecutable(plans) {
654
+ async convertPlanToExecutable(plans, opts) {
636
655
  const tasks = [];
637
656
  plans.forEach((plan2) => {
638
657
  if (plan2.type === "Locate") {
@@ -642,7 +661,10 @@ var PageTaskExecutor = class {
642
661
  const taskFind = {
643
662
  type: "Insight",
644
663
  subType: "Locate",
645
- param: plan2.locate || void 0,
664
+ param: plan2.locate ? {
665
+ ...plan2.locate,
666
+ cacheable: opts?.cacheable
667
+ } : void 0,
646
668
  thought: plan2.thought,
647
669
  locate: plan2.locate,
648
670
  executor: async (param, taskContext) => {
@@ -679,19 +701,21 @@ var PageTaskExecutor = class {
679
701
  let elementFromCache = null;
680
702
  try {
681
703
  if (xpaths?.length && this.taskCache?.isCacheResultUsed && param?.cacheable !== false) {
682
- const elementInfosScriptContent = getElementInfosScriptContent();
683
- const element2 = await this.page.evaluateJavaScript?.(
684
- `${elementInfosScriptContent}midscene_element_inspector.getElementInfoByXpath('${xpaths[0]}')`
685
- );
686
- if (element2?.id) {
687
- elementFromCache = element2;
688
- debug("cache hit, prompt: %s", cachePrompt);
689
- cacheHitFlag = true;
690
- debug(
691
- "found a new new element with same xpath, xpath: %s, id: %s",
692
- xpaths[0],
693
- element2?.id
704
+ for (let i = 0; i < xpaths.length; i++) {
705
+ const element2 = await this.page.getElementInfoByXpath(
706
+ xpaths[i]
694
707
  );
708
+ if (element2?.id) {
709
+ elementFromCache = element2;
710
+ debug("cache hit, prompt: %s", cachePrompt);
711
+ cacheHitFlag = true;
712
+ debug(
713
+ "found a new new element with same xpath, xpath: %s, id: %s",
714
+ xpaths[i],
715
+ element2?.id
716
+ );
717
+ break;
718
+ }
695
719
  }
696
720
  }
697
721
  } catch (error) {
@@ -704,12 +728,14 @@ var PageTaskExecutor = class {
704
728
  context: pageContext
705
729
  })).element;
706
730
  const aiCost = Date.now() - startTime;
731
+ let currentXpaths;
707
732
  if (element && this.taskCache && !cacheHitFlag && param?.cacheable !== false) {
708
733
  const elementXpaths = await this.getElementXpath(
709
734
  pageContext,
710
735
  element
711
736
  );
712
- if (elementXpaths) {
737
+ if (elementXpaths?.length) {
738
+ currentXpaths = elementXpaths;
713
739
  this.taskCache.updateOrAppendCacheRecord(
714
740
  {
715
741
  type: "locate",
@@ -719,7 +745,11 @@ var PageTaskExecutor = class {
719
745
  locateCacheRecord
720
746
  );
721
747
  } else {
722
- debug("no xpaths found, will not update cache", cachePrompt);
748
+ debug(
749
+ "no xpaths found, will not update cache",
750
+ cachePrompt,
751
+ elementXpaths
752
+ );
723
753
  }
724
754
  }
725
755
  if (!element) {
@@ -731,7 +761,9 @@ var PageTaskExecutor = class {
731
761
  },
732
762
  pageContext,
733
763
  cache: {
734
- hit: cacheHitFlag
764
+ hit: cacheHitFlag,
765
+ originalXpaths: xpaths,
766
+ currentXpaths
735
767
  },
736
768
  aiCost
737
769
  };
@@ -1099,6 +1131,7 @@ var PageTaskExecutor = class {
1099
1131
  sleep: sleep2
1100
1132
  } = planResult;
1101
1133
  executorContext.task.log = {
1134
+ ...executorContext.task.log || {},
1102
1135
  rawResponse
1103
1136
  };
1104
1137
  executorContext.task.usage = usage;
@@ -1223,11 +1256,11 @@ var PageTaskExecutor = class {
1223
1256
  };
1224
1257
  return task;
1225
1258
  }
1226
- async runPlans(title, plans) {
1259
+ async runPlans(title, plans, opts) {
1227
1260
  const taskExecutor = new Executor(title, {
1228
1261
  onTaskStart: this.onTaskStartCallback
1229
1262
  });
1230
- const { tasks } = await this.convertPlanToExecutable(plans);
1263
+ const { tasks } = await this.convertPlanToExecutable(plans, opts);
1231
1264
  await taskExecutor.append(tasks);
1232
1265
  const result = await taskExecutor.flush();
1233
1266
  return {
@@ -1235,7 +1268,7 @@ var PageTaskExecutor = class {
1235
1268
  executor: taskExecutor
1236
1269
  };
1237
1270
  }
1238
- async action(userPrompt, actionContext) {
1271
+ async action(userPrompt, actionContext, opts) {
1239
1272
  const taskExecutor = new Executor(taskTitleStr("Action", userPrompt), {
1240
1273
  onTaskStart: this.onTaskStartCallback
1241
1274
  });
@@ -1260,7 +1293,7 @@ var PageTaskExecutor = class {
1260
1293
  yamlFlow.push(...planResult.yamlFlow || []);
1261
1294
  let executables;
1262
1295
  try {
1263
- executables = await this.convertPlanToExecutable(plans);
1296
+ executables = await this.convertPlanToExecutable(plans, opts);
1264
1297
  taskExecutor.append(executables.tasks);
1265
1298
  } catch (error) {
1266
1299
  return this.appendErrorPlan(
@@ -1298,7 +1331,7 @@ var PageTaskExecutor = class {
1298
1331
  executor: taskExecutor
1299
1332
  };
1300
1333
  }
1301
- async actionToGoal(userPrompt) {
1334
+ async actionToGoal(userPrompt, opts) {
1302
1335
  const taskExecutor = new Executor(taskTitleStr("Action", userPrompt), {
1303
1336
  onTaskStart: this.onTaskStartCallback
1304
1337
  });
@@ -1322,7 +1355,7 @@ var PageTaskExecutor = class {
1322
1355
  yamlFlow.push(...output.yamlFlow || []);
1323
1356
  let executables;
1324
1357
  try {
1325
- executables = await this.convertPlanToExecutable(plans);
1358
+ executables = await this.convertPlanToExecutable(plans, opts);
1326
1359
  taskExecutor.append(executables.tasks);
1327
1360
  } catch (error) {
1328
1361
  return this.appendErrorPlan(
@@ -1627,7 +1660,7 @@ import yaml3 from "js-yaml";
1627
1660
  import semver from "semver";
1628
1661
 
1629
1662
  // package.json
1630
- var version = "1.0.2";
1663
+ var version = "1.0.4";
1631
1664
 
1632
1665
  // src/common/task-cache.ts
1633
1666
  var debug3 = getDebug3("cache");
@@ -1970,9 +2003,9 @@ var PageAgent = class {
1970
2003
  buildDetailedLocateParam(locatePrompt, opt) {
1971
2004
  assert7(locatePrompt, "missing locate prompt");
1972
2005
  if (typeof opt === "object") {
1973
- const prompt = opt.prompt || locatePrompt;
1974
- const deepThink = opt.deepThink || false;
1975
- const cacheable = opt.cacheable || true;
2006
+ const prompt = opt.prompt ?? locatePrompt;
2007
+ const deepThink = opt.deepThink ?? false;
2008
+ const cacheable = opt.cacheable ?? true;
1976
2009
  return {
1977
2010
  prompt,
1978
2011
  deepThink,
@@ -1991,7 +2024,8 @@ var PageAgent = class {
1991
2024
  const plans = buildPlans("Tap", detailedLocateParam);
1992
2025
  const { executor, output } = await this.taskExecutor.runPlans(
1993
2026
  taskTitleStr("Tap", locateParamStr(detailedLocateParam)),
1994
- plans
2027
+ plans,
2028
+ { cacheable: opt?.cacheable }
1995
2029
  );
1996
2030
  const metadata = this.afterTaskRunning(executor);
1997
2031
  return {
@@ -2007,7 +2041,8 @@ var PageAgent = class {
2007
2041
  const plans = buildPlans("Hover", detailedLocateParam);
2008
2042
  const { executor, output } = await this.taskExecutor.runPlans(
2009
2043
  taskTitleStr("Hover", locateParamStr(detailedLocateParam)),
2010
- plans
2044
+ plans,
2045
+ { cacheable: opt?.cacheable }
2011
2046
  );
2012
2047
  const metadata = this.afterTaskRunning(executor);
2013
2048
  return {
@@ -2030,7 +2065,8 @@ var PageAgent = class {
2030
2065
  });
2031
2066
  const { executor, output } = await this.taskExecutor.runPlans(
2032
2067
  taskTitleStr("Input", locateParamStr(detailedLocateParam)),
2033
- plans
2068
+ plans,
2069
+ { cacheable: opt?.cacheable }
2034
2070
  );
2035
2071
  const metadata = this.afterTaskRunning(executor);
2036
2072
  return {
@@ -2046,7 +2082,8 @@ var PageAgent = class {
2046
2082
  });
2047
2083
  const { executor, output } = await this.taskExecutor.runPlans(
2048
2084
  taskTitleStr("KeyboardPress", locateParamStr(detailedLocateParam)),
2049
- plans
2085
+ plans,
2086
+ { cacheable: opt?.cacheable }
2050
2087
  );
2051
2088
  const metadata = this.afterTaskRunning(executor);
2052
2089
  return {
@@ -2060,7 +2097,8 @@ var PageAgent = class {
2060
2097
  const paramInTitle = locatePrompt ? `${locateParamStr(detailedLocateParam)} - ${scrollParamStr(scrollParam)}` : scrollParamStr(scrollParam);
2061
2098
  const { executor, output } = await this.taskExecutor.runPlans(
2062
2099
  taskTitleStr("Scroll", paramInTitle),
2063
- plans
2100
+ plans,
2101
+ { cacheable: opt?.cacheable }
2064
2102
  );
2065
2103
  const metadata = this.afterTaskRunning(executor);
2066
2104
  return {
@@ -2069,6 +2107,19 @@ var PageAgent = class {
2069
2107
  };
2070
2108
  }
2071
2109
  async aiAction(taskPrompt, opt) {
2110
+ try {
2111
+ const aiModel = await import("misoai-core/ai-model");
2112
+ const contextStore = aiModel.getContextStore();
2113
+ const processedPrompt = contextStore.replaceAllReferences(taskPrompt, "action");
2114
+ contextStore.addStep({
2115
+ type: "action",
2116
+ summary: `Action: ${processedPrompt}`,
2117
+ prompt: processedPrompt
2118
+ });
2119
+ taskPrompt = processedPrompt;
2120
+ } catch (error) {
2121
+ debug4("Context store not available:", error);
2122
+ }
2072
2123
  const cacheable = opt?.cacheable;
2073
2124
  const isVlmUiTars = vlLocateMode() === "vlm-ui-tars";
2074
2125
  const matchedCache = isVlmUiTars || cacheable === false ? void 0 : this.taskCache?.matchPlanCache(taskPrompt);
@@ -2086,7 +2137,9 @@ var PageAgent = class {
2086
2137
  metadata: metadata2
2087
2138
  };
2088
2139
  }
2089
- const { output, executor } = await (isVlmUiTars ? this.taskExecutor.actionToGoal(taskPrompt) : this.taskExecutor.action(taskPrompt, this.opts.aiActionContext));
2140
+ const { output, executor } = await (isVlmUiTars ? this.taskExecutor.actionToGoal(taskPrompt, { cacheable }) : this.taskExecutor.action(taskPrompt, this.opts.aiActionContext, {
2141
+ cacheable
2142
+ }));
2090
2143
  if (this.taskCache && output?.yamlFlow && cacheable !== false) {
2091
2144
  const yamlContent = {
2092
2145
  tasks: [
@@ -2113,7 +2166,63 @@ var PageAgent = class {
2113
2166
  };
2114
2167
  }
2115
2168
  async aiQuery(demand) {
2116
- const { output, executor } = await this.taskExecutor.query(demand);
2169
+ let processedDemand = demand;
2170
+ let storageKey;
2171
+ try {
2172
+ const aiModel = await import("misoai-core/ai-model");
2173
+ const contextStore = aiModel.getContextStore();
2174
+ if (typeof demand === "string") {
2175
+ const storageInstruction = contextStore.parseStorageInstruction(demand);
2176
+ if (storageInstruction) {
2177
+ storageKey = storageInstruction.key;
2178
+ processedDemand = storageInstruction.cleanText;
2179
+ contextStore._pendingAliases = storageInstruction.aliases;
2180
+ } else {
2181
+ const storageMatch = demand.match(/store\s+(?:as\s+)?(\w+)/i);
2182
+ if (storageMatch) {
2183
+ storageKey = storageMatch[1];
2184
+ processedDemand = demand.replace(/,?\s*store\s+(?:as\s+)?\w+/i, "").trim();
2185
+ }
2186
+ }
2187
+ }
2188
+ } catch (error) {
2189
+ debug4("Context store not available:", error);
2190
+ }
2191
+ const { output, executor } = await this.taskExecutor.query(processedDemand);
2192
+ if (storageKey && output) {
2193
+ try {
2194
+ const aiModel = await import("misoai-core/ai-model");
2195
+ const contextStore = aiModel.getContextStore();
2196
+ const pendingAliases = contextStore._pendingAliases;
2197
+ if (pendingAliases) {
2198
+ contextStore.storeDataWithAliases(storageKey, output, pendingAliases, typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand));
2199
+ delete contextStore._pendingAliases;
2200
+ } else {
2201
+ contextStore.storeData(storageKey, output);
2202
+ }
2203
+ contextStore.addStep({
2204
+ type: "query",
2205
+ summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)} (stored as ${storageKey})`,
2206
+ data: output,
2207
+ prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
2208
+ });
2209
+ } catch (error) {
2210
+ debug4("Failed to store query result:", error);
2211
+ }
2212
+ } else {
2213
+ try {
2214
+ const aiModel = await import("misoai-core/ai-model");
2215
+ const contextStore = aiModel.getContextStore();
2216
+ contextStore.addStep({
2217
+ type: "query",
2218
+ summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)}`,
2219
+ data: output,
2220
+ prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
2221
+ });
2222
+ } catch (error) {
2223
+ debug4("Failed to add query step:", error);
2224
+ }
2225
+ }
2117
2226
  const metadata = this.afterTaskRunning(executor);
2118
2227
  return {
2119
2228
  result: output,
@@ -2208,7 +2317,8 @@ var PageAgent = class {
2208
2317
  const plans = buildPlans("Locate", detailedLocateParam);
2209
2318
  const { executor, output } = await this.taskExecutor.runPlans(
2210
2319
  taskTitleStr("Locate", locateParamStr(detailedLocateParam)),
2211
- plans
2320
+ plans,
2321
+ { cacheable: opt?.cacheable }
2212
2322
  );
2213
2323
  const metadata = this.afterTaskRunning(executor);
2214
2324
  const { element } = output;
@@ -2222,6 +2332,19 @@ var PageAgent = class {
2222
2332
  };
2223
2333
  }
2224
2334
  async aiAssert(assertion, msg, opt) {
2335
+ let processedAssertion = assertion;
2336
+ try {
2337
+ const aiModel = await import("misoai-core/ai-model");
2338
+ const contextStore = aiModel.getContextStore();
2339
+ processedAssertion = contextStore.replaceAllReferences(assertion, "assertion");
2340
+ contextStore.addStep({
2341
+ type: "assertion",
2342
+ summary: `Assertion: ${processedAssertion}`,
2343
+ prompt: processedAssertion
2344
+ });
2345
+ } catch (error) {
2346
+ debug4("Context store not available:", error);
2347
+ }
2225
2348
  let currentUrl = "";
2226
2349
  if (this.page.url) {
2227
2350
  try {
@@ -2229,7 +2352,7 @@ var PageAgent = class {
2229
2352
  } catch (e) {
2230
2353
  }
2231
2354
  }
2232
- const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
2355
+ const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${processedAssertion}` : processedAssertion;
2233
2356
  const { output, executor } = await this.taskExecutor.assert(assertionWithContext);
2234
2357
  const metadata = this.afterTaskRunning(executor, true);
2235
2358
  if (output && opt?.keepRawResponse) {