donobu 5.55.0 → 5.57.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/apis/GptConfigsApi.d.ts +5 -5
- package/dist/apis/GptConfigsApi.js +14 -14
- package/dist/bindings/PageInteractionTracker.d.ts +1 -1
- package/dist/bindings/PageInteractionTracker.js +3 -3
- package/dist/bindings/SetDonobuAnnotations.d.ts +1 -1
- package/dist/bindings/SetDonobuAnnotations.js +3 -3
- package/dist/clients/AnthropicGptClient.d.ts +2 -2
- package/dist/clients/AnthropicGptClient.js +77 -77
- package/dist/clients/OpenAiGptClient.d.ts +14 -14
- package/dist/clients/OpenAiGptClient.js +183 -183
- package/dist/esm/apis/GptConfigsApi.d.ts +5 -5
- package/dist/esm/apis/GptConfigsApi.js +14 -14
- package/dist/esm/bindings/PageInteractionTracker.d.ts +1 -1
- package/dist/esm/bindings/PageInteractionTracker.js +3 -3
- package/dist/esm/bindings/SetDonobuAnnotations.d.ts +1 -1
- package/dist/esm/bindings/SetDonobuAnnotations.js +3 -3
- package/dist/esm/clients/AnthropicGptClient.d.ts +2 -2
- package/dist/esm/clients/AnthropicGptClient.js +77 -77
- package/dist/esm/clients/OpenAiGptClient.d.ts +14 -14
- package/dist/esm/clients/OpenAiGptClient.js +183 -183
- package/dist/esm/lib/ai/PageAi.js +2 -1
- package/dist/esm/lib/page/extendPage.js +2 -1
- package/dist/esm/lib/test/utils/TestFileUpdater.d.ts +9 -9
- package/dist/esm/lib/test/utils/TestFileUpdater.js +49 -49
- package/dist/esm/main.d.ts +2 -0
- package/dist/esm/managers/AdminApiController.d.ts +16 -16
- package/dist/esm/managers/AdminApiController.js +35 -35
- package/dist/esm/managers/DonobuFlow.d.ts +57 -36
- package/dist/esm/managers/DonobuFlow.js +489 -564
- package/dist/esm/managers/DonobuFlowsManager.js +13 -17
- package/dist/esm/managers/FlowDependencyAnalyzer.d.ts +12 -12
- package/dist/esm/managers/FlowDependencyAnalyzer.js +77 -77
- package/dist/esm/managers/PageInspector.d.ts +38 -38
- package/dist/esm/managers/PageInspector.js +745 -745
- package/dist/esm/managers/TargetInspector.d.ts +28 -33
- package/dist/esm/managers/TestsManager.d.ts +25 -25
- package/dist/esm/managers/TestsManager.js +74 -74
- package/dist/esm/managers/ToolManager.js +7 -5
- package/dist/esm/managers/ToolRegistry.d.ts +5 -1
- package/dist/esm/managers/WebTargetInspector.d.ts +9 -5
- package/dist/esm/managers/WebTargetInspector.js +45 -47
- package/dist/esm/models/AiQuery.d.ts +29 -15
- package/dist/esm/models/AiQuery.js +31 -0
- package/dist/esm/models/ControlPanel.d.ts +18 -13
- package/dist/esm/models/InteractableElement.d.ts +6 -0
- package/dist/esm/models/InteractableElement.js +7 -1
- package/dist/esm/models/Observation.d.ts +38 -0
- package/dist/esm/models/Observation.js +3 -0
- package/dist/esm/models/ToolCallContext.d.ts +3 -2
- package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.d.ts +2 -2
- package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.js +19 -18
- package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js +2 -1
- package/dist/esm/targets/TargetProvider.d.ts +110 -0
- package/dist/esm/targets/TargetProvider.js +25 -0
- package/dist/esm/targets/TargetRuntime.d.ts +6 -3
- package/dist/esm/targets/WebDialogHandler.d.ts +14 -0
- package/dist/esm/targets/WebDialogHandler.js +198 -0
- package/dist/esm/targets/WebTargetProvider.d.ts +32 -0
- package/dist/esm/targets/WebTargetProvider.js +136 -0
- package/dist/esm/targets/WebTargetRuntime.d.ts +2 -2
- package/dist/esm/targets/WebTargetRuntime.js +2 -1
- package/dist/esm/tools/AcknowledgeUserInstruction.d.ts +6 -0
- package/dist/esm/tools/AcknowledgeUserInstruction.js +7 -0
- package/dist/esm/tools/AssertPageTool.d.ts +1 -1
- package/dist/esm/tools/AssertPageTool.js +3 -3
- package/dist/esm/tools/DetectBrokenLinksTool.d.ts +2 -2
- package/dist/esm/tools/DetectBrokenLinksTool.js +44 -44
- package/dist/esm/tools/InputFakerTool.d.ts +4 -4
- package/dist/esm/tools/InputFakerTool.js +10 -10
- package/dist/esm/tools/InputTextTool.d.ts +4 -4
- package/dist/esm/tools/InputTextTool.js +7 -7
- package/dist/esm/tools/ReplayableInteraction.d.ts +34 -34
- package/dist/esm/tools/ReplayableInteraction.js +245 -245
- package/dist/esm/tools/Tool.d.ts +6 -3
- package/dist/esm/tools/Tool.js +5 -2
- package/dist/esm/utils/BrowserUtils.d.ts +19 -19
- package/dist/esm/utils/BrowserUtils.js +57 -57
- package/dist/esm/utils/MiscUtils.d.ts +2 -2
- package/dist/esm/utils/MiscUtils.js +16 -16
- package/dist/esm/utils/PlaywrightUtils.d.ts +1 -1
- package/dist/esm/utils/TargetUtils.d.ts +1 -1
- package/dist/esm/utils/TargetUtils.js +15 -13
- package/dist/lib/ai/PageAi.js +2 -1
- package/dist/lib/page/extendPage.js +2 -1
- package/dist/lib/test/utils/TestFileUpdater.d.ts +9 -9
- package/dist/lib/test/utils/TestFileUpdater.js +49 -49
- package/dist/main.d.ts +2 -0
- package/dist/managers/AdminApiController.d.ts +16 -16
- package/dist/managers/AdminApiController.js +35 -35
- package/dist/managers/DonobuFlow.d.ts +57 -36
- package/dist/managers/DonobuFlow.js +489 -564
- package/dist/managers/DonobuFlowsManager.js +13 -17
- package/dist/managers/FlowDependencyAnalyzer.d.ts +12 -12
- package/dist/managers/FlowDependencyAnalyzer.js +77 -77
- package/dist/managers/PageInspector.d.ts +38 -38
- package/dist/managers/PageInspector.js +745 -745
- package/dist/managers/TargetInspector.d.ts +28 -33
- package/dist/managers/TestsManager.d.ts +25 -25
- package/dist/managers/TestsManager.js +74 -74
- package/dist/managers/ToolManager.js +7 -5
- package/dist/managers/ToolRegistry.d.ts +5 -1
- package/dist/managers/WebTargetInspector.d.ts +9 -5
- package/dist/managers/WebTargetInspector.js +45 -47
- package/dist/models/AiQuery.d.ts +29 -15
- package/dist/models/AiQuery.js +31 -0
- package/dist/models/ControlPanel.d.ts +18 -13
- package/dist/models/InteractableElement.d.ts +6 -0
- package/dist/models/InteractableElement.js +7 -1
- package/dist/models/Observation.d.ts +38 -0
- package/dist/models/Observation.js +3 -0
- package/dist/models/ToolCallContext.d.ts +3 -2
- package/dist/persistence/flows/FlowsPersistenceDonobuApi.d.ts +2 -2
- package/dist/persistence/flows/FlowsPersistenceDonobuApi.js +19 -18
- package/dist/persistence/flows/FlowsPersistenceSqlite.js +2 -1
- package/dist/targets/TargetProvider.d.ts +110 -0
- package/dist/targets/TargetProvider.js +25 -0
- package/dist/targets/TargetRuntime.d.ts +6 -3
- package/dist/targets/WebDialogHandler.d.ts +14 -0
- package/dist/targets/WebDialogHandler.js +198 -0
- package/dist/targets/WebTargetProvider.d.ts +32 -0
- package/dist/targets/WebTargetProvider.js +136 -0
- package/dist/targets/WebTargetRuntime.d.ts +2 -2
- package/dist/targets/WebTargetRuntime.js +2 -1
- package/dist/tools/AcknowledgeUserInstruction.d.ts +6 -0
- package/dist/tools/AcknowledgeUserInstruction.js +7 -0
- package/dist/tools/AssertPageTool.d.ts +1 -1
- package/dist/tools/AssertPageTool.js +3 -3
- package/dist/tools/DetectBrokenLinksTool.d.ts +2 -2
- package/dist/tools/DetectBrokenLinksTool.js +44 -44
- package/dist/tools/InputFakerTool.d.ts +4 -4
- package/dist/tools/InputFakerTool.js +10 -10
- package/dist/tools/InputTextTool.d.ts +4 -4
- package/dist/tools/InputTextTool.js +7 -7
- package/dist/tools/ReplayableInteraction.d.ts +34 -34
- package/dist/tools/ReplayableInteraction.js +245 -245
- package/dist/tools/Tool.d.ts +6 -3
- package/dist/tools/Tool.js +5 -2
- package/dist/utils/BrowserUtils.d.ts +19 -19
- package/dist/utils/BrowserUtils.js +57 -57
- package/dist/utils/MiscUtils.d.ts +2 -2
- package/dist/utils/MiscUtils.js +16 -16
- package/dist/utils/PlaywrightUtils.d.ts +1 -1
- package/dist/utils/TargetUtils.d.ts +1 -1
- package/dist/utils/TargetUtils.js +15 -13
- package/package.json +2 -1
|
@@ -29,6 +29,83 @@ class AnthropicGptClient extends GptClient_1.GptClient {
|
|
|
29
29
|
'Content-Type': AnthropicGptClient.CONTENT_TYPE_HEADER_VALUE,
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
+
static chatRequestMessageFromGptMessage(gptMessage) {
|
|
33
|
+
if (gptMessage.type === 'assistant') {
|
|
34
|
+
return {
|
|
35
|
+
role: 'assistant',
|
|
36
|
+
content: gptMessage.text,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (gptMessage.type === 'structured_output') {
|
|
40
|
+
const output = gptMessage.output;
|
|
41
|
+
return {
|
|
42
|
+
role: 'assistant',
|
|
43
|
+
content: JSON.stringify(JsonUtils_1.JsonUtils.objectToJson(output), null, 2),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (gptMessage.type === 'proposed_tool_calls') {
|
|
47
|
+
return {
|
|
48
|
+
role: 'assistant',
|
|
49
|
+
content: gptMessage.proposedToolCalls.map((tc) => ({
|
|
50
|
+
type: 'tool_use',
|
|
51
|
+
id: tc.toolCallId,
|
|
52
|
+
name: tc.name,
|
|
53
|
+
input: JsonUtils_1.JsonUtils.objectToJson(tc.parameters),
|
|
54
|
+
})),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (gptMessage.type === 'system') {
|
|
58
|
+
return {
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: gptMessage.text,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (gptMessage.type === 'user') {
|
|
64
|
+
return {
|
|
65
|
+
role: 'user',
|
|
66
|
+
content: gptMessage.items.map((item) => {
|
|
67
|
+
if ('bytes' in item) {
|
|
68
|
+
const imageType = MiscUtils_1.MiscUtils.detectImageType(item.bytes);
|
|
69
|
+
const mimeType = `image/${imageType}`;
|
|
70
|
+
return {
|
|
71
|
+
type: 'image',
|
|
72
|
+
source: {
|
|
73
|
+
type: 'base64',
|
|
74
|
+
media_type: mimeType,
|
|
75
|
+
data: Buffer.from(item.bytes).toString('base64'),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return {
|
|
81
|
+
type: 'text',
|
|
82
|
+
text: item.text,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (gptMessage.type === 'tool_call_result') {
|
|
89
|
+
return {
|
|
90
|
+
role: 'user',
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: 'tool_result',
|
|
94
|
+
tool_use_id: gptMessage.toolCallId,
|
|
95
|
+
content: gptMessage.data,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Unsupported message type: ${JsonUtils_1.JsonUtils.objectToJson(gptMessage)}`);
|
|
101
|
+
}
|
|
102
|
+
static toolChoiceFromTool(tool) {
|
|
103
|
+
return {
|
|
104
|
+
name: tool.name,
|
|
105
|
+
description: tool.description,
|
|
106
|
+
input_schema: v4_1.z.toJSONSchema(tool.inputSchema),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
32
109
|
async ping(options) {
|
|
33
110
|
const resp = await this.makeRequest(`/v1/models/${this.anthropicConfig.modelName}`, 'GET', undefined, undefined, options?.signal);
|
|
34
111
|
if (resp.status === 404) {
|
|
@@ -216,83 +293,6 @@ class AnthropicGptClient extends GptClient_1.GptClient {
|
|
|
216
293
|
}
|
|
217
294
|
}
|
|
218
295
|
}
|
|
219
|
-
static chatRequestMessageFromGptMessage(gptMessage) {
|
|
220
|
-
if (gptMessage.type === 'assistant') {
|
|
221
|
-
return {
|
|
222
|
-
role: 'assistant',
|
|
223
|
-
content: gptMessage.text,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
if (gptMessage.type === 'structured_output') {
|
|
227
|
-
const output = gptMessage.output;
|
|
228
|
-
return {
|
|
229
|
-
role: 'assistant',
|
|
230
|
-
content: JSON.stringify(JsonUtils_1.JsonUtils.objectToJson(output), null, 2),
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
if (gptMessage.type === 'proposed_tool_calls') {
|
|
234
|
-
return {
|
|
235
|
-
role: 'assistant',
|
|
236
|
-
content: gptMessage.proposedToolCalls.map((tc) => ({
|
|
237
|
-
type: 'tool_use',
|
|
238
|
-
id: tc.toolCallId,
|
|
239
|
-
name: tc.name,
|
|
240
|
-
input: JsonUtils_1.JsonUtils.objectToJson(tc.parameters),
|
|
241
|
-
})),
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
if (gptMessage.type === 'system') {
|
|
245
|
-
return {
|
|
246
|
-
type: 'text',
|
|
247
|
-
text: gptMessage.text,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
if (gptMessage.type === 'user') {
|
|
251
|
-
return {
|
|
252
|
-
role: 'user',
|
|
253
|
-
content: gptMessage.items.map((item) => {
|
|
254
|
-
if ('bytes' in item) {
|
|
255
|
-
const imageType = MiscUtils_1.MiscUtils.detectImageType(item.bytes);
|
|
256
|
-
const mimeType = `image/${imageType}`;
|
|
257
|
-
return {
|
|
258
|
-
type: 'image',
|
|
259
|
-
source: {
|
|
260
|
-
type: 'base64',
|
|
261
|
-
media_type: mimeType,
|
|
262
|
-
data: Buffer.from(item.bytes).toString('base64'),
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
return {
|
|
268
|
-
type: 'text',
|
|
269
|
-
text: item.text,
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
}),
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
if (gptMessage.type === 'tool_call_result') {
|
|
276
|
-
return {
|
|
277
|
-
role: 'user',
|
|
278
|
-
content: [
|
|
279
|
-
{
|
|
280
|
-
type: 'tool_result',
|
|
281
|
-
tool_use_id: gptMessage.toolCallId,
|
|
282
|
-
content: gptMessage.data,
|
|
283
|
-
},
|
|
284
|
-
],
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
throw new Error(`Unsupported message type: ${JsonUtils_1.JsonUtils.objectToJson(gptMessage)}`);
|
|
288
|
-
}
|
|
289
|
-
static toolChoiceFromTool(tool) {
|
|
290
|
-
return {
|
|
291
|
-
name: tool.name,
|
|
292
|
-
description: tool.description,
|
|
293
|
-
input_schema: v4_1.z.toJSONSchema(tool.inputSchema),
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
296
|
}
|
|
297
297
|
exports.AnthropicGptClient = AnthropicGptClient;
|
|
298
298
|
AnthropicGptClient.API_URL = 'https://api.anthropic.com';
|
|
@@ -14,6 +14,20 @@ export declare class OpenAiGptClient extends GptClient {
|
|
|
14
14
|
private static readonly REQUEST_TIMEOUT_MILLISECONDS;
|
|
15
15
|
private readonly headers;
|
|
16
16
|
constructor(openAiConfig: OpenAiConfig, apiUrl?: string);
|
|
17
|
+
/**
|
|
18
|
+
* Transform a general JSON Schema into one that fits the OpenAI Structured Outputs subset.
|
|
19
|
+
* Key behaviors:
|
|
20
|
+
* - Enforce additionalProperties:false on objects and require all defined properties.
|
|
21
|
+
* - Remove unsupported validation keywords.
|
|
22
|
+
* - Convert tuple `items: [A,B]` into `items: { anyOf: [A,B] }`.
|
|
23
|
+
* - Preserve $ref and $defs, cleaning nested definitions recursively.
|
|
24
|
+
* - If the root is `anyOf`, wrap it into an object schema with a single `value` property.
|
|
25
|
+
*
|
|
26
|
+
* Notes for optional fields:
|
|
27
|
+
* - Since all fields must be required, emulate optionals with union types that include "null".
|
|
28
|
+
* e.g., `type: ["string", "null"]` while keeping the field in `required`.
|
|
29
|
+
*/
|
|
30
|
+
private static createOpenAiCompatibleJsonSchema;
|
|
17
31
|
ping(options?: {
|
|
18
32
|
signal?: AbortSignal;
|
|
19
33
|
}): Promise<void>;
|
|
@@ -36,19 +50,5 @@ export declare class OpenAiGptClient extends GptClient {
|
|
|
36
50
|
* Makes an HTTP request to the OpenAI API with standard configuration.
|
|
37
51
|
*/
|
|
38
52
|
private makeRequest;
|
|
39
|
-
/**
|
|
40
|
-
* Transform a general JSON Schema into one that fits the OpenAI Structured Outputs subset.
|
|
41
|
-
* Key behaviors:
|
|
42
|
-
* - Enforce additionalProperties:false on objects and require all defined properties.
|
|
43
|
-
* - Remove unsupported validation keywords.
|
|
44
|
-
* - Convert tuple `items: [A,B]` into `items: { anyOf: [A,B] }`.
|
|
45
|
-
* - Preserve $ref and $defs, cleaning nested definitions recursively.
|
|
46
|
-
* - If the root is `anyOf`, wrap it into an object schema with a single `value` property.
|
|
47
|
-
*
|
|
48
|
-
* Notes for optional fields:
|
|
49
|
-
* - Since all fields must be required, emulate optionals with union types that include "null".
|
|
50
|
-
* e.g., `type: ["string", "null"]` while keeping the field in `required`.
|
|
51
|
-
*/
|
|
52
|
-
private static createOpenAiCompatibleJsonSchema;
|
|
53
53
|
}
|
|
54
54
|
//# sourceMappingURL=OpenAiGptClient.d.ts.map
|
|
@@ -29,6 +29,189 @@ class OpenAiGptClient extends GptClient_1.GptClient {
|
|
|
29
29
|
'Content-Type': 'application/json',
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Transform a general JSON Schema into one that fits the OpenAI Structured Outputs subset.
|
|
34
|
+
* Key behaviors:
|
|
35
|
+
* - Enforce additionalProperties:false on objects and require all defined properties.
|
|
36
|
+
* - Remove unsupported validation keywords.
|
|
37
|
+
* - Convert tuple `items: [A,B]` into `items: { anyOf: [A,B] }`.
|
|
38
|
+
* - Preserve $ref and $defs, cleaning nested definitions recursively.
|
|
39
|
+
* - If the root is `anyOf`, wrap it into an object schema with a single `value` property.
|
|
40
|
+
*
|
|
41
|
+
* Notes for optional fields:
|
|
42
|
+
* - Since all fields must be required, emulate optionals with union types that include "null".
|
|
43
|
+
* e.g., `type: ["string", "null"]` while keeping the field in `required`.
|
|
44
|
+
*/
|
|
45
|
+
static createOpenAiCompatibleJsonSchema(schema) {
|
|
46
|
+
// Defensive deep clone to avoid mutating the caller's object.
|
|
47
|
+
const clone = (obj) => obj === null || typeof obj !== 'object'
|
|
48
|
+
? obj
|
|
49
|
+
: Array.isArray(obj)
|
|
50
|
+
? obj.map(clone)
|
|
51
|
+
: Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, clone(v)]));
|
|
52
|
+
// Set of keywords we will strip because they are not supported or risky per docs.
|
|
53
|
+
// (Docs list these as unsupported in Structured Outputs.)
|
|
54
|
+
const STRIP_KEYS = new Set([
|
|
55
|
+
// string
|
|
56
|
+
'minLength',
|
|
57
|
+
'maxLength',
|
|
58
|
+
'pattern',
|
|
59
|
+
'format',
|
|
60
|
+
'contentMediaType',
|
|
61
|
+
'contentEncoding',
|
|
62
|
+
'contentSchema',
|
|
63
|
+
// number
|
|
64
|
+
'minimum',
|
|
65
|
+
'maximum',
|
|
66
|
+
'exclusiveMinimum',
|
|
67
|
+
'exclusiveMaximum',
|
|
68
|
+
'multipleOf',
|
|
69
|
+
// object
|
|
70
|
+
'patternProperties',
|
|
71
|
+
'unevaluatedProperties',
|
|
72
|
+
'propertyNames',
|
|
73
|
+
'minProperties',
|
|
74
|
+
'maxProperties',
|
|
75
|
+
'dependentRequired',
|
|
76
|
+
'dependentSchemas',
|
|
77
|
+
// arrays
|
|
78
|
+
'unevaluatedItems',
|
|
79
|
+
'contains',
|
|
80
|
+
'minContains',
|
|
81
|
+
'maxContains',
|
|
82
|
+
'minItems',
|
|
83
|
+
'maxItems',
|
|
84
|
+
'uniqueItems',
|
|
85
|
+
'additionalItems',
|
|
86
|
+
'prefixItems',
|
|
87
|
+
// schema/meta rarely needed for model guidance
|
|
88
|
+
'$dynamicRef',
|
|
89
|
+
'$dynamicAnchor',
|
|
90
|
+
'$vocabulary',
|
|
91
|
+
'allOf', // conservative: remove; can be rewritten as anyOf in many cases
|
|
92
|
+
'oneOf', // conservative: remove; prefer anyOf
|
|
93
|
+
'not', // conservative: remove
|
|
94
|
+
'if',
|
|
95
|
+
'then',
|
|
96
|
+
'else',
|
|
97
|
+
]);
|
|
98
|
+
// Normalize `items`:
|
|
99
|
+
// - if array (tuple validation), convert to anyOf branch for a simpler, supported pattern.
|
|
100
|
+
const normalizeItems = (items) => {
|
|
101
|
+
if (Array.isArray(items)) {
|
|
102
|
+
return {
|
|
103
|
+
anyOf: items.map((s) => cleanSchema(s)),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return cleanSchema(items);
|
|
107
|
+
};
|
|
108
|
+
// Ensure object properties are all required and additionalProperties:false
|
|
109
|
+
const normalizeObject = (s) => {
|
|
110
|
+
const out = s;
|
|
111
|
+
if (!out.properties) {
|
|
112
|
+
out.properties = {};
|
|
113
|
+
}
|
|
114
|
+
// Enforce additionalProperties:false per docs
|
|
115
|
+
out.additionalProperties = false;
|
|
116
|
+
// Compute required = all keys in properties (OpenAI requires all params/fields required)
|
|
117
|
+
const propKeys = Object.keys(out.properties);
|
|
118
|
+
out.required = Array.from(new Set([...(out.required ?? []), ...propKeys]));
|
|
119
|
+
// Recurse into each property
|
|
120
|
+
for (const [key, subschema] of Object.entries(out.properties)) {
|
|
121
|
+
if (typeof subschema === 'boolean') {
|
|
122
|
+
// Convert boolean schemas to permissive object (true) or impossible (false).
|
|
123
|
+
// We'll treat `true` as `{}` and `false` as `{ "enum": [] }` which is unmatchable.
|
|
124
|
+
out.properties[key] = subschema ? {} : { enum: [] };
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
out.properties[key] = cleanSchema(subschema);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
};
|
|
132
|
+
// Core cleaner: strip unsupported keys, normalize arrays/objects/anyOf/$defs.
|
|
133
|
+
const cleanSchema = (input) => {
|
|
134
|
+
if (input === undefined) {
|
|
135
|
+
return {};
|
|
136
|
+
}
|
|
137
|
+
if (typeof input === 'boolean') {
|
|
138
|
+
return input ? {} : { enum: [] }; // keep shape valid; `enum: []` is unsatisfiable.
|
|
139
|
+
}
|
|
140
|
+
let s = clone(input);
|
|
141
|
+
// Remove unsupported keys at this level
|
|
142
|
+
for (const k of Object.keys(s)) {
|
|
143
|
+
if (STRIP_KEYS.has(k)) {
|
|
144
|
+
delete s[k];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Clean $defs recursively
|
|
148
|
+
if (s.$defs) {
|
|
149
|
+
for (const [defKey, defSchema] of Object.entries(s.$defs)) {
|
|
150
|
+
s.$defs[defKey] = cleanSchema(defSchema);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Handle anyOf branches
|
|
154
|
+
if (s.anyOf) {
|
|
155
|
+
s.anyOf = s.anyOf.map((branch) => cleanSchema(branch));
|
|
156
|
+
}
|
|
157
|
+
// Keep enum/const/description/title/$ref as-is.
|
|
158
|
+
// Normalize arrays
|
|
159
|
+
if (s.type === 'array') {
|
|
160
|
+
if (s.items !== undefined) {
|
|
161
|
+
s.items = normalizeItems(s.items);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Provide a permissive default for items to avoid undefined behavior.
|
|
165
|
+
s.items = {};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Normalize objects
|
|
169
|
+
if (s.type === 'object') {
|
|
170
|
+
s = normalizeObject(s);
|
|
171
|
+
}
|
|
172
|
+
// If `type` is a union array, keep it (this is how optionals are expressed: includes "null")
|
|
173
|
+
// Nothing to do here; we just don't strip it.
|
|
174
|
+
// If `properties` exists but `type` is missing, make it an object to be explicit
|
|
175
|
+
if (!s.type && s.properties) {
|
|
176
|
+
s.type = 'object';
|
|
177
|
+
s = normalizeObject(s);
|
|
178
|
+
}
|
|
179
|
+
// If we still have tuple constructs in "items" (e.g., array of schemas after clean), ensure we normalized
|
|
180
|
+
if (Array.isArray(s.items)) {
|
|
181
|
+
s.items = normalizeItems(s.items);
|
|
182
|
+
}
|
|
183
|
+
return s;
|
|
184
|
+
};
|
|
185
|
+
// Start by cleaning the provided schema
|
|
186
|
+
let cleaned = cleanSchema(schema);
|
|
187
|
+
// Root cannot be `anyOf`: wrap if necessary
|
|
188
|
+
if (cleaned &&
|
|
189
|
+
!cleaned.type &&
|
|
190
|
+
cleaned.anyOf &&
|
|
191
|
+
Object.keys(cleaned).every((k) => k === 'anyOf' ||
|
|
192
|
+
k === '$defs' ||
|
|
193
|
+
k === 'description' ||
|
|
194
|
+
k === 'title')) {
|
|
195
|
+
cleaned = {
|
|
196
|
+
type: 'object',
|
|
197
|
+
properties: {
|
|
198
|
+
value: { anyOf: cleaned.anyOf.map((b) => cleanSchema(b)) },
|
|
199
|
+
},
|
|
200
|
+
required: ['value'],
|
|
201
|
+
additionalProperties: false,
|
|
202
|
+
...(cleaned.$defs ? { $defs: cleaned.$defs } : {}),
|
|
203
|
+
...(cleaned.title ? { title: cleaned.title } : {}),
|
|
204
|
+
...(cleaned.description ? { description: cleaned.description } : {}),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
// Final safety: if an object lacks properties, make properties:{} and still enforce additionalProperties:false
|
|
208
|
+
if (cleaned.type === 'object' && !cleaned.properties) {
|
|
209
|
+
cleaned.properties = {};
|
|
210
|
+
cleaned.required = [];
|
|
211
|
+
cleaned.additionalProperties = false;
|
|
212
|
+
}
|
|
213
|
+
return cleaned;
|
|
214
|
+
}
|
|
32
215
|
async ping(options) {
|
|
33
216
|
const resp = await this.makeRequest(`/v1/models/${this.openAiConfig.modelName}`, 'GET', undefined, options?.signal);
|
|
34
217
|
if (resp.status === 404) {
|
|
@@ -284,189 +467,6 @@ class OpenAiGptClient extends GptClient_1.GptClient {
|
|
|
284
467
|
}
|
|
285
468
|
}
|
|
286
469
|
}
|
|
287
|
-
/**
|
|
288
|
-
* Transform a general JSON Schema into one that fits the OpenAI Structured Outputs subset.
|
|
289
|
-
* Key behaviors:
|
|
290
|
-
* - Enforce additionalProperties:false on objects and require all defined properties.
|
|
291
|
-
* - Remove unsupported validation keywords.
|
|
292
|
-
* - Convert tuple `items: [A,B]` into `items: { anyOf: [A,B] }`.
|
|
293
|
-
* - Preserve $ref and $defs, cleaning nested definitions recursively.
|
|
294
|
-
* - If the root is `anyOf`, wrap it into an object schema with a single `value` property.
|
|
295
|
-
*
|
|
296
|
-
* Notes for optional fields:
|
|
297
|
-
* - Since all fields must be required, emulate optionals with union types that include "null".
|
|
298
|
-
* e.g., `type: ["string", "null"]` while keeping the field in `required`.
|
|
299
|
-
*/
|
|
300
|
-
static createOpenAiCompatibleJsonSchema(schema) {
|
|
301
|
-
// Defensive deep clone to avoid mutating the caller's object.
|
|
302
|
-
const clone = (obj) => obj === null || typeof obj !== 'object'
|
|
303
|
-
? obj
|
|
304
|
-
: Array.isArray(obj)
|
|
305
|
-
? obj.map(clone)
|
|
306
|
-
: Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, clone(v)]));
|
|
307
|
-
// Set of keywords we will strip because they are not supported or risky per docs.
|
|
308
|
-
// (Docs list these as unsupported in Structured Outputs.)
|
|
309
|
-
const STRIP_KEYS = new Set([
|
|
310
|
-
// string
|
|
311
|
-
'minLength',
|
|
312
|
-
'maxLength',
|
|
313
|
-
'pattern',
|
|
314
|
-
'format',
|
|
315
|
-
'contentMediaType',
|
|
316
|
-
'contentEncoding',
|
|
317
|
-
'contentSchema',
|
|
318
|
-
// number
|
|
319
|
-
'minimum',
|
|
320
|
-
'maximum',
|
|
321
|
-
'exclusiveMinimum',
|
|
322
|
-
'exclusiveMaximum',
|
|
323
|
-
'multipleOf',
|
|
324
|
-
// object
|
|
325
|
-
'patternProperties',
|
|
326
|
-
'unevaluatedProperties',
|
|
327
|
-
'propertyNames',
|
|
328
|
-
'minProperties',
|
|
329
|
-
'maxProperties',
|
|
330
|
-
'dependentRequired',
|
|
331
|
-
'dependentSchemas',
|
|
332
|
-
// arrays
|
|
333
|
-
'unevaluatedItems',
|
|
334
|
-
'contains',
|
|
335
|
-
'minContains',
|
|
336
|
-
'maxContains',
|
|
337
|
-
'minItems',
|
|
338
|
-
'maxItems',
|
|
339
|
-
'uniqueItems',
|
|
340
|
-
'additionalItems',
|
|
341
|
-
'prefixItems',
|
|
342
|
-
// schema/meta rarely needed for model guidance
|
|
343
|
-
'$dynamicRef',
|
|
344
|
-
'$dynamicAnchor',
|
|
345
|
-
'$vocabulary',
|
|
346
|
-
'allOf', // conservative: remove; can be rewritten as anyOf in many cases
|
|
347
|
-
'oneOf', // conservative: remove; prefer anyOf
|
|
348
|
-
'not', // conservative: remove
|
|
349
|
-
'if',
|
|
350
|
-
'then',
|
|
351
|
-
'else',
|
|
352
|
-
]);
|
|
353
|
-
// Normalize `items`:
|
|
354
|
-
// - if array (tuple validation), convert to anyOf branch for a simpler, supported pattern.
|
|
355
|
-
const normalizeItems = (items) => {
|
|
356
|
-
if (Array.isArray(items)) {
|
|
357
|
-
return {
|
|
358
|
-
anyOf: items.map((s) => cleanSchema(s)),
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
return cleanSchema(items);
|
|
362
|
-
};
|
|
363
|
-
// Ensure object properties are all required and additionalProperties:false
|
|
364
|
-
const normalizeObject = (s) => {
|
|
365
|
-
const out = s;
|
|
366
|
-
if (!out.properties) {
|
|
367
|
-
out.properties = {};
|
|
368
|
-
}
|
|
369
|
-
// Enforce additionalProperties:false per docs
|
|
370
|
-
out.additionalProperties = false;
|
|
371
|
-
// Compute required = all keys in properties (OpenAI requires all params/fields required)
|
|
372
|
-
const propKeys = Object.keys(out.properties);
|
|
373
|
-
out.required = Array.from(new Set([...(out.required ?? []), ...propKeys]));
|
|
374
|
-
// Recurse into each property
|
|
375
|
-
for (const [key, subschema] of Object.entries(out.properties)) {
|
|
376
|
-
if (typeof subschema === 'boolean') {
|
|
377
|
-
// Convert boolean schemas to permissive object (true) or impossible (false).
|
|
378
|
-
// We'll treat `true` as `{}` and `false` as `{ "enum": [] }` which is unmatchable.
|
|
379
|
-
out.properties[key] = subschema ? {} : { enum: [] };
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
out.properties[key] = cleanSchema(subschema);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return out;
|
|
386
|
-
};
|
|
387
|
-
// Core cleaner: strip unsupported keys, normalize arrays/objects/anyOf/$defs.
|
|
388
|
-
const cleanSchema = (input) => {
|
|
389
|
-
if (input === undefined) {
|
|
390
|
-
return {};
|
|
391
|
-
}
|
|
392
|
-
if (typeof input === 'boolean') {
|
|
393
|
-
return input ? {} : { enum: [] }; // keep shape valid; `enum: []` is unsatisfiable.
|
|
394
|
-
}
|
|
395
|
-
let s = clone(input);
|
|
396
|
-
// Remove unsupported keys at this level
|
|
397
|
-
for (const k of Object.keys(s)) {
|
|
398
|
-
if (STRIP_KEYS.has(k)) {
|
|
399
|
-
delete s[k];
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
// Clean $defs recursively
|
|
403
|
-
if (s.$defs) {
|
|
404
|
-
for (const [defKey, defSchema] of Object.entries(s.$defs)) {
|
|
405
|
-
s.$defs[defKey] = cleanSchema(defSchema);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
// Handle anyOf branches
|
|
409
|
-
if (s.anyOf) {
|
|
410
|
-
s.anyOf = s.anyOf.map((branch) => cleanSchema(branch));
|
|
411
|
-
}
|
|
412
|
-
// Keep enum/const/description/title/$ref as-is.
|
|
413
|
-
// Normalize arrays
|
|
414
|
-
if (s.type === 'array') {
|
|
415
|
-
if (s.items !== undefined) {
|
|
416
|
-
s.items = normalizeItems(s.items);
|
|
417
|
-
}
|
|
418
|
-
else {
|
|
419
|
-
// Provide a permissive default for items to avoid undefined behavior.
|
|
420
|
-
s.items = {};
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
// Normalize objects
|
|
424
|
-
if (s.type === 'object') {
|
|
425
|
-
s = normalizeObject(s);
|
|
426
|
-
}
|
|
427
|
-
// If `type` is a union array, keep it (this is how optionals are expressed: includes "null")
|
|
428
|
-
// Nothing to do here; we just don't strip it.
|
|
429
|
-
// If `properties` exists but `type` is missing, make it an object to be explicit
|
|
430
|
-
if (!s.type && s.properties) {
|
|
431
|
-
s.type = 'object';
|
|
432
|
-
s = normalizeObject(s);
|
|
433
|
-
}
|
|
434
|
-
// If we still have tuple constructs in "items" (e.g., array of schemas after clean), ensure we normalized
|
|
435
|
-
if (Array.isArray(s.items)) {
|
|
436
|
-
s.items = normalizeItems(s.items);
|
|
437
|
-
}
|
|
438
|
-
return s;
|
|
439
|
-
};
|
|
440
|
-
// Start by cleaning the provided schema
|
|
441
|
-
let cleaned = cleanSchema(schema);
|
|
442
|
-
// Root cannot be `anyOf`: wrap if necessary
|
|
443
|
-
if (cleaned &&
|
|
444
|
-
!cleaned.type &&
|
|
445
|
-
cleaned.anyOf &&
|
|
446
|
-
Object.keys(cleaned).every((k) => k === 'anyOf' ||
|
|
447
|
-
k === '$defs' ||
|
|
448
|
-
k === 'description' ||
|
|
449
|
-
k === 'title')) {
|
|
450
|
-
cleaned = {
|
|
451
|
-
type: 'object',
|
|
452
|
-
properties: {
|
|
453
|
-
value: { anyOf: cleaned.anyOf.map((b) => cleanSchema(b)) },
|
|
454
|
-
},
|
|
455
|
-
required: ['value'],
|
|
456
|
-
additionalProperties: false,
|
|
457
|
-
...(cleaned.$defs ? { $defs: cleaned.$defs } : {}),
|
|
458
|
-
...(cleaned.title ? { title: cleaned.title } : {}),
|
|
459
|
-
...(cleaned.description ? { description: cleaned.description } : {}),
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
// Final safety: if an object lacks properties, make properties:{} and still enforce additionalProperties:false
|
|
463
|
-
if (cleaned.type === 'object' && !cleaned.properties) {
|
|
464
|
-
cleaned.properties = {};
|
|
465
|
-
cleaned.required = [];
|
|
466
|
-
cleaned.additionalProperties = false;
|
|
467
|
-
}
|
|
468
|
-
return cleaned;
|
|
469
|
-
}
|
|
470
470
|
}
|
|
471
471
|
exports.OpenAiGptClient = OpenAiGptClient;
|
|
472
472
|
OpenAiGptClient.DEFAULT_API_URL = 'https://api.openai.com';
|
|
@@ -9,6 +9,7 @@ const DonobuFlowsManager_1 = require("../../managers/DonobuFlowsManager");
|
|
|
9
9
|
const ToolManager_1 = require("../../managers/ToolManager");
|
|
10
10
|
const WebTargetInspector_1 = require("../../managers/WebTargetInspector");
|
|
11
11
|
const ControlPanel_1 = require("../../models/ControlPanel");
|
|
12
|
+
const WebTargetProvider_1 = require("../../targets/WebTargetProvider");
|
|
12
13
|
const Logger_1 = require("../../utils/Logger");
|
|
13
14
|
const originalGotoRegistry_1 = require("../page/originalGotoRegistry");
|
|
14
15
|
const cache_1 = require("./cache/cache");
|
|
@@ -69,7 +70,7 @@ class PageAiRunner {
|
|
|
69
70
|
const persistence = await this.donobu.flowsPersistenceRegistry.get();
|
|
70
71
|
const pageWithOriginalGoto = Object.create(config.page);
|
|
71
72
|
pageWithOriginalGoto.goto = (0, originalGotoRegistry_1.getOriginalGoto)(config.page);
|
|
72
|
-
const donobuFlow = new DonobuFlow_1.DonobuFlow(this.donobu.flowsManager, envData, persistence, this.gptClient, toolManager, config.page._dnb.interactionVisualizer, [], [], [], new WebTargetInspector_1.WebTargetInspector({ type: 'web', current: pageWithOriginalGoto }, config.page.context(), config.page._dnb.interactionVisualizer), augmentedMetadata, config.page._dnb.controlPanelFactory
|
|
73
|
+
const donobuFlow = new DonobuFlow_1.DonobuFlow(this.donobu.flowsManager, envData, persistence, this.gptClient, toolManager, config.page._dnb.interactionVisualizer, [], [], [], new WebTargetProvider_1.WebTargetProvider(new WebTargetInspector_1.WebTargetInspector({ type: 'web', current: pageWithOriginalGoto }, config.page.context(), config.page._dnb.interactionVisualizer)), augmentedMetadata, config.page._dnb.controlPanelFactory
|
|
73
74
|
? await config.page._dnb.controlPanelFactory(augmentedMetadata.id)
|
|
74
75
|
: new ControlPanel_1.NoOpControlPanel());
|
|
75
76
|
const flowContext = { flowId: augmentedMetadata.id };
|
|
@@ -16,6 +16,7 @@ const ToolManager_1 = require("../../managers/ToolManager");
|
|
|
16
16
|
const WebTargetInspector_1 = require("../../managers/WebTargetInspector");
|
|
17
17
|
const ControlPanel_1 = require("../../models/ControlPanel");
|
|
18
18
|
const MetadataVersion_1 = require("../../models/MetadataVersion");
|
|
19
|
+
const WebTargetProvider_1 = require("../../targets/WebTargetProvider");
|
|
19
20
|
const AnalyzePageTextTool_1 = require("../../tools/AnalyzePageTextTool");
|
|
20
21
|
const AssertTool_1 = require("../../tools/AssertTool");
|
|
21
22
|
const AuditTool_1 = require("../../tools/AuditTool");
|
|
@@ -805,7 +806,7 @@ async function runTool(page, toolName, toolParams, gptClient) {
|
|
|
805
806
|
const toolCallContext = {
|
|
806
807
|
flowsManager: page._dnb.donobuStack.flowsManager,
|
|
807
808
|
envData,
|
|
808
|
-
|
|
809
|
+
provider: new WebTargetProvider_1.WebTargetProvider(new WebTargetInspector_1.WebTargetInspector(webTarget, page.context(), page._dnb.interactionVisualizer)),
|
|
809
810
|
controlPanel: new ControlPanel_1.NoOpControlPanel(),
|
|
810
811
|
persistence: page._dnb.persistence,
|
|
811
812
|
gptClient: getGptClient(page, gptClient),
|
|
@@ -12,6 +12,15 @@ export declare class TestFileUpdater {
|
|
|
12
12
|
* @returns True if the update was successful, false otherwise
|
|
13
13
|
*/
|
|
14
14
|
static updateTestCase(testFilePath: string, testName: string, newTestCode: string): Promise<boolean>;
|
|
15
|
+
/**
|
|
16
|
+
* Updates a test file based on a Playwright JSON reporter output.
|
|
17
|
+
*
|
|
18
|
+
* @param jsonReportPath Path to the Playwright JSON report
|
|
19
|
+
* @param testFilePath Path to the test file to update (if not specified, will be extracted from the report)
|
|
20
|
+
* @param newTestCode The new test code
|
|
21
|
+
* @returns True if the update was successful, false otherwise
|
|
22
|
+
*/
|
|
23
|
+
static updateFromPlaywrightReport(jsonReportPath: string, newTestCode: string, testFilePath?: string): Promise<boolean>;
|
|
15
24
|
/**
|
|
16
25
|
* Extracts a specific test case from source code.
|
|
17
26
|
*
|
|
@@ -43,14 +52,5 @@ export declare class TestFileUpdater {
|
|
|
43
52
|
* Checks if a test title matches the target test name.
|
|
44
53
|
*/
|
|
45
54
|
private static testTitleMatches;
|
|
46
|
-
/**
|
|
47
|
-
* Updates a test file based on a Playwright JSON reporter output.
|
|
48
|
-
*
|
|
49
|
-
* @param jsonReportPath Path to the Playwright JSON report
|
|
50
|
-
* @param testFilePath Path to the test file to update (if not specified, will be extracted from the report)
|
|
51
|
-
* @param newTestCode The new test code
|
|
52
|
-
* @returns True if the update was successful, false otherwise
|
|
53
|
-
*/
|
|
54
|
-
static updateFromPlaywrightReport(jsonReportPath: string, newTestCode: string, testFilePath?: string): Promise<boolean>;
|
|
55
55
|
}
|
|
56
56
|
//# sourceMappingURL=TestFileUpdater.d.ts.map
|