@mablhq/mabl-cli 2.94.5 → 2.94.10
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/execution/index.js +2 -2
- package/package.json +1 -1
- package/trainer/generation/TestGenerationOrchestrator.js +4 -12
- package/trainer/generation/toolExecutors/DeleteLastStepsExecutor.js +2 -1
- package/trainer/generation/toolExecutors/RecordAssertElementExecutor.js +3 -2
- package/trainer/generation/toolExecutors/RecordAssertionExecutor.js +13 -35
- package/trainer/generation/toolExecutors/RecordClickExecutor.js +4 -4
- package/trainer/generation/toolExecutors/RecordEnterTextExecutor.js +1 -1
- package/trainer/generation/toolExecutors/RecordHoverExecutor.js +1 -1
- package/trainer/generation/toolExecutors/ScrollExecutor.js +6 -2
- package/trainer/generation/toolExecutors/VisitUrlExecutor.js +1 -1
- package/trainer/generation/toolExecutors/WaitExecutor.js +1 -1
- package/trainer/sharedUtils/boundingBoxUtils.js +11 -0
- package/trainer/sharedUtils/messageConversion.js +31 -0
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ exports.TestGenerationOrchestrator = void 0;
|
|
|
7
7
|
const async_retry_1 = __importDefault(require("async-retry"));
|
|
8
8
|
const mablApi_1 = require("../../mablApi");
|
|
9
9
|
const toolExecutors_1 = require("./toolExecutors");
|
|
10
|
+
const boundingBoxUtils_1 = require("../sharedUtils/boundingBoxUtils");
|
|
10
11
|
const contentActions_1 = require("../background/capture/contentActions");
|
|
11
12
|
const generation_types_1 = require("../sharedUtils/generation-types");
|
|
12
13
|
const messageConversion_1 = require("../sharedUtils/messageConversion");
|
|
@@ -252,7 +253,9 @@ class TestGenerationOrchestrator {
|
|
|
252
253
|
};
|
|
253
254
|
this.logger.info('[runGenerationLoop] Tool call information', JSON.stringify(toolCall, undefined, 2));
|
|
254
255
|
if (toolExecutor.needsFind(toolCall)) {
|
|
255
|
-
const boundingBox =
|
|
256
|
+
const boundingBox = toolCall.toolParams?.elementBoundingBox
|
|
257
|
+
? (0, boundingBoxUtils_1.convertToolLibraryBoundingBox)(toolCall.toolParams.elementBoundingBox)
|
|
258
|
+
: undefined;
|
|
256
259
|
if (!boundingBox) {
|
|
257
260
|
this.logger.error(`Tool ${originalToolCall.name} requires element location but no bounding box was provided by the API`);
|
|
258
261
|
skippedTools.push({
|
|
@@ -452,17 +455,6 @@ class TestGenerationOrchestrator {
|
|
|
452
455
|
return true;
|
|
453
456
|
}
|
|
454
457
|
}
|
|
455
|
-
static buildBoundingBox(responseBoundingBox) {
|
|
456
|
-
if (!responseBoundingBox) {
|
|
457
|
-
return undefined;
|
|
458
|
-
}
|
|
459
|
-
return {
|
|
460
|
-
x: responseBoundingBox.left,
|
|
461
|
-
y: responseBoundingBox.top,
|
|
462
|
-
width: responseBoundingBox.right - responseBoundingBox.left,
|
|
463
|
-
height: responseBoundingBox.bottom - responseBoundingBox.top,
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
458
|
async captureToolOutputContext(success, toolName, tabsBefore = []) {
|
|
467
459
|
const { needsScreenshot, needsUrl, needsTabInfo } = (0, toolExecutors_1.toolNeedsPostExecutionContext)(toolName, success);
|
|
468
460
|
const context = {};
|
|
@@ -6,7 +6,8 @@ exports.deleteLastStepsExecutor = {
|
|
|
6
6
|
needsFind: () => false,
|
|
7
7
|
getStepType: () => mablApi_1.ExecuteToolName.DeleteLastSteps,
|
|
8
8
|
execute: (payload, _stateProvider, eventHandler, logger) => {
|
|
9
|
-
const toolParams = payload.toolCall
|
|
9
|
+
const toolParams = payload.toolCall
|
|
10
|
+
.toolParams;
|
|
10
11
|
const { stepsToDelete } = toolParams;
|
|
11
12
|
if (typeof stepsToDelete !== 'number' || stepsToDelete <= 0) {
|
|
12
13
|
logger.error('Invalid stepsToDelete for RecordDeleteLastStepsExecutor');
|
|
@@ -9,7 +9,8 @@ exports.recordAssertElementExecutor = {
|
|
|
9
9
|
needsFind: () => true,
|
|
10
10
|
getStepType: () => 'assert',
|
|
11
11
|
execute: async (payload, stateProvider, eventHandler, logger) => {
|
|
12
|
-
const toolParams = payload.toolCall
|
|
12
|
+
const toolParams = payload.toolCall
|
|
13
|
+
.toolParams;
|
|
13
14
|
if (!payload.find || !payload.contextInfo) {
|
|
14
15
|
logger.error('RecordAssertElementExecutor requires find and contextInfo');
|
|
15
16
|
return {
|
|
@@ -37,6 +38,6 @@ exports.recordAssertElementExecutor = {
|
|
|
37
38
|
elementAttrProp: 'innerText',
|
|
38
39
|
},
|
|
39
40
|
};
|
|
40
|
-
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(step, payload.contextInfo, true,
|
|
41
|
+
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(step, payload.contextInfo, true, undefined, stateProvider, eventHandler), 0, stateProvider, eventHandler, logger);
|
|
41
42
|
},
|
|
42
43
|
};
|
|
@@ -6,14 +6,9 @@ const generation_types_1 = require("../../sharedUtils/generation-types");
|
|
|
6
6
|
const ExtractDescriptor_1 = require("../../../mablscript/types/ExtractDescriptor");
|
|
7
7
|
const AssertStep_1 = require("../../../mablscript/steps/AssertStep");
|
|
8
8
|
const stepExecution_1 = require("../../sharedUtils/stepExecution");
|
|
9
|
-
const translateMablscript_1 = require("../../sharedUtils/capture/translateMablscript");
|
|
10
|
-
const mablscriptFind_1 = require("../../../mablscriptFind");
|
|
11
9
|
const stepCapture_1 = require("../../background/capture/stepCapture");
|
|
12
10
|
exports.recordAssertionExecutor = {
|
|
13
|
-
needsFind: (
|
|
14
|
-
const toolParams = toolCall.toolParams;
|
|
15
|
-
return isAssertToolParams(toolParams) && !!toolParams.elementBoundingBox;
|
|
16
|
-
},
|
|
11
|
+
needsFind: () => false,
|
|
17
12
|
getStepType: () => 'assert',
|
|
18
13
|
execute: async (payload, stateProvider, eventHandler, logger) => {
|
|
19
14
|
const toolParams = payload.toolCall.toolParams;
|
|
@@ -23,28 +18,14 @@ exports.recordAssertionExecutor = {
|
|
|
23
18
|
success: false,
|
|
24
19
|
};
|
|
25
20
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
if ((0, toolExecutors_1.isFindOneEventMessage)(payload.find)) {
|
|
36
|
-
delete payload.find.stepType;
|
|
37
|
-
}
|
|
38
|
-
const step = (0, toolExecutors_1.isFindOneEventMessage)(payload.find)
|
|
39
|
-
? { ...payload.find, listener: 'mouse-select' }
|
|
40
|
-
: {
|
|
41
|
-
selectionType: 'viewport',
|
|
42
|
-
listener: 'viewport-assert',
|
|
43
|
-
findDescriptor: {
|
|
44
|
-
type: 'viewport',
|
|
45
|
-
},
|
|
46
|
-
action: 'record',
|
|
47
|
-
};
|
|
21
|
+
const step = {
|
|
22
|
+
selectionType: 'viewport',
|
|
23
|
+
listener: 'viewport-assert',
|
|
24
|
+
findDescriptor: {
|
|
25
|
+
type: 'viewport',
|
|
26
|
+
},
|
|
27
|
+
action: 'record',
|
|
28
|
+
};
|
|
48
29
|
step.assertion = {
|
|
49
30
|
assertionType: 'ai_prompt',
|
|
50
31
|
assertionTarget: 'element',
|
|
@@ -54,14 +35,11 @@ exports.recordAssertionExecutor = {
|
|
|
54
35
|
},
|
|
55
36
|
extractionType: ExtractDescriptor_1.ExtractType.EXTRACT_PROMPT,
|
|
56
37
|
onFailure: AssertStep_1.OnFailure.FailTestAtEnd,
|
|
57
|
-
selectionType:
|
|
58
|
-
elementScreenshot:
|
|
38
|
+
selectionType: 'viewport',
|
|
39
|
+
elementScreenshot: false,
|
|
59
40
|
};
|
|
60
41
|
const contextInfo = payload.contextInfo ?? (await stateProvider.getActiveContextInfo());
|
|
61
|
-
const findDescriptor =
|
|
62
|
-
?
|
|
63
|
-
(0, translateMablscript_1.createFindDescriptor)(payload.find, new mablscriptFind_1.ElementSelectorStore())
|
|
64
|
-
: { type: 'viewport' };
|
|
42
|
+
const findDescriptor = { type: 'viewport' };
|
|
65
43
|
const variables = stateProvider.getVariables();
|
|
66
44
|
const testAssertionResult = await (0, stepExecution_1.runAIAssertion)(eventHandler, variables, findDescriptor, step.assertion, contextInfo.frameId, `${contextInfo.tabId}`);
|
|
67
45
|
step.assertion.aiPrompt.criteria =
|
|
@@ -74,7 +52,7 @@ exports.recordAssertionExecutor = {
|
|
|
74
52
|
success: false,
|
|
75
53
|
};
|
|
76
54
|
}
|
|
77
|
-
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(step, contextInfo, true,
|
|
55
|
+
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(step, contextInfo, true, undefined, stateProvider, eventHandler), 0, stateProvider, eventHandler, logger);
|
|
78
56
|
},
|
|
79
57
|
};
|
|
80
58
|
function isAssertToolParams(toolParams) {
|
|
@@ -37,10 +37,10 @@ exports.recordClickExecutor = {
|
|
|
37
37
|
success: false,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
const toolParams = payload.toolCall.toolParams;
|
|
40
41
|
if ((0, toolExecutors_1.isFindOneEventMessage)(payload.find) && payload.find.selectOptions) {
|
|
41
|
-
const elementDescription =
|
|
42
|
-
const elementBoundingBox =
|
|
43
|
-
?.elementBoundingBox;
|
|
42
|
+
const elementDescription = toolParams.elementDescription || 'unknown element';
|
|
43
|
+
const elementBoundingBox = toolParams.elementBoundingBox;
|
|
44
44
|
const { errorMessage, applicationStatement } = buildNativeSelectErrorMessage(elementDescription, elementBoundingBox, payload.find.selectOptions);
|
|
45
45
|
return {
|
|
46
46
|
success: false,
|
|
@@ -49,6 +49,6 @@ exports.recordClickExecutor = {
|
|
|
49
49
|
applicationInfo: [applicationStatement],
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(payload.find, payload.contextInfo, true,
|
|
52
|
+
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(payload.find, payload.contextInfo, true, undefined, stateProvider, eventHandler), CLICK_STEP_WAIT_TIME_MS, stateProvider, eventHandler, logger);
|
|
53
53
|
},
|
|
54
54
|
};
|
|
@@ -26,6 +26,6 @@ exports.recordEnterTextExecutor = {
|
|
|
26
26
|
else {
|
|
27
27
|
findEvent.inputValue = textToEnter;
|
|
28
28
|
}
|
|
29
|
-
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(findEvent, payload.contextInfo, true,
|
|
29
|
+
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(findEvent, payload.contextInfo, true, undefined, stateProvider, eventHandler), ENTER_TEXT_STEP_WAIT_TIME_MS, stateProvider, eventHandler, logger);
|
|
30
30
|
},
|
|
31
31
|
};
|
|
@@ -14,6 +14,6 @@ exports.recordHoverExecutor = {
|
|
|
14
14
|
success: false,
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(payload.find, payload.contextInfo, true,
|
|
17
|
+
return (0, toolExecutors_1.recordStepAndTrackResult)(() => (0, stepCapture_1.recordTrainedStep)(payload.find, payload.contextInfo, true, undefined, stateProvider, eventHandler), HOVER_STEP_WAIT_TIME_MS, stateProvider, eventHandler, logger);
|
|
18
18
|
},
|
|
19
19
|
};
|
|
@@ -4,6 +4,7 @@ exports.scrollExecutor = void 0;
|
|
|
4
4
|
const mablApi_1 = require("../../../mablApi");
|
|
5
5
|
const utilities_1 = require("../../utilities");
|
|
6
6
|
const contentActions_1 = require("../../background/capture/contentActions");
|
|
7
|
+
const boundingBoxUtils_1 = require("../../sharedUtils/boundingBoxUtils");
|
|
7
8
|
const DEFAULT_SCROLL_WAIT_TIME_MILLISECONDS = 1000;
|
|
8
9
|
exports.scrollExecutor = {
|
|
9
10
|
needsFind: () => false,
|
|
@@ -17,12 +18,15 @@ exports.scrollExecutor = {
|
|
|
17
18
|
errorCause: 'IllegalArguments',
|
|
18
19
|
};
|
|
19
20
|
}
|
|
21
|
+
const internalBoundingBox = toolParams.elementBoundingBox
|
|
22
|
+
? (0, boundingBoxUtils_1.convertToolLibraryBoundingBox)(toolParams.elementBoundingBox)
|
|
23
|
+
: undefined;
|
|
20
24
|
let scrollStatus;
|
|
21
25
|
if (toolParams.direction === 'up') {
|
|
22
|
-
scrollStatus = await (0, contentActions_1.sendScrollUpMessage)(stateProvider.getTrainingContext(), toolParams.scrollFactor, toolParams.elementTargetPoint,
|
|
26
|
+
scrollStatus = await (0, contentActions_1.sendScrollUpMessage)(stateProvider.getTrainingContext(), toolParams.scrollFactor, toolParams.elementTargetPoint, internalBoundingBox);
|
|
23
27
|
}
|
|
24
28
|
else if (toolParams.direction === 'down') {
|
|
25
|
-
scrollStatus = await (0, contentActions_1.sendScrollDownMessage)(stateProvider.getTrainingContext(), toolParams.scrollFactor, toolParams.elementTargetPoint,
|
|
29
|
+
scrollStatus = await (0, contentActions_1.sendScrollDownMessage)(stateProvider.getTrainingContext(), toolParams.scrollFactor, toolParams.elementTargetPoint, internalBoundingBox);
|
|
26
30
|
}
|
|
27
31
|
else {
|
|
28
32
|
logger.error(`Unknown scroll direction (${toolParams.direction}) in scroll executor`);
|
|
@@ -20,6 +20,6 @@ exports.visitUrlExecutor = {
|
|
|
20
20
|
action: 'record',
|
|
21
21
|
listener: 'visit-url',
|
|
22
22
|
url: toolParams.url,
|
|
23
|
-
}, contextInfo, true,
|
|
23
|
+
}, contextInfo, true, undefined, stateProvider, eventHandler), 0, stateProvider, eventHandler, logger);
|
|
24
24
|
},
|
|
25
25
|
};
|
|
@@ -15,7 +15,7 @@ exports.waitExecutor = {
|
|
|
15
15
|
action: 'record',
|
|
16
16
|
listener: 'wait',
|
|
17
17
|
time: toolParams?.waitTime ?? DEFAULT_WAIT_STEP_WAIT_TIME_SECONDS,
|
|
18
|
-
}, payload.contextInfo ?? (await stateProvider.getActiveContextInfo()), true,
|
|
18
|
+
}, payload.contextInfo ?? (await stateProvider.getActiveContextInfo()), true, undefined, stateProvider, eventHandler), 0, stateProvider, eventHandler, logger);
|
|
19
19
|
}
|
|
20
20
|
await (0, utilities_1.sleep)((toolParams?.waitTime ?? DEFAULT_WAIT_STEP_WAIT_TIME_SECONDS) * 1000);
|
|
21
21
|
return {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertToolLibraryBoundingBox = convertToolLibraryBoundingBox;
|
|
4
|
+
function convertToolLibraryBoundingBox(toolLibBox) {
|
|
5
|
+
return {
|
|
6
|
+
x: toolLibBox.left,
|
|
7
|
+
y: toolLibBox.top,
|
|
8
|
+
width: toolLibBox.right - toolLibBox.left,
|
|
9
|
+
height: toolLibBox.bottom - toolLibBox.top,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -4,6 +4,7 @@ exports.createUserTextMessage = createUserTextMessage;
|
|
|
4
4
|
exports.createUserFileMessage = createUserFileMessage;
|
|
5
5
|
exports.createToolOutputMessagePart = createToolOutputMessagePart;
|
|
6
6
|
exports.createToolOutputMessage = createToolOutputMessage;
|
|
7
|
+
exports.createToolOutputFromResult = createToolOutputFromResult;
|
|
7
8
|
exports.extractToolCallsFromMessages = extractToolCallsFromMessages;
|
|
8
9
|
exports.filterClientSideToolCalls = filterClientSideToolCalls;
|
|
9
10
|
exports.filterToolCallsWithoutOutputs = filterToolCallsWithoutOutputs;
|
|
@@ -85,6 +86,36 @@ function createToolOutputMessage(toolOutputMessageParts) {
|
|
|
85
86
|
parts: toolOutputMessageParts,
|
|
86
87
|
};
|
|
87
88
|
}
|
|
89
|
+
function createToolOutputFromResult(params) {
|
|
90
|
+
const { toolCallId, toolName, wrappedResult } = params;
|
|
91
|
+
const { result, isError } = wrappedResult;
|
|
92
|
+
const contentItems = [];
|
|
93
|
+
contentItems.push({
|
|
94
|
+
type: 'json',
|
|
95
|
+
json: result.toolResponse,
|
|
96
|
+
});
|
|
97
|
+
if (result.imageContentItems) {
|
|
98
|
+
for (const img of result.imageContentItems) {
|
|
99
|
+
if (img.type === 'image-data' && img.image_data && img.media_type) {
|
|
100
|
+
const imageDataContentItem = {
|
|
101
|
+
type: 'image-data',
|
|
102
|
+
image_data: img.image_data,
|
|
103
|
+
media_type: img.media_type,
|
|
104
|
+
};
|
|
105
|
+
contentItems.push(imageDataContentItem);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const output = isError
|
|
110
|
+
? { type: 'error-content', error_content: contentItems }
|
|
111
|
+
: { type: 'content', content: contentItems };
|
|
112
|
+
return {
|
|
113
|
+
type: 'tool_output',
|
|
114
|
+
tool_name: toolName,
|
|
115
|
+
tool_call_id: toolCallId,
|
|
116
|
+
output,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
88
119
|
function extractToolCallsFromMessages(messages, logger) {
|
|
89
120
|
const modelMessages = messages.filter((m) => m.role === 'model');
|
|
90
121
|
return modelMessages.flatMap((m) => (m.parts ?? [])
|