@xoxoai/checkmate 0.4.0
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 -0
- package/README.md +244 -0
- package/dist/ai/client.d.ts +49 -0
- package/dist/ai/client.d.ts.map +1 -0
- package/dist/ai/client.js +244 -0
- package/dist/ai/client.js.map +1 -0
- package/dist/ai/message-handler.d.ts +11 -0
- package/dist/ai/message-handler.d.ts.map +1 -0
- package/dist/ai/message-handler.js +33 -0
- package/dist/ai/message-handler.js.map +1 -0
- package/dist/ai/message-history.d.ts +19 -0
- package/dist/ai/message-history.d.ts.map +1 -0
- package/dist/ai/message-history.js +48 -0
- package/dist/ai/message-history.js.map +1 -0
- package/dist/ai/prompts.d.ts +4 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +24 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/rate-limit-policy.d.ts +7 -0
- package/dist/ai/rate-limit-policy.d.ts.map +1 -0
- package/dist/ai/rate-limit-policy.js +17 -0
- package/dist/ai/rate-limit-policy.js.map +1 -0
- package/dist/ai/response-processor.d.ts +20 -0
- package/dist/ai/response-processor.d.ts.map +1 -0
- package/dist/ai/response-processor.js +62 -0
- package/dist/ai/response-processor.js.map +1 -0
- package/dist/ai/token-pricing.d.ts +13 -0
- package/dist/ai/token-pricing.d.ts.map +1 -0
- package/dist/ai/token-pricing.js +348 -0
- package/dist/ai/token-pricing.js.map +1 -0
- package/dist/ai/token-tracker.d.ts +33 -0
- package/dist/ai/token-tracker.d.ts.map +1 -0
- package/dist/ai/token-tracker.js +138 -0
- package/dist/ai/token-tracker.js.map +1 -0
- package/dist/ai/tool-response-handler.d.ts +21 -0
- package/dist/ai/tool-response-handler.d.ts.map +1 -0
- package/dist/ai/tool-response-handler.js +54 -0
- package/dist/ai/tool-response-handler.js.map +1 -0
- package/dist/config/runtime-config.d.ts +21 -0
- package/dist/config/runtime-config.d.ts.map +1 -0
- package/dist/config/runtime-config.js +98 -0
- package/dist/config/runtime-config.js.map +1 -0
- package/dist/core.d.ts +8 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +4 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/salesforce/authenticator.d.ts +27 -0
- package/dist/integrations/salesforce/authenticator.d.ts.map +1 -0
- package/dist/integrations/salesforce/authenticator.js +27 -0
- package/dist/integrations/salesforce/authenticator.js.map +1 -0
- package/dist/integrations/salesforce/cli-handler.d.ts +14 -0
- package/dist/integrations/salesforce/cli-handler.d.ts.map +1 -0
- package/dist/integrations/salesforce/cli-handler.js +50 -0
- package/dist/integrations/salesforce/cli-handler.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +4 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +5 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +15 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/playwright.d.ts +102 -0
- package/dist/playwright.d.ts.map +1 -0
- package/dist/playwright.js +116 -0
- package/dist/playwright.js.map +1 -0
- package/dist/runtime/extension.d.ts +274 -0
- package/dist/runtime/extension.d.ts.map +1 -0
- package/dist/runtime/extension.js +171 -0
- package/dist/runtime/extension.js.map +1 -0
- package/dist/runtime/runner.d.ts +94 -0
- package/dist/runtime/runner.d.ts.map +1 -0
- package/dist/runtime/runner.js +86 -0
- package/dist/runtime/runner.js.map +1 -0
- package/dist/runtime/step-execution.d.ts +17 -0
- package/dist/runtime/step-execution.d.ts.map +1 -0
- package/dist/runtime/step-execution.js +49 -0
- package/dist/runtime/step-execution.js.map +1 -0
- package/dist/runtime/types.d.ts +79 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/salesforce.d.ts +71 -0
- package/dist/salesforce.d.ts.map +1 -0
- package/dist/salesforce.js +73 -0
- package/dist/salesforce.js.map +1 -0
- package/dist/tools/browser/screenshot-service.d.ts +10 -0
- package/dist/tools/browser/screenshot-service.d.ts.map +1 -0
- package/dist/tools/browser/screenshot-service.js +23 -0
- package/dist/tools/browser/screenshot-service.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/index.d.ts +4 -0
- package/dist/tools/browser/snapshot-filter/index.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/index.js +4 -0
- package/dist/tools/browser/snapshot-filter/index.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.d.ts +15 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.js +99 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.d.ts +4 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.js +57 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.d.ts +3 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.js +85 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.js.map +1 -0
- package/dist/tools/browser/snapshot-service.d.ts +19 -0
- package/dist/tools/browser/snapshot-service.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-service.js +67 -0
- package/dist/tools/browser/snapshot-service.js.map +1 -0
- package/dist/tools/browser/tool.d.ts +34 -0
- package/dist/tools/browser/tool.d.ts.map +1 -0
- package/dist/tools/browser/tool.js +226 -0
- package/dist/tools/browser/tool.js.map +1 -0
- package/dist/tools/browser/transient-state-tracker.d.ts +16 -0
- package/dist/tools/browser/transient-state-tracker.d.ts.map +1 -0
- package/dist/tools/browser/transient-state-tracker.js +266 -0
- package/dist/tools/browser/transient-state-tracker.js.map +1 -0
- package/dist/tools/define-agent-tool.d.ts +45 -0
- package/dist/tools/define-agent-tool.d.ts.map +1 -0
- package/dist/tools/define-agent-tool.js +55 -0
- package/dist/tools/define-agent-tool.js.map +1 -0
- package/dist/tools/dispatcher.d.ts +11 -0
- package/dist/tools/dispatcher.d.ts.map +1 -0
- package/dist/tools/dispatcher.js +49 -0
- package/dist/tools/dispatcher.js.map +1 -0
- package/dist/tools/loop-detector.d.ts +27 -0
- package/dist/tools/loop-detector.d.ts.map +1 -0
- package/dist/tools/loop-detector.js +76 -0
- package/dist/tools/loop-detector.js.map +1 -0
- package/dist/tools/registry.d.ts +21 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +46 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/salesforce/login-tool.d.ts +7 -0
- package/dist/tools/salesforce/login-tool.d.ts.map +1 -0
- package/dist/tools/salesforce/login-tool.js +25 -0
- package/dist/tools/salesforce/login-tool.js.map +1 -0
- package/dist/tools/step/result-tool.d.ts +7 -0
- package/dist/tools/step/result-tool.d.ts.map +1 -0
- package/dist/tools/step/result-tool.js +32 -0
- package/dist/tools/step/result-tool.js.map +1 -0
- package/dist/tools/tool-contract.d.ts +3 -0
- package/dist/tools/tool-contract.d.ts.map +1 -0
- package/dist/tools/tool-contract.js +2 -0
- package/dist/tools/tool-contract.js.map +1 -0
- package/dist/tools/types.d.ts +139 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/types.js.map +1 -0
- package/docs/EXTENSIONS.md +233 -0
- package/docs/GUIDE.md +467 -0
- package/docs/ROADMAP.md +47 -0
- package/package.json +106 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { cos_sim, pipeline } from '@huggingface/transformers';
|
|
2
|
+
const EMBEDDING_MODEL = 'snowflake/snowflake-arctic-embed-xs';
|
|
3
|
+
const SNAPSHOT_METADATA_REGEX = /\s*\[[^\]]*\]/g;
|
|
4
|
+
let featureExtractionPipelinePromise;
|
|
5
|
+
const embeddingCache = new Map();
|
|
6
|
+
export async function scoreSnapshotElements(json, query) {
|
|
7
|
+
const normalizedQuery = normalizeText(query);
|
|
8
|
+
if (!normalizedQuery) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
const candidates = [];
|
|
12
|
+
collectCandidates(json, [], candidates);
|
|
13
|
+
if (candidates.length === 0) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
const queryEmbedding = await getEmbedding(normalizedQuery);
|
|
17
|
+
const scoredElements = await Promise.all(candidates.map(async (candidate) => {
|
|
18
|
+
const normalizedText = normalizeText(candidate.text);
|
|
19
|
+
if (!normalizedText) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const elementEmbedding = await getEmbedding(normalizedText);
|
|
23
|
+
const score = Math.max(0, cos_sim(queryEmbedding, elementEmbedding));
|
|
24
|
+
if (score <= 0) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
score,
|
|
29
|
+
path: candidate.path,
|
|
30
|
+
element: candidate.element,
|
|
31
|
+
key: candidate.key,
|
|
32
|
+
};
|
|
33
|
+
}));
|
|
34
|
+
return scoredElements.filter((candidate) => candidate !== undefined);
|
|
35
|
+
}
|
|
36
|
+
function collectCandidates(value, currentPath, results) {
|
|
37
|
+
if (value === null || value === undefined) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
|
+
results.push({ path: [...currentPath], element: value, key: value, text: value });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
value.forEach((item, index) => {
|
|
46
|
+
collectCandidates(item, [...currentPath, index], results);
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const objectValue = value;
|
|
51
|
+
for (const key of Object.keys(objectValue)) {
|
|
52
|
+
results.push({ path: [...currentPath, key], element: objectValue[key], key, text: key });
|
|
53
|
+
collectCandidates(objectValue[key], [...currentPath, key], results);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function normalizeText(text) {
|
|
57
|
+
return text.replaceAll(SNAPSHOT_METADATA_REGEX, ' ').replaceAll(/\s+/g, ' ').trim().toLowerCase();
|
|
58
|
+
}
|
|
59
|
+
async function getFeatureExtractionPipeline() {
|
|
60
|
+
featureExtractionPipelinePromise ??= pipeline('feature-extraction', EMBEDDING_MODEL, {
|
|
61
|
+
dtype: 'int8',
|
|
62
|
+
});
|
|
63
|
+
return featureExtractionPipelinePromise;
|
|
64
|
+
}
|
|
65
|
+
async function getEmbedding(text) {
|
|
66
|
+
const normalizedText = normalizeText(text);
|
|
67
|
+
if (!normalizedText) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const cachedEmbedding = embeddingCache.get(normalizedText);
|
|
71
|
+
if (cachedEmbedding) {
|
|
72
|
+
return cachedEmbedding;
|
|
73
|
+
}
|
|
74
|
+
const embeddingPromise = (async () => {
|
|
75
|
+
const extractor = await getFeatureExtractionPipeline();
|
|
76
|
+
const output = await extractor(normalizedText, { pooling: 'mean', normalize: true });
|
|
77
|
+
return Array.from(output.data);
|
|
78
|
+
})();
|
|
79
|
+
embeddingCache.set(normalizedText, embeddingPromise);
|
|
80
|
+
try {
|
|
81
|
+
return await embeddingPromise;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
embeddingCache.delete(normalizedText);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function filterByThreshold(scoredElements, threshold) {
|
|
89
|
+
return scoredElements.filter((element) => element.score >= threshold);
|
|
90
|
+
}
|
|
91
|
+
export function filterTopPercent(scoredElements, topPercent) {
|
|
92
|
+
if (scoredElements.length === 0 || topPercent <= 0 || topPercent > 1) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const sortedElements = [...scoredElements].sort((a, b) => b.score - a.score);
|
|
96
|
+
const selectedCount = Math.max(1, Math.ceil(sortedElements.length * topPercent));
|
|
97
|
+
return sortedElements.slice(0, selectedCount);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=semantic-scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-scorer.js","sourceRoot":"","sources":["../../../../src/tools/browser/snapshot-filter/semantic-scorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-filter.d.ts","sourceRoot":"","sources":["../../../../src/tools/browser/snapshot-filter/snapshot-filter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAuC,SAAS,EAAyB,MAAM,mBAAmB,CAAA;AAMzG,wBAAsB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CA6CrF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { logger } from '../../../logging';
|
|
2
|
+
import { filterByThreshold, filterTopPercent, scoreSnapshotElements } from './semantic-scorer';
|
|
3
|
+
import { reconstructTree } from './tree-reconstructor';
|
|
4
|
+
const DEFAULT_SCORE_THRESHOLD = 0.3;
|
|
5
|
+
const DEFAULT_TOP_PERCENT = 10;
|
|
6
|
+
export async function filterSnapshot(json, step) {
|
|
7
|
+
if (!step) {
|
|
8
|
+
logger.debug('filterSnapshot: No step provided, returning original snapshot');
|
|
9
|
+
return json;
|
|
10
|
+
}
|
|
11
|
+
const searchQuery = resolveSearchQuery(step);
|
|
12
|
+
logger.debug(`filterSnapshot: Resolved search query: ${JSON.stringify(searchQuery)}`);
|
|
13
|
+
if (!searchQuery) {
|
|
14
|
+
logger.debug('filterSnapshot: No search query found, returning original snapshot');
|
|
15
|
+
return json;
|
|
16
|
+
}
|
|
17
|
+
const scoredElements = await scoreSnapshotElements(json, searchQuery);
|
|
18
|
+
logger.debug(`filterSnapshot: Scored ${scoredElements.length} elements`);
|
|
19
|
+
if (scoredElements.length === 0) {
|
|
20
|
+
logger.debug('filterSnapshot: No scored elements, returning original snapshot');
|
|
21
|
+
return json;
|
|
22
|
+
}
|
|
23
|
+
const topPercent = resolveTopPercent(step);
|
|
24
|
+
const selectedByPrimaryRule = filterTopPercent(scoredElements, topPercent / 100);
|
|
25
|
+
logger.debug(`filterSnapshot: Filtered to ${selectedByPrimaryRule.length} elements from top ${topPercent}%`);
|
|
26
|
+
const selectedElements = selectedByPrimaryRule.length > 0
|
|
27
|
+
? selectedByPrimaryRule
|
|
28
|
+
: filterByThreshold(scoredElements, DEFAULT_SCORE_THRESHOLD);
|
|
29
|
+
if (selectedElements !== selectedByPrimaryRule) {
|
|
30
|
+
logger.debug(`filterSnapshot: Top-percent selection was empty, falling back to threshold ${DEFAULT_SCORE_THRESHOLD}`);
|
|
31
|
+
}
|
|
32
|
+
const filtered = reconstructTree(json, selectedElements);
|
|
33
|
+
const originalSize = JSON.stringify(json).length;
|
|
34
|
+
const filteredSize = JSON.stringify(filtered).length;
|
|
35
|
+
logger.info(`filterSnapshot: Reduced snapshot from ${originalSize} to ${filteredSize} chars (${Math.round((1 - filteredSize / originalSize) * 100)}% reduction)`);
|
|
36
|
+
return filtered;
|
|
37
|
+
}
|
|
38
|
+
function resolveTopPercent(step) {
|
|
39
|
+
const candidate = step.topPercent;
|
|
40
|
+
if (typeof candidate === 'number' && candidate > 0 && candidate <= 100) {
|
|
41
|
+
return candidate;
|
|
42
|
+
}
|
|
43
|
+
return DEFAULT_TOP_PERCENT;
|
|
44
|
+
}
|
|
45
|
+
function resolveSearchQuery(step) {
|
|
46
|
+
if (step.search && step.search.length > 0) {
|
|
47
|
+
logger.info(`filterSnapshot: using search keywords: ${JSON.stringify(step.search)}`);
|
|
48
|
+
return step.search.join(' ');
|
|
49
|
+
}
|
|
50
|
+
const semanticQuery = `${step.action} ${step.expect}`.trim();
|
|
51
|
+
if (semanticQuery) {
|
|
52
|
+
logger.info(`filterSnapshot: using step semantics`);
|
|
53
|
+
return semanticQuery;
|
|
54
|
+
}
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=snapshot-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-filter.js","sourceRoot":"","sources":["../../../../src/tools/browser/snapshot-filter/snapshot-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-reconstructor.d.ts","sourceRoot":"","sources":["../../../../src/tools/browser/snapshot-filter/tree-reconstructor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,SAAS,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEnF,wBAAgB,eAAe,CAAC,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,GAAG,SAAS,CAOrG"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export function reconstructTree(originalJson, selectedElements) {
|
|
2
|
+
if (selectedElements.length === 0) {
|
|
3
|
+
return originalJson;
|
|
4
|
+
}
|
|
5
|
+
const allPaths = collectAllRequiredPaths(selectedElements);
|
|
6
|
+
return buildFilteredTree(originalJson, allPaths, []) ?? originalJson;
|
|
7
|
+
}
|
|
8
|
+
function collectAllRequiredPaths(elements) {
|
|
9
|
+
const paths = new Set();
|
|
10
|
+
for (const element of elements) {
|
|
11
|
+
for (let i = 0; i <= element.path.length; i++) {
|
|
12
|
+
paths.add(JSON.stringify(element.path.slice(0, i)));
|
|
13
|
+
}
|
|
14
|
+
paths.add(JSON.stringify(element.path));
|
|
15
|
+
}
|
|
16
|
+
return paths;
|
|
17
|
+
}
|
|
18
|
+
function buildFilteredTree(value, requiredPaths, currentPath) {
|
|
19
|
+
if (!isPathOrAncestorRequired(currentPath, requiredPaths)) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
if (value === null || typeof value !== 'object') {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
return buildFilteredArray(value, requiredPaths, currentPath);
|
|
27
|
+
}
|
|
28
|
+
return buildFilteredObject(value, requiredPaths, currentPath);
|
|
29
|
+
}
|
|
30
|
+
function isPathOrAncestorRequired(path, requiredPaths) {
|
|
31
|
+
const pathKey = JSON.stringify(path);
|
|
32
|
+
if (requiredPaths.has(pathKey)) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
for (const requiredPath of requiredPaths) {
|
|
36
|
+
const parsed = JSON.parse(requiredPath);
|
|
37
|
+
if (isAncestorOf(path, parsed)) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
function isAncestorOf(potentialAncestor, descendant) {
|
|
44
|
+
return (potentialAncestor.length < descendant.length &&
|
|
45
|
+
potentialAncestor.every((segment, index) => segment === descendant[index]));
|
|
46
|
+
}
|
|
47
|
+
function buildFilteredArray(value, requiredPaths, currentPath) {
|
|
48
|
+
const filteredItems = [];
|
|
49
|
+
for (let index = 0; index < value.length; index++) {
|
|
50
|
+
const filteredChild = buildFilteredTree(value[index], requiredPaths, [...currentPath, index]);
|
|
51
|
+
if (filteredChild !== undefined) {
|
|
52
|
+
filteredItems.push(filteredChild);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (filteredItems.length === 0) {
|
|
56
|
+
return includeDirectChildren(requiredPaths, currentPath) ? value : undefined;
|
|
57
|
+
}
|
|
58
|
+
return filteredItems;
|
|
59
|
+
}
|
|
60
|
+
function buildFilteredObject(value, requiredPaths, currentPath) {
|
|
61
|
+
const filteredObject = {};
|
|
62
|
+
let hasContent = false;
|
|
63
|
+
for (const key of Object.keys(value)) {
|
|
64
|
+
const filteredChild = buildFilteredTree(value[key], requiredPaths, [...currentPath, key]);
|
|
65
|
+
if (filteredChild !== undefined) {
|
|
66
|
+
filteredObject[key] = filteredChild;
|
|
67
|
+
hasContent = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!hasContent && includeDirectChildren(requiredPaths, currentPath)) {
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
return hasContent ? filteredObject : undefined;
|
|
74
|
+
}
|
|
75
|
+
function includeDirectChildren(requiredPaths, currentPath) {
|
|
76
|
+
const currentPathKey = JSON.stringify(currentPath);
|
|
77
|
+
for (const requiredPath of requiredPaths) {
|
|
78
|
+
const parsed = JSON.parse(requiredPath);
|
|
79
|
+
if (parsed.length === currentPath.length && currentPathKey === requiredPath) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=tree-reconstructor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-reconstructor.js","sourceRoot":"","sources":["../../../../src/tools/browser/snapshot-filter/tree-reconstructor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { Step } from '../../runtime/types';
|
|
3
|
+
export type BrowserSnapshot = string | null;
|
|
4
|
+
export interface SnapshotServiceOptions {
|
|
5
|
+
skipFilter?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class SnapshotService {
|
|
8
|
+
private readonly page;
|
|
9
|
+
private readonly step?;
|
|
10
|
+
private readonly options;
|
|
11
|
+
private readonly runtimeConfig;
|
|
12
|
+
constructor(page: Page | null, step?: Step, options?: SnapshotServiceOptions);
|
|
13
|
+
private getHeader;
|
|
14
|
+
private minify;
|
|
15
|
+
private redactAds;
|
|
16
|
+
private compress;
|
|
17
|
+
get(): Promise<BrowserSnapshot>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=snapshot-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-service.d.ts","sourceRoot":"","sources":["../../../src/tools/browser/snapshot-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAIvC,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAG1C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,IAAI,CAAA;AAE3C,MAAM,WAAW,sBAAsB;IACtC,UAAU,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,qBAAa,eAAe;IAI1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IALzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;gBAGlC,IAAI,EAAE,IAAI,GAAG,IAAI,EACjB,IAAI,CAAC,EAAE,IAAI,EACX,OAAO,GAAE,sBAA2B;YAGxC,SAAS;IAQvB,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,SAAS;YAkBH,QAAQ;IAQhB,GAAG,IAAI,OAAO,CAAC,eAAe,CAAC;CAcrC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { parse } from 'yaml';
|
|
2
|
+
import { RuntimeConfig } from '../../config/runtime-config';
|
|
3
|
+
import { logger } from '../../logging';
|
|
4
|
+
import { filterSnapshot } from './snapshot-filter';
|
|
5
|
+
export class SnapshotService {
|
|
6
|
+
page;
|
|
7
|
+
step;
|
|
8
|
+
options;
|
|
9
|
+
runtimeConfig = new RuntimeConfig();
|
|
10
|
+
constructor(page, step, options = {}) {
|
|
11
|
+
this.page = page;
|
|
12
|
+
this.step = step;
|
|
13
|
+
this.options = options;
|
|
14
|
+
}
|
|
15
|
+
async getHeader() {
|
|
16
|
+
if (!this.page) {
|
|
17
|
+
throw new Error('Page is not initialized');
|
|
18
|
+
}
|
|
19
|
+
return ['page data:', `url: '${this.page.url()}'`, `title: '${await this.page.title()}'`].join('\n');
|
|
20
|
+
}
|
|
21
|
+
minify(snapshot) {
|
|
22
|
+
return snapshot
|
|
23
|
+
.replaceAll(' ', '')
|
|
24
|
+
.replaceAll('"', '')
|
|
25
|
+
.replaceAll('\\', '')
|
|
26
|
+
.replaceAll(' [', '[')
|
|
27
|
+
.replaceAll('] ', ']');
|
|
28
|
+
}
|
|
29
|
+
redactAds(snapshot) {
|
|
30
|
+
const adPatterns = [
|
|
31
|
+
/googleadservices\.com/i,
|
|
32
|
+
/doubleclick\.net/i,
|
|
33
|
+
/googlesyndication\.com/i,
|
|
34
|
+
/googleads/i,
|
|
35
|
+
/pagead\/aclk/i,
|
|
36
|
+
/adurl=/i,
|
|
37
|
+
/\bgad_source\b/i,
|
|
38
|
+
/\bgclid\b/i,
|
|
39
|
+
];
|
|
40
|
+
const snapshotUrlWrapperRegex = /\{\/url:([^}]+)\}/g;
|
|
41
|
+
return snapshot.replace(snapshotUrlWrapperRegex, (match, urlContent) => {
|
|
42
|
+
return adPatterns.some((pattern) => pattern.test(urlContent)) ? '{/url:ADVERT}' : match;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async compress(snapshot) {
|
|
46
|
+
const snapshotTree = parse(snapshot)?.[0] ?? { state: 'page is blank - navigate to a relevant page url' };
|
|
47
|
+
const shouldSkipFilter = this.options.skipFilter || !this.runtimeConfig.isSnapshotFilteringEnabled();
|
|
48
|
+
const processed = shouldSkipFilter ? snapshotTree : await filterSnapshot(snapshotTree, this.step);
|
|
49
|
+
const minifiedSnapshot = `page snapshot:\n${this.minify(JSON.stringify(processed))}`;
|
|
50
|
+
return this.redactAds(`${await this.getHeader()}\n${minifiedSnapshot}`);
|
|
51
|
+
}
|
|
52
|
+
async get() {
|
|
53
|
+
try {
|
|
54
|
+
if (!this.page) {
|
|
55
|
+
throw new Error('Page is not initialized');
|
|
56
|
+
}
|
|
57
|
+
const rawSnapshot = await this.page.ariaSnapshot({ mode: 'ai' });
|
|
58
|
+
const compressedSnapshot = await this.compress(rawSnapshot);
|
|
59
|
+
logger.debug(`created aria page snapshot:\n${compressedSnapshot}`);
|
|
60
|
+
return compressedSnapshot;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new Error(`Failed to create aria page snapshot:\n${error}`, { cause: error });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=snapshot-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-service.js","sourceRoot":"","sources":["../../../src/tools/browser/snapshot-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { Step } from '../../runtime/types';
|
|
3
|
+
import { AgentTool, AgentToolResponse } from '../types';
|
|
4
|
+
type BrowserInputElement = {
|
|
5
|
+
ref: string;
|
|
6
|
+
text: string;
|
|
7
|
+
name: string;
|
|
8
|
+
clear: boolean;
|
|
9
|
+
select: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const BrowserTool: {
|
|
12
|
+
readonly TOOL_NAVIGATE: "browser_navigate";
|
|
13
|
+
readonly TOOL_CLICK_OR_HOVER: "browser_click_or_hover";
|
|
14
|
+
readonly TOOL_TYPE_OR_SELECT: "browser_type_or_select";
|
|
15
|
+
readonly TOOL_PRESS_KEY: "browser_press_key";
|
|
16
|
+
readonly TOOL_SNAPSHOT: "browser_snapshot";
|
|
17
|
+
readonly TOOL_WAIT: "browser_wait";
|
|
18
|
+
};
|
|
19
|
+
export declare class BrowserToolRuntime {
|
|
20
|
+
private readonly page;
|
|
21
|
+
constructor(page: Page);
|
|
22
|
+
navigateToUrl(url: string, step: Step): Promise<AgentToolResponse | string>;
|
|
23
|
+
clickElement(ref: string, hover: boolean, step: Step): Promise<AgentToolResponse | string>;
|
|
24
|
+
typeOrSelectInElement(elements: BrowserInputElement[], step: Step): Promise<AgentToolResponse | string>;
|
|
25
|
+
pressKey(key: string, step: Step): Promise<AgentToolResponse | string>;
|
|
26
|
+
captureCurrentSnapshot(step: Step, options?: {
|
|
27
|
+
skipFilter?: boolean;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
wait(seconds: number, step: Step): Promise<AgentToolResponse | string>;
|
|
30
|
+
private wrapWithTracker;
|
|
31
|
+
}
|
|
32
|
+
export declare function createBrowserTools(runtime: BrowserToolRuntime): AgentTool[];
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/tools/browser/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAG/C,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAE1C,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAIvD,KAAK,mBAAmB,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CACf,CAAA;AAED,eAAO,MAAM,WAAW;;;;;;;CAOd,CAAA;AAcV,qBAAa,kBAAkB;IAClB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAEjC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAkB3E,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAmB1F,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAsCvG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAmBtE,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAqB3F,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,GAAG,MAAM,CAAC;YAmB9D,eAAe;CAwB7B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,EAAE,CA2E3E"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
|
+
import { logger } from '../../logging';
|
|
4
|
+
import { defineAgentTool } from '../define-agent-tool';
|
|
5
|
+
import { SnapshotService } from './snapshot-service';
|
|
6
|
+
import { TransientStateTracker } from './transient-state-tracker';
|
|
7
|
+
export const BrowserTool = {
|
|
8
|
+
TOOL_NAVIGATE: 'browser_navigate',
|
|
9
|
+
TOOL_CLICK_OR_HOVER: 'browser_click_or_hover',
|
|
10
|
+
TOOL_TYPE_OR_SELECT: 'browser_type_or_select',
|
|
11
|
+
TOOL_PRESS_KEY: 'browser_press_key',
|
|
12
|
+
TOOL_SNAPSHOT: 'browser_snapshot',
|
|
13
|
+
TOOL_WAIT: 'browser_wait',
|
|
14
|
+
};
|
|
15
|
+
const browserInputElementSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
ref: z.string().describe('ref value of the element from the snapshot, example: e123'),
|
|
18
|
+
name: z.string().describe('name of the element to type into, example: Username Input'),
|
|
19
|
+
text: z.string().describe('The text to type into the element, example: Hello World'),
|
|
20
|
+
clear: z
|
|
21
|
+
.boolean()
|
|
22
|
+
.describe('If true, clears existing text before typing. Use false with dropdowns and selects'),
|
|
23
|
+
select: z.boolean().describe('If true, selects the option matching "text" from a dropdown or select element'),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
export class BrowserToolRuntime {
|
|
27
|
+
page;
|
|
28
|
+
constructor(page) {
|
|
29
|
+
this.page = page;
|
|
30
|
+
}
|
|
31
|
+
async navigateToUrl(url, step) {
|
|
32
|
+
return this.wrapWithTracker(async () => {
|
|
33
|
+
if (!url) {
|
|
34
|
+
throw new Error(`valid URL is required for ${BrowserTool.TOOL_NAVIGATE} but received: '${url}'`);
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
await this.page.goto(url);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new Error(`Failed to navigate to URL ${url}`, { cause: error });
|
|
41
|
+
}
|
|
42
|
+
}, `Navigated to: ${url}`, step);
|
|
43
|
+
}
|
|
44
|
+
async clickElement(ref, hover, step) {
|
|
45
|
+
return this.wrapWithTracker(async () => {
|
|
46
|
+
try {
|
|
47
|
+
if (hover) {
|
|
48
|
+
await this.page.hover(`aria-ref=${ref}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
await this.page.click(`aria-ref=${ref}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
logger.error(`error clicking element with ref '${ref}' due to:\n${error}`);
|
|
56
|
+
return `failed to click element with ref '${ref}':\n${error} try with different element type or ref`;
|
|
57
|
+
}
|
|
58
|
+
}, hover ? `Hovered element with ref '${ref}'.` : `Clicked element with ref '${ref}'.`, step);
|
|
59
|
+
}
|
|
60
|
+
async typeOrSelectInElement(elements, step) {
|
|
61
|
+
return this.wrapWithTracker(async () => {
|
|
62
|
+
for (const element of elements) {
|
|
63
|
+
try {
|
|
64
|
+
if (!element.ref || element.text === undefined || element.text === null) {
|
|
65
|
+
throw new Error(`both 'ref' and 'text' are required for ${BrowserTool.TOOL_TYPE_OR_SELECT} but received ref='${element.ref}' and text='${element.text}'`);
|
|
66
|
+
}
|
|
67
|
+
if (!element.select && element.clear) {
|
|
68
|
+
await this.page.locator(`aria-ref=${element.ref}`).clear();
|
|
69
|
+
}
|
|
70
|
+
if (element.select && element.text.length > 0) {
|
|
71
|
+
await this.page.locator(`aria-ref=${element.ref}`).selectOption(element.text);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!element.select && element.text.length > 0) {
|
|
75
|
+
await this.page
|
|
76
|
+
.locator(`aria-ref=${element.ref}`)
|
|
77
|
+
.pressSequentially(element.text, { delay: 50 });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
logger.error(`error ${element.select ? 'selecting' : 'typing'} '${element.text}' in element with ref '${element.ref}' due to:\n${error}`);
|
|
82
|
+
return `failed to ${element.select ? 'select' : 'type'} '${element.text}' in element with ref '${element.ref}':\n${error}\n try with different element type or ref`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}, `Updated ${elements.length} page element${elements.length === 1 ? '' : 's'}.`, step);
|
|
86
|
+
}
|
|
87
|
+
async pressKey(key, step) {
|
|
88
|
+
return this.wrapWithTracker(async () => {
|
|
89
|
+
try {
|
|
90
|
+
if (!key) {
|
|
91
|
+
throw new Error(`'key' is required for ${BrowserTool.TOOL_PRESS_KEY} but received: '${key}'`);
|
|
92
|
+
}
|
|
93
|
+
await this.page.keyboard.press(key);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
logger.error(`error pressing key '${key}' due to:\n${error}`);
|
|
97
|
+
return `failed to press key '${key}':\n${error}`;
|
|
98
|
+
}
|
|
99
|
+
}, `Pressed key '${key}'.`, step);
|
|
100
|
+
}
|
|
101
|
+
async captureCurrentSnapshot(step, options = {}) {
|
|
102
|
+
try {
|
|
103
|
+
await expect
|
|
104
|
+
.poll(async () => {
|
|
105
|
+
const readHtml = async () => this.page.locator('html').innerHTML();
|
|
106
|
+
const first = await readHtml();
|
|
107
|
+
await this.page.waitForTimeout(500);
|
|
108
|
+
const second = await readHtml();
|
|
109
|
+
return first !== second ? 'not stable' : 'stable';
|
|
110
|
+
}, { timeout: 30_000, message: 'page snapshots should be stable' })
|
|
111
|
+
.toEqual('stable');
|
|
112
|
+
return new SnapshotService(this.page, step, { skipFilter: options.skipFilter }).get();
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw new Error(`Failed to capture page snapshot:\n${error}`, { cause: error });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async wait(seconds, step) {
|
|
119
|
+
return this.wrapWithTracker(async () => {
|
|
120
|
+
try {
|
|
121
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
122
|
+
throw new Error(`invalid seconds value received: ${seconds}. It should be a positive number.`);
|
|
123
|
+
}
|
|
124
|
+
await this.page.waitForTimeout(seconds * 1000);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
logger.error(`error waiting for ${seconds} seconds due to:\n${error}`);
|
|
128
|
+
return `failed to wait for ${seconds} seconds:\n${error}`;
|
|
129
|
+
}
|
|
130
|
+
}, `Waited ${seconds} seconds.`, step);
|
|
131
|
+
}
|
|
132
|
+
async wrapWithTracker(action, fallbackResponse, step) {
|
|
133
|
+
const tracker = new TransientStateTracker(this.page);
|
|
134
|
+
await tracker.start();
|
|
135
|
+
try {
|
|
136
|
+
const actionResult = await action();
|
|
137
|
+
if (typeof actionResult === 'string') {
|
|
138
|
+
await tracker.stop();
|
|
139
|
+
return actionResult;
|
|
140
|
+
}
|
|
141
|
+
const snapshot = await this.captureCurrentSnapshot(step);
|
|
142
|
+
await tracker.stop();
|
|
143
|
+
const formattedTimeline = tracker.formatTimeline();
|
|
144
|
+
return { response: formattedTimeline || fallbackResponse, snapshot };
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
await tracker.stop();
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function createBrowserTools(runtime) {
|
|
153
|
+
return [
|
|
154
|
+
defineAgentTool({
|
|
155
|
+
name: BrowserTool.TOOL_NAVIGATE,
|
|
156
|
+
description: 'Navigate to a specified URL in the browser, example: https://www.example.com',
|
|
157
|
+
schema: z
|
|
158
|
+
.object({
|
|
159
|
+
url: z.string().describe('The URL to navigate to'),
|
|
160
|
+
goal: z.string().describe('The goal or purpose of navigating to this URL'),
|
|
161
|
+
})
|
|
162
|
+
.strict(),
|
|
163
|
+
handler: ({ url }, context) => runtime.navigateToUrl(url, context.step),
|
|
164
|
+
}),
|
|
165
|
+
defineAgentTool({
|
|
166
|
+
name: BrowserTool.TOOL_CLICK_OR_HOVER,
|
|
167
|
+
description: 'Click or hover a specified element reference in the browser',
|
|
168
|
+
schema: z
|
|
169
|
+
.object({
|
|
170
|
+
ref: z.string().describe('ref value of the element from the snapshot, example: e123'),
|
|
171
|
+
name: z.string().describe('name of the element to click or hover, example: Submit Button'),
|
|
172
|
+
hover: z.boolean().describe('If true: hover the element, if false: click element'),
|
|
173
|
+
goal: z.string().describe('The goal or purpose of clicking this element'),
|
|
174
|
+
})
|
|
175
|
+
.strict(),
|
|
176
|
+
handler: ({ ref, hover }, context) => runtime.clickElement(ref, hover, context.step),
|
|
177
|
+
}),
|
|
178
|
+
defineAgentTool({
|
|
179
|
+
name: BrowserTool.TOOL_TYPE_OR_SELECT,
|
|
180
|
+
description: 'Type text into a specified element reference in the browser or select an option from a dropdown.',
|
|
181
|
+
schema: z
|
|
182
|
+
.object({
|
|
183
|
+
elements: z.array(browserInputElementSchema).min(1).describe('array of elements to type into'),
|
|
184
|
+
goal: z.string().describe('The goal or purpose of typing this text into the element'),
|
|
185
|
+
})
|
|
186
|
+
.strict(),
|
|
187
|
+
handler: ({ elements }, context) => runtime.typeOrSelectInElement(elements, context.step),
|
|
188
|
+
}),
|
|
189
|
+
defineAgentTool({
|
|
190
|
+
name: BrowserTool.TOOL_PRESS_KEY,
|
|
191
|
+
description: 'Press a specified key in the browser',
|
|
192
|
+
schema: z
|
|
193
|
+
.object({
|
|
194
|
+
key: z.string().describe('The key to press, example: Enter, Escape, ArrowDown'),
|
|
195
|
+
goal: z.string().describe('The goal or purpose of pressing this key'),
|
|
196
|
+
})
|
|
197
|
+
.strict(),
|
|
198
|
+
handler: ({ key }, context) => runtime.pressKey(key, context.step),
|
|
199
|
+
}),
|
|
200
|
+
defineAgentTool({
|
|
201
|
+
name: BrowserTool.TOOL_SNAPSHOT,
|
|
202
|
+
description: 'Capture the ARIA snapshot of the current page - use only if you miss information from previous snapshot.',
|
|
203
|
+
schema: z
|
|
204
|
+
.object({
|
|
205
|
+
goal: z.string().describe('The goal or purpose of capturing the snapshot'),
|
|
206
|
+
})
|
|
207
|
+
.strict(),
|
|
208
|
+
handler: async (_args, context) => ({
|
|
209
|
+
response: 'Captured latest page snapshot.',
|
|
210
|
+
snapshot: await runtime.captureCurrentSnapshot(context.step, { skipFilter: true }),
|
|
211
|
+
}),
|
|
212
|
+
}),
|
|
213
|
+
defineAgentTool({
|
|
214
|
+
name: BrowserTool.TOOL_WAIT,
|
|
215
|
+
description: 'Wait for a timeout in seconds',
|
|
216
|
+
schema: z
|
|
217
|
+
.object({
|
|
218
|
+
seconds: z.number().describe('Number of seconds to wait, example: 5'),
|
|
219
|
+
goal: z.string().describe('The goal or purpose of waiting'),
|
|
220
|
+
})
|
|
221
|
+
.strict(),
|
|
222
|
+
handler: ({ seconds }, context) => runtime.wait(seconds, context.step),
|
|
223
|
+
}),
|
|
224
|
+
];
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=tool.js.map
|