misoai-web 1.0.4 → 1.0.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.
- package/LICENSE +21 -21
- package/README.md +353 -9
- package/bin/midscene-playground +2 -2
- package/dist/es/agent.js +378 -92
- package/dist/es/agent.js.map +1 -1
- package/dist/es/bridge-mode-browser.js +3 -3
- package/dist/es/bridge-mode-browser.js.map +1 -1
- package/dist/es/bridge-mode.js +380 -94
- package/dist/es/bridge-mode.js.map +1 -1
- package/dist/es/chrome-extension.js +379 -93
- package/dist/es/chrome-extension.js.map +1 -1
- package/dist/es/index.js +378 -92
- package/dist/es/index.js.map +1 -1
- package/dist/es/midscene-playground.js +378 -92
- package/dist/es/midscene-playground.js.map +1 -1
- package/dist/es/midscene-server.js.map +1 -1
- package/dist/es/playground.js +378 -92
- package/dist/es/playground.js.map +1 -1
- package/dist/es/playwright-report.js.map +1 -1
- package/dist/es/playwright.js +378 -92
- package/dist/es/playwright.js.map +1 -1
- package/dist/es/puppeteer-agent-launcher.js +378 -92
- package/dist/es/puppeteer-agent-launcher.js.map +1 -1
- package/dist/es/puppeteer.js +378 -92
- package/dist/es/puppeteer.js.map +1 -1
- package/dist/es/ui-utils.js.map +1 -1
- package/dist/es/utils.js.map +1 -1
- package/dist/es/yaml.js.map +1 -1
- package/dist/lib/agent.js +378 -92
- package/dist/lib/agent.js.map +1 -1
- package/dist/lib/bridge-mode-browser.js +3 -3
- package/dist/lib/bridge-mode-browser.js.map +1 -1
- package/dist/lib/bridge-mode.js +380 -94
- package/dist/lib/bridge-mode.js.map +1 -1
- package/dist/lib/chrome-extension.js +379 -93
- package/dist/lib/chrome-extension.js.map +1 -1
- package/dist/lib/index.js +378 -92
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/midscene-playground.js +378 -92
- package/dist/lib/midscene-playground.js.map +1 -1
- package/dist/lib/midscene-server.js.map +1 -1
- package/dist/lib/playground.js +378 -92
- package/dist/lib/playground.js.map +1 -1
- package/dist/lib/playwright-report.js.map +1 -1
- package/dist/lib/playwright.js +378 -92
- package/dist/lib/playwright.js.map +1 -1
- package/dist/lib/puppeteer-agent-launcher.js +378 -92
- package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
- package/dist/lib/puppeteer.js +378 -92
- package/dist/lib/puppeteer.js.map +1 -1
- package/dist/lib/ui-utils.js.map +1 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/yaml.js.map +1 -1
- package/dist/types/agent.d.ts +45 -4
- package/dist/types/bridge-mode-browser.d.ts +2 -2
- package/dist/types/bridge-mode.d.ts +2 -2
- package/dist/types/{browser-a1877d18.d.ts → browser-aec1055d.d.ts} +1 -1
- package/dist/types/chrome-extension.d.ts +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/midscene-server.d.ts +1 -1
- package/dist/types/{page-663ece08.d.ts → page-86ab0fe1.d.ts} +34 -34
- package/dist/types/playground.d.ts +2 -2
- package/dist/types/playwright.d.ts +1 -1
- package/dist/types/puppeteer-agent-launcher.d.ts +1 -1
- package/dist/types/puppeteer.d.ts +1 -1
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/yaml.d.ts +1 -1
- package/package.json +3 -3
package/dist/lib/puppeteer.js
CHANGED
@@ -1706,7 +1706,7 @@ var import_js_yaml3 = __toESM(require("js-yaml"));
|
|
1706
1706
|
var import_semver = __toESM(require("semver"));
|
1707
1707
|
|
1708
1708
|
// package.json
|
1709
|
-
var version = "1.0.
|
1709
|
+
var version = "1.0.5";
|
1710
1710
|
|
1711
1711
|
// src/common/task-cache.ts
|
1712
1712
|
var debug3 = (0, import_logger3.getDebug)("cache");
|
@@ -1734,44 +1734,70 @@ var TaskCache = class {
|
|
1734
1734
|
this.cache = cacheContent;
|
1735
1735
|
this.cacheOriginalLength = this.cache.caches.length;
|
1736
1736
|
}
|
1737
|
-
matchCache(prompt, type) {
|
1737
|
+
matchCache(prompt, type, contextData) {
|
1738
|
+
const contextHash = contextData ? this.generateContextHash(contextData) : void 0;
|
1738
1739
|
for (let i = 0; i < this.cacheOriginalLength; i++) {
|
1739
1740
|
const item = this.cache.caches[i];
|
1740
1741
|
const key = `${type}:${prompt}:${i}`;
|
1741
|
-
if (item.type
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
cacheContent: item,
|
1751
|
-
updateFn: (cb) => {
|
1752
|
-
debug3(
|
1753
|
-
"will call updateFn to update cache, type: %s, prompt: %s, index: %d",
|
1754
|
-
type,
|
1755
|
-
prompt,
|
1756
|
-
i
|
1757
|
-
);
|
1758
|
-
cb(item);
|
1759
|
-
debug3(
|
1760
|
-
"cache updated, will flush to file, type: %s, prompt: %s, index: %d",
|
1761
|
-
type,
|
1762
|
-
prompt,
|
1763
|
-
i
|
1764
|
-
);
|
1765
|
-
this.flushCacheToFile();
|
1742
|
+
if (item.type !== type || item.prompt !== prompt || this.matchedCacheIndices.has(key)) {
|
1743
|
+
continue;
|
1744
|
+
}
|
1745
|
+
if (type === "plan" && item.type === "plan") {
|
1746
|
+
const planItem = item;
|
1747
|
+
if (contextHash && planItem.contextHash) {
|
1748
|
+
if (contextHash !== planItem.contextHash) {
|
1749
|
+
debug3("cache context mismatch, type: %s, prompt: %s, index: %d", type, prompt, i);
|
1750
|
+
continue;
|
1766
1751
|
}
|
1767
|
-
}
|
1752
|
+
} else if (contextHash || planItem.contextHash) {
|
1753
|
+
debug3("cache context availability mismatch, type: %s, prompt: %s, index: %d", type, prompt, i);
|
1754
|
+
continue;
|
1755
|
+
}
|
1768
1756
|
}
|
1757
|
+
this.matchedCacheIndices.add(key);
|
1758
|
+
debug3(
|
1759
|
+
"cache found and marked as used, type: %s, prompt: %s, index: %d, contextMatch: %s",
|
1760
|
+
type,
|
1761
|
+
prompt,
|
1762
|
+
i,
|
1763
|
+
contextHash ? "yes" : "no-context"
|
1764
|
+
);
|
1765
|
+
return {
|
1766
|
+
cacheContent: item,
|
1767
|
+
updateFn: (cb) => {
|
1768
|
+
debug3(
|
1769
|
+
"will call updateFn to update cache, type: %s, prompt: %s, index: %d",
|
1770
|
+
type,
|
1771
|
+
prompt,
|
1772
|
+
i
|
1773
|
+
);
|
1774
|
+
cb(item);
|
1775
|
+
debug3(
|
1776
|
+
"cache updated, will flush to file, type: %s, prompt: %s, index: %d",
|
1777
|
+
type,
|
1778
|
+
prompt,
|
1779
|
+
i
|
1780
|
+
);
|
1781
|
+
this.flushCacheToFile();
|
1782
|
+
}
|
1783
|
+
};
|
1769
1784
|
}
|
1770
|
-
debug3("no unused cache found, type: %s, prompt: %s", type, prompt);
|
1785
|
+
debug3("no unused cache found, type: %s, prompt: %s, contextHash: %s", type, prompt, contextHash);
|
1771
1786
|
return void 0;
|
1772
1787
|
}
|
1773
|
-
|
1774
|
-
|
1788
|
+
generateContextHash(contextData) {
|
1789
|
+
const sortedKeys = Object.keys(contextData).sort();
|
1790
|
+
const stableString = sortedKeys.map((key) => `${key}:${JSON.stringify(contextData[key])}`).join("|");
|
1791
|
+
let hash = 0;
|
1792
|
+
for (let i = 0; i < stableString.length; i++) {
|
1793
|
+
const char = stableString.charCodeAt(i);
|
1794
|
+
hash = (hash << 5) - hash + char;
|
1795
|
+
hash = hash & hash;
|
1796
|
+
}
|
1797
|
+
return hash.toString(36);
|
1798
|
+
}
|
1799
|
+
matchPlanCache(prompt, contextData) {
|
1800
|
+
return this.matchCache(prompt, "plan", contextData);
|
1775
1801
|
}
|
1776
1802
|
matchLocateCache(prompt) {
|
1777
1803
|
return this.matchCache(prompt, "locate");
|
@@ -1847,11 +1873,16 @@ cache file: ${cacheFile}`
|
|
1847
1873
|
);
|
1848
1874
|
}
|
1849
1875
|
}
|
1850
|
-
updateOrAppendCacheRecord(newRecord, cachedRecord) {
|
1876
|
+
updateOrAppendCacheRecord(newRecord, cachedRecord, contextData) {
|
1851
1877
|
if (cachedRecord) {
|
1852
1878
|
if (newRecord.type === "plan") {
|
1853
1879
|
cachedRecord.updateFn((cache) => {
|
1854
|
-
|
1880
|
+
const planCache = cache;
|
1881
|
+
planCache.yamlWorkflow = newRecord.yamlWorkflow;
|
1882
|
+
if (contextData) {
|
1883
|
+
planCache.contextHash = this.generateContextHash(contextData);
|
1884
|
+
planCache.contextData = { ...contextData };
|
1885
|
+
}
|
1855
1886
|
});
|
1856
1887
|
} else {
|
1857
1888
|
cachedRecord.updateFn((cache) => {
|
@@ -1859,6 +1890,11 @@ cache file: ${cacheFile}`
|
|
1859
1890
|
});
|
1860
1891
|
}
|
1861
1892
|
} else {
|
1893
|
+
if (newRecord.type === "plan" && contextData) {
|
1894
|
+
const planRecord = newRecord;
|
1895
|
+
planRecord.contextHash = this.generateContextHash(contextData);
|
1896
|
+
planRecord.contextData = { ...contextData };
|
1897
|
+
}
|
1862
1898
|
this.appendCache(newRecord);
|
1863
1899
|
}
|
1864
1900
|
}
|
@@ -1888,10 +1924,13 @@ var PageAgent = class {
|
|
1888
1924
|
generateReport: true,
|
1889
1925
|
autoPrintReportMsg: true,
|
1890
1926
|
groupName: "Midscene Report",
|
1891
|
-
groupDescription: ""
|
1927
|
+
groupDescription: "",
|
1928
|
+
enableCumulativeContext: true,
|
1929
|
+
autoClearContext: false
|
1892
1930
|
},
|
1893
1931
|
opts || {}
|
1894
1932
|
);
|
1933
|
+
this.initializeContextStore();
|
1895
1934
|
if (this.page.pageType === "puppeteer" || this.page.pageType === "playwright") {
|
1896
1935
|
this.page.waitForNavigationTimeout = this.opts.waitForNavigationTimeout || import_constants2.DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT;
|
1897
1936
|
this.page.waitForNetworkIdleTimeout = this.opts.waitForNetworkIdleTimeout || import_constants2.DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;
|
@@ -1918,6 +1957,69 @@ var PageAgent = class {
|
|
1918
1957
|
opts?.testId || this.page.pageType || "web"
|
1919
1958
|
);
|
1920
1959
|
}
|
1960
|
+
/**
|
1961
|
+
* Initialize context store for cumulative context functionality
|
1962
|
+
*/
|
1963
|
+
async initializeContextStore() {
|
1964
|
+
if (!this.opts.enableCumulativeContext) {
|
1965
|
+
debug4("Cumulative context disabled via options");
|
1966
|
+
return;
|
1967
|
+
}
|
1968
|
+
try {
|
1969
|
+
const aiModel = await import("misoai-core/ai-model");
|
1970
|
+
this.contextStore = aiModel.getContextStore();
|
1971
|
+
debug4("Context store initialized successfully", {
|
1972
|
+
autoClearContext: this.opts.autoClearContext,
|
1973
|
+
testId: this.opts.testId
|
1974
|
+
});
|
1975
|
+
if (this.opts.autoClearContext) {
|
1976
|
+
this.contextStore.clear();
|
1977
|
+
debug4("Context store cleared due to autoClearContext option");
|
1978
|
+
} else {
|
1979
|
+
const existingData = this.contextStore.getAllData();
|
1980
|
+
const existingSteps = this.contextStore.getRecentSteps(100).length;
|
1981
|
+
debug4("Context store preserving existing data", {
|
1982
|
+
existingDataKeys: Object.keys(existingData),
|
1983
|
+
existingStepsCount: existingSteps
|
1984
|
+
});
|
1985
|
+
}
|
1986
|
+
} catch (error) {
|
1987
|
+
debug4("Failed to initialize context store:", error);
|
1988
|
+
console.warn("⚠️ Could not initialize context store:", error);
|
1989
|
+
}
|
1990
|
+
}
|
1991
|
+
/**
|
1992
|
+
* Get the context store instance
|
1993
|
+
*/
|
1994
|
+
getContextStore() {
|
1995
|
+
return this.contextStore;
|
1996
|
+
}
|
1997
|
+
/**
|
1998
|
+
* Clear the context store
|
1999
|
+
*/
|
2000
|
+
clearContext() {
|
2001
|
+
if (this.contextStore) {
|
2002
|
+
this.contextStore.clear();
|
2003
|
+
}
|
2004
|
+
}
|
2005
|
+
/**
|
2006
|
+
* Get all stored data from context store
|
2007
|
+
*/
|
2008
|
+
getStoredData() {
|
2009
|
+
if (this.contextStore) {
|
2010
|
+
return this.contextStore.getAllData();
|
2011
|
+
}
|
2012
|
+
return {};
|
2013
|
+
}
|
2014
|
+
/**
|
2015
|
+
* Get step summary from context store
|
2016
|
+
*/
|
2017
|
+
getStepSummary() {
|
2018
|
+
if (this.contextStore) {
|
2019
|
+
return this.contextStore.getStepSummary();
|
2020
|
+
}
|
2021
|
+
return "";
|
2022
|
+
}
|
1921
2023
|
async getUIContext(action) {
|
1922
2024
|
if (action && (action === "extract" || action === "assert" || action === "captcha")) {
|
1923
2025
|
return await parseContextFromWebPage(this.page, {
|
@@ -2153,22 +2255,35 @@ var PageAgent = class {
|
|
2153
2255
|
};
|
2154
2256
|
}
|
2155
2257
|
async aiAction(taskPrompt, opt) {
|
2156
|
-
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
|
2161
|
-
|
2162
|
-
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
2166
|
-
|
2167
|
-
|
2258
|
+
const originalPrompt = taskPrompt;
|
2259
|
+
let processedPrompt = taskPrompt;
|
2260
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2261
|
+
try {
|
2262
|
+
const storedData = this.contextStore.getAllData();
|
2263
|
+
if (Object.keys(storedData).length > 0) {
|
2264
|
+
debug4("Available data for aiAction:", {
|
2265
|
+
prompt: taskPrompt,
|
2266
|
+
availableData: storedData
|
2267
|
+
});
|
2268
|
+
}
|
2269
|
+
} catch (error) {
|
2270
|
+
debug4("Context store operation failed:", error);
|
2271
|
+
}
|
2168
2272
|
}
|
2169
2273
|
const cacheable = opt?.cacheable;
|
2170
2274
|
const isVlmUiTars = (0, import_env2.vlLocateMode)() === "vlm-ui-tars";
|
2171
|
-
|
2275
|
+
let contextData;
|
2276
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2277
|
+
try {
|
2278
|
+
contextData = this.contextStore.getAllData();
|
2279
|
+
if (contextData && Object.keys(contextData).length === 0) {
|
2280
|
+
contextData = void 0;
|
2281
|
+
}
|
2282
|
+
} catch (error) {
|
2283
|
+
debug4("Failed to get context data for cache:", error);
|
2284
|
+
}
|
2285
|
+
}
|
2286
|
+
const matchedCache = isVlmUiTars || cacheable === false ? void 0 : this.taskCache?.matchPlanCache(taskPrompt, contextData);
|
2172
2287
|
if (matchedCache && this.taskCache?.isCacheResultUsed) {
|
2173
2288
|
const { executor: executor2 } = await this.taskExecutor.loadYamlFlowAsPlanning(
|
2174
2289
|
taskPrompt,
|
@@ -2178,6 +2293,28 @@ var PageAgent = class {
|
|
2178
2293
|
debug4("matched cache, will call .runYaml to run the action");
|
2179
2294
|
const yaml5 = matchedCache.cacheContent?.yamlWorkflow;
|
2180
2295
|
const result = await this.runYaml(yaml5);
|
2296
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2297
|
+
try {
|
2298
|
+
const executionResult = {
|
2299
|
+
success: true,
|
2300
|
+
actionType: "cached",
|
2301
|
+
description: `Executed cached action: ${processedPrompt}`,
|
2302
|
+
timing: result.metadata?.totalTime
|
2303
|
+
};
|
2304
|
+
this.contextStore.addStep({
|
2305
|
+
type: "action",
|
2306
|
+
summary: `Action: ${processedPrompt} (cached)`,
|
2307
|
+
prompt: processedPrompt,
|
2308
|
+
executionResult
|
2309
|
+
});
|
2310
|
+
debug4("Added cached action step to context store:", {
|
2311
|
+
stepNumber: this.contextStore.getRecentSteps(1)[0]?.stepNumber,
|
2312
|
+
totalSteps: this.contextStore.getRecentSteps(100).length
|
2313
|
+
});
|
2314
|
+
} catch (error) {
|
2315
|
+
debug4("Failed to add cached action step:", error);
|
2316
|
+
}
|
2317
|
+
}
|
2181
2318
|
return {
|
2182
2319
|
result: result.result,
|
2183
2320
|
metadata: metadata2
|
@@ -2202,10 +2339,39 @@ var PageAgent = class {
|
|
2202
2339
|
prompt: taskPrompt,
|
2203
2340
|
yamlWorkflow: yamlFlowStr
|
2204
2341
|
},
|
2205
|
-
matchedCache
|
2342
|
+
matchedCache,
|
2343
|
+
contextData
|
2344
|
+
// Pass context data for cache creation
|
2206
2345
|
);
|
2207
2346
|
}
|
2208
2347
|
const metadata = this.afterTaskRunning(executor);
|
2348
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2349
|
+
try {
|
2350
|
+
const executionResult = this.analyzeExecutionResults(executor, originalPrompt);
|
2351
|
+
this.contextStore.addStep({
|
2352
|
+
type: "action",
|
2353
|
+
summary: `Action: ${processedPrompt}`,
|
2354
|
+
prompt: processedPrompt,
|
2355
|
+
executionResult
|
2356
|
+
});
|
2357
|
+
debug4("Added action step with execution result to context store:", {
|
2358
|
+
stepNumber: this.contextStore.getRecentSteps(1)[0]?.stepNumber,
|
2359
|
+
totalSteps: this.contextStore.getRecentSteps(100).length,
|
2360
|
+
executionResult
|
2361
|
+
});
|
2362
|
+
} catch (error) {
|
2363
|
+
debug4("Failed to analyze execution results, adding step without execution result:", error);
|
2364
|
+
try {
|
2365
|
+
this.contextStore.addStep({
|
2366
|
+
type: "action",
|
2367
|
+
summary: `Action: ${processedPrompt}`,
|
2368
|
+
prompt: processedPrompt
|
2369
|
+
});
|
2370
|
+
} catch (stepError) {
|
2371
|
+
debug4("Failed to add action step:", stepError);
|
2372
|
+
}
|
2373
|
+
}
|
2374
|
+
}
|
2209
2375
|
return {
|
2210
2376
|
result: output,
|
2211
2377
|
metadata
|
@@ -2235,38 +2401,50 @@ var PageAgent = class {
|
|
2235
2401
|
debug4("Context store not available:", error);
|
2236
2402
|
}
|
2237
2403
|
const { output, executor } = await this.taskExecutor.query(processedDemand);
|
2238
|
-
if (
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2246
|
-
|
2247
|
-
|
2404
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2405
|
+
if (storageKey && output) {
|
2406
|
+
try {
|
2407
|
+
const pendingAliases = this.contextStore._pendingAliases;
|
2408
|
+
if (pendingAliases) {
|
2409
|
+
this.contextStore.storeDataWithAliases(storageKey, output, pendingAliases, typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand));
|
2410
|
+
delete this.contextStore._pendingAliases;
|
2411
|
+
debug4("Stored query result with aliases:", {
|
2412
|
+
key: storageKey,
|
2413
|
+
value: output,
|
2414
|
+
aliases: pendingAliases
|
2415
|
+
});
|
2416
|
+
} else {
|
2417
|
+
this.contextStore.storeData(storageKey, output);
|
2418
|
+
debug4("Stored query result:", {
|
2419
|
+
key: storageKey,
|
2420
|
+
value: output
|
2421
|
+
});
|
2422
|
+
}
|
2423
|
+
this.contextStore.addStep({
|
2424
|
+
type: "query",
|
2425
|
+
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)} (stored as ${storageKey})`,
|
2426
|
+
data: output,
|
2427
|
+
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2428
|
+
});
|
2429
|
+
debug4("Added query step to context store:", {
|
2430
|
+
storageKey,
|
2431
|
+
totalStoredItems: Object.keys(this.contextStore.getAllData()).length,
|
2432
|
+
totalSteps: this.contextStore.getRecentSteps(100).length
|
2433
|
+
});
|
2434
|
+
} catch (error) {
|
2435
|
+
debug4("Failed to store query result:", error);
|
2436
|
+
}
|
2437
|
+
} else {
|
2438
|
+
try {
|
2439
|
+
this.contextStore.addStep({
|
2440
|
+
type: "query",
|
2441
|
+
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)}`,
|
2442
|
+
data: output,
|
2443
|
+
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2444
|
+
});
|
2445
|
+
} catch (error) {
|
2446
|
+
debug4("Failed to add query step:", error);
|
2248
2447
|
}
|
2249
|
-
contextStore.addStep({
|
2250
|
-
type: "query",
|
2251
|
-
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)} (stored as ${storageKey})`,
|
2252
|
-
data: output,
|
2253
|
-
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2254
|
-
});
|
2255
|
-
} catch (error) {
|
2256
|
-
debug4("Failed to store query result:", error);
|
2257
|
-
}
|
2258
|
-
} else {
|
2259
|
-
try {
|
2260
|
-
const aiModel = await import("misoai-core/ai-model");
|
2261
|
-
const contextStore = aiModel.getContextStore();
|
2262
|
-
contextStore.addStep({
|
2263
|
-
type: "query",
|
2264
|
-
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)}`,
|
2265
|
-
data: output,
|
2266
|
-
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2267
|
-
});
|
2268
|
-
} catch (error) {
|
2269
|
-
debug4("Failed to add query step:", error);
|
2270
2448
|
}
|
2271
2449
|
}
|
2272
2450
|
const metadata = this.afterTaskRunning(executor);
|
@@ -2378,18 +2556,47 @@ var PageAgent = class {
|
|
2378
2556
|
};
|
2379
2557
|
}
|
2380
2558
|
async aiAssert(assertion, msg, opt) {
|
2381
|
-
let
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
2386
|
-
|
2387
|
-
|
2388
|
-
|
2389
|
-
|
2390
|
-
|
2391
|
-
|
2392
|
-
|
2559
|
+
let executionContext = "";
|
2560
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2561
|
+
try {
|
2562
|
+
const recentSteps = this.contextStore.getRecentSteps(3);
|
2563
|
+
const stepsWithExecutionResults = recentSteps.filter((step) => step.executionResult);
|
2564
|
+
const storedData = this.contextStore.getAllData();
|
2565
|
+
if (stepsWithExecutionResults.length > 0) {
|
2566
|
+
const recentActions = stepsWithExecutionResults.map((step) => {
|
2567
|
+
const result = step.executionResult;
|
2568
|
+
return `- ${result.description}${result.success ? "" : " (FAILED)"}`;
|
2569
|
+
}).join("\n");
|
2570
|
+
executionContext = `
|
2571
|
+
|
2572
|
+
Recent actions performed:
|
2573
|
+
${recentActions}
|
2574
|
+
|
2575
|
+
This context may help verify the assertion.`;
|
2576
|
+
}
|
2577
|
+
if (storedData && Object.keys(storedData).length > 0) {
|
2578
|
+
executionContext += `
|
2579
|
+
|
2580
|
+
Available data for reference:
|
2581
|
+
${JSON.stringify(storedData, null, 2)}
|
2582
|
+
|
2583
|
+
Note: If the assertion references any data keys or natural language equivalents, consider the stored values when verifying.`;
|
2584
|
+
debug4("Available data for aiAssert:", {
|
2585
|
+
assertion,
|
2586
|
+
availableData: storedData
|
2587
|
+
});
|
2588
|
+
}
|
2589
|
+
this.contextStore.addStep({
|
2590
|
+
type: "assertion",
|
2591
|
+
summary: `Assertion: ${assertion}`,
|
2592
|
+
prompt: assertion
|
2593
|
+
});
|
2594
|
+
debug4("Added assertion step to context store:", {
|
2595
|
+
totalSteps: this.contextStore.getRecentSteps(100).length
|
2596
|
+
});
|
2597
|
+
} catch (error) {
|
2598
|
+
debug4("Context store operation failed:", error);
|
2599
|
+
}
|
2393
2600
|
}
|
2394
2601
|
let currentUrl = "";
|
2395
2602
|
if (this.page.url) {
|
@@ -2398,7 +2605,13 @@ var PageAgent = class {
|
|
2398
2605
|
} catch (e) {
|
2399
2606
|
}
|
2400
2607
|
}
|
2401
|
-
|
2608
|
+
let assertionWithContext = assertion;
|
2609
|
+
if (currentUrl) {
|
2610
|
+
assertionWithContext = `For the page at URL "${currentUrl}", ${assertion}`;
|
2611
|
+
}
|
2612
|
+
if (executionContext) {
|
2613
|
+
assertionWithContext += executionContext;
|
2614
|
+
}
|
2402
2615
|
const { output, executor } = await this.taskExecutor.assert(assertionWithContext);
|
2403
2616
|
const metadata = this.afterTaskRunning(executor, true);
|
2404
2617
|
if (output && opt?.keepRawResponse) {
|
@@ -2612,6 +2825,79 @@ ${errors}`);
|
|
2612
2825
|
async destroy() {
|
2613
2826
|
await this.page.destroy();
|
2614
2827
|
}
|
2828
|
+
/**
|
2829
|
+
* Analyze execution results from executor to generate meaningful descriptions
|
2830
|
+
*/
|
2831
|
+
analyzeExecutionResults(executor, originalPrompt) {
|
2832
|
+
const tasks = executor.tasks;
|
2833
|
+
const success = !executor.isInErrorState();
|
2834
|
+
if (!success) {
|
2835
|
+
const errorTask = executor.latestErrorTask();
|
2836
|
+
return {
|
2837
|
+
success: false,
|
2838
|
+
actionType: "error",
|
2839
|
+
description: `Failed to execute: ${originalPrompt}`,
|
2840
|
+
error: errorTask?.error
|
2841
|
+
};
|
2842
|
+
}
|
2843
|
+
const actionTasks = tasks.filter((t) => t.type === "Action" && t.status === "finished");
|
2844
|
+
const locateTasks = tasks.filter((t) => t.type === "Insight" && t.subType === "Locate");
|
2845
|
+
const lastAction = actionTasks[actionTasks.length - 1];
|
2846
|
+
const lastLocate = locateTasks[locateTasks.length - 1];
|
2847
|
+
if (!lastAction) {
|
2848
|
+
return {
|
2849
|
+
success: true,
|
2850
|
+
actionType: "unknown",
|
2851
|
+
description: `Completed: ${originalPrompt}`
|
2852
|
+
};
|
2853
|
+
}
|
2854
|
+
const actionType = lastAction.subType || "unknown";
|
2855
|
+
const elementInfo = this.extractElementInfo(lastLocate, lastAction);
|
2856
|
+
const description = this.generateActionDescription(actionType, lastAction.param, elementInfo);
|
2857
|
+
return {
|
2858
|
+
success: true,
|
2859
|
+
actionType,
|
2860
|
+
description,
|
2861
|
+
elementInfo,
|
2862
|
+
timing: lastAction.timing?.cost
|
2863
|
+
};
|
2864
|
+
}
|
2865
|
+
/**
|
2866
|
+
* Extract element information from locate task
|
2867
|
+
*/
|
2868
|
+
extractElementInfo(locateTask, _actionTask) {
|
2869
|
+
if (!locateTask?.output?.element)
|
2870
|
+
return void 0;
|
2871
|
+
const element = locateTask.output.element;
|
2872
|
+
return {
|
2873
|
+
type: element.attributes?.nodeType || "unknown",
|
2874
|
+
text: element.content || element.attributes?.placeholder || element.attributes?.title || "",
|
2875
|
+
location: `(${element.center[0]}, ${element.center[1]})`
|
2876
|
+
};
|
2877
|
+
}
|
2878
|
+
/**
|
2879
|
+
* Generate natural language description for actions
|
2880
|
+
*/
|
2881
|
+
generateActionDescription(actionType, param, elementInfo) {
|
2882
|
+
const elementDesc = elementInfo ? `'${elementInfo.text || elementInfo.type}' element` : "element";
|
2883
|
+
switch (actionType) {
|
2884
|
+
case "Tap":
|
2885
|
+
return `Clicked on ${elementDesc}`;
|
2886
|
+
case "Input":
|
2887
|
+
const inputValue = param?.value || "";
|
2888
|
+
return `Entered "${inputValue}" into ${elementDesc}`;
|
2889
|
+
case "KeyboardPress":
|
2890
|
+
return `Pressed ${param?.value || "key"}`;
|
2891
|
+
case "Scroll":
|
2892
|
+
return `Scrolled ${param?.direction || "on page"}`;
|
2893
|
+
case "Hover":
|
2894
|
+
return `Hovered over ${elementDesc}`;
|
2895
|
+
case "Drag":
|
2896
|
+
return `Dragged ${elementDesc}`;
|
2897
|
+
default:
|
2898
|
+
return `Performed ${actionType} action on ${elementDesc}`;
|
2899
|
+
}
|
2900
|
+
}
|
2615
2901
|
};
|
2616
2902
|
|
2617
2903
|
// src/puppeteer/index.ts
|