@depup/openai 7.32.0-depup.0 → 7.34.0-depup.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/CHANGELOG.md +54 -0
- package/README.md +2 -2
- package/changes.json +1 -1
- package/helpers/browser.d.mts +634 -0
- package/helpers/browser.d.mts.map +1 -0
- package/helpers/browser.d.ts +634 -0
- package/helpers/browser.d.ts.map +1 -0
- package/helpers/browser.js +1148 -0
- package/helpers/browser.js.map +1 -0
- package/helpers/browser.mjs +1143 -0
- package/helpers/browser.mjs.map +1 -0
- package/helpers/computer.d.mts +133 -0
- package/helpers/computer.d.mts.map +1 -0
- package/helpers/computer.d.ts +133 -0
- package/helpers/computer.d.ts.map +1 -0
- package/helpers/computer.js +782 -0
- package/helpers/computer.js.map +1 -0
- package/helpers/computer.mjs +778 -0
- package/helpers/computer.mjs.map +1 -0
- package/helpers/decisions-tool-runner.d.mts +74 -0
- package/helpers/decisions-tool-runner.d.mts.map +1 -0
- package/helpers/decisions-tool-runner.d.ts +74 -0
- package/helpers/decisions-tool-runner.d.ts.map +1 -0
- package/helpers/decisions-tool-runner.js +491 -0
- package/helpers/decisions-tool-runner.js.map +1 -0
- package/helpers/decisions-tool-runner.mjs +486 -0
- package/helpers/decisions-tool-runner.mjs.map +1 -0
- package/helpers/responses-tool-runner.d.mts +241 -0
- package/helpers/responses-tool-runner.d.mts.map +1 -0
- package/helpers/responses-tool-runner.d.ts +241 -0
- package/helpers/responses-tool-runner.d.ts.map +1 -0
- package/helpers/responses-tool-runner.js +2525 -0
- package/helpers/responses-tool-runner.js.map +1 -0
- package/helpers/responses-tool-runner.mjs +2519 -0
- package/helpers/responses-tool-runner.mjs.map +1 -0
- package/index.d.mts +1 -0
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +3 -1
- package/index.js.map +1 -1
- package/index.mjs +1 -0
- package/index.mjs.map +1 -1
- package/internal/native-response-message.d.mts +4 -0
- package/internal/native-response-message.d.mts.map +1 -0
- package/internal/native-response-message.d.ts +4 -0
- package/internal/native-response-message.d.ts.map +1 -0
- package/internal/native-response-message.js +179 -0
- package/internal/native-response-message.js.map +1 -0
- package/internal/native-response-message.mjs +174 -0
- package/internal/native-response-message.mjs.map +1 -0
- package/internal/responses/response-accumulator.d.mts +8 -1
- package/internal/responses/response-accumulator.d.mts.map +1 -1
- package/internal/responses/response-accumulator.d.ts +8 -1
- package/internal/responses/response-accumulator.d.ts.map +1 -1
- package/internal/responses/response-accumulator.js +54 -30
- package/internal/responses/response-accumulator.js.map +1 -1
- package/internal/responses/response-accumulator.mjs +50 -30
- package/internal/responses/response-accumulator.mjs.map +1 -1
- package/internal/runner-diagnostics.d.mts +21 -0
- package/internal/runner-diagnostics.d.mts.map +1 -0
- package/internal/runner-diagnostics.d.ts +21 -0
- package/internal/runner-diagnostics.d.ts.map +1 -0
- package/internal/runner-diagnostics.js +57 -0
- package/internal/runner-diagnostics.js.map +1 -0
- package/internal/runner-diagnostics.mjs +53 -0
- package/internal/runner-diagnostics.mjs.map +1 -0
- package/internal/runner-lifecycle.d.mts +19 -0
- package/internal/runner-lifecycle.d.mts.map +1 -0
- package/internal/runner-lifecycle.d.ts +19 -0
- package/internal/runner-lifecycle.d.ts.map +1 -0
- package/internal/runner-lifecycle.js +230 -0
- package/internal/runner-lifecycle.js.map +1 -0
- package/internal/runner-lifecycle.mjs +221 -0
- package/internal/runner-lifecycle.mjs.map +1 -0
- package/internal/utils/log.d.mts.map +1 -1
- package/internal/utils/log.d.ts.map +1 -1
- package/internal/utils/log.js +4 -0
- package/internal/utils/log.js.map +1 -1
- package/internal/utils/log.mjs +4 -0
- package/internal/utils/log.mjs.map +1 -1
- package/lib/beta/agents/parse-result.d.mts +2 -0
- package/lib/beta/agents/parse-result.d.mts.map +1 -1
- package/lib/beta/agents/parse-result.d.ts +2 -0
- package/lib/beta/agents/parse-result.d.ts.map +1 -1
- package/lib/responses/ResponseStream.d.mts +2 -2
- package/lib/responses/ResponseStream.d.mts.map +1 -1
- package/lib/responses/ResponseStream.d.ts +2 -2
- package/lib/responses/ResponseStream.d.ts.map +1 -1
- package/lib/responses/ResponseStream.js +355 -20
- package/lib/responses/ResponseStream.js.map +1 -1
- package/lib/responses/ResponseStream.mjs +357 -22
- package/lib/responses/ResponseStream.mjs.map +1 -1
- package/package.json +3 -3
- package/resources/admin/organization/audit-logs.d.mts +1 -1
- package/resources/admin/organization/audit-logs.d.mts.map +1 -1
- package/resources/admin/organization/audit-logs.d.ts +1 -1
- package/resources/admin/organization/audit-logs.d.ts.map +1 -1
- package/resources/admin/organization/external-storage.d.mts +15 -3
- package/resources/admin/organization/external-storage.d.mts.map +1 -1
- package/resources/admin/organization/external-storage.d.ts +15 -3
- package/resources/admin/organization/external-storage.d.ts.map +1 -1
- package/resources/admin/organization/index.d.mts +2 -2
- package/resources/admin/organization/index.d.mts.map +1 -1
- package/resources/admin/organization/index.d.ts +2 -2
- package/resources/admin/organization/index.d.ts.map +1 -1
- package/resources/admin/organization/index.js.map +1 -1
- package/resources/admin/organization/index.mjs.map +1 -1
- package/resources/admin/organization/organization.d.mts +4 -4
- package/resources/admin/organization/organization.d.mts.map +1 -1
- package/resources/admin/organization/organization.d.ts +4 -4
- package/resources/admin/organization/organization.d.ts.map +1 -1
- package/resources/admin/organization/organization.js.map +1 -1
- package/resources/admin/organization/organization.mjs.map +1 -1
- package/resources/admin/organization/projects/api-keys.d.mts +32 -1
- package/resources/admin/organization/projects/api-keys.d.mts.map +1 -1
- package/resources/admin/organization/projects/api-keys.d.ts +32 -1
- package/resources/admin/organization/projects/api-keys.d.ts.map +1 -1
- package/resources/admin/organization/projects/api-keys.js +26 -0
- package/resources/admin/organization/projects/api-keys.js.map +1 -1
- package/resources/admin/organization/projects/api-keys.mjs +26 -0
- package/resources/admin/organization/projects/api-keys.mjs.map +1 -1
- package/resources/admin/organization/projects/index.d.mts +1 -1
- package/resources/admin/organization/projects/index.d.mts.map +1 -1
- package/resources/admin/organization/projects/index.d.ts +1 -1
- package/resources/admin/organization/projects/index.d.ts.map +1 -1
- package/resources/admin/organization/projects/index.js.map +1 -1
- package/resources/admin/organization/projects/index.mjs.map +1 -1
- package/resources/admin/organization/projects/projects.d.mts +3 -3
- package/resources/admin/organization/projects/projects.d.mts.map +1 -1
- package/resources/admin/organization/projects/projects.d.ts +3 -3
- package/resources/admin/organization/projects/projects.d.ts.map +1 -1
- package/resources/admin/organization/projects/projects.js.map +1 -1
- package/resources/admin/organization/projects/projects.mjs.map +1 -1
- package/resources/admin/organization/usage.d.mts +202 -1
- package/resources/admin/organization/usage.d.mts.map +1 -1
- package/resources/admin/organization/usage.d.ts +202 -1
- package/resources/admin/organization/usage.d.ts.map +1 -1
- package/resources/admin/organization/usage.js +19 -0
- package/resources/admin/organization/usage.js.map +1 -1
- package/resources/admin/organization/usage.mjs +19 -0
- package/resources/admin/organization/usage.mjs.map +1 -1
- package/resources/beta/agents/agents.d.mts +28 -10
- package/resources/beta/agents/agents.d.mts.map +1 -1
- package/resources/beta/agents/agents.d.ts +28 -10
- package/resources/beta/agents/agents.d.ts.map +1 -1
- package/resources/beta/agents/agents.js.map +1 -1
- package/resources/beta/agents/agents.mjs.map +1 -1
- package/resources/beta/agents/environments/environments.d.mts +2 -2
- package/resources/beta/agents/environments/environments.d.mts.map +1 -1
- package/resources/beta/agents/environments/environments.d.ts +2 -2
- package/resources/beta/agents/environments/environments.d.ts.map +1 -1
- package/resources/beta/agents/environments/files.d.mts +3 -2
- package/resources/beta/agents/environments/files.d.mts.map +1 -1
- package/resources/beta/agents/environments/files.d.ts +3 -2
- package/resources/beta/agents/environments/files.d.ts.map +1 -1
- package/resources/beta/agents/environments/files.js +3 -2
- package/resources/beta/agents/environments/files.js.map +1 -1
- package/resources/beta/agents/environments/files.mjs +3 -2
- package/resources/beta/agents/environments/files.mjs.map +1 -1
- package/resources/beta/agents/index.d.mts +1 -1
- package/resources/beta/agents/index.d.mts.map +1 -1
- package/resources/beta/agents/index.d.ts +1 -1
- package/resources/beta/agents/index.d.ts.map +1 -1
- package/resources/beta/agents/index.js.map +1 -1
- package/resources/beta/agents/index.mjs.map +1 -1
- package/resources/beta/agents/sessions/artifacts.d.mts +2 -10
- package/resources/beta/agents/sessions/artifacts.d.mts.map +1 -1
- package/resources/beta/agents/sessions/artifacts.d.ts +2 -10
- package/resources/beta/agents/sessions/artifacts.d.ts.map +1 -1
- package/resources/beta/agents/sessions/sessions.d.mts +35 -8
- package/resources/beta/agents/sessions/sessions.d.mts.map +1 -1
- package/resources/beta/agents/sessions/sessions.d.ts +35 -8
- package/resources/beta/agents/sessions/sessions.d.ts.map +1 -1
- package/resources/beta/agents/sessions/sessions.js.map +1 -1
- package/resources/beta/agents/sessions/sessions.mjs.map +1 -1
- package/resources/beta/agents/vaults/credentials.d.mts +9 -6
- package/resources/beta/agents/vaults/credentials.d.mts.map +1 -1
- package/resources/beta/agents/vaults/credentials.d.ts +9 -6
- package/resources/beta/agents/vaults/credentials.d.ts.map +1 -1
- package/resources/beta/agents/vaults/credentials.js +1 -1
- package/resources/beta/agents/vaults/credentials.js.map +1 -1
- package/resources/beta/agents/vaults/credentials.mjs +1 -1
- package/resources/beta/agents/vaults/credentials.mjs.map +1 -1
- package/resources/beta/agents/vaults/index.d.mts +1 -1
- package/resources/beta/agents/vaults/index.d.mts.map +1 -1
- package/resources/beta/agents/vaults/index.d.ts +1 -1
- package/resources/beta/agents/vaults/index.d.ts.map +1 -1
- package/resources/beta/agents/vaults/index.js.map +1 -1
- package/resources/beta/agents/vaults/index.mjs.map +1 -1
- package/resources/beta/agents/vaults/vaults.d.mts +38 -7
- package/resources/beta/agents/vaults/vaults.d.mts.map +1 -1
- package/resources/beta/agents/vaults/vaults.d.ts +38 -7
- package/resources/beta/agents/vaults/vaults.d.ts.map +1 -1
- package/resources/beta/agents/vaults/vaults.js +22 -1
- package/resources/beta/agents/vaults/vaults.js.map +1 -1
- package/resources/beta/agents/vaults/vaults.mjs +22 -1
- package/resources/beta/agents/vaults/vaults.mjs.map +1 -1
- package/resources/beta/responses/responses.d.mts +135 -3
- package/resources/beta/responses/responses.d.mts.map +1 -1
- package/resources/beta/responses/responses.d.ts +135 -3
- package/resources/beta/responses/responses.d.ts.map +1 -1
- package/resources/beta/responses/responses.js.map +1 -1
- package/resources/beta/responses/responses.mjs.map +1 -1
- package/resources/chat/completions/completions.d.mts +1 -1
- package/resources/chat/completions/completions.d.ts +1 -1
- package/resources/conversations/items.d.mts +46 -0
- package/resources/conversations/items.d.mts.map +1 -1
- package/resources/conversations/items.d.ts +46 -0
- package/resources/conversations/items.d.ts.map +1 -1
- package/resources/decisions.d.mts +48 -21
- package/resources/decisions.d.mts.map +1 -1
- package/resources/decisions.d.ts +48 -21
- package/resources/decisions.d.ts.map +1 -1
- package/resources/decisions.js +2 -11
- package/resources/decisions.js.map +1 -1
- package/resources/decisions.mjs +2 -11
- package/resources/decisions.mjs.map +1 -1
- package/resources/live/live.d.mts +1 -1
- package/resources/live/live.d.mts.map +1 -1
- package/resources/live/live.d.ts +1 -1
- package/resources/live/live.d.ts.map +1 -1
- package/resources/live/live.js.map +1 -1
- package/resources/live/live.mjs.map +1 -1
- package/resources/responses/responses.d.mts +141 -3
- package/resources/responses/responses.d.mts.map +1 -1
- package/resources/responses/responses.d.ts +141 -3
- package/resources/responses/responses.d.ts.map +1 -1
- package/resources/responses/responses.js.map +1 -1
- package/resources/responses/responses.mjs.map +1 -1
- package/resources/safety/alerts.d.mts +5 -0
- package/resources/safety/alerts.d.mts.map +1 -1
- package/resources/safety/alerts.d.ts +5 -0
- package/resources/safety/alerts.d.ts.map +1 -1
- package/resources/webhooks/webhooks.d.mts +5 -6
- package/resources/webhooks/webhooks.d.mts.map +1 -1
- package/resources/webhooks/webhooks.d.ts +5 -6
- package/resources/webhooks/webhooks.d.ts.map +1 -1
- package/resources/webhooks/webhooks.js.map +1 -1
- package/resources/webhooks/webhooks.mjs.map +1 -1
- package/src/helpers/browser.ts +1583 -0
- package/src/helpers/computer.ts +1001 -0
- package/src/helpers/decisions-tool-runner.ts +641 -0
- package/src/helpers/responses-tool-runner.ts +3265 -0
- package/src/index.ts +1 -0
- package/src/internal/native-response-message.ts +218 -0
- package/src/internal/responses/response-accumulator.ts +63 -32
- package/src/internal/runner-diagnostics.ts +93 -0
- package/src/internal/runner-lifecycle.ts +248 -0
- package/src/internal/utils/log.ts +4 -0
- package/src/lib/responses/ResponseStream.ts +387 -21
- package/src/resources/admin/organization/audit-logs.ts +2 -1
- package/src/resources/admin/organization/external-storage.ts +28 -2
- package/src/resources/admin/organization/index.ts +3 -0
- package/src/resources/admin/organization/organization.ts +6 -0
- package/src/resources/admin/organization/projects/api-keys.ts +45 -0
- package/src/resources/admin/organization/projects/index.ts +1 -0
- package/src/resources/admin/organization/projects/projects.ts +5 -0
- package/src/resources/admin/organization/usage.ts +259 -0
- package/src/resources/beta/agents/agents.ts +31 -8
- package/src/resources/beta/agents/environments/environments.ts +2 -2
- package/src/resources/beta/agents/environments/files.ts +3 -2
- package/src/resources/beta/agents/index.ts +1 -0
- package/src/resources/beta/agents/sessions/artifacts.ts +2 -12
- package/src/resources/beta/agents/sessions/sessions.ts +39 -9
- package/src/resources/beta/agents/vaults/credentials.ts +8 -7
- package/src/resources/beta/agents/vaults/index.ts +1 -0
- package/src/resources/beta/agents/vaults/vaults.ts +48 -7
- package/src/resources/beta/responses/responses.ts +159 -3
- package/src/resources/chat/completions/completions.ts +1 -1
- package/src/resources/conversations/items.ts +54 -0
- package/src/resources/decisions.ts +48 -21
- package/src/resources/live/live.ts +1 -0
- package/src/resources/responses/responses.ts +165 -3
- package/src/resources/safety/alerts.ts +6 -0
- package/src/resources/webhooks/webhooks.ts +11 -12
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ComputerToolset = void 0;
|
|
4
|
+
const error_1 = require("../error.js");
|
|
5
|
+
const ResponseInputItems_1 = require("../lib/responses/ResponseInputItems.js");
|
|
6
|
+
const runner_diagnostics_1 = require("../internal/runner-diagnostics.js");
|
|
7
|
+
const runner_lifecycle_1 = require("../internal/runner-lifecycle.js");
|
|
8
|
+
const native_response_message_1 = require("../internal/native-response-message.js");
|
|
9
|
+
const values_1 = require("../internal/utils/values.js");
|
|
10
|
+
// Modern actions calls may omit the checklist. Legacy single actions still require it.
|
|
11
|
+
function validateComputerSafetyChecks(call) {
|
|
12
|
+
const checks = (0, runner_lifecycle_1.configuredOption)(call, 'pending_safety_checks');
|
|
13
|
+
if (!(0, runner_lifecycle_1.configuredOption)(call, 'actions') || checks !== undefined) {
|
|
14
|
+
if (!Array.isArray(checks)) {
|
|
15
|
+
throw new error_1.OpenAIError('ComputerToolset requires valid pending safety checks before execution.');
|
|
16
|
+
}
|
|
17
|
+
// oxlint-disable-next-line typescript/prefer-for-of -- Validate each JSON slot, including holes that must become invalid nulls.
|
|
18
|
+
for (let index = 0; index < checks.length; index += 1) {
|
|
19
|
+
const check = (0, values_1.hasOwn)(checks, index) ? checks[index] : undefined;
|
|
20
|
+
const code = check ? (0, runner_lifecycle_1.configuredOption)(check, 'code') : undefined;
|
|
21
|
+
const message = check ? (0, runner_lifecycle_1.configuredOption)(check, 'message') : undefined;
|
|
22
|
+
if (!check ||
|
|
23
|
+
!(0, values_1.hasOwn)(check, 'id') ||
|
|
24
|
+
typeof check.id !== 'string' ||
|
|
25
|
+
(code !== undefined && code !== null && typeof code !== 'string') ||
|
|
26
|
+
(message !== undefined && message !== null && typeof message !== 'string')) {
|
|
27
|
+
throw new error_1.OpenAIError('ComputerToolset requires valid pending safety checks before execution.');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function validComputerPoint(point) {
|
|
33
|
+
return ((0, values_1.isObj)(point) &&
|
|
34
|
+
(0, values_1.hasOwn)(point, 'x') &&
|
|
35
|
+
(0, values_1.hasOwn)(point, 'y') &&
|
|
36
|
+
Number.isInteger(point.x) &&
|
|
37
|
+
Number.isInteger(point.y));
|
|
38
|
+
}
|
|
39
|
+
function isDenseArray(values) {
|
|
40
|
+
if (!Array.isArray(values)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
// oxlint-disable-next-line typescript/prefer-for-of -- Iteration alone cannot distinguish an inherited entry from an owned slot.
|
|
44
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
45
|
+
if (!(0, values_1.hasOwn)(values, index)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
function validComputerKeys(keys) {
|
|
52
|
+
return isDenseArray(keys) && keys.every((key) => typeof key === 'string');
|
|
53
|
+
}
|
|
54
|
+
function validComputerAction(action) {
|
|
55
|
+
if (!action || !(0, values_1.hasOwn)(action, 'type')) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const keys = 'keys' in action ? (0, runner_lifecycle_1.configuredOption)(action, 'keys') : undefined;
|
|
59
|
+
if (keys !== null && keys !== undefined && !validComputerKeys(keys)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
switch (action.type) {
|
|
63
|
+
case 'click': {
|
|
64
|
+
const button = (0, runner_lifecycle_1.configuredOption)(action, 'button');
|
|
65
|
+
return (validComputerPoint(action) &&
|
|
66
|
+
['left', 'right', 'wheel', 'back', 'forward'].some((value) => value === button));
|
|
67
|
+
}
|
|
68
|
+
case 'double_click':
|
|
69
|
+
case 'move': {
|
|
70
|
+
return validComputerPoint(action);
|
|
71
|
+
}
|
|
72
|
+
case 'scroll': {
|
|
73
|
+
return (validComputerPoint(action) &&
|
|
74
|
+
Number.isInteger((0, runner_lifecycle_1.configuredOption)(action, 'scroll_x')) &&
|
|
75
|
+
Number.isInteger((0, runner_lifecycle_1.configuredOption)(action, 'scroll_y')));
|
|
76
|
+
}
|
|
77
|
+
case 'drag': {
|
|
78
|
+
const path = (0, runner_lifecycle_1.configuredOption)(action, 'path');
|
|
79
|
+
return isDenseArray(path) && path.every(validComputerPoint);
|
|
80
|
+
}
|
|
81
|
+
case 'keypress': {
|
|
82
|
+
return validComputerKeys((0, runner_lifecycle_1.configuredOption)(action, 'keys'));
|
|
83
|
+
}
|
|
84
|
+
case 'type': {
|
|
85
|
+
return typeof (0, runner_lifecycle_1.configuredOption)(action, 'text') === 'string';
|
|
86
|
+
}
|
|
87
|
+
case 'screenshot':
|
|
88
|
+
case 'wait': {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
default: {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function computerActions(call) {
|
|
97
|
+
const singleAction = (0, runner_lifecycle_1.configuredOption)(call, 'action');
|
|
98
|
+
const batch = (0, runner_lifecycle_1.configuredOption)(call, 'actions');
|
|
99
|
+
if (!(0, values_1.hasOwn)(call, 'type') ||
|
|
100
|
+
!(0, values_1.hasOwn)(call, 'status') ||
|
|
101
|
+
!(0, values_1.hasOwn)(call, 'id') ||
|
|
102
|
+
!(0, values_1.hasOwn)(call, 'call_id') ||
|
|
103
|
+
call.type !== 'computer_call' ||
|
|
104
|
+
call.status !== 'completed' ||
|
|
105
|
+
typeof call.id !== 'string' ||
|
|
106
|
+
typeof call.call_id !== 'string' ||
|
|
107
|
+
singleAction === null ||
|
|
108
|
+
batch === null ||
|
|
109
|
+
(singleAction !== undefined) === (batch !== undefined)) {
|
|
110
|
+
throw new error_1.OpenAIError('ComputerToolset requires a completed call with exactly one of action or actions.');
|
|
111
|
+
}
|
|
112
|
+
validateComputerSafetyChecks(call);
|
|
113
|
+
// SAFETY: The guard above established exactly one of action/actions is present.
|
|
114
|
+
const actions = batch ?? [singleAction];
|
|
115
|
+
if (!Array.isArray(actions) || actions.length === 0) {
|
|
116
|
+
throw new error_1.OpenAIError('ComputerToolset requires at least one computer action.');
|
|
117
|
+
}
|
|
118
|
+
if (!isDenseArray(actions)) {
|
|
119
|
+
throw new error_1.OpenAIError('ComputerToolset received an invalid computer action.');
|
|
120
|
+
}
|
|
121
|
+
for (const action of actions) {
|
|
122
|
+
if (Array.isArray(action) || !validComputerAction(action)) {
|
|
123
|
+
throw new error_1.OpenAIError('ComputerToolset received an invalid computer action.');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return actions;
|
|
127
|
+
}
|
|
128
|
+
function snapshotComputerPolicy(options) {
|
|
129
|
+
return {
|
|
130
|
+
signal: (0, runner_lifecycle_1.configuredOption)(options, 'signal'),
|
|
131
|
+
approveSafetyChecks: (0, runner_lifecycle_1.configuredOption)(options, 'approveSafetyChecks')?.bind(options),
|
|
132
|
+
beforeAction: (0, runner_lifecycle_1.configuredOption)(options, 'beforeAction')?.bind(options),
|
|
133
|
+
onDiagnostic: (0, runner_lifecycle_1.configuredOption)(options, 'onDiagnostic')?.bind(options),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function computerRunTools(params, maxSteps) {
|
|
137
|
+
if (!Number.isSafeInteger(maxSteps) || maxSteps < 1) {
|
|
138
|
+
throw new TypeError('ComputerToolset maxSteps must be a positive safe integer.');
|
|
139
|
+
}
|
|
140
|
+
const suppliedTools = (0, runner_lifecycle_1.configuredOption)(params, 'tools');
|
|
141
|
+
const tools = suppliedTools === undefined ? [{ type: 'computer' }] : suppliedTools;
|
|
142
|
+
const conversation = (0, runner_lifecycle_1.configuredOption)(params, 'conversation');
|
|
143
|
+
const previousResponse = (0, runner_lifecycle_1.configuredOption)(params, 'previous_response_id');
|
|
144
|
+
if ((0, runner_lifecycle_1.configuredOption)(params, 'stream') ||
|
|
145
|
+
(0, runner_lifecycle_1.configuredOption)(params, 'background') ||
|
|
146
|
+
(conversation !== undefined && conversation !== null) ||
|
|
147
|
+
(previousResponse !== undefined && previousResponse !== null) ||
|
|
148
|
+
!Array.isArray(tools) ||
|
|
149
|
+
tools.length !== 1 ||
|
|
150
|
+
tools.some((tool) => {
|
|
151
|
+
const type = tool && (0, runner_lifecycle_1.configuredOption)(tool, 'type');
|
|
152
|
+
return type !== 'computer' && type !== 'computer_use_preview';
|
|
153
|
+
})) {
|
|
154
|
+
throw new TypeError('ComputerToolset.run requires non-streaming, foreground, one computer tool and explicit input history.');
|
|
155
|
+
}
|
|
156
|
+
return tools;
|
|
157
|
+
}
|
|
158
|
+
function releaseForcedComputerChoice(choice) {
|
|
159
|
+
if (choice === 'required' ||
|
|
160
|
+
(typeof choice === 'object' &&
|
|
161
|
+
(0, values_1.hasOwn)(choice, 'type') &&
|
|
162
|
+
['computer', 'computer_use_preview', 'computer_use'].includes(choice.type))) {
|
|
163
|
+
return 'auto';
|
|
164
|
+
}
|
|
165
|
+
if (typeof choice === 'object' &&
|
|
166
|
+
(0, values_1.hasOwn)(choice, 'type') &&
|
|
167
|
+
choice.type === 'allowed_tools' &&
|
|
168
|
+
(0, values_1.hasOwn)(choice, 'mode') &&
|
|
169
|
+
choice.mode === 'required') {
|
|
170
|
+
return { ...choice, mode: 'auto' };
|
|
171
|
+
}
|
|
172
|
+
return choice;
|
|
173
|
+
}
|
|
174
|
+
function validateComputerChecklistOwner(call) {
|
|
175
|
+
// Match configured options' owner boundary without invoking a checklist getter.
|
|
176
|
+
let owner = call;
|
|
177
|
+
while (owner !== null && !(0, runner_lifecycle_1.isObjectPrototype)(owner)) {
|
|
178
|
+
const descriptor = Object.getOwnPropertyDescriptor(owner, 'pending_safety_checks');
|
|
179
|
+
if (descriptor) {
|
|
180
|
+
if (owner !== call || !descriptor.enumerable || !('value' in descriptor)) {
|
|
181
|
+
throw new error_1.OpenAIError('ComputerToolset requires own enumerable data for safety checks.');
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
// SAFETY: Object.getPrototypeOf returns the object's prototype or null.
|
|
186
|
+
owner = Object.getPrototypeOf(owner);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function snapshotComputerCall(call) {
|
|
190
|
+
if (Array.isArray(call)) {
|
|
191
|
+
throw new error_1.OpenAIError('ComputerToolset requires a call object.');
|
|
192
|
+
}
|
|
193
|
+
validateComputerChecklistOwner(call);
|
|
194
|
+
const snapshot = structuredClone(call);
|
|
195
|
+
for (const action of computerActions(snapshot)) {
|
|
196
|
+
if (action.type === 'double_click' && (0, runner_lifecycle_1.configuredOption)(action, 'keys') === undefined) {
|
|
197
|
+
action.keys = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return snapshot;
|
|
201
|
+
}
|
|
202
|
+
function actionApprovalCall(call) {
|
|
203
|
+
const checks = (0, runner_lifecycle_1.configuredOption)(call, 'pending_safety_checks') ?? [];
|
|
204
|
+
const actions = (0, runner_lifecycle_1.configuredOption)(call, 'actions');
|
|
205
|
+
if (!Array.isArray(actions)) {
|
|
206
|
+
const view = structuredClone({ ...call, pending_safety_checks: checks });
|
|
207
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(view);
|
|
208
|
+
return view;
|
|
209
|
+
}
|
|
210
|
+
const sources = { actions, pending_safety_checks: checks };
|
|
211
|
+
const view = structuredClone({
|
|
212
|
+
...call,
|
|
213
|
+
actions: [],
|
|
214
|
+
pending_safety_checks: [],
|
|
215
|
+
});
|
|
216
|
+
// Protect the base before installing accessors so unused batch views stay lazy.
|
|
217
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(view);
|
|
218
|
+
for (const key of ['actions', 'pending_safety_checks']) {
|
|
219
|
+
const source = sources[key];
|
|
220
|
+
let materialized = false;
|
|
221
|
+
let value;
|
|
222
|
+
const save = (replacement) => {
|
|
223
|
+
value = replacement;
|
|
224
|
+
materialized = true;
|
|
225
|
+
if (Object.getOwnPropertyDescriptor(view, key)?.configurable) {
|
|
226
|
+
Object.defineProperty(view, key, {
|
|
227
|
+
value,
|
|
228
|
+
writable: true,
|
|
229
|
+
enumerable: true,
|
|
230
|
+
configurable: true,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
};
|
|
235
|
+
Object.defineProperty(view, key, {
|
|
236
|
+
configurable: true,
|
|
237
|
+
enumerable: true,
|
|
238
|
+
get() {
|
|
239
|
+
if (materialized) {
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
const captured = structuredClone(source);
|
|
243
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(captured);
|
|
244
|
+
return save(captured);
|
|
245
|
+
},
|
|
246
|
+
set(replacement) {
|
|
247
|
+
if (Object.isFrozen(view)) {
|
|
248
|
+
throw new TypeError('Cannot assign to frozen computer approval call.');
|
|
249
|
+
}
|
|
250
|
+
save(replacement);
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return view;
|
|
255
|
+
}
|
|
256
|
+
// oxlint-disable-next-line complexity -- Validate every supported native output before any computer effect.
|
|
257
|
+
function computerCalls(response, earlierIdentities, earlierCallIds) {
|
|
258
|
+
if ((0, runner_lifecycle_1.configuredOption)(response, 'status') !== 'completed') {
|
|
259
|
+
throw new error_1.OpenAIError('ComputerToolset.run received a response that is not completed.');
|
|
260
|
+
}
|
|
261
|
+
// Preflight the entire response before any effects, even when unsupported items follow a valid call.
|
|
262
|
+
const calls = [];
|
|
263
|
+
const output = [];
|
|
264
|
+
const source = (0, runner_lifecycle_1.configuredOption)(response, 'output');
|
|
265
|
+
if (!Array.isArray(source)) {
|
|
266
|
+
throw new error_1.OpenAIError('ComputerToolset.run received an invalid output array.');
|
|
267
|
+
}
|
|
268
|
+
const { length } = source;
|
|
269
|
+
if (!Number.isSafeInteger(length) || length < 0) {
|
|
270
|
+
throw new error_1.OpenAIError('ComputerToolset.run received an invalid output array.');
|
|
271
|
+
}
|
|
272
|
+
let hasFinalMessage = false;
|
|
273
|
+
const identities = new Set();
|
|
274
|
+
const callIds = new Set();
|
|
275
|
+
for (let index = 0; index < length; index += 1) {
|
|
276
|
+
const raw = (0, values_1.hasOwn)(source, index) ? source[index] : undefined;
|
|
277
|
+
if (!raw) {
|
|
278
|
+
throw new error_1.OpenAIError('ComputerToolset.run received an absent output item.');
|
|
279
|
+
}
|
|
280
|
+
const descriptors = Object.getOwnPropertyDescriptors(raw);
|
|
281
|
+
for (const [name, descriptor] of Object.entries(descriptors)) {
|
|
282
|
+
if (descriptor.get) {
|
|
283
|
+
if (name === 'type') {
|
|
284
|
+
descriptors.type = {
|
|
285
|
+
value: descriptor.get.call(raw),
|
|
286
|
+
enumerable: Boolean(descriptor.enumerable),
|
|
287
|
+
configurable: Boolean(descriptor.configurable),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
descriptor.get = descriptor.get.bind(raw);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// SAFETY: This shadow has exactly the provider's own descriptors and prototype, with type captured once.
|
|
296
|
+
const captured = Object.create(Object.getPrototypeOf(raw), descriptors);
|
|
297
|
+
const item = (0, values_1.hasOwn)(captured, 'type') && captured.type === 'computer_call'
|
|
298
|
+
? snapshotComputerCall(captured)
|
|
299
|
+
: structuredClone(captured);
|
|
300
|
+
if (!(0, values_1.hasOwn)(item, 'type') || !(0, values_1.hasOwn)(item, 'id') || typeof item.id !== 'string') {
|
|
301
|
+
throw new error_1.OpenAIError('ComputerToolset.run requires emitted output type and id fields.');
|
|
302
|
+
}
|
|
303
|
+
if (item.type === 'computer_call') {
|
|
304
|
+
if (callIds.has(item.call_id) || earlierCallIds.has(item.call_id)) {
|
|
305
|
+
throw new error_1.OpenAIError('ComputerToolset.run received a duplicate computer call identity.');
|
|
306
|
+
}
|
|
307
|
+
callIds.add(item.call_id);
|
|
308
|
+
calls.push(item);
|
|
309
|
+
}
|
|
310
|
+
else if (item.type === 'message') {
|
|
311
|
+
if (!(0, native_response_message_1.isNativeResponseMessage)(item)) {
|
|
312
|
+
throw new error_1.OpenAIError('ComputerToolset.run requires native assistant content before replay.');
|
|
313
|
+
}
|
|
314
|
+
hasFinalMessage || (hasFinalMessage = item.status === 'completed' && (!(0, values_1.hasOwn)(item, 'phase') || item.phase !== 'commentary'));
|
|
315
|
+
}
|
|
316
|
+
else if (item.type === 'reasoning') {
|
|
317
|
+
if (!(0, native_response_message_1.isNativeResponseReasoning)(item)) {
|
|
318
|
+
throw new error_1.OpenAIError('ComputerToolset.run requires native reasoning content before replay.');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else if (item.type === 'compaction') {
|
|
322
|
+
if (!(0, values_1.hasOwn)(item, 'encrypted_content') || typeof item.encrypted_content !== 'string') {
|
|
323
|
+
throw new error_1.OpenAIError('ComputerToolset.run requires native compaction content before replay.');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
throw new error_1.OpenAIError('ComputerToolset.run cannot handle a non-computer output item.');
|
|
328
|
+
}
|
|
329
|
+
output.push(item);
|
|
330
|
+
if (identities.has(item.id) || (item.id !== '' && earlierIdentities.has(item.id))) {
|
|
331
|
+
throw new error_1.OpenAIError('ComputerToolset.run received a duplicate output item identity.');
|
|
332
|
+
}
|
|
333
|
+
identities.add(item.id);
|
|
334
|
+
}
|
|
335
|
+
if (calls.length === 0 && !hasFinalMessage) {
|
|
336
|
+
throw new error_1.OpenAIError('ComputerToolset.run received no completed final message.');
|
|
337
|
+
}
|
|
338
|
+
for (const id of identities) {
|
|
339
|
+
if (id !== '') {
|
|
340
|
+
earlierIdentities.add(id);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
for (const id of callIds) {
|
|
344
|
+
earlierCallIds.add(id);
|
|
345
|
+
}
|
|
346
|
+
return { calls, output };
|
|
347
|
+
}
|
|
348
|
+
function computerDriverMethod(driver, name) {
|
|
349
|
+
const method = (0, runner_lifecycle_1.configuredOption)(driver, name);
|
|
350
|
+
if (typeof method !== 'function') {
|
|
351
|
+
throw new error_1.OpenAIError('ComputerToolset requires callable computer driver methods.');
|
|
352
|
+
}
|
|
353
|
+
return method;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Dispatches existing computer actions for a caller-owned browser or computer.
|
|
357
|
+
* run() handles computer-only conversations; execute() supports caller-managed loops.
|
|
358
|
+
*/
|
|
359
|
+
class ComputerToolset {
|
|
360
|
+
/** The environment remains owned by the caller and is never opened or closed by the helper. */
|
|
361
|
+
constructor(driver) {
|
|
362
|
+
this.lifecycle = new runner_lifecycle_1.RunnerLifecycle();
|
|
363
|
+
const methods = {
|
|
364
|
+
click: computerDriverMethod(driver, 'click'),
|
|
365
|
+
double_click: computerDriverMethod(driver, 'double_click'),
|
|
366
|
+
drag: computerDriverMethod(driver, 'drag'),
|
|
367
|
+
keypress: computerDriverMethod(driver, 'keypress'),
|
|
368
|
+
move: computerDriverMethod(driver, 'move'),
|
|
369
|
+
screenshot: computerDriverMethod(driver, 'screenshot'),
|
|
370
|
+
scroll: computerDriverMethod(driver, 'scroll'),
|
|
371
|
+
type: computerDriverMethod(driver, 'type'),
|
|
372
|
+
wait: computerDriverMethod(driver, 'wait'),
|
|
373
|
+
};
|
|
374
|
+
this.driver = {
|
|
375
|
+
click: methods.click.bind(driver),
|
|
376
|
+
double_click: methods.double_click.bind(driver),
|
|
377
|
+
drag: methods.drag.bind(driver),
|
|
378
|
+
keypress: methods.keypress.bind(driver),
|
|
379
|
+
move: methods.move.bind(driver),
|
|
380
|
+
screenshot: methods.screenshot.bind(driver),
|
|
381
|
+
scroll: methods.scroll.bind(driver),
|
|
382
|
+
type: methods.type.bind(driver),
|
|
383
|
+
wait: methods.wait.bind(driver),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/** Stop new work. If draining, await the current operation before closing your driver. */
|
|
387
|
+
close() {
|
|
388
|
+
return this.lifecycle.close();
|
|
389
|
+
}
|
|
390
|
+
/** Snapshot and check a complete call before a runner dispatches any effects from its response.
|
|
391
|
+
* @internal
|
|
392
|
+
*/
|
|
393
|
+
static validate(call) {
|
|
394
|
+
return snapshotComputerCall(call);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Run until a completed response contains no computer calls.
|
|
398
|
+
* Defaults to the computer tool when tools is omitted. Other tools, streams,
|
|
399
|
+
* background work, conversation, and previous_response_id are rejected.
|
|
400
|
+
* Replays history (including encrypted reasoning for store:false).
|
|
401
|
+
*
|
|
402
|
+
* @throws {OpenAIError} If a response is incomplete, unsupported, declined, or exceeds maxSteps.
|
|
403
|
+
*/
|
|
404
|
+
async run(client, params, options = {}) {
|
|
405
|
+
this.lifecycle.enter();
|
|
406
|
+
try {
|
|
407
|
+
return await this.runOwned(client, params, options);
|
|
408
|
+
}
|
|
409
|
+
finally {
|
|
410
|
+
this.lifecycle.leave();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
// oxlint-disable-next-line complexity -- Ordered requests share cancellation and continuation policy.
|
|
414
|
+
async runOwned(client, params, options) {
|
|
415
|
+
const suppliedMaxSteps = (0, runner_lifecycle_1.configuredOption)(options, 'maxSteps');
|
|
416
|
+
const maxSteps = suppliedMaxSteps === undefined ? 20 : suppliedMaxSteps;
|
|
417
|
+
// Match the ordinary SDK JSON encoder once, then validate and reuse the resulting body.
|
|
418
|
+
const encoded = JSON.stringify(params);
|
|
419
|
+
const decoded = JSON.parse(encoded);
|
|
420
|
+
if (!(0, values_1.isObj)(decoded)) {
|
|
421
|
+
throw new TypeError('ComputerToolset request must be an object.');
|
|
422
|
+
}
|
|
423
|
+
// SAFETY: computerRunTools validates the serialized modes/tools before the request can reach the API.
|
|
424
|
+
const request = decoded;
|
|
425
|
+
const tools = computerRunTools(request, maxSteps);
|
|
426
|
+
const suppliedInput = (0, runner_lifecycle_1.configuredOption)(request, 'input');
|
|
427
|
+
const input = typeof suppliedInput === 'string'
|
|
428
|
+
? [{ role: 'user', content: suppliedInput }]
|
|
429
|
+
: [...(suppliedInput === undefined ? [] : suppliedInput)];
|
|
430
|
+
const include = [...((0, runner_lifecycle_1.configuredOption)(request, 'include') ?? [])];
|
|
431
|
+
if (!include.includes('reasoning.encrypted_content')) {
|
|
432
|
+
include.push('reasoning.encrypted_content');
|
|
433
|
+
}
|
|
434
|
+
const body = { ...request, tools, include, input };
|
|
435
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(body);
|
|
436
|
+
const policy = snapshotComputerPolicy(options);
|
|
437
|
+
let supplied = (0, runner_lifecycle_1.configuredOption)(options, 'requestOptions');
|
|
438
|
+
const ownSignal = supplied && Object.getOwnPropertyDescriptor(supplied, 'signal');
|
|
439
|
+
const signal = policy.signal ?? (supplied && (0, runner_lifecycle_1.configuredOption)(supplied, 'signal')) ?? undefined;
|
|
440
|
+
if (policy.signal || (ownSignal && !('value' in ownSignal)) || (signal && !ownSignal?.enumerable)) {
|
|
441
|
+
// Capture accessors once and expose hidden signals to the native request spread.
|
|
442
|
+
supplied = (0, runner_lifecycle_1.overlayRequestOptions)(supplied, { signal });
|
|
443
|
+
}
|
|
444
|
+
const executionOptions = { ...policy, signal };
|
|
445
|
+
const earlierIdentities = new Set();
|
|
446
|
+
const earlierCallIds = new Set();
|
|
447
|
+
for (const item of input) {
|
|
448
|
+
if (!(0, values_1.isObj)(item)) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const id = (0, values_1.hasOwn)(item, 'id') ? item['id'] : undefined;
|
|
452
|
+
const callId = (0, values_1.hasOwn)(item, 'call_id') ? item['call_id'] : undefined;
|
|
453
|
+
if (typeof id === 'string' && id !== '') {
|
|
454
|
+
earlierIdentities.add(id);
|
|
455
|
+
}
|
|
456
|
+
if (typeof callId === 'string') {
|
|
457
|
+
earlierCallIds.add(callId);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
for (let step = 0;; step += 1) {
|
|
461
|
+
signal?.throwIfAborted();
|
|
462
|
+
const nextOptions = step === 0 ? supplied : (0, runner_lifecycle_1.continuationRequestOptions)(client, supplied, signal);
|
|
463
|
+
if (nextOptions && Object.getOwnPropertyDescriptor(nextOptions, 'body')?.enumerable) {
|
|
464
|
+
throw new TypeError('ComputerToolset.run requestOptions.body is not supported.');
|
|
465
|
+
}
|
|
466
|
+
let response;
|
|
467
|
+
try {
|
|
468
|
+
// Each response depends on observations from the preceding one.
|
|
469
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
470
|
+
response = await client.responses.create(body, nextOptions);
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
signal?.throwIfAborted();
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
signal?.throwIfAborted();
|
|
477
|
+
const { calls, output } = computerCalls(response, earlierIdentities, earlierCallIds);
|
|
478
|
+
if (calls.length === 0) {
|
|
479
|
+
return response;
|
|
480
|
+
}
|
|
481
|
+
if (step >= maxSteps - 1) {
|
|
482
|
+
throw new error_1.OpenAIError('ComputerToolset.run reached maxSteps before executing another computer call.');
|
|
483
|
+
}
|
|
484
|
+
// Capture the native replay as it will be sent, before an action can change the environment.
|
|
485
|
+
const projected = (0, ResponseInputItems_1.toResponseInputItems)(output);
|
|
486
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(projected);
|
|
487
|
+
// SAFETY: computerCalls validated every supported item; toResponseInputItems strips output-only fields.
|
|
488
|
+
// oxlint-disable-next-line unicorn/prefer-structured-clone -- Replay must satisfy the native JSON encoder, not just be cloneable.
|
|
489
|
+
const replay = JSON.parse(JSON.stringify(projected));
|
|
490
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(replay);
|
|
491
|
+
for (const item of replay) {
|
|
492
|
+
body.input.push(item);
|
|
493
|
+
}
|
|
494
|
+
for (const call of calls) {
|
|
495
|
+
// Calls share one environment and must run in server order.
|
|
496
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
497
|
+
const observation = await this.executeOwned(call, executionOptions);
|
|
498
|
+
body.input.push(observation);
|
|
499
|
+
}
|
|
500
|
+
const choice = (0, runner_lifecycle_1.configuredOption)(body, 'tool_choice');
|
|
501
|
+
if (choice !== undefined && choice !== null) {
|
|
502
|
+
body.tool_choice = releaseForcedComputerChoice(choice);
|
|
503
|
+
if (typeof body.tool_choice === 'object') {
|
|
504
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(body.tool_choice);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Execute one completed call for a caller-managed Responses loop.
|
|
511
|
+
* Returns exactly one observation captured after all actions in the call.
|
|
512
|
+
* Screenshot actions still pass through beforeAction; intermediate captures
|
|
513
|
+
* are omitted because Responses accepts only the final observation.
|
|
514
|
+
* Approval, policy rejection, abort, and driver failures stop immediately.
|
|
515
|
+
*/
|
|
516
|
+
async execute(call, options = {}) {
|
|
517
|
+
this.lifecycle.enter();
|
|
518
|
+
try {
|
|
519
|
+
return await this.executeOwned(call, snapshotComputerPolicy(options));
|
|
520
|
+
}
|
|
521
|
+
finally {
|
|
522
|
+
this.lifecycle.leave();
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// oxlint-disable-next-line eslint/complexity -- Keep the execution snapshot shared by safety approval, action approval and dispatch.
|
|
526
|
+
async executeOwned(call, policy) {
|
|
527
|
+
const snapshot = ComputerToolset.validate(call);
|
|
528
|
+
// Use the same native projection as run(), before any callback or effect.
|
|
529
|
+
// SAFETY: Validation permits modern calls to omit only the legacy checklist required by the output type.
|
|
530
|
+
const projected = (0, ResponseInputItems_1.toResponseInputItems)([snapshot]);
|
|
531
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(projected);
|
|
532
|
+
// SAFETY: The validated single computer call retains its native fields after projection.
|
|
533
|
+
// oxlint-disable-next-line unicorn/prefer-structured-clone -- Direct replay must satisfy the native JSON encoder too.
|
|
534
|
+
const replay = JSON.parse(JSON.stringify(projected));
|
|
535
|
+
const actions = computerActions(snapshot);
|
|
536
|
+
for (const action of actions) {
|
|
537
|
+
if ((action.type === 'click' ||
|
|
538
|
+
action.type === 'drag' ||
|
|
539
|
+
action.type === 'move' ||
|
|
540
|
+
action.type === 'scroll') &&
|
|
541
|
+
(0, runner_lifecycle_1.configuredOption)(action, 'keys') === undefined) {
|
|
542
|
+
// Shadow omitted modifiers only in execution copies; wire snapshots must remain JSON values.
|
|
543
|
+
Object.defineProperty(action, 'keys', {
|
|
544
|
+
value: undefined,
|
|
545
|
+
enumerable: true,
|
|
546
|
+
writable: true,
|
|
547
|
+
configurable: true,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// The final capture still requires approval when a driver mutates its action.
|
|
552
|
+
// The SDK compiles against ES2020, which does not include Array.at.
|
|
553
|
+
// oxlint-disable-next-line prefer-at
|
|
554
|
+
const needsScreenshot = actions[actions.length - 1]?.type !== 'screenshot';
|
|
555
|
+
policy.signal?.throwIfAborted();
|
|
556
|
+
const checks = (0, runner_lifecycle_1.configuredOption)(snapshot, 'pending_safety_checks') ?? [];
|
|
557
|
+
const nativeChecks = checks.map((check) => ({
|
|
558
|
+
id: check.id,
|
|
559
|
+
code: (0, values_1.hasOwn)(check, 'code') ? check.code : undefined,
|
|
560
|
+
message: (0, values_1.hasOwn)(check, 'message') ? check.message : undefined,
|
|
561
|
+
}));
|
|
562
|
+
// Native fields in the captured replay must still describe the same checks.
|
|
563
|
+
const captured = replay[0]?.pending_safety_checks ?? [];
|
|
564
|
+
if (!Array.isArray(captured) ||
|
|
565
|
+
captured.length !== nativeChecks.length ||
|
|
566
|
+
!captured.every((value, index) => (0, values_1.isObj)(value) &&
|
|
567
|
+
(0, values_1.hasOwn)(value, 'id') &&
|
|
568
|
+
value['id'] === nativeChecks[index]?.id &&
|
|
569
|
+
((0, values_1.hasOwn)(value, 'code') ? value['code'] : undefined) === nativeChecks[index]?.code &&
|
|
570
|
+
((0, values_1.hasOwn)(value, 'message') ? value['message'] : undefined) === nativeChecks[index]?.message)) {
|
|
571
|
+
throw new error_1.OpenAIError('ComputerToolset serialization changed the pending safety checks.');
|
|
572
|
+
}
|
|
573
|
+
// SAFETY: Every captured native field matches its already validated check; optional extensions are JSON values.
|
|
574
|
+
const acknowledged = captured;
|
|
575
|
+
if (checks.length > 0) {
|
|
576
|
+
// Preserve omissions in replay/acknowledgement; callbacks own absent fields in execution copies.
|
|
577
|
+
for (const check of checks) {
|
|
578
|
+
for (const key of ['code', 'message']) {
|
|
579
|
+
if (!(0, values_1.hasOwn)(check, key)) {
|
|
580
|
+
Object.defineProperty(check, key, {
|
|
581
|
+
value: undefined,
|
|
582
|
+
enumerable: true,
|
|
583
|
+
writable: true,
|
|
584
|
+
configurable: true,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const started = performance.now();
|
|
590
|
+
try {
|
|
591
|
+
const view = structuredClone({ ...snapshot, pending_safety_checks: checks });
|
|
592
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(view);
|
|
593
|
+
const approved = await policy.approveSafetyChecks?.(view, { signal: policy.signal });
|
|
594
|
+
policy.signal?.throwIfAborted();
|
|
595
|
+
if (approved !== true) {
|
|
596
|
+
throw new error_1.OpenAIError('ComputerToolset requires explicit approval of pending safety checks.');
|
|
597
|
+
}
|
|
598
|
+
(0, runner_diagnostics_1.reportDiagnostic)(policy.onDiagnostic, { api: 'computer', stage: 'approval', reason: 'completed', call_id: snapshot.call_id }, started);
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
(0, runner_diagnostics_1.reportDiagnostic)(policy.onDiagnostic, {
|
|
602
|
+
api: 'computer',
|
|
603
|
+
stage: 'approval',
|
|
604
|
+
reason: policy.signal?.aborted ? 'cancelled' : 'policy_failed',
|
|
605
|
+
call_id: snapshot.call_id,
|
|
606
|
+
}, started);
|
|
607
|
+
policy.signal?.throwIfAborted();
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
for (const action of actions) {
|
|
612
|
+
// Computer effects are ordered and must never execute concurrently.
|
|
613
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
614
|
+
await this.perform(action, snapshot, policy);
|
|
615
|
+
}
|
|
616
|
+
if (needsScreenshot) {
|
|
617
|
+
await this.perform({ type: 'screenshot' }, snapshot, policy);
|
|
618
|
+
}
|
|
619
|
+
policy.signal?.throwIfAborted();
|
|
620
|
+
const output = await this.captureScreenshot(snapshot, policy);
|
|
621
|
+
const observation = {
|
|
622
|
+
type: 'computer_call_output',
|
|
623
|
+
call_id: snapshot.call_id,
|
|
624
|
+
output,
|
|
625
|
+
...(checks.length > 0 ? { acknowledged_safety_checks: acknowledged } : {}),
|
|
626
|
+
};
|
|
627
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(observation);
|
|
628
|
+
return observation;
|
|
629
|
+
}
|
|
630
|
+
async captureScreenshot(snapshot, policy) {
|
|
631
|
+
const started = performance.now();
|
|
632
|
+
let output;
|
|
633
|
+
try {
|
|
634
|
+
const supplied = await this.driver.screenshot({ signal: policy.signal });
|
|
635
|
+
policy.signal?.throwIfAborted();
|
|
636
|
+
if (!(0, values_1.isObj)(supplied)) {
|
|
637
|
+
throw new error_1.OpenAIError('ComputerToolset screenshot must return a computer_screenshot with image_url or file_id.');
|
|
638
|
+
}
|
|
639
|
+
const type = (0, runner_lifecycle_1.configuredOption)(supplied, 'type');
|
|
640
|
+
const image_url = (0, runner_lifecycle_1.configuredOption)(supplied, 'image_url');
|
|
641
|
+
const file_id = (0, runner_lifecycle_1.configuredOption)(supplied, 'file_id');
|
|
642
|
+
if (type !== 'computer_screenshot' ||
|
|
643
|
+
(image_url !== undefined && (typeof image_url !== 'string' || !image_url.trim())) ||
|
|
644
|
+
(file_id !== undefined && (typeof file_id !== 'string' || !file_id.trim())) ||
|
|
645
|
+
(image_url === undefined && file_id === undefined)) {
|
|
646
|
+
throw new error_1.OpenAIError('ComputerToolset screenshot must return a computer_screenshot with image_url or file_id.');
|
|
647
|
+
}
|
|
648
|
+
output = {
|
|
649
|
+
type,
|
|
650
|
+
...(image_url === undefined ? {} : { image_url }),
|
|
651
|
+
...(file_id === undefined ? {} : { file_id }),
|
|
652
|
+
};
|
|
653
|
+
(0, runner_diagnostics_1.reportDiagnostic)(policy.onDiagnostic, {
|
|
654
|
+
api: 'computer',
|
|
655
|
+
stage: 'action',
|
|
656
|
+
reason: 'completed',
|
|
657
|
+
call_id: snapshot.call_id,
|
|
658
|
+
member: 'screenshot',
|
|
659
|
+
}, started);
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
(0, runner_diagnostics_1.reportDiagnostic)(policy.onDiagnostic, {
|
|
663
|
+
api: 'computer',
|
|
664
|
+
stage: 'action',
|
|
665
|
+
reason: policy.signal?.aborted ? 'cancelled' : 'driver_failed',
|
|
666
|
+
call_id: snapshot.call_id,
|
|
667
|
+
member: 'screenshot',
|
|
668
|
+
}, started);
|
|
669
|
+
policy.signal?.throwIfAborted();
|
|
670
|
+
throw error;
|
|
671
|
+
}
|
|
672
|
+
policy.signal?.throwIfAborted();
|
|
673
|
+
return output;
|
|
674
|
+
}
|
|
675
|
+
async perform(action, call, options) {
|
|
676
|
+
options.signal?.throwIfAborted();
|
|
677
|
+
if (options.beforeAction) {
|
|
678
|
+
await ComputerToolset.approveAction(action, call, options.beforeAction, options);
|
|
679
|
+
}
|
|
680
|
+
options.signal?.throwIfAborted();
|
|
681
|
+
const started = performance.now();
|
|
682
|
+
try {
|
|
683
|
+
const dispatched = structuredClone(action);
|
|
684
|
+
switch (dispatched.type) {
|
|
685
|
+
case 'click': {
|
|
686
|
+
await this.driver.click(dispatched, { signal: options.signal });
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
case 'double_click': {
|
|
690
|
+
await this.driver.double_click(dispatched, { signal: options.signal });
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
case 'drag': {
|
|
694
|
+
await this.driver.drag(dispatched, { signal: options.signal });
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
case 'keypress': {
|
|
698
|
+
await this.driver.keypress(dispatched, { signal: options.signal });
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
case 'move': {
|
|
702
|
+
await this.driver.move(dispatched, { signal: options.signal });
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
case 'screenshot': {
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
case 'scroll': {
|
|
709
|
+
await this.driver.scroll(dispatched, { signal: options.signal });
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
case 'type': {
|
|
713
|
+
await this.driver.type(dispatched, { signal: options.signal });
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
case 'wait': {
|
|
717
|
+
await this.driver.wait(dispatched, { signal: options.signal });
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
default: {
|
|
721
|
+
throw new error_1.OpenAIError('ComputerToolset received an unsupported computer action.');
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
options.signal?.throwIfAborted();
|
|
725
|
+
if (action.type !== 'screenshot') {
|
|
726
|
+
(0, runner_diagnostics_1.reportDiagnostic)(options.onDiagnostic, {
|
|
727
|
+
api: 'computer',
|
|
728
|
+
stage: 'action',
|
|
729
|
+
reason: 'completed',
|
|
730
|
+
call_id: call.call_id,
|
|
731
|
+
member: action.type,
|
|
732
|
+
}, started);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
catch (error) {
|
|
736
|
+
(0, runner_diagnostics_1.reportDiagnostic)(options.onDiagnostic, {
|
|
737
|
+
api: 'computer',
|
|
738
|
+
stage: 'action',
|
|
739
|
+
reason: options.signal?.aborted ? 'cancelled' : 'driver_failed',
|
|
740
|
+
call_id: call.call_id,
|
|
741
|
+
member: action.type,
|
|
742
|
+
}, started);
|
|
743
|
+
options.signal?.throwIfAborted();
|
|
744
|
+
throw error;
|
|
745
|
+
}
|
|
746
|
+
options.signal?.throwIfAborted();
|
|
747
|
+
}
|
|
748
|
+
static async approveAction(action, call, beforeAction, options) {
|
|
749
|
+
const started = performance.now();
|
|
750
|
+
try {
|
|
751
|
+
const view = structuredClone(action);
|
|
752
|
+
(0, runner_lifecycle_1.protectRunnerJSON)(view);
|
|
753
|
+
const approved = await beforeAction(view, actionApprovalCall(call), {
|
|
754
|
+
signal: options.signal,
|
|
755
|
+
});
|
|
756
|
+
options.signal?.throwIfAborted();
|
|
757
|
+
if (approved !== true) {
|
|
758
|
+
throw new error_1.OpenAIError('ComputerToolset action declined by beforeAction.');
|
|
759
|
+
}
|
|
760
|
+
(0, runner_diagnostics_1.reportDiagnostic)(options.onDiagnostic, {
|
|
761
|
+
api: 'computer',
|
|
762
|
+
stage: 'approval',
|
|
763
|
+
reason: 'completed',
|
|
764
|
+
call_id: call.call_id,
|
|
765
|
+
member: action.type,
|
|
766
|
+
}, started);
|
|
767
|
+
}
|
|
768
|
+
catch (error) {
|
|
769
|
+
(0, runner_diagnostics_1.reportDiagnostic)(options.onDiagnostic, {
|
|
770
|
+
api: 'computer',
|
|
771
|
+
stage: 'approval',
|
|
772
|
+
reason: options.signal?.aborted ? 'cancelled' : 'policy_failed',
|
|
773
|
+
call_id: call.call_id,
|
|
774
|
+
member: action.type,
|
|
775
|
+
}, started);
|
|
776
|
+
options.signal?.throwIfAborted();
|
|
777
|
+
throw error;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
exports.ComputerToolset = ComputerToolset;
|
|
782
|
+
//# sourceMappingURL=computer.js.map
|