donobu 5.56.0 → 5.57.1
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/cli/donobu-cli.d.ts +8 -0
- package/dist/cli/donobu-cli.js +23 -0
- 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/cli/donobu-cli.d.ts +8 -0
- package/dist/esm/cli/donobu-cli.js +23 -0
- 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 +41 -33
- package/dist/esm/managers/DonobuFlow.js +362 -532
- package/dist/esm/managers/DonobuFlowsManager.js +2 -10
- 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/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/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/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 +41 -33
- package/dist/managers/DonobuFlow.js +362 -532
- package/dist/managers/DonobuFlowsManager.js +2 -10
- 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/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/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/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,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';
|
|
@@ -34,6 +34,11 @@ export declare class GptConfigsApi {
|
|
|
34
34
|
*/
|
|
35
35
|
private static readonly REDACTED_FIELD_NAMES;
|
|
36
36
|
constructor(gptConfigsManager: GptConfigsManager, agentsManager: AgentsManager);
|
|
37
|
+
/**
|
|
38
|
+
* Redacts sensative data from the given GPT configuration so that the record
|
|
39
|
+
* can be safely returned through the API.
|
|
40
|
+
*/
|
|
41
|
+
static redactSensativeData(config: GptConfigInput): GptConfigInput;
|
|
37
42
|
/**
|
|
38
43
|
* Creates or updates a GPT configuration.
|
|
39
44
|
*
|
|
@@ -82,10 +87,5 @@ export declare class GptConfigsApi {
|
|
|
82
87
|
* 3. Unlinks the configuration from all dependent agents
|
|
83
88
|
*/
|
|
84
89
|
delete(req: Request, res: Response): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Redacts sensative data from the given GPT configuration so that the record
|
|
87
|
-
* can be safely returned through the API.
|
|
88
|
-
*/
|
|
89
|
-
static redactSensativeData(config: GptConfigInput): GptConfigInput;
|
|
90
90
|
}
|
|
91
91
|
//# sourceMappingURL=GptConfigsApi.d.ts.map
|
|
@@ -27,6 +27,20 @@ class GptConfigsApi {
|
|
|
27
27
|
this.gptConfigsManager = gptConfigsManager;
|
|
28
28
|
this.agentsManager = agentsManager;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Redacts sensative data from the given GPT configuration so that the record
|
|
32
|
+
* can be safely returned through the API.
|
|
33
|
+
*/
|
|
34
|
+
static redactSensativeData(config) {
|
|
35
|
+
const configCopy = { ...config };
|
|
36
|
+
for (const redactedFieldName of GptConfigsApi.REDACTED_FIELD_NAMES) {
|
|
37
|
+
if (redactedFieldName in configCopy) {
|
|
38
|
+
// Use type assertion to tell TypeScript this is allowed
|
|
39
|
+
configCopy[redactedFieldName] = '****************';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return configCopy;
|
|
43
|
+
}
|
|
30
44
|
/**
|
|
31
45
|
* Creates or updates a GPT configuration.
|
|
32
46
|
*
|
|
@@ -112,20 +126,6 @@ class GptConfigsApi {
|
|
|
112
126
|
}
|
|
113
127
|
res.json({});
|
|
114
128
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Redacts sensative data from the given GPT configuration so that the record
|
|
117
|
-
* can be safely returned through the API.
|
|
118
|
-
*/
|
|
119
|
-
static redactSensativeData(config) {
|
|
120
|
-
const configCopy = { ...config };
|
|
121
|
-
for (const redactedFieldName of GptConfigsApi.REDACTED_FIELD_NAMES) {
|
|
122
|
-
if (redactedFieldName in configCopy) {
|
|
123
|
-
// Use type assertion to tell TypeScript this is allowed
|
|
124
|
-
configCopy[redactedFieldName] = '****************';
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return configCopy;
|
|
128
|
-
}
|
|
129
129
|
}
|
|
130
130
|
exports.GptConfigsApi = GptConfigsApi;
|
|
131
131
|
/**
|
|
@@ -46,8 +46,8 @@ export interface InteractionTrackingHost {
|
|
|
46
46
|
export declare class PageInteractionTracker implements NamedBindingCallback {
|
|
47
47
|
private readonly host;
|
|
48
48
|
static readonly NAME = "__donobuTrackInteraction";
|
|
49
|
-
static register(host: InteractionTrackingHost, browserContext: BrowserContext): Promise<PageInteractionTracker>;
|
|
50
49
|
private constructor();
|
|
50
|
+
static register(host: InteractionTrackingHost, browserContext: BrowserContext): Promise<PageInteractionTracker>;
|
|
51
51
|
name(): string;
|
|
52
52
|
/**
|
|
53
53
|
* Handles tracking of page interactions.
|
|
@@ -38,6 +38,9 @@ exports.InteractionEventSchema = v4_1.z.object({
|
|
|
38
38
|
* This tracker records direct user actions for reliable replay and GPT visibility.
|
|
39
39
|
*/
|
|
40
40
|
class PageInteractionTracker {
|
|
41
|
+
constructor(host) {
|
|
42
|
+
this.host = host;
|
|
43
|
+
}
|
|
41
44
|
static async register(host, browserContext) {
|
|
42
45
|
const instance = new PageInteractionTracker(host);
|
|
43
46
|
try {
|
|
@@ -62,9 +65,6 @@ class PageInteractionTracker {
|
|
|
62
65
|
}
|
|
63
66
|
return instance;
|
|
64
67
|
}
|
|
65
|
-
constructor(host) {
|
|
66
|
-
this.host = host;
|
|
67
|
-
}
|
|
68
68
|
name() {
|
|
69
69
|
return PageInteractionTracker.NAME;
|
|
70
70
|
}
|
|
@@ -9,8 +9,8 @@ import type { NamedBindingCallback } from './NamedBindingCallback';
|
|
|
9
9
|
export declare class SetDonobuAnnotations implements NamedBindingCallback {
|
|
10
10
|
private readonly pageInspector;
|
|
11
11
|
static readonly NAME = "__donobuSetAnnotations";
|
|
12
|
-
static register(pageInspector: PageInspector, browserContext: BrowserContext): Promise<SetDonobuAnnotations>;
|
|
13
12
|
constructor(pageInspector: PageInspector);
|
|
13
|
+
static register(pageInspector: PageInspector, browserContext: BrowserContext): Promise<SetDonobuAnnotations>;
|
|
14
14
|
name(): string;
|
|
15
15
|
call(source: {
|
|
16
16
|
context: BrowserContext;
|
|
@@ -9,6 +9,9 @@ const JsonUtils_1 = require("../utils/JsonUtils");
|
|
|
9
9
|
* as understood by the Donobu engine.
|
|
10
10
|
*/
|
|
11
11
|
class SetDonobuAnnotations {
|
|
12
|
+
constructor(pageInspector) {
|
|
13
|
+
this.pageInspector = pageInspector;
|
|
14
|
+
}
|
|
12
15
|
static async register(pageInspector, browserContext) {
|
|
13
16
|
const instance = new SetDonobuAnnotations(pageInspector);
|
|
14
17
|
try {
|
|
@@ -19,9 +22,6 @@ class SetDonobuAnnotations {
|
|
|
19
22
|
}
|
|
20
23
|
return instance;
|
|
21
24
|
}
|
|
22
|
-
constructor(pageInspector) {
|
|
23
|
-
this.pageInspector = pageInspector;
|
|
24
|
-
}
|
|
25
25
|
name() {
|
|
26
26
|
return SetDonobuAnnotations.NAME;
|
|
27
27
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { type DonobuReport } from '../reporter/model';
|
|
2
3
|
declare function hasReporterArg(args: string[]): boolean;
|
|
3
4
|
declare function injectJsonReporterIntoArgs(args: string[]): {
|
|
4
5
|
/** True when the args contained any `--reporter` / `-r` flag. */
|
|
@@ -11,8 +12,15 @@ declare function ensureReporterValueHasJson(value: string): {
|
|
|
11
12
|
value: string;
|
|
12
13
|
changed: boolean;
|
|
13
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Read the count of still-failing tests from a merged report's stats. Returns
|
|
17
|
+
* `undefined` when the report lacks a numeric `unexpected` stat, signalling the
|
|
18
|
+
* caller to fall back to the rerun's own exit code rather than assume success.
|
|
19
|
+
*/
|
|
20
|
+
declare function countUnexpectedTests(report: DonobuReport): number | undefined;
|
|
14
21
|
/** @internal Exposed for unit tests only — not part of the public API. */
|
|
15
22
|
export declare const _forTesting: {
|
|
23
|
+
countUnexpectedTests: typeof countUnexpectedTests;
|
|
16
24
|
ensureReporterValueHasJson: typeof ensureReporterValueHasJson;
|
|
17
25
|
hasReporterArg: typeof hasReporterArg;
|
|
18
26
|
injectJsonReporterIntoArgs: typeof injectJsonReporterIntoArgs;
|
|
@@ -1416,6 +1416,18 @@ async function attemptAutoHealRun(params) {
|
|
|
1416
1416
|
if (mergedReport) {
|
|
1417
1417
|
await regenerateDonobuReports(mergedReport);
|
|
1418
1418
|
await writeAutoHealPullRequestBody(mergedReport, params.playwrightOutputDir);
|
|
1419
|
+
// The heal rerun only re-runs the grep-filtered subset of healable
|
|
1420
|
+
// tests, so `healExitCode` is blind to failures triage declined to
|
|
1421
|
+
// retry (e.g. real product bugs). Re-derive the status from the merged
|
|
1422
|
+
// report so those remaining failures still fail CI. We only escalate
|
|
1423
|
+
// (never downgrade a non-zero heal exit) to preserve infra/crash codes.
|
|
1424
|
+
const remainingFailures = countUnexpectedTests(mergedReport);
|
|
1425
|
+
if (healExitCode === 0 &&
|
|
1426
|
+
remainingFailures !== undefined &&
|
|
1427
|
+
remainingFailures > 0) {
|
|
1428
|
+
Logger_1.appLogger.warn(`Auto-heal rerun passed for the healed subset, but ${remainingFailures} test(s) remain failing in the merged report. Exiting non-zero.`);
|
|
1429
|
+
healExitCode = 1;
|
|
1430
|
+
}
|
|
1419
1431
|
}
|
|
1420
1432
|
}
|
|
1421
1433
|
}
|
|
@@ -1424,6 +1436,16 @@ async function attemptAutoHealRun(params) {
|
|
|
1424
1436
|
}
|
|
1425
1437
|
return { attempted: true, exitCode: healExitCode };
|
|
1426
1438
|
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Read the count of still-failing tests from a merged report's stats. Returns
|
|
1441
|
+
* `undefined` when the report lacks a numeric `unexpected` stat, signalling the
|
|
1442
|
+
* caller to fall back to the rerun's own exit code rather than assume success.
|
|
1443
|
+
*/
|
|
1444
|
+
function countUnexpectedTests(report) {
|
|
1445
|
+
const stats = report.stats;
|
|
1446
|
+
const unexpected = stats?.unexpected;
|
|
1447
|
+
return typeof unexpected === 'number' ? unexpected : undefined;
|
|
1448
|
+
}
|
|
1427
1449
|
/**
|
|
1428
1450
|
* Filename of the auto-heal PR body artifact. Lands in the Playwright output
|
|
1429
1451
|
* directory alongside the merged JSON / HTML / Markdown reports so the
|
|
@@ -2135,6 +2157,7 @@ main().catch((error) => {
|
|
|
2135
2157
|
});
|
|
2136
2158
|
/** @internal Exposed for unit tests only — not part of the public API. */
|
|
2137
2159
|
exports._forTesting = {
|
|
2160
|
+
countUnexpectedTests,
|
|
2138
2161
|
ensureReporterValueHasJson,
|
|
2139
2162
|
hasReporterArg,
|
|
2140
2163
|
injectJsonReporterIntoArgs,
|
|
@@ -18,6 +18,8 @@ export declare class AnthropicGptClient extends GptClient {
|
|
|
18
18
|
private static readonly MAX_TOKENS;
|
|
19
19
|
private readonly headers;
|
|
20
20
|
constructor(anthropicConfig: AnthropicConfig);
|
|
21
|
+
private static chatRequestMessageFromGptMessage;
|
|
22
|
+
private static toolChoiceFromTool;
|
|
21
23
|
ping(options?: {
|
|
22
24
|
signal?: AbortSignal;
|
|
23
25
|
}): Promise<void>;
|
|
@@ -32,7 +34,5 @@ export declare class AnthropicGptClient extends GptClient {
|
|
|
32
34
|
}): Promise<ProposedToolCallsMessage>;
|
|
33
35
|
private mapErrorResponseToDonobuException;
|
|
34
36
|
private makeRequest;
|
|
35
|
-
private static chatRequestMessageFromGptMessage;
|
|
36
|
-
private static toolChoiceFromTool;
|
|
37
37
|
}
|
|
38
38
|
//# sourceMappingURL=AnthropicGptClient.d.ts.map
|