alumnium 0.16.0 → 0.18.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/dist/Alumni.d.ts +6 -1
- package/dist/Alumni.js +73 -32
- package/dist/Area.d.ts +2 -1
- package/dist/Area.js +53 -10
- package/dist/Model.d.ts +1 -0
- package/dist/Model.js +7 -5
- package/dist/accessibility/AccessibilityElement.d.ts +4 -1
- package/dist/accessibility/AccessibilityElement.js +4 -1
- package/dist/accessibility/ChromiumAccessibilityTree.d.ts +3 -0
- package/dist/accessibility/ChromiumAccessibilityTree.js +86 -9
- package/dist/accessibility/UIAutomator2AccessibilityTree.d.ts +1 -0
- package/dist/accessibility/UIAutomator2AccessibilityTree.js +6 -1
- package/dist/accessibility/XCUITestAccessibilityTree.d.ts +2 -0
- package/dist/accessibility/XCUITestAccessibilityTree.js +31 -2
- package/dist/clients/ApiModels.d.ts +20 -0
- package/dist/clients/HttpClient.d.ts +15 -6
- package/dist/clients/HttpClient.js +36 -8
- package/dist/drivers/AppiumDriver.d.ts +16 -6
- package/dist/drivers/AppiumDriver.js +84 -61
- package/dist/drivers/BaseDriver.d.ts +19 -9
- package/dist/drivers/PlaywrightDriver.d.ts +35 -3
- package/dist/drivers/PlaywrightDriver.js +481 -41
- package/dist/drivers/SeleniumDriver.d.ts +22 -3
- package/dist/drivers/SeleniumDriver.js +272 -27
- package/dist/drivers/index.d.ts +1 -2
- package/dist/drivers/scripts/waiter.js +133 -19
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/result.d.ts +9 -0
- package/dist/result.js +1 -0
- package/dist/tools/BaseTool.d.ts +1 -1
- package/dist/tools/BaseTool.js +9 -3
- package/dist/tools/ClickTool.js +2 -1
- package/dist/tools/DragSliderTool.d.ts +14 -0
- package/dist/tools/DragSliderTool.js +25 -0
- package/dist/tools/ExecuteJavascriptTool.d.ts +12 -0
- package/dist/tools/ExecuteJavascriptTool.js +19 -0
- package/dist/tools/Field.d.ts +6 -0
- package/dist/tools/Field.js +1 -0
- package/dist/tools/HoverTool.d.ts +3 -2
- package/dist/tools/NavigateToUrlTool.d.ts +12 -0
- package/dist/tools/NavigateToUrlTool.js +19 -0
- package/dist/tools/PressKeyTool.js +1 -1
- package/dist/tools/PrintToPdfTool.d.ts +12 -0
- package/dist/tools/PrintToPdfTool.js +19 -0
- package/dist/tools/{SelectTool.d.ts → ScrollTool.d.ts} +1 -3
- package/dist/tools/ScrollTool.js +19 -0
- package/dist/tools/SwitchToNextTabTool.d.ts +6 -0
- package/dist/tools/SwitchToNextTabTool.js +7 -0
- package/dist/tools/SwitchToPreviousTabTool.d.ts +6 -0
- package/dist/tools/SwitchToPreviousTabTool.js +7 -0
- package/dist/tools/TypeTool.js +1 -1
- package/dist/tools/UploadTool.d.ts +16 -0
- package/dist/tools/UploadTool.js +37 -0
- package/dist/tools/WaitForElementTool.d.ts +14 -0
- package/dist/tools/WaitForElementTool.js +33 -0
- package/dist/tools/WaitTool.d.ts +12 -0
- package/dist/tools/WaitTool.js +26 -0
- package/dist/tools/toolToSchemaConverter.d.ts +3 -0
- package/dist/tools/toolToSchemaConverter.js +3 -0
- package/dist/utils/retry.d.ts +3 -3
- package/dist/utils/retry.js +15 -4
- package/package.json +1 -1
- package/dist/tools/SelectTool.js +0 -21
package/dist/Alumni.d.ts
CHANGED
|
@@ -7,11 +7,15 @@ import { Data } from "./clients/typecasting.js";
|
|
|
7
7
|
import { BaseDriver } from "./drivers/BaseDriver.js";
|
|
8
8
|
import { Element } from "./drivers/index.js";
|
|
9
9
|
import { Model } from "./Model.js";
|
|
10
|
+
import { DoResult } from "./result.js";
|
|
10
11
|
import { ToolClass } from "./tools/BaseTool.js";
|
|
11
12
|
export interface AlumniOptions {
|
|
12
13
|
url?: string;
|
|
13
14
|
model?: Model;
|
|
14
15
|
extraTools?: ToolClass[];
|
|
16
|
+
planner?: boolean;
|
|
17
|
+
changeAnalysis?: boolean;
|
|
18
|
+
excludedAttributes?: Set<string>;
|
|
15
19
|
}
|
|
16
20
|
export interface VisionOptions {
|
|
17
21
|
vision?: boolean;
|
|
@@ -23,9 +27,10 @@ export declare class Alumni {
|
|
|
23
27
|
cache: Cache;
|
|
24
28
|
private url;
|
|
25
29
|
private model;
|
|
30
|
+
private changeAnalysis;
|
|
26
31
|
constructor(driver: WebDriver | Page | Browser, options?: AlumniOptions);
|
|
27
32
|
quit(): Promise<void>;
|
|
28
|
-
do(goal: string): Promise<
|
|
33
|
+
do(goal: string): Promise<DoResult>;
|
|
29
34
|
check(statement: string, options?: VisionOptions): Promise<string>;
|
|
30
35
|
get(data: string, options?: VisionOptions): Promise<Data>;
|
|
31
36
|
find(description: string): Promise<Element>;
|
package/dist/Alumni.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
1
10
|
import { WebDriver } from "selenium-webdriver";
|
|
2
11
|
import { Area } from "./Area.js";
|
|
3
12
|
import { Cache } from "./Cache.js";
|
|
@@ -8,18 +17,18 @@ import { SeleniumDriver } from "./drivers/SeleniumDriver.js";
|
|
|
8
17
|
import { AssertionError } from "./errors/AssertionError.js";
|
|
9
18
|
import { Model } from "./Model.js";
|
|
10
19
|
import { BaseTool } from "./tools/BaseTool.js";
|
|
11
|
-
import { ClickTool } from "./tools/ClickTool.js";
|
|
12
|
-
import { DragAndDropTool } from "./tools/DragAndDropTool.js";
|
|
13
|
-
import { HoverTool } from "./tools/HoverTool.js";
|
|
14
|
-
import { PressKeyTool } from "./tools/PressKeyTool.js";
|
|
15
|
-
import { SelectTool } from "./tools/SelectTool.js";
|
|
16
|
-
import { TypeTool } from "./tools/TypeTool.js";
|
|
17
20
|
import { getLogger } from "./utils/logger.js";
|
|
21
|
+
import { retry } from "./utils/retry.js";
|
|
18
22
|
const logger = getLogger(["Alumni"]);
|
|
23
|
+
const changeAnalysis = (process.env.ALUMNIUM_CHANGE_ANALYSIS || "false").toLowerCase() === "true";
|
|
24
|
+
const planner = (process.env.ALUMNIUM_PLANNER || "true").toLowerCase() === "true";
|
|
25
|
+
const excludedAttributes = new Set((process.env.ALUMNIUM_EXCLUDE_ATTRIBUTES || "").split(",").filter(Boolean));
|
|
19
26
|
export class Alumni {
|
|
20
27
|
constructor(driver, options = {}) {
|
|
28
|
+
this.tools = {};
|
|
21
29
|
this.url = options.url || "http://localhost:8013";
|
|
22
30
|
this.model = options.model || Model.current;
|
|
31
|
+
this.changeAnalysis = options.changeAnalysis ?? changeAnalysis;
|
|
23
32
|
// Wrap driver or use directly if already wrapped
|
|
24
33
|
if (driver instanceof WebDriver) {
|
|
25
34
|
this.driver = new SeleniumDriver(driver);
|
|
@@ -35,23 +44,14 @@ export class Alumni {
|
|
|
35
44
|
else {
|
|
36
45
|
throw new Error(`Unsupported driver type '${typeof driver}'`);
|
|
37
46
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
SelectTool,
|
|
44
|
-
PressKeyTool,
|
|
45
|
-
DragAndDropTool,
|
|
46
|
-
};
|
|
47
|
-
// Add extra tools if provided
|
|
48
|
-
if (options.extraTools) {
|
|
49
|
-
for (const tool of options.extraTools) {
|
|
50
|
-
this.tools[tool.name] = tool;
|
|
51
|
-
}
|
|
47
|
+
for (const tool of new Set([
|
|
48
|
+
...this.driver.supportedTools,
|
|
49
|
+
...(options.extraTools || []),
|
|
50
|
+
])) {
|
|
51
|
+
this.tools[tool.name] = tool;
|
|
52
52
|
}
|
|
53
53
|
// Initialize HTTP client
|
|
54
|
-
this.client = new HttpClient(this.url, this.model, this.driver.platform, this.tools);
|
|
54
|
+
this.client = new HttpClient(this.url, this.model, this.driver.platform, this.tools, options.planner ?? planner, options.excludedAttributes ?? excludedAttributes);
|
|
55
55
|
this.cache = new Cache(this.client);
|
|
56
56
|
logger.info(`Using model: ${this.model.provider}/${this.model.name}`);
|
|
57
57
|
logger.info(`Using HTTP client with server: ${this.url}`);
|
|
@@ -61,27 +61,45 @@ export class Alumni {
|
|
|
61
61
|
await this.driver.quit();
|
|
62
62
|
}
|
|
63
63
|
async do(goal) {
|
|
64
|
+
const app = await this.driver.app();
|
|
64
65
|
const initialAccessibilityTree = await this.driver.getAccessibilityTree();
|
|
65
|
-
const
|
|
66
|
+
const beforeTree = this.changeAnalysis
|
|
67
|
+
? initialAccessibilityTree.toStr()
|
|
68
|
+
: null;
|
|
69
|
+
const beforeUrl = this.changeAnalysis ? await this.driver.url() : null;
|
|
70
|
+
const { explanation, steps } = await this.client.planActions(goal, initialAccessibilityTree.toStr(), app);
|
|
71
|
+
let finalExplanation = explanation;
|
|
72
|
+
const executedSteps = [];
|
|
66
73
|
for (let idx = 0; idx < steps.length; idx++) {
|
|
67
74
|
const step = steps[idx];
|
|
68
75
|
// Use initial tree for first step, fresh tree for subsequent steps
|
|
69
76
|
const accessibilityTree = idx === 0
|
|
70
77
|
? initialAccessibilityTree
|
|
71
78
|
: await this.driver.getAccessibilityTree();
|
|
72
|
-
const
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
const { explanation: actorExplanation, actions } = await this.client.executeAction(goal, step, accessibilityTree.toStr(), app);
|
|
80
|
+
// When planner is off, explanation is just the goal — replace with actor's reasoning.
|
|
81
|
+
if (finalExplanation === goal) {
|
|
82
|
+
finalExplanation = actorExplanation;
|
|
83
|
+
}
|
|
84
|
+
const calledTools = [];
|
|
85
|
+
for (const toolCall of actions) {
|
|
86
|
+
const calledTool = await BaseTool.executeToolCall(toolCall, this.tools, this.driver);
|
|
87
|
+
calledTools.push(calledTool);
|
|
76
88
|
}
|
|
89
|
+
executedSteps.push({ name: step, tools: calledTools });
|
|
90
|
+
}
|
|
91
|
+
let changes = "";
|
|
92
|
+
if (this.changeAnalysis && executedSteps.length > 0) {
|
|
93
|
+
changes = await this.client.analyzeChanges(beforeTree, beforeUrl, (await this.driver.getAccessibilityTree()).toStr(), await this.driver.url());
|
|
77
94
|
}
|
|
95
|
+
return { explanation: finalExplanation, steps: executedSteps, changes };
|
|
78
96
|
}
|
|
79
97
|
async check(statement, options = {}) {
|
|
80
98
|
const screenshot = options.vision
|
|
81
99
|
? await this.driver.screenshot()
|
|
82
100
|
: undefined;
|
|
83
101
|
const accessibilityTree = await this.driver.getAccessibilityTree();
|
|
84
|
-
const [explanation, value] = await this.client.retrieve(`Is the following true or false - ${statement}`, accessibilityTree.toStr(), await this.driver.title(), await this.driver.url(), screenshot);
|
|
102
|
+
const [explanation, value] = await this.client.retrieve(`Is the following true or false - ${statement}`, accessibilityTree.toStr(), await this.driver.title(), await this.driver.url(), screenshot, await this.driver.app());
|
|
85
103
|
if (!value) {
|
|
86
104
|
throw new AssertionError(explanation);
|
|
87
105
|
}
|
|
@@ -92,18 +110,17 @@ export class Alumni {
|
|
|
92
110
|
? await this.driver.screenshot()
|
|
93
111
|
: undefined;
|
|
94
112
|
const accessibilityTree = await this.driver.getAccessibilityTree();
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return value;
|
|
113
|
+
const [explanation, value] = await this.client.retrieve(data, accessibilityTree.toStr(), await this.driver.title(), await this.driver.url(), screenshot, await this.driver.app());
|
|
114
|
+
return value === null ? explanation : value;
|
|
98
115
|
}
|
|
99
116
|
async find(description) {
|
|
100
117
|
const accessibilityTree = await this.driver.getAccessibilityTree();
|
|
101
|
-
const response = await this.client.findElement(description, accessibilityTree.toStr());
|
|
118
|
+
const response = await this.client.findElement(description, accessibilityTree.toStr(), await this.driver.app());
|
|
102
119
|
return this.driver.findElement(response.id);
|
|
103
120
|
}
|
|
104
121
|
async area(description) {
|
|
105
122
|
const accessibilityTree = await this.driver.getAccessibilityTree();
|
|
106
|
-
const response = await this.client.findArea(description, accessibilityTree.toStr());
|
|
123
|
+
const response = await this.client.findArea(description, accessibilityTree.toStr(), await this.driver.app());
|
|
107
124
|
const scopedTree = accessibilityTree.scopeToArea(response.id);
|
|
108
125
|
return new Area(response.id, response.explanation, scopedTree, this.driver, this.tools, this.client);
|
|
109
126
|
}
|
|
@@ -117,3 +134,27 @@ export class Alumni {
|
|
|
117
134
|
return await this.client.getStats();
|
|
118
135
|
}
|
|
119
136
|
}
|
|
137
|
+
__decorate([
|
|
138
|
+
retry(),
|
|
139
|
+
__metadata("design:type", Function),
|
|
140
|
+
__metadata("design:paramtypes", [String]),
|
|
141
|
+
__metadata("design:returntype", Promise)
|
|
142
|
+
], Alumni.prototype, "do", null);
|
|
143
|
+
__decorate([
|
|
144
|
+
retry(),
|
|
145
|
+
__metadata("design:type", Function),
|
|
146
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
147
|
+
__metadata("design:returntype", Promise)
|
|
148
|
+
], Alumni.prototype, "check", null);
|
|
149
|
+
__decorate([
|
|
150
|
+
retry(),
|
|
151
|
+
__metadata("design:type", Function),
|
|
152
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
153
|
+
__metadata("design:returntype", Promise)
|
|
154
|
+
], Alumni.prototype, "get", null);
|
|
155
|
+
__decorate([
|
|
156
|
+
retry(),
|
|
157
|
+
__metadata("design:type", Function),
|
|
158
|
+
__metadata("design:paramtypes", [String]),
|
|
159
|
+
__metadata("design:returntype", Promise)
|
|
160
|
+
], Alumni.prototype, "find", null);
|
package/dist/Area.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { HttpClient } from "./clients/HttpClient.js";
|
|
|
4
4
|
import { Data } from "./clients/typecasting.js";
|
|
5
5
|
import { BaseDriver } from "./drivers/BaseDriver.js";
|
|
6
6
|
import { Element } from "./drivers/index.js";
|
|
7
|
+
import { DoResult } from "./result.js";
|
|
7
8
|
import { ToolClass } from "./tools/BaseTool.js";
|
|
8
9
|
export declare class Area {
|
|
9
10
|
id: number;
|
|
@@ -13,7 +14,7 @@ export declare class Area {
|
|
|
13
14
|
private tools;
|
|
14
15
|
private client;
|
|
15
16
|
constructor(id: number, description: string, accessibilityTree: BaseAccessibilityTree, driver: BaseDriver, tools: Record<string, ToolClass>, client: HttpClient);
|
|
16
|
-
do(goal: string): Promise<
|
|
17
|
+
do(goal: string): Promise<DoResult>;
|
|
17
18
|
check(statement: string, options?: VisionOptions): Promise<string>;
|
|
18
19
|
get(data: string, options?: VisionOptions): Promise<Data>;
|
|
19
20
|
find(description: string): Promise<Element>;
|
package/dist/Area.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
1
10
|
import { AssertionError } from "./errors/AssertionError.js";
|
|
2
11
|
import { BaseTool } from "./tools/BaseTool.js";
|
|
12
|
+
import { retry } from "./utils/retry.js";
|
|
3
13
|
export class Area {
|
|
4
14
|
constructor(id, description, accessibilityTree, driver, tools, client) {
|
|
5
15
|
this.id = id;
|
|
@@ -10,20 +20,30 @@ export class Area {
|
|
|
10
20
|
this.client = client;
|
|
11
21
|
}
|
|
12
22
|
async do(goal) {
|
|
13
|
-
const
|
|
23
|
+
const app = await this.driver.app();
|
|
24
|
+
const { explanation, steps } = await this.client.planActions(goal, this.accessibilityTree.toStr(), app);
|
|
25
|
+
let finalExplanation = explanation;
|
|
26
|
+
const executedSteps = [];
|
|
14
27
|
for (const step of steps) {
|
|
15
|
-
const
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
const { explanation: actorExplanation, actions } = await this.client.executeAction(goal, step, this.accessibilityTree.toStr(), app);
|
|
29
|
+
// When planner is off, explanation is just the goal — replace with actor's reasoning.
|
|
30
|
+
if (finalExplanation === goal) {
|
|
31
|
+
finalExplanation = actorExplanation;
|
|
19
32
|
}
|
|
33
|
+
const calledTools = [];
|
|
34
|
+
for (const toolCall of actions) {
|
|
35
|
+
const calledTool = await BaseTool.executeToolCall(toolCall, this.tools, this.driver);
|
|
36
|
+
calledTools.push(calledTool);
|
|
37
|
+
}
|
|
38
|
+
executedSteps.push({ name: step, tools: calledTools });
|
|
20
39
|
}
|
|
40
|
+
return { explanation: finalExplanation, steps: executedSteps, changes: "" };
|
|
21
41
|
}
|
|
22
42
|
async check(statement, options = {}) {
|
|
23
43
|
const screenshot = options.vision
|
|
24
44
|
? await this.driver.screenshot()
|
|
25
45
|
: undefined;
|
|
26
|
-
const [explanation, value] = await this.client.retrieve(`Is the following true or false - ${statement}`, this.accessibilityTree.toStr(), await this.driver.title(), await this.driver.url(), screenshot);
|
|
46
|
+
const [explanation, value] = await this.client.retrieve(`Is the following true or false - ${statement}`, this.accessibilityTree.toStr(), await this.driver.title(), await this.driver.url(), screenshot, await this.driver.app());
|
|
27
47
|
if (!value) {
|
|
28
48
|
throw new AssertionError(explanation);
|
|
29
49
|
}
|
|
@@ -33,12 +53,35 @@ export class Area {
|
|
|
33
53
|
const screenshot = options.vision
|
|
34
54
|
? await this.driver.screenshot()
|
|
35
55
|
: undefined;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return value;
|
|
56
|
+
const [explanation, value] = await this.client.retrieve(data, this.accessibilityTree.toStr(), await this.driver.title(), await this.driver.url(), screenshot, await this.driver.app());
|
|
57
|
+
return value === null ? explanation : value;
|
|
39
58
|
}
|
|
40
59
|
async find(description) {
|
|
41
|
-
const response = await this.client.findElement(description, this.accessibilityTree.toStr());
|
|
60
|
+
const response = await this.client.findElement(description, this.accessibilityTree.toStr(), await this.driver.app());
|
|
42
61
|
return this.driver.findElement(response.id);
|
|
43
62
|
}
|
|
44
63
|
}
|
|
64
|
+
__decorate([
|
|
65
|
+
retry(),
|
|
66
|
+
__metadata("design:type", Function),
|
|
67
|
+
__metadata("design:paramtypes", [String]),
|
|
68
|
+
__metadata("design:returntype", Promise)
|
|
69
|
+
], Area.prototype, "do", null);
|
|
70
|
+
__decorate([
|
|
71
|
+
retry(),
|
|
72
|
+
__metadata("design:type", Function),
|
|
73
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
74
|
+
__metadata("design:returntype", Promise)
|
|
75
|
+
], Area.prototype, "check", null);
|
|
76
|
+
__decorate([
|
|
77
|
+
retry(),
|
|
78
|
+
__metadata("design:type", Function),
|
|
79
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
80
|
+
__metadata("design:returntype", Promise)
|
|
81
|
+
], Area.prototype, "get", null);
|
|
82
|
+
__decorate([
|
|
83
|
+
retry(),
|
|
84
|
+
__metadata("design:type", Function),
|
|
85
|
+
__metadata("design:paramtypes", [String]),
|
|
86
|
+
__metadata("design:returntype", Promise)
|
|
87
|
+
], Area.prototype, "find", null);
|
package/dist/Model.d.ts
CHANGED
package/dist/Model.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export var Provider;
|
|
2
2
|
(function (Provider) {
|
|
3
|
+
Provider["AZURE_FOUNDRY"] = "azure_foundry";
|
|
3
4
|
Provider["AZURE_OPENAI"] = "azure_openai";
|
|
4
5
|
Provider["ANTHROPIC"] = "anthropic";
|
|
5
6
|
Provider["AWS_ANTHROPIC"] = "aws_anthropic";
|
|
@@ -15,17 +16,18 @@ export var Provider;
|
|
|
15
16
|
export class ModelName {
|
|
16
17
|
}
|
|
17
18
|
ModelName.DEFAULT = {
|
|
18
|
-
[Provider.
|
|
19
|
+
[Provider.AZURE_FOUNDRY]: "gpt-5-nano",
|
|
20
|
+
[Provider.AZURE_OPENAI]: "gpt-5-nano",
|
|
19
21
|
[Provider.ANTHROPIC]: "claude-haiku-4-5-20251001",
|
|
20
22
|
[Provider.AWS_ANTHROPIC]: "us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
21
23
|
[Provider.AWS_META]: "us.meta.llama4-maverick-17b-instruct-v1:0",
|
|
22
|
-
[Provider.DEEPSEEK]: "deepseek-
|
|
24
|
+
[Provider.DEEPSEEK]: "deepseek-reasoner",
|
|
23
25
|
[Provider.GITHUB]: "gpt-4o-mini",
|
|
24
|
-
[Provider.GOOGLE]: "gemini-
|
|
26
|
+
[Provider.GOOGLE]: "gemini-3.1-flash-lite-preview",
|
|
25
27
|
[Provider.MISTRALAI]: "mistral-medium-2505",
|
|
26
28
|
[Provider.OLLAMA]: "mistral-small3.1",
|
|
27
|
-
[Provider.OPENAI]: "gpt-
|
|
28
|
-
[Provider.XAI]: "grok-4-fast-
|
|
29
|
+
[Provider.OPENAI]: "gpt-5-nano-2025-08-07",
|
|
30
|
+
[Provider.XAI]: "grok-4-1-fast-reasoning",
|
|
29
31
|
};
|
|
30
32
|
export class Model {
|
|
31
33
|
constructor(provider, name) {
|
|
@@ -10,5 +10,8 @@ export declare class AccessibilityElement {
|
|
|
10
10
|
androidText?: string;
|
|
11
11
|
androidContentDesc?: string;
|
|
12
12
|
androidBounds?: string;
|
|
13
|
-
|
|
13
|
+
frame?: object;
|
|
14
|
+
locatorInfo?: Record<string, unknown>;
|
|
15
|
+
frameChain?: number[];
|
|
16
|
+
constructor(id?: number, name?: string, label?: string, type?: string, value?: string, backendNodeId?: number, androidResourceId?: string, androidClass?: string, androidText?: string, androidContentDesc?: string, androidBounds?: string, frame?: object, locatorInfo?: Record<string, unknown>, frameChain?: number[]);
|
|
14
17
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export class AccessibilityElement {
|
|
2
|
-
constructor(id, name, label, type, value, backendNodeId, androidResourceId, androidClass, androidText, androidContentDesc, androidBounds) {
|
|
2
|
+
constructor(id, name, label, type, value, backendNodeId, androidResourceId, androidClass, androidText, androidContentDesc, androidBounds, frame, locatorInfo, frameChain) {
|
|
3
3
|
this.id = id;
|
|
4
4
|
this.backendNodeId = backendNodeId;
|
|
5
5
|
this.name = name;
|
|
@@ -11,5 +11,8 @@ export class AccessibilityElement {
|
|
|
11
11
|
this.androidText = androidText;
|
|
12
12
|
this.androidContentDesc = androidContentDesc;
|
|
13
13
|
this.androidBounds = androidBounds;
|
|
14
|
+
this.frame = frame;
|
|
15
|
+
this.locatorInfo = locatorInfo;
|
|
16
|
+
this.frameChain = frameChain;
|
|
14
17
|
}
|
|
15
18
|
}
|
|
@@ -4,11 +4,14 @@ export declare class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
4
4
|
private cdpResponse;
|
|
5
5
|
private nextRawId;
|
|
6
6
|
private raw;
|
|
7
|
+
private frameMap;
|
|
8
|
+
private frameChainMap;
|
|
7
9
|
constructor(cdpResponse: unknown);
|
|
8
10
|
private static fromXml;
|
|
9
11
|
toStr(): string;
|
|
10
12
|
private nodeToXml;
|
|
11
13
|
private elementToString;
|
|
14
|
+
private unescapeXml;
|
|
12
15
|
elementById(rawId: number): AccessibilityElement;
|
|
13
16
|
scopeToArea(rawId: number): ChromiumAccessibilityTree;
|
|
14
17
|
private findElementByRawId;
|
|
@@ -5,11 +5,16 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
5
5
|
super();
|
|
6
6
|
this.nextRawId = 0;
|
|
7
7
|
this.raw = null;
|
|
8
|
+
this.frameMap = new Map();
|
|
9
|
+
this.frameChainMap = new Map(); // raw_id -> frame chain
|
|
8
10
|
this.cdpResponse = cdpResponse;
|
|
9
11
|
}
|
|
10
|
-
static fromXml(xmlString) {
|
|
12
|
+
static fromXml(xmlString, frameMap) {
|
|
11
13
|
const instance = new ChromiumAccessibilityTree({ nodes: [] });
|
|
12
14
|
instance.raw = xmlString;
|
|
15
|
+
if (frameMap) {
|
|
16
|
+
instance.frameMap = frameMap;
|
|
17
|
+
}
|
|
13
18
|
return instance;
|
|
14
19
|
}
|
|
15
20
|
toStr() {
|
|
@@ -17,18 +22,38 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
17
22
|
return this.raw;
|
|
18
23
|
}
|
|
19
24
|
const nodes = this.cdpResponse.nodes;
|
|
25
|
+
if (!nodes || nodes.length === 0) {
|
|
26
|
+
this.raw = "";
|
|
27
|
+
return this.raw;
|
|
28
|
+
}
|
|
20
29
|
const nodeLookup = {};
|
|
21
30
|
for (const node of nodes) {
|
|
22
31
|
nodeLookup[node.nodeId] = node;
|
|
23
32
|
}
|
|
24
|
-
// Build
|
|
25
|
-
|
|
33
|
+
// Build mapping: backendDOMNodeId -> list of iframe child root nodes
|
|
34
|
+
// This allows us to inline iframe content inside their parent <Iframe> elements
|
|
35
|
+
const iframeChildren = new Map();
|
|
36
|
+
const trueRoots = [];
|
|
26
37
|
for (const node of nodes) {
|
|
27
38
|
if (!node.parentId) {
|
|
28
|
-
const
|
|
29
|
-
|
|
39
|
+
const parentIframeId = node._parent_iframe_backend_node_id;
|
|
40
|
+
if (parentIframeId !== undefined) {
|
|
41
|
+
if (!iframeChildren.has(parentIframeId)) {
|
|
42
|
+
iframeChildren.set(parentIframeId, []);
|
|
43
|
+
}
|
|
44
|
+
iframeChildren.get(parentIframeId).push(node);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
trueRoots.push(node);
|
|
48
|
+
}
|
|
30
49
|
}
|
|
31
50
|
}
|
|
51
|
+
// Build tree structure and convert to XML (only from true roots)
|
|
52
|
+
const rootNodes = [];
|
|
53
|
+
for (const node of trueRoots) {
|
|
54
|
+
const xmlNode = this.nodeToXml(node, nodeLookup, iframeChildren);
|
|
55
|
+
rootNodes.push(xmlNode);
|
|
56
|
+
}
|
|
32
57
|
// Combine all root nodes into a single XML string
|
|
33
58
|
let xmlString = "";
|
|
34
59
|
for (const root of rootNodes) {
|
|
@@ -37,7 +62,7 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
37
62
|
this.raw = xmlString;
|
|
38
63
|
return this.raw;
|
|
39
64
|
}
|
|
40
|
-
nodeToXml(node, nodeLookup) {
|
|
65
|
+
nodeToXml(node, nodeLookup, iframeChildren) {
|
|
41
66
|
const role = node.role?.value || "unknown";
|
|
42
67
|
const elem = {
|
|
43
68
|
tag: role,
|
|
@@ -47,6 +72,24 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
47
72
|
// Add our own sequential raw_id attribute
|
|
48
73
|
this.nextRawId++;
|
|
49
74
|
elem.attributes.raw_id = String(this.nextRawId);
|
|
75
|
+
// Store frame reference if present
|
|
76
|
+
if (node._frame) {
|
|
77
|
+
this.frameMap.set(this.nextRawId, node._frame);
|
|
78
|
+
}
|
|
79
|
+
// Store frame chain if present (for Selenium nested frame switching)
|
|
80
|
+
if (node._frame_chain) {
|
|
81
|
+
this.frameChainMap.set(this.nextRawId, node._frame_chain);
|
|
82
|
+
}
|
|
83
|
+
// Store Playwright node metadata
|
|
84
|
+
if (node._playwright_node) {
|
|
85
|
+
elem.attributes._playwright_node = "true";
|
|
86
|
+
}
|
|
87
|
+
if (node._locator_info) {
|
|
88
|
+
elem.attributes._locator_info = JSON.stringify(node._locator_info);
|
|
89
|
+
}
|
|
90
|
+
if (node._frame_url) {
|
|
91
|
+
elem.attributes._frame_url = node._frame_url;
|
|
92
|
+
}
|
|
50
93
|
// Add all node attributes as XML attributes
|
|
51
94
|
if (node.backendDOMNodeId !== undefined) {
|
|
52
95
|
elem.attributes.backendDOMNodeId = String(node.backendDOMNodeId);
|
|
@@ -84,11 +127,19 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
84
127
|
if (node.childIds) {
|
|
85
128
|
for (const childId of node.childIds) {
|
|
86
129
|
if (childId in nodeLookup) {
|
|
87
|
-
const childElem = this.nodeToXml(nodeLookup[childId], nodeLookup);
|
|
130
|
+
const childElem = this.nodeToXml(nodeLookup[childId], nodeLookup, iframeChildren);
|
|
88
131
|
elem.children.push(childElem);
|
|
89
132
|
}
|
|
90
133
|
}
|
|
91
134
|
}
|
|
135
|
+
// Inline iframe content: if this element is an iframe, add its child trees
|
|
136
|
+
const backendNodeId = node.backendDOMNodeId;
|
|
137
|
+
if (backendNodeId !== undefined && iframeChildren.has(backendNodeId)) {
|
|
138
|
+
for (const childRoot of iframeChildren.get(backendNodeId)) {
|
|
139
|
+
const childElem = this.nodeToXml(childRoot, nodeLookup, iframeChildren);
|
|
140
|
+
elem.children.push(childElem);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
92
143
|
return elem;
|
|
93
144
|
}
|
|
94
145
|
elementToString(elem, indent) {
|
|
@@ -124,17 +175,39 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
124
175
|
}
|
|
125
176
|
return result;
|
|
126
177
|
}
|
|
178
|
+
unescapeXml(value) {
|
|
179
|
+
return value
|
|
180
|
+
.replace(/'/g, "'")
|
|
181
|
+
.replace(/"/g, '"')
|
|
182
|
+
.replace(/>/g, ">")
|
|
183
|
+
.replace(/</g, "<")
|
|
184
|
+
.replace(/&/g, "&");
|
|
185
|
+
}
|
|
127
186
|
elementById(rawId) {
|
|
128
187
|
const rawXml = this.toStr();
|
|
129
188
|
const element = this.findElementByRawId(rawXml, rawId);
|
|
130
189
|
if (!element) {
|
|
131
190
|
throw new Error(`No element with raw_id=${rawId} found`);
|
|
132
191
|
}
|
|
192
|
+
// Handle Playwright nodes (cross-origin iframes)
|
|
193
|
+
if (element.attributes._playwright_node === "true") {
|
|
194
|
+
// Synthetic frame node
|
|
195
|
+
if (element.attributes._frame_url) {
|
|
196
|
+
return new AccessibilityElement(undefined, undefined, undefined, element.tag, undefined, undefined, undefined, undefined, undefined, undefined, undefined, this.frameMap.get(rawId), { _synthetic_frame: true, _frame_url: element.attributes._frame_url });
|
|
197
|
+
}
|
|
198
|
+
// Regular Playwright node with locator info
|
|
199
|
+
const locatorInfo = element.attributes
|
|
200
|
+
._locator_info
|
|
201
|
+
? JSON.parse(element.attributes._locator_info)
|
|
202
|
+
: {};
|
|
203
|
+
return new AccessibilityElement(undefined, undefined, undefined, element.tag, undefined, undefined, undefined, undefined, undefined, undefined, undefined, this.frameMap.get(rawId), locatorInfo);
|
|
204
|
+
}
|
|
205
|
+
// Existing CDP node logic
|
|
133
206
|
const backendNodeIdStr = element.attributes.backendDOMNodeId;
|
|
134
207
|
if (!backendNodeIdStr) {
|
|
135
208
|
throw new Error(`Element with raw_id=${rawId} has no backendDOMNodeId attribute`);
|
|
136
209
|
}
|
|
137
|
-
return new AccessibilityElement(undefined, undefined, undefined, element.tag, undefined, parseInt(backendNodeIdStr));
|
|
210
|
+
return new AccessibilityElement(undefined, undefined, undefined, element.tag, undefined, parseInt(backendNodeIdStr), undefined, undefined, undefined, undefined, undefined, this.frameMap.get(rawId), undefined, this.frameChainMap.get(rawId));
|
|
138
211
|
}
|
|
139
212
|
scopeToArea(rawId) {
|
|
140
213
|
const rawXml = this.toStr();
|
|
@@ -143,7 +216,7 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
143
216
|
return this;
|
|
144
217
|
}
|
|
145
218
|
const scopedXml = this.elementToString(element, 0);
|
|
146
|
-
return ChromiumAccessibilityTree.fromXml(scopedXml);
|
|
219
|
+
return ChromiumAccessibilityTree.fromXml(scopedXml, this.frameMap);
|
|
147
220
|
}
|
|
148
221
|
findElementByRawId(xmlString, targetRawId) {
|
|
149
222
|
// Parse the XML string to find the element
|
|
@@ -195,6 +268,10 @@ export class ChromiumAccessibilityTree extends BaseAccessibilityTree {
|
|
|
195
268
|
while ((attrMatch = attrRegex.exec(attrsString)) !== null) {
|
|
196
269
|
attributes[attrMatch[1]] = attrMatch[2];
|
|
197
270
|
}
|
|
271
|
+
// Unescape XML entities in attribute values
|
|
272
|
+
for (const key of Object.keys(attributes)) {
|
|
273
|
+
attributes[key] = this.unescapeXml(attributes[key]);
|
|
274
|
+
}
|
|
198
275
|
const elem = {
|
|
199
276
|
tag: tagName,
|
|
200
277
|
attributes,
|
|
@@ -5,6 +5,7 @@ export declare class UIAutomator2AccessibilityTree extends BaseAccessibilityTree
|
|
|
5
5
|
private nextRawId;
|
|
6
6
|
private raw;
|
|
7
7
|
constructor(xmlString: string);
|
|
8
|
+
private static fromXml;
|
|
8
9
|
toStr(): string;
|
|
9
10
|
private addRawIds;
|
|
10
11
|
elementById(rawId: number): AccessibilityElement;
|
|
@@ -12,6 +12,11 @@ export class UIAutomator2AccessibilityTree extends BaseAccessibilityTree {
|
|
|
12
12
|
const cleanedXmlContent = cleanedLines.join("\n");
|
|
13
13
|
this.xmlString = `<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\n<root>\n${cleanedXmlContent}\n</root>`;
|
|
14
14
|
}
|
|
15
|
+
static fromXml(xmlString) {
|
|
16
|
+
const instance = new UIAutomator2AccessibilityTree("");
|
|
17
|
+
instance.raw = xmlString;
|
|
18
|
+
return instance;
|
|
19
|
+
}
|
|
15
20
|
toStr() {
|
|
16
21
|
if (this.raw !== null) {
|
|
17
22
|
return this.raw;
|
|
@@ -53,7 +58,7 @@ export class UIAutomator2AccessibilityTree extends BaseAccessibilityTree {
|
|
|
53
58
|
return this;
|
|
54
59
|
}
|
|
55
60
|
const scopedXml = this.elementToString(element, 0);
|
|
56
|
-
return
|
|
61
|
+
return UIAutomator2AccessibilityTree.fromXml(scopedXml);
|
|
57
62
|
}
|
|
58
63
|
findElementByRawId(xmlString, targetRawId) {
|
|
59
64
|
const elements = this.parseSimpleXml(xmlString);
|
|
@@ -5,11 +5,13 @@ export declare class XCUITestAccessibilityTree extends BaseAccessibilityTree {
|
|
|
5
5
|
private nextRawId;
|
|
6
6
|
private raw;
|
|
7
7
|
constructor(xmlString: string);
|
|
8
|
+
private static fromXml;
|
|
8
9
|
toStr(): string;
|
|
9
10
|
private addRawIds;
|
|
10
11
|
elementById(rawId: number): AccessibilityElement;
|
|
11
12
|
scopeToArea(rawId: number): XCUITestAccessibilityTree;
|
|
12
13
|
private findElementByRawId;
|
|
13
14
|
private elementToString;
|
|
15
|
+
private decodeHtmlEntities;
|
|
14
16
|
private parseSimpleXml;
|
|
15
17
|
}
|