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/playground.js
CHANGED
@@ -1679,7 +1679,7 @@ var import_js_yaml3 = __toESM(require("js-yaml"));
|
|
1679
1679
|
var import_semver = __toESM(require("semver"));
|
1680
1680
|
|
1681
1681
|
// package.json
|
1682
|
-
var version = "1.0.
|
1682
|
+
var version = "1.0.5";
|
1683
1683
|
|
1684
1684
|
// src/common/task-cache.ts
|
1685
1685
|
var debug3 = (0, import_logger3.getDebug)("cache");
|
@@ -1707,44 +1707,70 @@ var TaskCache = class {
|
|
1707
1707
|
this.cache = cacheContent;
|
1708
1708
|
this.cacheOriginalLength = this.cache.caches.length;
|
1709
1709
|
}
|
1710
|
-
matchCache(prompt, type) {
|
1710
|
+
matchCache(prompt, type, contextData) {
|
1711
|
+
const contextHash = contextData ? this.generateContextHash(contextData) : void 0;
|
1711
1712
|
for (let i = 0; i < this.cacheOriginalLength; i++) {
|
1712
1713
|
const item = this.cache.caches[i];
|
1713
1714
|
const key = `${type}:${prompt}:${i}`;
|
1714
|
-
if (item.type
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
cacheContent: item,
|
1724
|
-
updateFn: (cb) => {
|
1725
|
-
debug3(
|
1726
|
-
"will call updateFn to update cache, type: %s, prompt: %s, index: %d",
|
1727
|
-
type,
|
1728
|
-
prompt,
|
1729
|
-
i
|
1730
|
-
);
|
1731
|
-
cb(item);
|
1732
|
-
debug3(
|
1733
|
-
"cache updated, will flush to file, type: %s, prompt: %s, index: %d",
|
1734
|
-
type,
|
1735
|
-
prompt,
|
1736
|
-
i
|
1737
|
-
);
|
1738
|
-
this.flushCacheToFile();
|
1715
|
+
if (item.type !== type || item.prompt !== prompt || this.matchedCacheIndices.has(key)) {
|
1716
|
+
continue;
|
1717
|
+
}
|
1718
|
+
if (type === "plan" && item.type === "plan") {
|
1719
|
+
const planItem = item;
|
1720
|
+
if (contextHash && planItem.contextHash) {
|
1721
|
+
if (contextHash !== planItem.contextHash) {
|
1722
|
+
debug3("cache context mismatch, type: %s, prompt: %s, index: %d", type, prompt, i);
|
1723
|
+
continue;
|
1739
1724
|
}
|
1740
|
-
}
|
1725
|
+
} else if (contextHash || planItem.contextHash) {
|
1726
|
+
debug3("cache context availability mismatch, type: %s, prompt: %s, index: %d", type, prompt, i);
|
1727
|
+
continue;
|
1728
|
+
}
|
1741
1729
|
}
|
1730
|
+
this.matchedCacheIndices.add(key);
|
1731
|
+
debug3(
|
1732
|
+
"cache found and marked as used, type: %s, prompt: %s, index: %d, contextMatch: %s",
|
1733
|
+
type,
|
1734
|
+
prompt,
|
1735
|
+
i,
|
1736
|
+
contextHash ? "yes" : "no-context"
|
1737
|
+
);
|
1738
|
+
return {
|
1739
|
+
cacheContent: item,
|
1740
|
+
updateFn: (cb) => {
|
1741
|
+
debug3(
|
1742
|
+
"will call updateFn to update cache, type: %s, prompt: %s, index: %d",
|
1743
|
+
type,
|
1744
|
+
prompt,
|
1745
|
+
i
|
1746
|
+
);
|
1747
|
+
cb(item);
|
1748
|
+
debug3(
|
1749
|
+
"cache updated, will flush to file, type: %s, prompt: %s, index: %d",
|
1750
|
+
type,
|
1751
|
+
prompt,
|
1752
|
+
i
|
1753
|
+
);
|
1754
|
+
this.flushCacheToFile();
|
1755
|
+
}
|
1756
|
+
};
|
1742
1757
|
}
|
1743
|
-
debug3("no unused cache found, type: %s, prompt: %s", type, prompt);
|
1758
|
+
debug3("no unused cache found, type: %s, prompt: %s, contextHash: %s", type, prompt, contextHash);
|
1744
1759
|
return void 0;
|
1745
1760
|
}
|
1746
|
-
|
1747
|
-
|
1761
|
+
generateContextHash(contextData) {
|
1762
|
+
const sortedKeys = Object.keys(contextData).sort();
|
1763
|
+
const stableString = sortedKeys.map((key) => `${key}:${JSON.stringify(contextData[key])}`).join("|");
|
1764
|
+
let hash = 0;
|
1765
|
+
for (let i = 0; i < stableString.length; i++) {
|
1766
|
+
const char = stableString.charCodeAt(i);
|
1767
|
+
hash = (hash << 5) - hash + char;
|
1768
|
+
hash = hash & hash;
|
1769
|
+
}
|
1770
|
+
return hash.toString(36);
|
1771
|
+
}
|
1772
|
+
matchPlanCache(prompt, contextData) {
|
1773
|
+
return this.matchCache(prompt, "plan", contextData);
|
1748
1774
|
}
|
1749
1775
|
matchLocateCache(prompt) {
|
1750
1776
|
return this.matchCache(prompt, "locate");
|
@@ -1820,11 +1846,16 @@ cache file: ${cacheFile}`
|
|
1820
1846
|
);
|
1821
1847
|
}
|
1822
1848
|
}
|
1823
|
-
updateOrAppendCacheRecord(newRecord, cachedRecord) {
|
1849
|
+
updateOrAppendCacheRecord(newRecord, cachedRecord, contextData) {
|
1824
1850
|
if (cachedRecord) {
|
1825
1851
|
if (newRecord.type === "plan") {
|
1826
1852
|
cachedRecord.updateFn((cache) => {
|
1827
|
-
|
1853
|
+
const planCache = cache;
|
1854
|
+
planCache.yamlWorkflow = newRecord.yamlWorkflow;
|
1855
|
+
if (contextData) {
|
1856
|
+
planCache.contextHash = this.generateContextHash(contextData);
|
1857
|
+
planCache.contextData = { ...contextData };
|
1858
|
+
}
|
1828
1859
|
});
|
1829
1860
|
} else {
|
1830
1861
|
cachedRecord.updateFn((cache) => {
|
@@ -1832,6 +1863,11 @@ cache file: ${cacheFile}`
|
|
1832
1863
|
});
|
1833
1864
|
}
|
1834
1865
|
} else {
|
1866
|
+
if (newRecord.type === "plan" && contextData) {
|
1867
|
+
const planRecord = newRecord;
|
1868
|
+
planRecord.contextHash = this.generateContextHash(contextData);
|
1869
|
+
planRecord.contextData = { ...contextData };
|
1870
|
+
}
|
1835
1871
|
this.appendCache(newRecord);
|
1836
1872
|
}
|
1837
1873
|
}
|
@@ -1861,10 +1897,13 @@ var PageAgent = class {
|
|
1861
1897
|
generateReport: true,
|
1862
1898
|
autoPrintReportMsg: true,
|
1863
1899
|
groupName: "Midscene Report",
|
1864
|
-
groupDescription: ""
|
1900
|
+
groupDescription: "",
|
1901
|
+
enableCumulativeContext: true,
|
1902
|
+
autoClearContext: false
|
1865
1903
|
},
|
1866
1904
|
opts || {}
|
1867
1905
|
);
|
1906
|
+
this.initializeContextStore();
|
1868
1907
|
if (this.page.pageType === "puppeteer" || this.page.pageType === "playwright") {
|
1869
1908
|
this.page.waitForNavigationTimeout = this.opts.waitForNavigationTimeout || import_constants2.DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT;
|
1870
1909
|
this.page.waitForNetworkIdleTimeout = this.opts.waitForNetworkIdleTimeout || import_constants2.DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;
|
@@ -1891,6 +1930,69 @@ var PageAgent = class {
|
|
1891
1930
|
opts?.testId || this.page.pageType || "web"
|
1892
1931
|
);
|
1893
1932
|
}
|
1933
|
+
/**
|
1934
|
+
* Initialize context store for cumulative context functionality
|
1935
|
+
*/
|
1936
|
+
async initializeContextStore() {
|
1937
|
+
if (!this.opts.enableCumulativeContext) {
|
1938
|
+
debug4("Cumulative context disabled via options");
|
1939
|
+
return;
|
1940
|
+
}
|
1941
|
+
try {
|
1942
|
+
const aiModel = await import("misoai-core/ai-model");
|
1943
|
+
this.contextStore = aiModel.getContextStore();
|
1944
|
+
debug4("Context store initialized successfully", {
|
1945
|
+
autoClearContext: this.opts.autoClearContext,
|
1946
|
+
testId: this.opts.testId
|
1947
|
+
});
|
1948
|
+
if (this.opts.autoClearContext) {
|
1949
|
+
this.contextStore.clear();
|
1950
|
+
debug4("Context store cleared due to autoClearContext option");
|
1951
|
+
} else {
|
1952
|
+
const existingData = this.contextStore.getAllData();
|
1953
|
+
const existingSteps = this.contextStore.getRecentSteps(100).length;
|
1954
|
+
debug4("Context store preserving existing data", {
|
1955
|
+
existingDataKeys: Object.keys(existingData),
|
1956
|
+
existingStepsCount: existingSteps
|
1957
|
+
});
|
1958
|
+
}
|
1959
|
+
} catch (error) {
|
1960
|
+
debug4("Failed to initialize context store:", error);
|
1961
|
+
console.warn("⚠️ Could not initialize context store:", error);
|
1962
|
+
}
|
1963
|
+
}
|
1964
|
+
/**
|
1965
|
+
* Get the context store instance
|
1966
|
+
*/
|
1967
|
+
getContextStore() {
|
1968
|
+
return this.contextStore;
|
1969
|
+
}
|
1970
|
+
/**
|
1971
|
+
* Clear the context store
|
1972
|
+
*/
|
1973
|
+
clearContext() {
|
1974
|
+
if (this.contextStore) {
|
1975
|
+
this.contextStore.clear();
|
1976
|
+
}
|
1977
|
+
}
|
1978
|
+
/**
|
1979
|
+
* Get all stored data from context store
|
1980
|
+
*/
|
1981
|
+
getStoredData() {
|
1982
|
+
if (this.contextStore) {
|
1983
|
+
return this.contextStore.getAllData();
|
1984
|
+
}
|
1985
|
+
return {};
|
1986
|
+
}
|
1987
|
+
/**
|
1988
|
+
* Get step summary from context store
|
1989
|
+
*/
|
1990
|
+
getStepSummary() {
|
1991
|
+
if (this.contextStore) {
|
1992
|
+
return this.contextStore.getStepSummary();
|
1993
|
+
}
|
1994
|
+
return "";
|
1995
|
+
}
|
1894
1996
|
async getUIContext(action) {
|
1895
1997
|
if (action && (action === "extract" || action === "assert" || action === "captcha")) {
|
1896
1998
|
return await parseContextFromWebPage(this.page, {
|
@@ -2126,22 +2228,35 @@ var PageAgent = class {
|
|
2126
2228
|
};
|
2127
2229
|
}
|
2128
2230
|
async aiAction(taskPrompt, opt) {
|
2129
|
-
|
2130
|
-
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2136
|
-
|
2137
|
-
|
2138
|
-
|
2139
|
-
|
2140
|
-
|
2231
|
+
const originalPrompt = taskPrompt;
|
2232
|
+
let processedPrompt = taskPrompt;
|
2233
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2234
|
+
try {
|
2235
|
+
const storedData = this.contextStore.getAllData();
|
2236
|
+
if (Object.keys(storedData).length > 0) {
|
2237
|
+
debug4("Available data for aiAction:", {
|
2238
|
+
prompt: taskPrompt,
|
2239
|
+
availableData: storedData
|
2240
|
+
});
|
2241
|
+
}
|
2242
|
+
} catch (error) {
|
2243
|
+
debug4("Context store operation failed:", error);
|
2244
|
+
}
|
2141
2245
|
}
|
2142
2246
|
const cacheable = opt?.cacheable;
|
2143
2247
|
const isVlmUiTars = (0, import_env2.vlLocateMode)() === "vlm-ui-tars";
|
2144
|
-
|
2248
|
+
let contextData;
|
2249
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2250
|
+
try {
|
2251
|
+
contextData = this.contextStore.getAllData();
|
2252
|
+
if (contextData && Object.keys(contextData).length === 0) {
|
2253
|
+
contextData = void 0;
|
2254
|
+
}
|
2255
|
+
} catch (error) {
|
2256
|
+
debug4("Failed to get context data for cache:", error);
|
2257
|
+
}
|
2258
|
+
}
|
2259
|
+
const matchedCache = isVlmUiTars || cacheable === false ? void 0 : this.taskCache?.matchPlanCache(taskPrompt, contextData);
|
2145
2260
|
if (matchedCache && this.taskCache?.isCacheResultUsed) {
|
2146
2261
|
const { executor: executor2 } = await this.taskExecutor.loadYamlFlowAsPlanning(
|
2147
2262
|
taskPrompt,
|
@@ -2151,6 +2266,28 @@ var PageAgent = class {
|
|
2151
2266
|
debug4("matched cache, will call .runYaml to run the action");
|
2152
2267
|
const yaml5 = matchedCache.cacheContent?.yamlWorkflow;
|
2153
2268
|
const result = await this.runYaml(yaml5);
|
2269
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2270
|
+
try {
|
2271
|
+
const executionResult = {
|
2272
|
+
success: true,
|
2273
|
+
actionType: "cached",
|
2274
|
+
description: `Executed cached action: ${processedPrompt}`,
|
2275
|
+
timing: result.metadata?.totalTime
|
2276
|
+
};
|
2277
|
+
this.contextStore.addStep({
|
2278
|
+
type: "action",
|
2279
|
+
summary: `Action: ${processedPrompt} (cached)`,
|
2280
|
+
prompt: processedPrompt,
|
2281
|
+
executionResult
|
2282
|
+
});
|
2283
|
+
debug4("Added cached action step to context store:", {
|
2284
|
+
stepNumber: this.contextStore.getRecentSteps(1)[0]?.stepNumber,
|
2285
|
+
totalSteps: this.contextStore.getRecentSteps(100).length
|
2286
|
+
});
|
2287
|
+
} catch (error) {
|
2288
|
+
debug4("Failed to add cached action step:", error);
|
2289
|
+
}
|
2290
|
+
}
|
2154
2291
|
return {
|
2155
2292
|
result: result.result,
|
2156
2293
|
metadata: metadata2
|
@@ -2175,10 +2312,39 @@ var PageAgent = class {
|
|
2175
2312
|
prompt: taskPrompt,
|
2176
2313
|
yamlWorkflow: yamlFlowStr
|
2177
2314
|
},
|
2178
|
-
matchedCache
|
2315
|
+
matchedCache,
|
2316
|
+
contextData
|
2317
|
+
// Pass context data for cache creation
|
2179
2318
|
);
|
2180
2319
|
}
|
2181
2320
|
const metadata = this.afterTaskRunning(executor);
|
2321
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2322
|
+
try {
|
2323
|
+
const executionResult = this.analyzeExecutionResults(executor, originalPrompt);
|
2324
|
+
this.contextStore.addStep({
|
2325
|
+
type: "action",
|
2326
|
+
summary: `Action: ${processedPrompt}`,
|
2327
|
+
prompt: processedPrompt,
|
2328
|
+
executionResult
|
2329
|
+
});
|
2330
|
+
debug4("Added action step with execution result to context store:", {
|
2331
|
+
stepNumber: this.contextStore.getRecentSteps(1)[0]?.stepNumber,
|
2332
|
+
totalSteps: this.contextStore.getRecentSteps(100).length,
|
2333
|
+
executionResult
|
2334
|
+
});
|
2335
|
+
} catch (error) {
|
2336
|
+
debug4("Failed to analyze execution results, adding step without execution result:", error);
|
2337
|
+
try {
|
2338
|
+
this.contextStore.addStep({
|
2339
|
+
type: "action",
|
2340
|
+
summary: `Action: ${processedPrompt}`,
|
2341
|
+
prompt: processedPrompt
|
2342
|
+
});
|
2343
|
+
} catch (stepError) {
|
2344
|
+
debug4("Failed to add action step:", stepError);
|
2345
|
+
}
|
2346
|
+
}
|
2347
|
+
}
|
2182
2348
|
return {
|
2183
2349
|
result: output,
|
2184
2350
|
metadata
|
@@ -2208,38 +2374,50 @@ var PageAgent = class {
|
|
2208
2374
|
debug4("Context store not available:", error);
|
2209
2375
|
}
|
2210
2376
|
const { output, executor } = await this.taskExecutor.query(processedDemand);
|
2211
|
-
if (
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2377
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2378
|
+
if (storageKey && output) {
|
2379
|
+
try {
|
2380
|
+
const pendingAliases = this.contextStore._pendingAliases;
|
2381
|
+
if (pendingAliases) {
|
2382
|
+
this.contextStore.storeDataWithAliases(storageKey, output, pendingAliases, typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand));
|
2383
|
+
delete this.contextStore._pendingAliases;
|
2384
|
+
debug4("Stored query result with aliases:", {
|
2385
|
+
key: storageKey,
|
2386
|
+
value: output,
|
2387
|
+
aliases: pendingAliases
|
2388
|
+
});
|
2389
|
+
} else {
|
2390
|
+
this.contextStore.storeData(storageKey, output);
|
2391
|
+
debug4("Stored query result:", {
|
2392
|
+
key: storageKey,
|
2393
|
+
value: output
|
2394
|
+
});
|
2395
|
+
}
|
2396
|
+
this.contextStore.addStep({
|
2397
|
+
type: "query",
|
2398
|
+
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)} (stored as ${storageKey})`,
|
2399
|
+
data: output,
|
2400
|
+
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2401
|
+
});
|
2402
|
+
debug4("Added query step to context store:", {
|
2403
|
+
storageKey,
|
2404
|
+
totalStoredItems: Object.keys(this.contextStore.getAllData()).length,
|
2405
|
+
totalSteps: this.contextStore.getRecentSteps(100).length
|
2406
|
+
});
|
2407
|
+
} catch (error) {
|
2408
|
+
debug4("Failed to store query result:", error);
|
2409
|
+
}
|
2410
|
+
} else {
|
2411
|
+
try {
|
2412
|
+
this.contextStore.addStep({
|
2413
|
+
type: "query",
|
2414
|
+
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)}`,
|
2415
|
+
data: output,
|
2416
|
+
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2417
|
+
});
|
2418
|
+
} catch (error) {
|
2419
|
+
debug4("Failed to add query step:", error);
|
2221
2420
|
}
|
2222
|
-
contextStore.addStep({
|
2223
|
-
type: "query",
|
2224
|
-
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)} (stored as ${storageKey})`,
|
2225
|
-
data: output,
|
2226
|
-
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2227
|
-
});
|
2228
|
-
} catch (error) {
|
2229
|
-
debug4("Failed to store query result:", error);
|
2230
|
-
}
|
2231
|
-
} else {
|
2232
|
-
try {
|
2233
|
-
const aiModel = await import("misoai-core/ai-model");
|
2234
|
-
const contextStore = aiModel.getContextStore();
|
2235
|
-
contextStore.addStep({
|
2236
|
-
type: "query",
|
2237
|
-
summary: `Query: ${typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)}`,
|
2238
|
-
data: output,
|
2239
|
-
prompt: typeof processedDemand === "string" ? processedDemand : JSON.stringify(processedDemand)
|
2240
|
-
});
|
2241
|
-
} catch (error) {
|
2242
|
-
debug4("Failed to add query step:", error);
|
2243
2421
|
}
|
2244
2422
|
}
|
2245
2423
|
const metadata = this.afterTaskRunning(executor);
|
@@ -2351,18 +2529,47 @@ var PageAgent = class {
|
|
2351
2529
|
};
|
2352
2530
|
}
|
2353
2531
|
async aiAssert(assertion, msg, opt) {
|
2354
|
-
let
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2358
|
-
|
2359
|
-
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2532
|
+
let executionContext = "";
|
2533
|
+
if (this.opts.enableCumulativeContext && this.contextStore) {
|
2534
|
+
try {
|
2535
|
+
const recentSteps = this.contextStore.getRecentSteps(3);
|
2536
|
+
const stepsWithExecutionResults = recentSteps.filter((step) => step.executionResult);
|
2537
|
+
const storedData = this.contextStore.getAllData();
|
2538
|
+
if (stepsWithExecutionResults.length > 0) {
|
2539
|
+
const recentActions = stepsWithExecutionResults.map((step) => {
|
2540
|
+
const result = step.executionResult;
|
2541
|
+
return `- ${result.description}${result.success ? "" : " (FAILED)"}`;
|
2542
|
+
}).join("\n");
|
2543
|
+
executionContext = `
|
2544
|
+
|
2545
|
+
Recent actions performed:
|
2546
|
+
${recentActions}
|
2547
|
+
|
2548
|
+
This context may help verify the assertion.`;
|
2549
|
+
}
|
2550
|
+
if (storedData && Object.keys(storedData).length > 0) {
|
2551
|
+
executionContext += `
|
2552
|
+
|
2553
|
+
Available data for reference:
|
2554
|
+
${JSON.stringify(storedData, null, 2)}
|
2555
|
+
|
2556
|
+
Note: If the assertion references any data keys or natural language equivalents, consider the stored values when verifying.`;
|
2557
|
+
debug4("Available data for aiAssert:", {
|
2558
|
+
assertion,
|
2559
|
+
availableData: storedData
|
2560
|
+
});
|
2561
|
+
}
|
2562
|
+
this.contextStore.addStep({
|
2563
|
+
type: "assertion",
|
2564
|
+
summary: `Assertion: ${assertion}`,
|
2565
|
+
prompt: assertion
|
2566
|
+
});
|
2567
|
+
debug4("Added assertion step to context store:", {
|
2568
|
+
totalSteps: this.contextStore.getRecentSteps(100).length
|
2569
|
+
});
|
2570
|
+
} catch (error) {
|
2571
|
+
debug4("Context store operation failed:", error);
|
2572
|
+
}
|
2366
2573
|
}
|
2367
2574
|
let currentUrl = "";
|
2368
2575
|
if (this.page.url) {
|
@@ -2371,7 +2578,13 @@ var PageAgent = class {
|
|
2371
2578
|
} catch (e) {
|
2372
2579
|
}
|
2373
2580
|
}
|
2374
|
-
|
2581
|
+
let assertionWithContext = assertion;
|
2582
|
+
if (currentUrl) {
|
2583
|
+
assertionWithContext = `For the page at URL "${currentUrl}", ${assertion}`;
|
2584
|
+
}
|
2585
|
+
if (executionContext) {
|
2586
|
+
assertionWithContext += executionContext;
|
2587
|
+
}
|
2375
2588
|
const { output, executor } = await this.taskExecutor.assert(assertionWithContext);
|
2376
2589
|
const metadata = this.afterTaskRunning(executor, true);
|
2377
2590
|
if (output && opt?.keepRawResponse) {
|
@@ -2585,6 +2798,79 @@ ${errors}`);
|
|
2585
2798
|
async destroy() {
|
2586
2799
|
await this.page.destroy();
|
2587
2800
|
}
|
2801
|
+
/**
|
2802
|
+
* Analyze execution results from executor to generate meaningful descriptions
|
2803
|
+
*/
|
2804
|
+
analyzeExecutionResults(executor, originalPrompt) {
|
2805
|
+
const tasks = executor.tasks;
|
2806
|
+
const success = !executor.isInErrorState();
|
2807
|
+
if (!success) {
|
2808
|
+
const errorTask = executor.latestErrorTask();
|
2809
|
+
return {
|
2810
|
+
success: false,
|
2811
|
+
actionType: "error",
|
2812
|
+
description: `Failed to execute: ${originalPrompt}`,
|
2813
|
+
error: errorTask?.error
|
2814
|
+
};
|
2815
|
+
}
|
2816
|
+
const actionTasks = tasks.filter((t) => t.type === "Action" && t.status === "finished");
|
2817
|
+
const locateTasks = tasks.filter((t) => t.type === "Insight" && t.subType === "Locate");
|
2818
|
+
const lastAction = actionTasks[actionTasks.length - 1];
|
2819
|
+
const lastLocate = locateTasks[locateTasks.length - 1];
|
2820
|
+
if (!lastAction) {
|
2821
|
+
return {
|
2822
|
+
success: true,
|
2823
|
+
actionType: "unknown",
|
2824
|
+
description: `Completed: ${originalPrompt}`
|
2825
|
+
};
|
2826
|
+
}
|
2827
|
+
const actionType = lastAction.subType || "unknown";
|
2828
|
+
const elementInfo = this.extractElementInfo(lastLocate, lastAction);
|
2829
|
+
const description = this.generateActionDescription(actionType, lastAction.param, elementInfo);
|
2830
|
+
return {
|
2831
|
+
success: true,
|
2832
|
+
actionType,
|
2833
|
+
description,
|
2834
|
+
elementInfo,
|
2835
|
+
timing: lastAction.timing?.cost
|
2836
|
+
};
|
2837
|
+
}
|
2838
|
+
/**
|
2839
|
+
* Extract element information from locate task
|
2840
|
+
*/
|
2841
|
+
extractElementInfo(locateTask, _actionTask) {
|
2842
|
+
if (!locateTask?.output?.element)
|
2843
|
+
return void 0;
|
2844
|
+
const element = locateTask.output.element;
|
2845
|
+
return {
|
2846
|
+
type: element.attributes?.nodeType || "unknown",
|
2847
|
+
text: element.content || element.attributes?.placeholder || element.attributes?.title || "",
|
2848
|
+
location: `(${element.center[0]}, ${element.center[1]})`
|
2849
|
+
};
|
2850
|
+
}
|
2851
|
+
/**
|
2852
|
+
* Generate natural language description for actions
|
2853
|
+
*/
|
2854
|
+
generateActionDescription(actionType, param, elementInfo) {
|
2855
|
+
const elementDesc = elementInfo ? `'${elementInfo.text || elementInfo.type}' element` : "element";
|
2856
|
+
switch (actionType) {
|
2857
|
+
case "Tap":
|
2858
|
+
return `Clicked on ${elementDesc}`;
|
2859
|
+
case "Input":
|
2860
|
+
const inputValue = param?.value || "";
|
2861
|
+
return `Entered "${inputValue}" into ${elementDesc}`;
|
2862
|
+
case "KeyboardPress":
|
2863
|
+
return `Pressed ${param?.value || "key"}`;
|
2864
|
+
case "Scroll":
|
2865
|
+
return `Scrolled ${param?.direction || "on page"}`;
|
2866
|
+
case "Hover":
|
2867
|
+
return `Hovered over ${elementDesc}`;
|
2868
|
+
case "Drag":
|
2869
|
+
return `Dragged ${elementDesc}`;
|
2870
|
+
default:
|
2871
|
+
return `Performed ${actionType} action on ${elementDesc}`;
|
2872
|
+
}
|
2873
|
+
}
|
2588
2874
|
};
|
2589
2875
|
|
2590
2876
|
// src/playground/agent.ts
|