askui 0.30.0 → 0.32.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/cjs/core/cache/cache-config.d.ts +5 -0
- package/dist/cjs/core/cache/cache-config.js +2 -0
- package/dist/cjs/core/cache/cache-entry-reference.d.ts +7 -0
- package/dist/cjs/core/cache/cache-entry-reference.js +20 -0
- package/dist/cjs/core/cache/cache-entry.d.ts +11 -0
- package/dist/cjs/core/cache/cache-entry.js +47 -0
- package/dist/cjs/core/cache/cache-interface.d.ts +11 -0
- package/dist/cjs/core/cache/cache-interface.js +2 -0
- package/dist/cjs/core/cache/cache-manager.d.ts +24 -0
- package/dist/cjs/core/cache/cache-manager.js +145 -0
- package/dist/cjs/core/cache/cahe-file.d.ts +19 -0
- package/dist/cjs/core/cache/cahe-file.js +128 -0
- package/dist/cjs/core/cache/dummy-cache-manager.d.ts +12 -0
- package/dist/cjs/core/cache/dummy-cache-manager.js +27 -0
- package/dist/cjs/core/cache/image-reference.d.ts +10 -0
- package/dist/cjs/core/cache/image-reference.js +40 -0
- package/dist/cjs/core/cache/index.d.ts +7 -0
- package/dist/cjs/core/cache/index.js +13 -0
- package/dist/cjs/core/model/annotation-result/boundary-box.js +1 -1
- package/dist/cjs/core/model/custom-element.d.ts +1 -0
- package/dist/cjs/core/model/custom-element.js +3 -0
- package/dist/cjs/core/ui-control-commands/action.d.ts +1 -0
- package/dist/cjs/core/ui-control-commands/action.js +10 -2
- package/dist/cjs/core/ui-control-commands/control-command.d.ts +1 -0
- package/dist/cjs/core/ui-control-commands/control-command.js +7 -0
- package/dist/cjs/execution/dsl.d.ts +12 -5
- package/dist/cjs/execution/dsl.js +30 -15
- package/dist/cjs/execution/execution-runtime.d.ts +1 -1
- package/dist/cjs/execution/execution-runtime.js +21 -17
- package/dist/cjs/execution/inference-client.d.ts +5 -3
- package/dist/cjs/execution/inference-client.js +22 -3
- package/dist/cjs/execution/ui-control-client-dependency-builder.js +6 -1
- package/dist/cjs/execution/ui-control-client.d.ts +2 -1
- package/dist/cjs/execution/ui-control-client.js +28 -11
- package/dist/cjs/execution/ui-controller-client-interface.d.ts +2 -0
- package/dist/cjs/utils/base_64_image/base-64-image.d.ts +2 -0
- package/dist/cjs/utils/base_64_image/base-64-image.js +27 -4
- package/dist/cjs/utils/http/http-client-got.d.ts +15 -0
- package/dist/cjs/utils/http/http-client-got.js +59 -11
- package/dist/esm/core/cache/cache-config.d.ts +5 -0
- package/dist/esm/core/cache/cache-config.js +1 -0
- package/dist/esm/core/cache/cache-entry-reference.d.ts +7 -0
- package/dist/esm/core/cache/cache-entry-reference.js +16 -0
- package/dist/esm/core/cache/cache-entry.d.ts +11 -0
- package/dist/esm/core/cache/cache-entry.js +43 -0
- package/dist/esm/core/cache/cache-interface.d.ts +11 -0
- package/dist/esm/core/cache/cache-interface.js +1 -0
- package/dist/esm/core/cache/cache-manager.d.ts +24 -0
- package/dist/esm/core/cache/cache-manager.js +141 -0
- package/dist/esm/core/cache/cahe-file.d.ts +19 -0
- package/dist/esm/core/cache/cahe-file.js +121 -0
- package/dist/esm/core/cache/dummy-cache-manager.d.ts +12 -0
- package/dist/esm/core/cache/dummy-cache-manager.js +23 -0
- package/dist/esm/core/cache/image-reference.d.ts +10 -0
- package/dist/esm/core/cache/image-reference.js +36 -0
- package/dist/esm/core/cache/index.d.ts +7 -0
- package/dist/esm/core/cache/index.js +5 -0
- package/dist/esm/core/model/annotation-result/boundary-box.js +1 -1
- package/dist/esm/core/model/custom-element.d.ts +1 -0
- package/dist/esm/core/model/custom-element.js +3 -0
- package/dist/esm/core/ui-control-commands/action.d.ts +1 -0
- package/dist/esm/core/ui-control-commands/action.js +10 -2
- package/dist/esm/core/ui-control-commands/control-command.d.ts +1 -0
- package/dist/esm/core/ui-control-commands/control-command.js +7 -0
- package/dist/esm/execution/dsl.d.ts +12 -5
- package/dist/esm/execution/dsl.js +30 -15
- package/dist/esm/execution/execution-runtime.d.ts +1 -1
- package/dist/esm/execution/execution-runtime.js +21 -17
- package/dist/esm/execution/inference-client.d.ts +5 -3
- package/dist/esm/execution/inference-client.js +22 -3
- package/dist/esm/execution/ui-control-client-dependency-builder.js +6 -1
- package/dist/esm/execution/ui-control-client.d.ts +2 -1
- package/dist/esm/execution/ui-control-client.js +28 -11
- package/dist/esm/execution/ui-controller-client-interface.d.ts +2 -0
- package/dist/esm/utils/base_64_image/base-64-image.d.ts +2 -0
- package/dist/esm/utils/base_64_image/base-64-image.js +27 -4
- package/dist/esm/utils/http/http-client-got.d.ts +15 -0
- package/dist/esm/utils/http/http-client-got.js +36 -8
- package/package.json +4 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CustomElementJson } from '../core/model/custom-element-json';
|
|
2
2
|
import { DetectedElement } from '../core/model/annotation-result/detected-element';
|
|
3
3
|
import { ModelCompositionBranch } from './model-composition-branch';
|
|
4
|
+
import { RetryStrategy } from './retry-strategies/retry-strategy';
|
|
4
5
|
export declare enum Separators {
|
|
5
6
|
STRING = "<|string|>"
|
|
6
7
|
}
|
|
@@ -17,22 +18,27 @@ export interface CommandExecutorContext {
|
|
|
17
18
|
customElementsJson: CustomElementJson[];
|
|
18
19
|
aiElementNames: string[];
|
|
19
20
|
}
|
|
21
|
+
export interface ExecOptions {
|
|
22
|
+
modelComposition?: ModelCompositionBranch[];
|
|
23
|
+
skipCache?: boolean;
|
|
24
|
+
retryStrategy?: RetryStrategy;
|
|
25
|
+
}
|
|
20
26
|
declare abstract class FluentBase {
|
|
21
27
|
protected prev?: FluentBase | undefined;
|
|
22
28
|
constructor(prev?: FluentBase | undefined);
|
|
23
29
|
protected _textStr: string;
|
|
24
30
|
protected _params: Map<string, unknown>;
|
|
25
31
|
protected static addParams(paramsList: Map<string, unknown[]>, params: Map<string, unknown>): Map<string, unknown[]>;
|
|
26
|
-
protected fluentCommandStringBuilder(modelComposition
|
|
32
|
+
protected fluentCommandStringBuilder(modelComposition?: ModelCompositionBranch[], skipCache?: boolean, retryStrategy?: RetryStrategy, currentInstruction?: string, paramsList?: Map<string, unknown[]>): Promise<void>;
|
|
27
33
|
protected getterStringBuilder(currentInstruction?: string, paramsList?: Map<string, unknown[]>): Promise<DetectedElement[]>;
|
|
28
34
|
protected get textStr(): string;
|
|
29
35
|
protected get params(): Map<string, unknown>;
|
|
30
36
|
}
|
|
31
37
|
export interface Executable {
|
|
32
|
-
exec(): Promise<void>;
|
|
38
|
+
exec(execOptions?: ExecOptions): Promise<void>;
|
|
33
39
|
}
|
|
34
40
|
export declare class Exec extends FluentBase implements Executable {
|
|
35
|
-
exec(
|
|
41
|
+
exec(execOptions?: ExecOptions): Promise<void>;
|
|
36
42
|
}
|
|
37
43
|
export declare class FluentFilters extends FluentBase {
|
|
38
44
|
/**
|
|
@@ -808,7 +814,7 @@ export declare class FluentFiltersOrRelations extends FluentFilters {
|
|
|
808
814
|
* @return {FluentFilters}
|
|
809
815
|
*/
|
|
810
816
|
contains(): FluentFilters;
|
|
811
|
-
exec(
|
|
817
|
+
exec(execOptions?: ExecOptions): Promise<void>;
|
|
812
818
|
}
|
|
813
819
|
export declare class FluentFiltersCondition extends FluentBase {
|
|
814
820
|
/**
|
|
@@ -1634,6 +1640,7 @@ export declare class FluentFiltersOrRelationsCondition extends FluentFiltersCond
|
|
|
1634
1640
|
notExists(): ExecCondition;
|
|
1635
1641
|
}
|
|
1636
1642
|
declare class ExecCondition extends Exec {
|
|
1643
|
+
exec(execOptions?: ExecOptions): Promise<void>;
|
|
1637
1644
|
}
|
|
1638
1645
|
export declare abstract class FluentCommand extends FluentBase {
|
|
1639
1646
|
constructor();
|
|
@@ -2082,7 +2089,7 @@ export declare abstract class FluentCommand extends FluentBase {
|
|
|
2082
2089
|
* @return {Exec}
|
|
2083
2090
|
*/
|
|
2084
2091
|
pressAndroidKey(key: ANDROID_KEY): Exec;
|
|
2085
|
-
abstract fluentCommandExecutor(instruction: string, modelComposition: ModelCompositionBranch[], context: CommandExecutorContext): Promise<void>;
|
|
2092
|
+
abstract fluentCommandExecutor(instruction: string, modelComposition: ModelCompositionBranch[], context: CommandExecutorContext, skipCache: boolean, retryStrategy?: RetryStrategy): Promise<void>;
|
|
2086
2093
|
}
|
|
2087
2094
|
export interface ExecutableGetter {
|
|
2088
2095
|
exec(): Promise<DetectedElement[]>;
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
/* eslint-disable max-classes-per-file */
|
|
5
5
|
/* eslint-disable max-len */
|
|
6
6
|
// Autogenerated from typescript.template file
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
7
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
17
|
exports.ApiCommands = exports.Getter = exports.FluentFiltersOrRelationsGetter = exports.FluentFiltersGetter = exports.ExecGetter = exports.FluentCommand = exports.FluentFiltersOrRelationsCondition = exports.FluentFiltersCondition = exports.FluentFiltersOrRelations = exports.FluentFilters = exports.Exec = exports.MODIFIER_KEY_VALUES = exports.ANDROID_KEY_VALUES = exports.PC_KEY_VALUES = exports.Separators = void 0;
|
|
9
18
|
function isStackTraceCodeline(line) {
|
|
@@ -17,21 +26,18 @@ function splitStackTrace(stacktrace) {
|
|
|
17
26
|
return { head: errorStacktraceHead, codelines: errorStacktraceCodeLines };
|
|
18
27
|
}
|
|
19
28
|
function rewriteStackTraceForError(error, newStackTrace) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
errorCopy.stack = newStackTrace;
|
|
23
|
-
return errorCopy;
|
|
24
|
-
}
|
|
25
|
-
const errorStacktraceSplit = splitStackTrace(error.stack);
|
|
29
|
+
var _a;
|
|
30
|
+
const errorStacktraceSplit = splitStackTrace((_a = error.stack) !== null && _a !== void 0 ? _a : '');
|
|
26
31
|
const newStacktraceSplit = splitStackTrace(newStackTrace);
|
|
27
|
-
|
|
32
|
+
// eslint-disable-next-line no-param-reassign
|
|
33
|
+
error.stack = [
|
|
28
34
|
...errorStacktraceSplit.head,
|
|
29
35
|
...newStacktraceSplit.codelines,
|
|
30
36
|
' ',
|
|
31
37
|
...errorStacktraceSplit.head,
|
|
32
38
|
...errorStacktraceSplit.codelines,
|
|
33
39
|
].join('\n');
|
|
34
|
-
return
|
|
40
|
+
return error;
|
|
35
41
|
}
|
|
36
42
|
var Separators;
|
|
37
43
|
(function (Separators) {
|
|
@@ -55,7 +61,7 @@ class FluentBase {
|
|
|
55
61
|
});
|
|
56
62
|
return paramsList;
|
|
57
63
|
}
|
|
58
|
-
fluentCommandStringBuilder(modelComposition, currentInstruction = '', paramsList = new Map()) {
|
|
64
|
+
fluentCommandStringBuilder(modelComposition = [], skipCache = false, retryStrategy, currentInstruction = '', paramsList = new Map()) {
|
|
59
65
|
const newCurrentInstruction = `${this.textStr} ${currentInstruction}`;
|
|
60
66
|
const newParamsList = FluentBase.addParams(paramsList, this._params);
|
|
61
67
|
if (this instanceof FluentCommand) {
|
|
@@ -65,12 +71,12 @@ class FluentBase {
|
|
|
65
71
|
return fluentCommand.fluentCommandExecutor(newCurrentInstruction.trim(), modelComposition, {
|
|
66
72
|
customElementsJson: customElements,
|
|
67
73
|
aiElementNames,
|
|
68
|
-
});
|
|
74
|
+
}, skipCache, retryStrategy);
|
|
69
75
|
}
|
|
70
76
|
if (!this.prev) {
|
|
71
77
|
throw new Error('Prev element not defined');
|
|
72
78
|
}
|
|
73
|
-
return this.prev.fluentCommandStringBuilder(modelComposition, newCurrentInstruction, newParamsList);
|
|
79
|
+
return this.prev.fluentCommandStringBuilder(modelComposition, skipCache, retryStrategy, newCurrentInstruction, newParamsList);
|
|
74
80
|
}
|
|
75
81
|
getterStringBuilder(currentInstruction = '', paramsList = new Map()) {
|
|
76
82
|
const newCurrentInstruction = `${this.textStr} ${currentInstruction}`;
|
|
@@ -93,10 +99,10 @@ class FluentBase {
|
|
|
93
99
|
get params() { return this._params; }
|
|
94
100
|
}
|
|
95
101
|
class Exec extends FluentBase {
|
|
96
|
-
exec(
|
|
102
|
+
exec(execOptions) {
|
|
97
103
|
const originStacktrace = { stack: '' };
|
|
98
104
|
Error.captureStackTrace(originStacktrace, this.exec);
|
|
99
|
-
return this.fluentCommandStringBuilder(modelComposition).catch((err) => Promise.reject(rewriteStackTraceForError(err, originStacktrace.stack)));
|
|
105
|
+
return this.fluentCommandStringBuilder(execOptions === null || execOptions === void 0 ? void 0 : execOptions.modelComposition, execOptions === null || execOptions === void 0 ? void 0 : execOptions.skipCache, execOptions === null || execOptions === void 0 ? void 0 : execOptions.retryStrategy).catch((err) => Promise.reject(rewriteStackTraceForError(err, originStacktrace.stack)));
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
108
|
exports.Exec = Exec;
|
|
@@ -1048,10 +1054,10 @@ class FluentFiltersOrRelations extends FluentFilters {
|
|
|
1048
1054
|
this._textStr += 'contains';
|
|
1049
1055
|
return new FluentFilters(this);
|
|
1050
1056
|
}
|
|
1051
|
-
exec(
|
|
1057
|
+
exec(execOptions) {
|
|
1052
1058
|
const originStacktrace = { stack: '' };
|
|
1053
1059
|
Error.captureStackTrace(originStacktrace, this.exec);
|
|
1054
|
-
return this.fluentCommandStringBuilder(modelComposition).catch((err) => Promise.reject(rewriteStackTraceForError(err, originStacktrace.stack)));
|
|
1060
|
+
return this.fluentCommandStringBuilder(execOptions === null || execOptions === void 0 ? void 0 : execOptions.modelComposition, execOptions === null || execOptions === void 0 ? void 0 : execOptions.skipCache, execOptions === null || execOptions === void 0 ? void 0 : execOptions.retryStrategy).catch((err) => Promise.reject(rewriteStackTraceForError(err, originStacktrace.stack)));
|
|
1055
1061
|
}
|
|
1056
1062
|
}
|
|
1057
1063
|
exports.FluentFiltersOrRelations = FluentFiltersOrRelations;
|
|
@@ -2063,6 +2069,15 @@ class FluentFiltersOrRelationsCondition extends FluentFiltersCondition {
|
|
|
2063
2069
|
}
|
|
2064
2070
|
exports.FluentFiltersOrRelationsCondition = FluentFiltersOrRelationsCondition;
|
|
2065
2071
|
class ExecCondition extends Exec {
|
|
2072
|
+
exec(execOptions) {
|
|
2073
|
+
const _super = Object.create(null, {
|
|
2074
|
+
exec: { get: () => super.exec }
|
|
2075
|
+
});
|
|
2076
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2077
|
+
const options = Object.assign(Object.assign({}, execOptions), { skipCache: true });
|
|
2078
|
+
return _super.exec.call(this, options);
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2066
2081
|
}
|
|
2067
2082
|
// Commands
|
|
2068
2083
|
class FluentCommand extends FluentBase {
|
|
@@ -21,7 +21,7 @@ export declare class ExecutionRuntime {
|
|
|
21
21
|
stopVideoRecording(): Promise<void>;
|
|
22
22
|
readVideoRecording(): Promise<string>;
|
|
23
23
|
requestControl(controlCommand: ControlCommand): Promise<void>;
|
|
24
|
-
executeInstruction(instruction: Instruction, modelComposition: ModelCompositionBranch[]): Promise<void>;
|
|
24
|
+
executeInstruction(instruction: Instruction, modelComposition: ModelCompositionBranch[], skipCache?: boolean, retryStrategy?: RetryStrategy): Promise<void>;
|
|
25
25
|
private readonly EXEC_REPETITION_COUNT;
|
|
26
26
|
private executeCommandRepeatedly;
|
|
27
27
|
/**
|
|
@@ -28,10 +28,12 @@ class ExecutionRuntime {
|
|
|
28
28
|
}
|
|
29
29
|
connect() {
|
|
30
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
this.inferenceClient.cacheManager.loadFromFile();
|
|
31
32
|
return this.uiControllerClient.connect();
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
disconnect() {
|
|
36
|
+
this.inferenceClient.cacheManager.saveToFile();
|
|
35
37
|
this.uiControllerClient.disconnect();
|
|
36
38
|
}
|
|
37
39
|
startVideoRecording() {
|
|
@@ -55,10 +57,10 @@ class ExecutionRuntime {
|
|
|
55
57
|
yield this.uiControllerClient.requestControl(controlCommand);
|
|
56
58
|
});
|
|
57
59
|
}
|
|
58
|
-
executeInstruction(
|
|
59
|
-
return __awaiter(this,
|
|
60
|
+
executeInstruction(instruction_1, modelComposition_1) {
|
|
61
|
+
return __awaiter(this, arguments, void 0, function* (instruction, modelComposition, skipCache = false, retryStrategy) {
|
|
60
62
|
var _a, _b, _c;
|
|
61
|
-
const controlCommand = yield this.predictCommandWithRetry(instruction, modelComposition);
|
|
63
|
+
const controlCommand = yield this.predictCommandWithRetry(instruction, modelComposition, skipCache, retryStrategy);
|
|
62
64
|
if (controlCommand.code === ui_control_commands_1.ControlCommandCode.OK) {
|
|
63
65
|
return this.requestControl(controlCommand);
|
|
64
66
|
}
|
|
@@ -98,19 +100,20 @@ class ExecutionRuntime {
|
|
|
98
100
|
* --> retry with linear back-off
|
|
99
101
|
*/
|
|
100
102
|
/* eslint-disable-next-line consistent-return */
|
|
101
|
-
predictCommandWithRetry(
|
|
102
|
-
return __awaiter(this,
|
|
103
|
+
predictCommandWithRetry(instruction_1, modelComposition_1) {
|
|
104
|
+
return __awaiter(this, arguments, void 0, function* (instruction, modelComposition, skipCache = false, retryStrategy) {
|
|
103
105
|
var _a, _b, _c;
|
|
104
|
-
|
|
106
|
+
const strategy = retryStrategy !== null && retryStrategy !== void 0 ? retryStrategy : this.retryStrategy;
|
|
107
|
+
let command = yield this.predictCommand(instruction, modelComposition, skipCache);
|
|
105
108
|
/* eslint-disable no-await-in-loop */
|
|
106
|
-
for (let k = 0; k <
|
|
109
|
+
for (let k = 0; k < strategy.retryCount; k += 1) {
|
|
107
110
|
if (command.code === ui_control_commands_1.ControlCommandCode.OK) {
|
|
108
111
|
return command;
|
|
109
112
|
}
|
|
110
|
-
const msUntilRetry =
|
|
111
|
-
logger_1.logger.debug(`Wait ${msUntilRetry} and retry predicting command...`);
|
|
113
|
+
const msUntilRetry = strategy.getDelay(k + 1);
|
|
114
|
+
logger_1.logger.debug(`Wait ${msUntilRetry} and retry ${k + 1}/${strategy.retryCount} predicting command...`);
|
|
112
115
|
yield (0, misc_1.delay)(msUntilRetry);
|
|
113
|
-
command = yield this.predictCommand(instruction, modelComposition, new control_command_error_1.ControlCommandError((_c = (_b = (_a = command.actions) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.text) !== null && _c !== void 0 ? _c : ''));
|
|
116
|
+
command = yield this.predictCommand(instruction, modelComposition, skipCache, new control_command_error_1.ControlCommandError((_c = (_b = (_a = command.actions) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.text) !== null && _c !== void 0 ? _c : ''));
|
|
114
117
|
}
|
|
115
118
|
/* eslint-enable no-await-in-loop */
|
|
116
119
|
return command;
|
|
@@ -120,11 +123,11 @@ class ExecutionRuntime {
|
|
|
120
123
|
return this.stepReporter.config.withScreenshots === 'begin'
|
|
121
124
|
|| this.stepReporter.config.withScreenshots === 'always';
|
|
122
125
|
}
|
|
123
|
-
isImageRequired(instruction) {
|
|
126
|
+
isImageRequired(instruction, customElements) {
|
|
124
127
|
return __awaiter(this, void 0, void 0, function* () {
|
|
125
128
|
if (this.isImageRequiredByConfig())
|
|
126
129
|
return Promise.resolve(true);
|
|
127
|
-
return this.inferenceClient.isImageRequired(instruction);
|
|
130
|
+
return this.inferenceClient.isImageRequired(instruction, customElements);
|
|
128
131
|
});
|
|
129
132
|
}
|
|
130
133
|
isAnnotationRequired() {
|
|
@@ -139,8 +142,9 @@ class ExecutionRuntime {
|
|
|
139
142
|
}
|
|
140
143
|
buildSnapshot(instruction) {
|
|
141
144
|
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
var _a;
|
|
142
146
|
const createdAt = new Date();
|
|
143
|
-
const screenshot = (yield this.isImageRequired(instruction))
|
|
147
|
+
const screenshot = (yield this.isImageRequired(instruction.value, (_a = instruction.customElements) !== null && _a !== void 0 ? _a : []))
|
|
144
148
|
? yield this.getScreenshot() : undefined;
|
|
145
149
|
const annotation = this.isAnnotationRequired() ? yield this.annotateImage() : undefined;
|
|
146
150
|
return {
|
|
@@ -150,14 +154,14 @@ class ExecutionRuntime {
|
|
|
150
154
|
};
|
|
151
155
|
});
|
|
152
156
|
}
|
|
153
|
-
predictCommand(
|
|
154
|
-
return __awaiter(this,
|
|
155
|
-
const snapshot = yield this.buildSnapshot(instruction
|
|
157
|
+
predictCommand(instruction_1, modelComposition_1) {
|
|
158
|
+
return __awaiter(this, arguments, void 0, function* (instruction, modelComposition, skipCache = false, retryError) {
|
|
159
|
+
const snapshot = yield this.buildSnapshot(instruction);
|
|
156
160
|
if (retryError !== undefined)
|
|
157
161
|
this.stepReporter.onStepRetry(snapshot, retryError);
|
|
158
162
|
else
|
|
159
163
|
this.stepReporter.onStepBegin(snapshot);
|
|
160
|
-
const controlCommand = yield this.inferenceClient.predictControlCommand(instruction.value, modelComposition, instruction.customElements, snapshot.screenshot);
|
|
164
|
+
const controlCommand = yield this.inferenceClient.predictControlCommand(instruction.value, modelComposition, instruction.customElements, snapshot.screenshot, skipCache);
|
|
161
165
|
if (instruction.secretText !== undefined) {
|
|
162
166
|
controlCommand.setTextToBeTyped(instruction.secretText);
|
|
163
167
|
}
|
|
@@ -6,21 +6,23 @@ import { Annotation } from '../core/annotation/annotation';
|
|
|
6
6
|
import { DetectedElement } from '../core/model/annotation-result/detected-element';
|
|
7
7
|
import { VQAInferenceResponseBody } from '../core/inference-response/inference-response';
|
|
8
8
|
import { ModelCompositionBranch } from './model-composition-branch';
|
|
9
|
+
import { CacheInterface } from '../core/cache';
|
|
9
10
|
export declare class InferenceClient {
|
|
10
11
|
private readonly baseUrl;
|
|
11
12
|
private readonly httpClient;
|
|
13
|
+
readonly cacheManager: CacheInterface;
|
|
12
14
|
private readonly resize?;
|
|
13
15
|
readonly workspaceId?: string | undefined;
|
|
14
16
|
readonly modelComposition?: ModelCompositionBranch[] | undefined;
|
|
15
17
|
private readonly apiVersion;
|
|
16
18
|
private urls;
|
|
17
|
-
constructor(baseUrl: string, httpClient: HttpClientGot, resize?: number | undefined, workspaceId?: string | undefined, modelComposition?: ModelCompositionBranch[] | undefined, apiVersion?: string);
|
|
18
|
-
isImageRequired(instruction: string): Promise<boolean>;
|
|
19
|
+
constructor(baseUrl: string, httpClient: HttpClientGot, cacheManager: CacheInterface, resize?: number | undefined, workspaceId?: string | undefined, modelComposition?: ModelCompositionBranch[] | undefined, apiVersion?: string);
|
|
20
|
+
isImageRequired(instruction: string, customElements: CustomElement[]): Promise<boolean>;
|
|
19
21
|
private resizeIfNeeded;
|
|
20
22
|
inference(customElements?: CustomElement[], image?: string, instruction?: string, modelComposition?: ModelCompositionBranch[]): Promise<ControlCommand | Annotation>;
|
|
21
23
|
vqaInference(image: string, prompt: string, config?: object): Promise<VQAInferenceResponseBody>;
|
|
22
24
|
private static logMetaInformation;
|
|
23
|
-
predictControlCommand(instruction: string, modelComposition: ModelCompositionBranch[], customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
|
|
25
|
+
predictControlCommand(instruction: string, modelComposition: ModelCompositionBranch[], customElements?: CustomElement[], image?: string, skipCache?: boolean): Promise<ControlCommand>;
|
|
24
26
|
getDetectedElements(instruction: string, image: string, customElements?: CustomElement[]): Promise<DetectedElement[]>;
|
|
25
27
|
predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
|
|
26
28
|
predictVQAAnswer(prompt: string, image: string, config?: object): Promise<any>;
|
|
@@ -20,10 +20,12 @@ const transformations_1 = require("../utils/transformations");
|
|
|
20
20
|
const inference_response_error_1 = require("./inference-response-error");
|
|
21
21
|
const config_error_1 = require("./config-error");
|
|
22
22
|
const logger_1 = require("../lib/logger");
|
|
23
|
+
const control_command_code_1 = require("../core/ui-control-commands/control-command-code");
|
|
23
24
|
class InferenceClient {
|
|
24
|
-
constructor(baseUrl, httpClient, resize, workspaceId, modelComposition, apiVersion = 'v1') {
|
|
25
|
+
constructor(baseUrl, httpClient, cacheManager, resize, workspaceId, modelComposition, apiVersion = 'v1') {
|
|
25
26
|
this.baseUrl = baseUrl;
|
|
26
27
|
this.httpClient = httpClient;
|
|
28
|
+
this.cacheManager = cacheManager;
|
|
27
29
|
this.resize = resize;
|
|
28
30
|
this.workspaceId = workspaceId;
|
|
29
31
|
this.modelComposition = modelComposition;
|
|
@@ -44,8 +46,13 @@ class InferenceClient {
|
|
|
44
46
|
}
|
|
45
47
|
this.resize = this.resize ? Math.ceil(this.resize) : this.resize;
|
|
46
48
|
}
|
|
47
|
-
isImageRequired(instruction) {
|
|
49
|
+
isImageRequired(instruction, customElements) {
|
|
48
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const cachedImageRequired = this.cacheManager.isImageRequired(instruction, customElements);
|
|
52
|
+
if (cachedImageRequired !== undefined) {
|
|
53
|
+
logger_1.logger.debug(`Cache hit for image required: '${instruction}'.`);
|
|
54
|
+
return Promise.resolve(cachedImageRequired);
|
|
55
|
+
}
|
|
49
56
|
const response = yield this.httpClient.post(this.urls.isImageRequired, {
|
|
50
57
|
instruction,
|
|
51
58
|
});
|
|
@@ -96,11 +103,23 @@ class InferenceClient {
|
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
105
|
predictControlCommand(instruction_1, modelComposition_1) {
|
|
99
|
-
return __awaiter(this, arguments, void 0, function* (instruction, modelComposition, customElements = [], image) {
|
|
106
|
+
return __awaiter(this, arguments, void 0, function* (instruction, modelComposition, customElements = [], image, skipCache = false) {
|
|
107
|
+
if (!skipCache) {
|
|
108
|
+
const cachedControlCommand = yield this.cacheManager.getCachedControlCommand(instruction, customElements, image);
|
|
109
|
+
if (cachedControlCommand !== undefined) {
|
|
110
|
+
logger_1.logger.debug(`Cache hit for instruction: '${instruction}'.`);
|
|
111
|
+
return Promise.resolve(cachedControlCommand);
|
|
112
|
+
}
|
|
113
|
+
logger_1.logger.debug(`Cache miss for instruction: '${instruction}'.`);
|
|
114
|
+
}
|
|
100
115
|
const inferenceResponse = yield this.inference(customElements, image, instruction, modelComposition);
|
|
101
116
|
if (!(inferenceResponse instanceof ui_control_commands_1.ControlCommand)) {
|
|
102
117
|
throw new inference_response_error_1.InferenceResponseError('Internal Error. Can not execute command');
|
|
103
118
|
}
|
|
119
|
+
if (!skipCache && inferenceResponse.code === control_command_code_1.ControlCommandCode.OK) {
|
|
120
|
+
yield this.cacheManager.addCacheEntryFromControlCommand(instruction, inferenceResponse, customElements, image);
|
|
121
|
+
logger_1.logger.debug(`Cache added for instruction: '${instruction}'`);
|
|
122
|
+
}
|
|
104
123
|
return inferenceResponse;
|
|
105
124
|
});
|
|
106
125
|
}
|
|
@@ -23,6 +23,7 @@ const execution_runtime_1 = require("./execution-runtime");
|
|
|
23
23
|
const reporting_1 = require("../core/reporting");
|
|
24
24
|
const read_credentials_1 = require("./read-credentials");
|
|
25
25
|
const linear_retry_strategy_1 = require("./retry-strategies/linear-retry-strategy");
|
|
26
|
+
const cache_1 = require("../core/cache");
|
|
26
27
|
class UiControlClientDependencyBuilder {
|
|
27
28
|
static buildHttpClient(clientArgs) {
|
|
28
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -37,7 +38,11 @@ class UiControlClientDependencyBuilder {
|
|
|
37
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
39
|
var _a;
|
|
39
40
|
const httpClient = yield UiControlClientDependencyBuilder.buildHttpClient(clientArgs);
|
|
40
|
-
|
|
41
|
+
let cacheManager = new cache_1.DummyCacheManager();
|
|
42
|
+
if (clientArgs.cacheConfig) {
|
|
43
|
+
cacheManager = new cache_1.CacheManager(clientArgs.cacheConfig);
|
|
44
|
+
}
|
|
45
|
+
return new inference_client_1.InferenceClient(clientArgs.inferenceServerUrl, httpClient, cacheManager, clientArgs.resize, (_a = clientArgs.credentials) === null || _a === void 0 ? void 0 : _a.workspaceId, clientArgs.modelComposition, clientArgs.inferenceServerApiVersion);
|
|
41
46
|
});
|
|
42
47
|
}
|
|
43
48
|
static buildUiControllerClient(clientArgs) {
|
|
@@ -5,6 +5,7 @@ import { AnnotationRequest } from '../core/model/annotation-result/annotation-in
|
|
|
5
5
|
import { DetectedElement } from '../core/model/annotation-result/detected-element';
|
|
6
6
|
import { ClientArgs } from './ui-controller-client-interface';
|
|
7
7
|
import { ModelCompositionBranch } from './model-composition-branch';
|
|
8
|
+
import { RetryStrategy } from './retry-strategies';
|
|
8
9
|
import { AskUIAgent, AgentHistory, ActOptions } from '../core/models/anthropic';
|
|
9
10
|
export type RelationsForConvenienceMethods = 'nearestTo' | 'leftOf' | 'above' | 'rightOf' | 'below' | 'contains';
|
|
10
11
|
export type TextMatchingOption = 'similar' | 'exact' | 'regex';
|
|
@@ -62,7 +63,7 @@ export declare class UiControlClient extends ApiCommands {
|
|
|
62
63
|
private escapeSeparatorString;
|
|
63
64
|
private buildInstruction;
|
|
64
65
|
private getAIElementsByNames;
|
|
65
|
-
fluentCommandExecutor(instructionString: string, modelComposition: ModelCompositionBranch[], context?: CommandExecutorContext): Promise<void>;
|
|
66
|
+
fluentCommandExecutor(instructionString: string, modelComposition: ModelCompositionBranch[], context?: CommandExecutorContext, skipCache?: boolean, retryStrategy?: RetryStrategy): Promise<void>;
|
|
66
67
|
getterExecutor(instruction: string, context?: CommandExecutorContext): Promise<DetectedElement[]>;
|
|
67
68
|
/**
|
|
68
69
|
* Takes a prompt that contains a question you want to be answered
|
|
@@ -18,6 +18,7 @@ const logger_1 = require("../lib/logger");
|
|
|
18
18
|
const ui_control_client_dependency_builder_1 = require("./ui-control-client-dependency-builder");
|
|
19
19
|
const ai_element_collection_1 = require("../core/ai-element/ai-element-collection");
|
|
20
20
|
const retry_strategies_1 = require("./retry-strategies");
|
|
21
|
+
const control_command_error_1 = require("./control-command-error");
|
|
21
22
|
const anthropic_1 = require("../core/models/anthropic");
|
|
22
23
|
const askui_api_tools_1 = require("../core/models/anthropic/tools/askui-api-tools");
|
|
23
24
|
class UiControlClient extends dsl_1.ApiCommands {
|
|
@@ -160,7 +161,7 @@ class UiControlClient extends dsl_1.ApiCommands {
|
|
|
160
161
|
});
|
|
161
162
|
}
|
|
162
163
|
fluentCommandExecutor(instructionString_1, modelComposition_1) {
|
|
163
|
-
return __awaiter(this, arguments, void 0, function* (instructionString, modelComposition, context = { customElementsJson: [], aiElementNames: [] }) {
|
|
164
|
+
return __awaiter(this, arguments, void 0, function* (instructionString, modelComposition, context = { customElementsJson: [], aiElementNames: [] }, skipCache = false, retryStrategy) {
|
|
164
165
|
const aiElements = yield this.getAIElementsByNames(context.aiElementNames);
|
|
165
166
|
const instruction = yield this.buildInstruction(instructionString, [
|
|
166
167
|
...context.customElementsJson,
|
|
@@ -169,7 +170,7 @@ class UiControlClient extends dsl_1.ApiCommands {
|
|
|
169
170
|
logger_1.logger.debug(instruction);
|
|
170
171
|
try {
|
|
171
172
|
this.stepReporter.resetStep(instruction);
|
|
172
|
-
yield this.executionRuntime.executeInstruction(instruction, modelComposition);
|
|
173
|
+
yield this.executionRuntime.executeInstruction(instruction, modelComposition, skipCache, retryStrategy);
|
|
173
174
|
yield this.afterCommandExecution(instruction);
|
|
174
175
|
return yield Promise.resolve();
|
|
175
176
|
}
|
|
@@ -453,18 +454,34 @@ class UiControlClient extends dsl_1.ApiCommands {
|
|
|
453
454
|
*/
|
|
454
455
|
waitUntil(AskUICommand_1) {
|
|
455
456
|
return __awaiter(this, arguments, void 0, function* (AskUICommand, maxTry = 5, waitTime = 2000) {
|
|
457
|
+
logger_1.logger.debug(`waitUntil: Starting with maxTry=${maxTry}, waitTime=${waitTime}ms, retryStrategy=${this.executionRuntime.retryStrategy.constructor.name}`);
|
|
456
458
|
const userDefinedStrategy = this.executionRuntime.retryStrategy;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
459
|
+
this.executionRuntime.retryStrategy = new retry_strategies_1.NoRetryStrategy();
|
|
460
|
+
const attempt = (retriesLeft) => __awaiter(this, void 0, void 0, function* () {
|
|
461
|
+
const attemptNumber = maxTry - retriesLeft;
|
|
462
|
+
logger_1.logger.debug(`waitUntil: Attempt ${attemptNumber}/${maxTry} (${retriesLeft} retries remaining)`);
|
|
463
|
+
try {
|
|
464
|
+
yield AskUICommand.exec();
|
|
465
|
+
logger_1.logger.debug(`waitUntil: Command succeeded on attempt ${attemptNumber}/${maxTry}`);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
if (error instanceof control_command_error_1.ControlCommandError && retriesLeft > 0) {
|
|
470
|
+
logger_1.logger.debug(`waitUntil: ControlCommandError on attempt ${attemptNumber}/${maxTry}, waiting ${waitTime}ms before retry.`, error);
|
|
471
|
+
yield this.waitFor(waitTime).exec();
|
|
472
|
+
yield attempt(retriesLeft - 1);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const errorName = error instanceof Error ? error.name : 'Error';
|
|
476
|
+
logger_1.logger.debug(`waitUntil: ${errorName} on attempt ${attemptNumber}/${maxTry}, no retries remaining.`, error);
|
|
464
477
|
throw error;
|
|
465
478
|
}
|
|
466
|
-
|
|
467
|
-
|
|
479
|
+
});
|
|
480
|
+
try {
|
|
481
|
+
yield attempt(maxTry - 1);
|
|
482
|
+
}
|
|
483
|
+
finally {
|
|
484
|
+
this.executionRuntime.retryStrategy = userDefinedStrategy;
|
|
468
485
|
}
|
|
469
486
|
});
|
|
470
487
|
}
|
|
@@ -5,6 +5,7 @@ import { Reporter } from '../core/reporting';
|
|
|
5
5
|
import { Context } from './context';
|
|
6
6
|
import { RetryStrategy } from './retry-strategies/retry-strategy';
|
|
7
7
|
import { AIElementArgs } from '../core/ai-element/ai-elements-args';
|
|
8
|
+
import { CacheConfig } from '../core/cache';
|
|
8
9
|
/**
|
|
9
10
|
* Context object to provide additional information about the context of (test) automation.
|
|
10
11
|
*
|
|
@@ -63,6 +64,7 @@ export interface ClientArgs {
|
|
|
63
64
|
readonly inferenceServerApiVersion?: string;
|
|
64
65
|
readonly retryStrategy?: RetryStrategy;
|
|
65
66
|
readonly aiElementArgs?: AIElementArgs;
|
|
67
|
+
readonly cacheConfig?: CacheConfig;
|
|
66
68
|
}
|
|
67
69
|
export interface ClientArgsWithDefaults extends ClientArgs {
|
|
68
70
|
readonly uiControllerUrl: string;
|
|
@@ -12,5 +12,7 @@ export declare class Base64Image {
|
|
|
12
12
|
getInfo(): Promise<sharp.OutputInfo>;
|
|
13
13
|
resizeToFitInto(dimension: number): Promise<Base64Image>;
|
|
14
14
|
resizeWithSameAspectRatio(width: number, height: number): Promise<Base64Image>;
|
|
15
|
+
cropRegion(x: number, y: number, croppedWidth: number, croppedHeight: number): Promise<Base64Image>;
|
|
15
16
|
toString(withPrefix?: boolean): string;
|
|
17
|
+
toBuffer(): Buffer;
|
|
16
18
|
}
|
|
@@ -67,11 +67,12 @@ class Base64Image {
|
|
|
67
67
|
resizeToFitInto(dimension) {
|
|
68
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
69
|
const { width, height } = yield this.getInfo();
|
|
70
|
+
const roundedDimension = Math.round(dimension);
|
|
70
71
|
const buffer = yield (yield this.getSharp())
|
|
71
72
|
.resize({
|
|
72
73
|
fit: 'contain',
|
|
73
|
-
height: height > width ?
|
|
74
|
-
width: width >= height ?
|
|
74
|
+
height: height > width ? roundedDimension : undefined,
|
|
75
|
+
width: width >= height ? roundedDimension : undefined,
|
|
75
76
|
})
|
|
76
77
|
.toBuffer();
|
|
77
78
|
return Base64Image.fromBuffer(buffer);
|
|
@@ -79,11 +80,30 @@ class Base64Image {
|
|
|
79
80
|
}
|
|
80
81
|
resizeWithSameAspectRatio(width, height) {
|
|
81
82
|
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
const roundedWidth = Math.round(width);
|
|
84
|
+
const roundedHeight = Math.round(height);
|
|
82
85
|
const buffer = yield (yield this.getSharp())
|
|
83
86
|
.resize({
|
|
84
87
|
fit: 'contain',
|
|
85
|
-
height,
|
|
86
|
-
width,
|
|
88
|
+
height: roundedHeight,
|
|
89
|
+
width: roundedWidth,
|
|
90
|
+
})
|
|
91
|
+
.toBuffer();
|
|
92
|
+
return Base64Image.fromBuffer(buffer);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
cropRegion(x, y, croppedWidth, croppedHeight) {
|
|
96
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
const roundedX = Math.round(x);
|
|
98
|
+
const roundedY = Math.round(y);
|
|
99
|
+
const roundedCroppedWidth = Math.round(croppedWidth);
|
|
100
|
+
const roundedCroppedHeight = Math.round(croppedHeight);
|
|
101
|
+
const buffer = yield (yield this.getSharp())
|
|
102
|
+
.extract({
|
|
103
|
+
height: roundedCroppedHeight,
|
|
104
|
+
left: roundedX,
|
|
105
|
+
top: roundedY,
|
|
106
|
+
width: roundedCroppedWidth,
|
|
87
107
|
})
|
|
88
108
|
.toBuffer();
|
|
89
109
|
return Base64Image.fromBuffer(buffer);
|
|
@@ -95,6 +115,9 @@ class Base64Image {
|
|
|
95
115
|
}
|
|
96
116
|
return this.buffer.toString('base64');
|
|
97
117
|
}
|
|
118
|
+
toBuffer() {
|
|
119
|
+
return this.buffer;
|
|
120
|
+
}
|
|
98
121
|
}
|
|
99
122
|
exports.Base64Image = Base64Image;
|
|
100
123
|
Base64Image.strPrefix = 'data:image/png;base64,';
|
|
@@ -16,7 +16,22 @@ export declare class HttpClientGot {
|
|
|
16
16
|
http: http.Agent;
|
|
17
17
|
https: https.Agent;
|
|
18
18
|
} | undefined);
|
|
19
|
+
/**
|
|
20
|
+
* Configures got with retry behavior for transient server errors.
|
|
21
|
+
*
|
|
22
|
+
* Got retries requests that fail with retryable status codes
|
|
23
|
+
* (500, 502, 503, 504, etc.) up to `limit` times using exponential backoff.
|
|
24
|
+
*
|
|
25
|
+
* POST requests are only retried if their URL is registered in `urlsToRetry`
|
|
26
|
+
* (see `shouldRetryOnError`), to avoid retrying non-idempotent calls
|
|
27
|
+
* to unknown endpoints.
|
|
28
|
+
*/
|
|
19
29
|
private buildGotExtendOptions;
|
|
30
|
+
/**
|
|
31
|
+
* Only retry POST requests if the URL is explicitly registered in `urlsToRetry`
|
|
32
|
+
* (populated by InferenceClient with inference endpoint URLs).
|
|
33
|
+
* Non-POST requests (GET, PUT, etc.) are always retried.
|
|
34
|
+
*/
|
|
20
35
|
private shouldRetryOnError;
|
|
21
36
|
private shouldRetryPostRequest;
|
|
22
37
|
private initHeaders;
|