codex-chatgpt-control 0.5.1-alpha.2 → 0.5.1-alpha.4
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 +42 -0
- package/README.md +43 -0
- package/contracts/v1/fixtures/backend-capabilities.json +40 -1
- package/contracts/v1/fixtures/backend-compatibility.json +21 -0
- package/contracts/v1/fixtures/backend-version.json +6 -1
- package/contracts/v1/fixtures/download-blocked-by-browser.json +22 -0
- package/contracts/v1/fixtures/download-receipt-failed.json +22 -0
- package/contracts/v1/fixtures/download-receipt-timeout.json +22 -0
- package/contracts/v1/fixtures/journal-rpc-indeterminate.json +32 -0
- package/contracts/v1/fixtures/journal-rpc-unsupported-platform.json +32 -0
- package/contracts/v1/fixtures/journal-runtime-unavailable.json +32 -0
- package/contracts/v1/fixtures/operation-action-prepared-event.json +42 -0
- package/contracts/v1/fixtures/operation-action.json +13 -0
- package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
- package/contracts/v1/fixtures/operation-blocker.json +10 -0
- package/contracts/v1/fixtures/operation-collect-request.json +17 -0
- package/contracts/v1/fixtures/operation-collect-result.json +42 -0
- package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
- package/contracts/v1/fixtures/operation-control-request.json +18 -0
- package/contracts/v1/fixtures/operation-control-result.json +31 -0
- package/contracts/v1/fixtures/operation-event.json +18 -0
- package/contracts/v1/fixtures/operation-handle.json +10 -0
- package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
- package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
- package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
- package/contracts/v1/fixtures/operation-receipt.json +32 -0
- package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
- package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
- package/contracts/v1/fixtures/operation-request.json +33 -0
- package/contracts/v1/fixtures/operation-state.json +144 -0
- package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
- package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
- package/contracts/v1/fixtures/operation-submit-result.json +16 -0
- package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
- package/contracts/v1/manifest.json +185 -1
- package/contracts/v1/parity-suite.json +106 -8
- package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
- package/contracts/v1/schemas/backend-request.schema.json +8 -2
- package/contracts/v1/schemas/capabilities.schema.json +81 -1
- package/contracts/v1/schemas/manifest.schema.json +57 -0
- package/contracts/v1/schemas/operation-action.schema.json +155 -0
- package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
- package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
- package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
- package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
- package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
- package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
- package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
- package/contracts/v1/schemas/operation-event.schema.json +756 -0
- package/contracts/v1/schemas/operation-handle.schema.json +55 -0
- package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
- package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
- package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
- package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
- package/contracts/v1/schemas/operation-request.schema.json +158 -0
- package/contracts/v1/schemas/operation-state.schema.json +691 -0
- package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
- package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
- package/contracts/v1/surface-drift-policy.json +50 -0
- package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
- package/dist/codex-chatgpt-control-backend.mjs +45882 -9361
- package/dist/codex-chatgpt-control-journal.mjs +5547 -0
- package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +51677 -0
- package/dist/codex-chatgpt-control-release-canary.bundle.mjs +52104 -0
- package/dist/codex-chatgpt-control.bundle.mjs +48392 -10260
- package/dist/src/backend/client.d.ts +103 -2
- package/dist/src/backend/client.js +1436 -97
- package/dist/src/backend/compatibility.d.ts +12 -0
- package/dist/src/backend/compatibility.js +208 -0
- package/dist/src/backend/protocol.d.ts +84 -1
- package/dist/src/backend/protocol.js +31 -5
- package/dist/src/backend/runtime-identity.d.ts +10 -0
- package/dist/src/backend/runtime-identity.js +141 -0
- package/dist/src/backend/session.d.ts +10 -2
- package/dist/src/backend/session.js +478 -7
- package/dist/src/backend/stdio-server.d.ts +4 -1
- package/dist/src/backend/stdio-server.js +240 -28
- package/dist/src/browser/active-composer-file-input.d.ts +9 -0
- package/dist/src/browser/active-composer-file-input.js +33 -0
- package/dist/src/browser/attach.d.ts +4 -1
- package/dist/src/browser/attach.js +136 -28
- package/dist/src/browser/chatgpt-url.d.ts +2 -0
- package/dist/src/browser/chatgpt-url.js +9 -0
- package/dist/src/browser/downloads.d.ts +17 -1
- package/dist/src/browser/downloads.js +150 -28
- package/dist/src/browser/page-state.js +6 -0
- package/dist/src/client.d.ts +43 -0
- package/dist/src/client.js +1279 -59
- package/dist/src/commands/artifacts.js +6 -4
- package/dist/src/commands/chat-popover.d.ts +37 -0
- package/dist/src/commands/chat-popover.js +537 -0
- package/dist/src/commands/configuration.d.ts +5 -0
- package/dist/src/commands/configuration.js +134 -21
- package/dist/src/commands/context.js +10 -3
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +27 -4
- package/dist/src/commands/experience.d.ts +5 -0
- package/dist/src/commands/experience.js +104 -21
- package/dist/src/commands/files.js +14 -33
- package/dist/src/commands/modes.js +85 -21
- package/dist/src/commands/power-discovery.d.ts +130 -0
- package/dist/src/commands/power-discovery.js +669 -0
- package/dist/src/commands/project-sources.js +325 -31
- package/dist/src/commands/sequence.js +59 -32
- package/dist/src/commands/session.js +19 -6
- package/dist/src/commands/work.js +31 -0
- package/dist/src/dom/composer-text.d.ts +6 -0
- package/dist/src/dom/composer-text.js +85 -0
- package/dist/src/errors.d.ts +9 -0
- package/dist/src/errors.js +22 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +9 -0
- package/dist/src/operations/artifact-output.d.ts +69 -0
- package/dist/src/operations/artifact-output.js +1748 -0
- package/dist/src/operations/artifact-stream.d.ts +19 -0
- package/dist/src/operations/artifact-stream.js +35 -0
- package/dist/src/operations/artifact-transfer.d.ts +149 -0
- package/dist/src/operations/artifact-transfer.js +1312 -0
- package/dist/src/operations/browser-adapter.d.ts +167 -0
- package/dist/src/operations/browser-adapter.js +2103 -0
- package/dist/src/operations/browser-observation.d.ts +110 -0
- package/dist/src/operations/browser-observation.js +1256 -0
- package/dist/src/operations/browser-target.d.ts +105 -0
- package/dist/src/operations/browser-target.js +531 -0
- package/dist/src/operations/canonical.d.ts +4 -0
- package/dist/src/operations/canonical.js +412 -0
- package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
- package/dist/src/operations/chatgpt-runtime.js +1232 -0
- package/dist/src/operations/client.d.ts +138 -0
- package/dist/src/operations/client.js +1145 -0
- package/dist/src/operations/collector.d.ts +195 -0
- package/dist/src/operations/collector.js +1039 -0
- package/dist/src/operations/configuration-routing.d.ts +4 -0
- package/dist/src/operations/configuration-routing.js +14 -0
- package/dist/src/operations/control.d.ts +372 -0
- package/dist/src/operations/control.js +1498 -0
- package/dist/src/operations/file-identity.d.ts +33 -0
- package/dist/src/operations/file-identity.js +153 -0
- package/dist/src/operations/handle.d.ts +19 -0
- package/dist/src/operations/handle.js +727 -0
- package/dist/src/operations/index.d.ts +25 -0
- package/dist/src/operations/index.js +25 -0
- package/dist/src/operations/journal-authority.d.ts +12 -0
- package/dist/src/operations/journal-authority.js +1 -0
- package/dist/src/operations/journal-rpc-client.d.ts +12 -0
- package/dist/src/operations/journal-rpc-client.js +225 -0
- package/dist/src/operations/journal-rpc-protocol.d.ts +32 -0
- package/dist/src/operations/journal-rpc-protocol.js +214 -0
- package/dist/src/operations/journal-rpc-server.d.ts +15 -0
- package/dist/src/operations/journal-rpc-server.js +272 -0
- package/dist/src/operations/journal.d.ts +143 -0
- package/dist/src/operations/journal.js +1957 -0
- package/dist/src/operations/production-attachments.d.ts +118 -0
- package/dist/src/operations/production-attachments.js +1035 -0
- package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
- package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
- package/dist/src/operations/production-chatgpt-attachments.d.ts +80 -0
- package/dist/src/operations/production-chatgpt-attachments.js +1639 -0
- package/dist/src/operations/production-configuration.d.ts +42 -0
- package/dist/src/operations/production-configuration.js +1544 -0
- package/dist/src/operations/production-primitives.d.ts +53 -0
- package/dist/src/operations/production-primitives.js +856 -0
- package/dist/src/operations/production-work-steer.d.ts +203 -0
- package/dist/src/operations/production-work-steer.js +1218 -0
- package/dist/src/operations/recovery.d.ts +80 -0
- package/dist/src/operations/recovery.js +174 -0
- package/dist/src/operations/runtime-adapter.d.ts +126 -0
- package/dist/src/operations/runtime-adapter.js +802 -0
- package/dist/src/operations/send-once.d.ts +224 -0
- package/dist/src/operations/send-once.js +1081 -0
- package/dist/src/operations/service.d.ts +286 -0
- package/dist/src/operations/service.js +2831 -0
- package/dist/src/operations/staging.d.ts +136 -0
- package/dist/src/operations/staging.js +630 -0
- package/dist/src/operations/state-machine.d.ts +29 -0
- package/dist/src/operations/state-machine.js +2047 -0
- package/dist/src/operations/submission.d.ts +423 -0
- package/dist/src/operations/submission.js +1676 -0
- package/dist/src/operations/transactional-chat-power.d.ts +17 -0
- package/dist/src/operations/transactional-chat-power.js +212 -0
- package/dist/src/operations/turn-ownership.d.ts +202 -0
- package/dist/src/operations/turn-ownership.js +700 -0
- package/dist/src/operations/types.d.ts +454 -0
- package/dist/src/operations/types.js +20 -0
- package/dist/src/operations/wire-requests.d.ts +21 -0
- package/dist/src/operations/wire-requests.js +396 -0
- package/dist/src/operations/wire-results.d.ts +97 -0
- package/dist/src/operations/wire-results.js +818 -0
- package/dist/src/runner/responses.d.ts +3 -1
- package/dist/src/runner/responses.js +19 -1
- package/dist/src/runner/result.js +227 -55
- package/dist/src/runner/types.d.ts +12 -0
- package/dist/src/runtime/command-routing.d.ts +149 -0
- package/dist/src/runtime/command-routing.js +431 -0
- package/dist/src/runtime/coordinated-browser.d.ts +24 -0
- package/dist/src/runtime/coordinated-browser.js +315 -0
- package/dist/src/runtime/coordinated-page.d.ts +41 -0
- package/dist/src/runtime/coordinated-page.js +651 -0
- package/dist/src/runtime/operation-context.d.ts +142 -0
- package/dist/src/runtime/operation-context.js +410 -0
- package/dist/src/runtime/runtime-session.d.ts +95 -0
- package/dist/src/runtime/runtime-session.js +314 -0
- package/dist/src/runtime/tab-coordinator.d.ts +200 -0
- package/dist/src/runtime/tab-coordinator.js +1200 -0
- package/dist/src/runtime/value-boundaries.d.ts +18 -0
- package/dist/src/runtime/value-boundaries.js +49 -0
- package/dist/src/safety/blockers.js +8 -1
- package/dist/src/safety/untrusted-output.js +2 -1
- package/dist/src/scripts/backend-server.js +4 -1
- package/dist/src/scripts/capture-surface-profile.js +7 -2
- package/dist/src/scripts/journal-server.d.ts +2 -0
- package/dist/src/scripts/journal-server.js +37 -0
- package/dist/src/scripts/live-smoke/harness.js +79 -7
- package/dist/src/scripts/live-smoke/scenarios.d.ts +42 -1
- package/dist/src/scripts/live-smoke/scenarios.js +147 -30
- package/dist/src/scripts/live-smoke/transactional.d.ts +17 -0
- package/dist/src/scripts/live-smoke/transactional.js +254 -0
- package/dist/src/scripts/live-smoke/types.d.ts +3 -0
- package/dist/src/scripts/release-canary-module.js +17 -4
- package/dist/src/types.d.ts +38 -1
- package/package.json +8 -3
- package/references/2026-08-16-transactional-operations.md +459 -0
- package/references/2026-09-06-journal-service.md +140 -0
- package/references/agents-runner.md +34 -0
- package/references/backend-protocol.md +176 -0
- package/references/python-parity.md +137 -0
- package/references/responses-adapter.md +19 -0
- package/references/streaming.md +6 -0
|
@@ -1,14 +1,25 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { createChatGPT } from "../client.js";
|
|
3
|
+
import { toOperationCollectWireResult, toOperationControlWireResult, toOperationInspectWireResult, toOperationSubmitWireResult } from "../operations/wire-results.js";
|
|
4
|
+
import { OperationWireRequestError, validateOperationCollectRequest as validateWireCollectRequest, validateOperationControlRequest as validateWireControlRequest, validateOperationInspectRequest as validateWireInspectRequest, validateOperationSubmitRequest as validateWireSubmitRequest } from "../operations/wire-requests.js";
|
|
5
|
+
import { assertOperationAwareDispatchAllowed, classifyCommandRouting, commandRoutingDisposition, CommandRoutingError } from "../runtime/command-routing.js";
|
|
2
6
|
import { BACKEND_REQUEST_SCHEMA_VERSION, backendCommands, backendResponseError, backendEvent, backendEventCompleted, backendResponseOk, ProtocolError } from "./protocol.js";
|
|
7
|
+
// A stdio backend process owns one identity. BackendSession objects created by
|
|
8
|
+
// that process share it unless an embedding explicitly injects a diagnostic
|
|
9
|
+
// identity (for example, a test or a separately fenced runtime).
|
|
10
|
+
const PROCESS_BACKEND_SESSION_ID = randomUUID();
|
|
11
|
+
const MAX_IDENTITY_FIELD_LENGTH = 512;
|
|
3
12
|
export class BackendSession {
|
|
4
13
|
options;
|
|
5
14
|
clientInstance;
|
|
15
|
+
identity;
|
|
6
16
|
constructor(options = {}) {
|
|
7
17
|
this.options = options;
|
|
18
|
+
this.identity = backendRuntimeIdentity(options.backendIdentity);
|
|
8
19
|
}
|
|
9
20
|
async dispatch(request) {
|
|
10
21
|
try {
|
|
11
|
-
const result = await dispatchBackendCommand(this.
|
|
22
|
+
const result = await dispatchBackendCommand(request, payload => this.hello(payload), this.identity, () => this.client());
|
|
12
23
|
return backendResponseOk(request.requestId, result);
|
|
13
24
|
}
|
|
14
25
|
catch (error) {
|
|
@@ -17,6 +28,8 @@ export class BackendSession {
|
|
|
17
28
|
}
|
|
18
29
|
async *stream(request) {
|
|
19
30
|
try {
|
|
31
|
+
assertCommandRoutingClassified(request.command);
|
|
32
|
+
assertBackendOperationRoutingAllowed(request.command, request.payload);
|
|
20
33
|
if (request.command !== "runner.stream") {
|
|
21
34
|
const response = await this.dispatch(request);
|
|
22
35
|
if (response.ok) {
|
|
@@ -40,9 +53,11 @@ export class BackendSession {
|
|
|
40
53
|
yield backendEventCompleted(request.requestId, await stream.completed);
|
|
41
54
|
}
|
|
42
55
|
catch (error) {
|
|
56
|
+
// Runner/provider errors may contain prompt or page content. Only an
|
|
57
|
+
// explicit ProtocolError carries a reviewed wire-safe message.
|
|
43
58
|
const protocolError = error instanceof ProtocolError
|
|
44
59
|
? error
|
|
45
|
-
: new ProtocolError("invalid_request",
|
|
60
|
+
: new ProtocolError("invalid_request", "Backend stream failed safely.", false);
|
|
46
61
|
yield backendEvent(request.requestId, {
|
|
47
62
|
type: "error",
|
|
48
63
|
error: {
|
|
@@ -53,19 +68,41 @@ export class BackendSession {
|
|
|
53
68
|
});
|
|
54
69
|
}
|
|
55
70
|
}
|
|
71
|
+
hello(payload) {
|
|
72
|
+
const requestedProtocol = payload.protocolVersion;
|
|
73
|
+
const hasRequestedCapabilities = Object.hasOwn(payload, "capabilities");
|
|
74
|
+
const baseCapabilities = backendCapabilities(this.identity);
|
|
75
|
+
const requestedCapabilities = isRecord(payload.capabilities) ? payload.capabilities : undefined;
|
|
76
|
+
const capabilities = intersectCapabilities(baseCapabilities, requestedCapabilities);
|
|
77
|
+
const accepted = (requestedProtocol === undefined || requestedProtocol === this.identity.protocolVersion)
|
|
78
|
+
&& (!hasRequestedCapabilities
|
|
79
|
+
|| (requestedCapabilities !== undefined
|
|
80
|
+
&& requestedCapabilitiesSatisfied(baseCapabilities, capabilities, requestedCapabilities)));
|
|
81
|
+
return {
|
|
82
|
+
...this.identity,
|
|
83
|
+
accepted,
|
|
84
|
+
capabilities
|
|
85
|
+
};
|
|
86
|
+
}
|
|
56
87
|
client() {
|
|
57
88
|
this.clientInstance ??= createChatGPT(this.options);
|
|
58
89
|
return this.clientInstance;
|
|
59
90
|
}
|
|
60
91
|
}
|
|
61
|
-
async function dispatchBackendCommand(
|
|
92
|
+
async function dispatchBackendCommand(request, hello, identity, clientFactory) {
|
|
93
|
+
assertCommandRoutingClassified(request.command);
|
|
94
|
+
assertBackendOperationRoutingAllowed(request.command, request.payload);
|
|
62
95
|
const payload = request.payload;
|
|
96
|
+
const client = new Proxy({}, {
|
|
97
|
+
get: (_target, property, receiver) => Reflect.get(clientFactory(), property, receiver)
|
|
98
|
+
});
|
|
63
99
|
switch (request.command) {
|
|
100
|
+
case "backend.hello":
|
|
101
|
+
return hello(payload);
|
|
64
102
|
case "backend.version":
|
|
65
103
|
return {
|
|
66
104
|
name: "codex-chatgpt-control-backend",
|
|
67
|
-
|
|
68
|
-
protocolVersion: BACKEND_REQUEST_SCHEMA_VERSION
|
|
105
|
+
...identity
|
|
69
106
|
};
|
|
70
107
|
case "backend.health":
|
|
71
108
|
return {
|
|
@@ -74,7 +111,7 @@ async function dispatchBackendCommand(client, request) {
|
|
|
74
111
|
timestamp: new Date().toISOString()
|
|
75
112
|
};
|
|
76
113
|
case "backend.capabilities":
|
|
77
|
-
return backendCapabilities();
|
|
114
|
+
return backendCapabilities(identity);
|
|
78
115
|
case "runner.run": {
|
|
79
116
|
const agent = client.agent(agentConfig(payload));
|
|
80
117
|
return client.runner.run(agent, runInput(payload));
|
|
@@ -189,19 +226,453 @@ async function dispatchBackendCommand(client, request) {
|
|
|
189
226
|
return client.tools.select(payload);
|
|
190
227
|
case "response.copy":
|
|
191
228
|
return client.response.copy(emptyToUndefined(payload));
|
|
229
|
+
case "operations.submit":
|
|
230
|
+
return dispatchOperationSubmit(client, payload);
|
|
231
|
+
case "operations.collect":
|
|
232
|
+
return dispatchOperationCollect(client, payload);
|
|
233
|
+
case "operations.inspect":
|
|
234
|
+
return dispatchOperationInspect(client, payload);
|
|
235
|
+
case "operations.control":
|
|
236
|
+
return dispatchOperationControl(client, payload);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function assertCommandRoutingClassified(command) {
|
|
240
|
+
if (classifyCommandRouting(command) === undefined) {
|
|
241
|
+
throw new ProtocolError("invalid_request", "Backend command routing classification is unavailable.", false);
|
|
242
|
+
}
|
|
243
|
+
if (commandRoutingDisposition(command) === undefined) {
|
|
244
|
+
// A known legacy browser command may only be admitted once its bounded
|
|
245
|
+
// coordinator seam is present. Keep this static: command payloads can
|
|
246
|
+
// contain prompts, local paths, or operation handles.
|
|
247
|
+
throw new ProtocolError("invalid_request", "Backend command has no bounded coordinator route.", false);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function assertBackendOperationRoutingAllowed(command, payload) {
|
|
251
|
+
try {
|
|
252
|
+
assertOperationAwareDispatchAllowed(command, payload);
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
if (error instanceof CommandRoutingError) {
|
|
256
|
+
// Keep the protocol error static. Operation payloads can contain raw
|
|
257
|
+
// prompts, instructions, file paths, or handles and must never be
|
|
258
|
+
// echoed as part of a routing failure.
|
|
259
|
+
throw new ProtocolError("invalid_request", error.message, false);
|
|
260
|
+
}
|
|
261
|
+
throw error;
|
|
192
262
|
}
|
|
193
263
|
}
|
|
194
|
-
function backendCapabilities() {
|
|
264
|
+
function backendCapabilities(identity) {
|
|
195
265
|
return {
|
|
266
|
+
...identity,
|
|
196
267
|
protocolVersion: BACKEND_REQUEST_SCHEMA_VERSION,
|
|
197
268
|
commands: [...backendCommands],
|
|
198
269
|
transports: ["stdio"],
|
|
199
270
|
streaming: {
|
|
200
271
|
modes: ["ndjson"],
|
|
201
272
|
tokenDeltas: false
|
|
273
|
+
},
|
|
274
|
+
supportedProtocolVersions: [BACKEND_REQUEST_SCHEMA_VERSION],
|
|
275
|
+
requestIds: {
|
|
276
|
+
required: true,
|
|
277
|
+
scope: "connection"
|
|
278
|
+
},
|
|
279
|
+
multiplexing: {
|
|
280
|
+
unary: true,
|
|
281
|
+
streams: true
|
|
282
|
+
},
|
|
283
|
+
cancellation: {
|
|
284
|
+
supported: false,
|
|
285
|
+
requests: false,
|
|
286
|
+
streams: false
|
|
287
|
+
},
|
|
288
|
+
tabs: {
|
|
289
|
+
stableProviderIdentity: false,
|
|
290
|
+
stableBrowserIdentity: false,
|
|
291
|
+
stableTabIdentity: false,
|
|
292
|
+
coordinationScope: "none",
|
|
293
|
+
authoritativeClaim: false,
|
|
294
|
+
fencing: false,
|
|
295
|
+
concurrentTabs: false,
|
|
296
|
+
stableIdentity: false,
|
|
297
|
+
coordination: false,
|
|
298
|
+
concurrent: false
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
async function dispatchOperationSubmit(client, payload) {
|
|
303
|
+
const operations = requireOperations(client);
|
|
304
|
+
const request = operationSubmitRequest(payload);
|
|
305
|
+
const result = await runOperationSafely(() => operations.submit(request));
|
|
306
|
+
const inspected = await runOperationSafely(() => operations.inspect(result.handle));
|
|
307
|
+
return operationWireSafely(() => toOperationSubmitWireResult(result, inspected.state.receipt));
|
|
308
|
+
}
|
|
309
|
+
async function dispatchOperationCollect(client, payload) {
|
|
310
|
+
const operations = requireOperations(client);
|
|
311
|
+
const request = operationCollectRequest(payload);
|
|
312
|
+
const result = await runOperationSafely(() => operations.collect(request.handle, {
|
|
313
|
+
...(request.wait === undefined ? {} : { wait: request.wait }),
|
|
314
|
+
...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
|
|
315
|
+
...(request.pollIntervalMs === undefined ? {} : { pollIntervalMs: request.pollIntervalMs }),
|
|
316
|
+
...(request.responseContent === undefined ? {} : { responseContent: request.responseContent })
|
|
317
|
+
}));
|
|
318
|
+
// The caller's locator is never returned as authoritative state. Reloading
|
|
319
|
+
// after the attempt obtains a fresh, authenticated handle for the wire
|
|
320
|
+
// envelope and keeps collection's browser-free terminal path intact.
|
|
321
|
+
const inspected = await runOperationSafely(() => operations.inspect(request.handle));
|
|
322
|
+
return operationWireSafely(() => toOperationCollectWireResult(inspected.handle, result, inspected.state.receipt));
|
|
323
|
+
}
|
|
324
|
+
async function dispatchOperationInspect(client, payload) {
|
|
325
|
+
const operations = requireOperations(client);
|
|
326
|
+
const request = operationInspectRequest(payload);
|
|
327
|
+
// OperationClient.inspect is explicitly browser-free. Keep this command on
|
|
328
|
+
// that path; no adapter factory or browser bridge is consulted here.
|
|
329
|
+
const result = await runOperationSafely(() => operations.inspect(request.handle));
|
|
330
|
+
return operationWireSafely(() => toOperationInspectWireResult(result));
|
|
331
|
+
}
|
|
332
|
+
async function dispatchOperationControl(client, payload) {
|
|
333
|
+
const operations = requireOperations(client);
|
|
334
|
+
const request = operationControlRequest(payload);
|
|
335
|
+
const result = await runOperationSafely(() => operations.control(request));
|
|
336
|
+
const inspected = await runOperationSafely(() => operations.inspect(request.parent));
|
|
337
|
+
return operationWireSafely(() => toOperationControlWireResult(result, inspected.handle));
|
|
338
|
+
}
|
|
339
|
+
function requireOperations(client) {
|
|
340
|
+
const operations = client.operations;
|
|
341
|
+
if (operations === undefined
|
|
342
|
+
|| typeof operations !== "object"
|
|
343
|
+
|| typeof operations.submit !== "function"
|
|
344
|
+
|| typeof operations.collect !== "function"
|
|
345
|
+
|| typeof operations.inspect !== "function"
|
|
346
|
+
|| typeof operations.control !== "function") {
|
|
347
|
+
throw new ProtocolError("invalid_request", "Transactional browser operations are unavailable in this backend.", false);
|
|
348
|
+
}
|
|
349
|
+
return operations;
|
|
350
|
+
}
|
|
351
|
+
function operationSubmitRequest(payload) {
|
|
352
|
+
return validateOperationPayload(payload, validateWireSubmitRequest);
|
|
353
|
+
}
|
|
354
|
+
function operationCollectRequest(payload) {
|
|
355
|
+
return validateOperationPayload(payload, validateWireCollectRequest);
|
|
356
|
+
}
|
|
357
|
+
function operationInspectRequest(payload) {
|
|
358
|
+
return validateOperationPayload(payload, validateWireInspectRequest);
|
|
359
|
+
}
|
|
360
|
+
function operationControlRequest(payload) {
|
|
361
|
+
return validateOperationPayload(payload, validateWireControlRequest);
|
|
362
|
+
}
|
|
363
|
+
function validateOperationPayload(payload, validator) {
|
|
364
|
+
try {
|
|
365
|
+
validator(payload);
|
|
366
|
+
return payload;
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
if (error instanceof OperationWireRequestError)
|
|
370
|
+
throw invalidOperationPayload();
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function invalidOperationPayload() {
|
|
375
|
+
// Do not include the offending value: it may contain a prompt or local path.
|
|
376
|
+
return new ProtocolError("invalid_request", "Transactional operation payload is invalid.", false);
|
|
377
|
+
}
|
|
378
|
+
async function runOperationSafely(call) {
|
|
379
|
+
try {
|
|
380
|
+
return await call();
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
if (error instanceof ProtocolError)
|
|
384
|
+
throw error;
|
|
385
|
+
// Operation adapters and journal errors can contain raw prompts, paths,
|
|
386
|
+
// URLs, or provider-private diagnostics. None may cross the backend wire.
|
|
387
|
+
throw new ProtocolError("invalid_request", "Transactional browser operation could not complete safely.", false);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function operationWireSafely(call) {
|
|
391
|
+
try {
|
|
392
|
+
return call();
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
if (error instanceof ProtocolError)
|
|
396
|
+
throw error;
|
|
397
|
+
throw new ProtocolError("invalid_request", "Transactional browser operation could not complete safely.", false);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function intersectCapabilities(base, requested) {
|
|
401
|
+
if (requested === undefined)
|
|
402
|
+
return base;
|
|
403
|
+
const requestedStreaming = isRecord(requested.streaming) ? requested.streaming : undefined;
|
|
404
|
+
const requestedRequestIds = isRecord(requested.requestIds) ? requested.requestIds : undefined;
|
|
405
|
+
const requestedMultiplexing = isRecord(requested.multiplexing) ? requested.multiplexing : undefined;
|
|
406
|
+
const requestedCancellation = isRecord(requested.cancellation) ? requested.cancellation : undefined;
|
|
407
|
+
const requestedTabs = isRecord(requested.tabs) ? requested.tabs : undefined;
|
|
408
|
+
const intersectedCommands = Array.isArray(requested.commands)
|
|
409
|
+
? base.commands.filter(command => includesString(requested.commands, command))
|
|
410
|
+
: base.commands;
|
|
411
|
+
const commands = intersectedCommands.length > 0 ? intersectedCommands : base.commands;
|
|
412
|
+
const intersectedTransports = Array.isArray(requested.transports)
|
|
413
|
+
? base.transports.filter(transport => includesString(requested.transports, transport))
|
|
414
|
+
: base.transports;
|
|
415
|
+
const transports = intersectedTransports.length > 0 ? intersectedTransports : base.transports;
|
|
416
|
+
const intersectedModes = requestedStreaming !== undefined && Array.isArray(requestedStreaming.modes)
|
|
417
|
+
? base.streaming.modes.filter(mode => includesString(requestedStreaming.modes, mode))
|
|
418
|
+
: base.streaming.modes;
|
|
419
|
+
const modes = intersectedModes.length > 0 ? intersectedModes : base.streaming.modes;
|
|
420
|
+
const intersectedProtocolVersions = Array.isArray(requested.supportedProtocolVersions)
|
|
421
|
+
? base.supportedProtocolVersions.filter(version => includesString(requested.supportedProtocolVersions, version))
|
|
422
|
+
: base.supportedProtocolVersions;
|
|
423
|
+
const requestIdScope = requestedRequestIds?.scope === undefined || requestedRequestIds.scope === base.requestIds.scope
|
|
424
|
+
? base.requestIds.scope
|
|
425
|
+
: "none";
|
|
426
|
+
const coordinationScope = requestedTabs?.coordinationScope === undefined
|
|
427
|
+
|| requestedTabs.coordinationScope === base.tabs.coordinationScope
|
|
428
|
+
? base.tabs.coordinationScope
|
|
429
|
+
: "none";
|
|
430
|
+
const stableProviderIdentity = base.tabs.stableProviderIdentity && requestedTabs?.stableProviderIdentity !== false;
|
|
431
|
+
const stableBrowserIdentity = base.tabs.stableBrowserIdentity && requestedTabs?.stableBrowserIdentity !== false;
|
|
432
|
+
const stableTabIdentity = base.tabs.stableTabIdentity && requestedTabs?.stableTabIdentity !== false;
|
|
433
|
+
const authoritativeClaim = base.tabs.authoritativeClaim && requestedTabs?.authoritativeClaim !== false;
|
|
434
|
+
const fencing = base.tabs.fencing && requestedTabs?.fencing !== false;
|
|
435
|
+
const concurrentTabs = base.tabs.concurrentTabs && requestedTabs?.concurrentTabs !== false;
|
|
436
|
+
return {
|
|
437
|
+
...base,
|
|
438
|
+
supportedProtocolVersions: intersectedProtocolVersions.length > 0
|
|
439
|
+
? intersectedProtocolVersions
|
|
440
|
+
: base.supportedProtocolVersions,
|
|
441
|
+
commands,
|
|
442
|
+
transports,
|
|
443
|
+
streaming: {
|
|
444
|
+
modes,
|
|
445
|
+
tokenDeltas: base.streaming.tokenDeltas && requestedStreaming?.tokenDeltas !== false
|
|
446
|
+
},
|
|
447
|
+
requestIds: {
|
|
448
|
+
required: base.requestIds.required && requestedRequestIds?.required !== false,
|
|
449
|
+
scope: requestIdScope
|
|
450
|
+
},
|
|
451
|
+
multiplexing: {
|
|
452
|
+
unary: base.multiplexing.unary && requestedMultiplexing?.unary !== false,
|
|
453
|
+
streams: base.multiplexing.streams && requestedMultiplexing?.streams !== false
|
|
454
|
+
},
|
|
455
|
+
cancellation: {
|
|
456
|
+
supported: base.cancellation.supported && requestedCancellation?.supported === true,
|
|
457
|
+
requests: base.cancellation.requests && requestedCancellation?.requests === true,
|
|
458
|
+
streams: base.cancellation.streams && requestedCancellation?.streams === true
|
|
459
|
+
},
|
|
460
|
+
tabs: {
|
|
461
|
+
...base.tabs,
|
|
462
|
+
stableProviderIdentity,
|
|
463
|
+
stableBrowserIdentity,
|
|
464
|
+
stableTabIdentity,
|
|
465
|
+
coordinationScope,
|
|
466
|
+
authoritativeClaim,
|
|
467
|
+
fencing,
|
|
468
|
+
concurrentTabs,
|
|
469
|
+
stableIdentity: stableProviderIdentity && stableBrowserIdentity && stableTabIdentity,
|
|
470
|
+
coordination: coordinationScope !== "none",
|
|
471
|
+
concurrent: concurrentTabs
|
|
202
472
|
}
|
|
203
473
|
};
|
|
204
474
|
}
|
|
475
|
+
function requestedCapabilitiesSatisfied(base, intersection, requested) {
|
|
476
|
+
if (!requestedCapabilitiesShapeValid(requested))
|
|
477
|
+
return false;
|
|
478
|
+
if ((Array.isArray(requested.commands) && requested.commands.length === 0)
|
|
479
|
+
|| (Array.isArray(requested.transports) && requested.transports.length === 0)
|
|
480
|
+
|| (Array.isArray(requested.supportedProtocolVersions) && requested.supportedProtocolVersions.length === 0))
|
|
481
|
+
return false;
|
|
482
|
+
if (Array.isArray(requested.commands)
|
|
483
|
+
&& requested.commands.some(command => typeof command !== "string" || !base.commands.includes(command)))
|
|
484
|
+
return false;
|
|
485
|
+
if (Array.isArray(requested.transports)
|
|
486
|
+
&& requested.transports.some(transport => typeof transport !== "string" || !base.transports.includes(transport)))
|
|
487
|
+
return false;
|
|
488
|
+
const requestedStreaming = isRecord(requested.streaming) ? requested.streaming : undefined;
|
|
489
|
+
if (requested.streaming !== undefined && requestedStreaming === undefined)
|
|
490
|
+
return false;
|
|
491
|
+
if (requestedStreaming
|
|
492
|
+
&& Array.isArray(requestedStreaming.modes)) {
|
|
493
|
+
if (requestedStreaming.modes.length === 0
|
|
494
|
+
|| requestedStreaming.modes.some(mode => typeof mode !== "string" || !base.streaming.modes.includes(mode)))
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
if (requestedStreaming?.tokenDeltas === true && !intersection.streaming.tokenDeltas)
|
|
498
|
+
return false;
|
|
499
|
+
if (Array.isArray(requested.supportedProtocolVersions)
|
|
500
|
+
&& requested.supportedProtocolVersions.some(version => typeof version !== "string" || !base.supportedProtocolVersions.includes(version)))
|
|
501
|
+
return false;
|
|
502
|
+
const requestedRequestIds = isRecord(requested.requestIds) ? requested.requestIds : undefined;
|
|
503
|
+
if (requested.requestIds !== undefined && requestedRequestIds === undefined)
|
|
504
|
+
return false;
|
|
505
|
+
if (requestedRequestIds
|
|
506
|
+
&& ((requestedRequestIds.required === true && !intersection.requestIds.required)
|
|
507
|
+
|| (requestedRequestIds.scope !== undefined && requestedRequestIds.scope !== intersection.requestIds.scope)))
|
|
508
|
+
return false;
|
|
509
|
+
const requestedMultiplexing = isRecord(requested.multiplexing) ? requested.multiplexing : undefined;
|
|
510
|
+
if (requested.multiplexing !== undefined && requestedMultiplexing === undefined)
|
|
511
|
+
return false;
|
|
512
|
+
if (requestedMultiplexing
|
|
513
|
+
&& ((requestedMultiplexing.unary === true && !intersection.multiplexing.unary)
|
|
514
|
+
|| (requestedMultiplexing.streams === true && !intersection.multiplexing.streams)))
|
|
515
|
+
return false;
|
|
516
|
+
const requestedCancellation = isRecord(requested.cancellation) ? requested.cancellation : undefined;
|
|
517
|
+
if (requested.cancellation !== undefined && requestedCancellation === undefined)
|
|
518
|
+
return false;
|
|
519
|
+
if (requestedCancellation
|
|
520
|
+
&& ((requestedCancellation.supported === true && !intersection.cancellation.supported)
|
|
521
|
+
|| (requestedCancellation.requests === true && !intersection.cancellation.requests)
|
|
522
|
+
|| (requestedCancellation.streams === true && !intersection.cancellation.streams)))
|
|
523
|
+
return false;
|
|
524
|
+
const requestedTabs = isRecord(requested.tabs) ? requested.tabs : undefined;
|
|
525
|
+
if (requested.tabs !== undefined && requestedTabs === undefined)
|
|
526
|
+
return false;
|
|
527
|
+
if (requestedTabs
|
|
528
|
+
&& ((requestedTabs.stableProviderIdentity === true && !intersection.tabs.stableProviderIdentity)
|
|
529
|
+
|| (requestedTabs.stableBrowserIdentity === true && !intersection.tabs.stableBrowserIdentity)
|
|
530
|
+
|| (requestedTabs.stableTabIdentity === true && !intersection.tabs.stableTabIdentity)
|
|
531
|
+
|| (requestedTabs.authoritativeClaim === true && !intersection.tabs.authoritativeClaim)
|
|
532
|
+
|| (requestedTabs.fencing === true && !intersection.tabs.fencing)
|
|
533
|
+
|| (requestedTabs.concurrentTabs === true && !intersection.tabs.concurrentTabs)
|
|
534
|
+
|| (requestedTabs.stableIdentity === true && !intersection.tabs.stableIdentity)
|
|
535
|
+
|| (requestedTabs.coordination === true && !intersection.tabs.coordination)
|
|
536
|
+
|| (requestedTabs.concurrent === true && !intersection.tabs.concurrent)
|
|
537
|
+
|| (requestedTabs.coordinationScope !== undefined && requestedTabs.coordinationScope !== intersection.tabs.coordinationScope)
|
|
538
|
+
|| !requestedDeprecatedTabAliasesConsistent(requestedTabs)))
|
|
539
|
+
return false;
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
function requestedCapabilitiesShapeValid(requested) {
|
|
543
|
+
if (!optionalStringArray(requested.commands)
|
|
544
|
+
|| !optionalStringArray(requested.transports)
|
|
545
|
+
|| !optionalStringArray(requested.supportedProtocolVersions))
|
|
546
|
+
return false;
|
|
547
|
+
for (const field of ["backendSessionId", "packageName", "packageVersion", "runtimeVersion", "buildDigest"]) {
|
|
548
|
+
if (Object.hasOwn(requested, field) && !optionalIdentityString(requested[field]))
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
if (Object.hasOwn(requested, "runtime") && requested.runtime !== "node")
|
|
552
|
+
return false;
|
|
553
|
+
if (Object.hasOwn(requested, "protocolVersion")
|
|
554
|
+
&& requested.protocolVersion !== BACKEND_REQUEST_SCHEMA_VERSION)
|
|
555
|
+
return false;
|
|
556
|
+
if (Object.hasOwn(requested, "streaming")) {
|
|
557
|
+
if (!isRecord(requested.streaming)
|
|
558
|
+
|| !optionalStringArray(requested.streaming.modes)
|
|
559
|
+
|| !optionalBoolean(requested.streaming.tokenDeltas))
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
if (Object.hasOwn(requested, "requestIds")) {
|
|
563
|
+
if (!isRecord(requested.requestIds)
|
|
564
|
+
|| !optionalBoolean(requested.requestIds.required)
|
|
565
|
+
|| (requested.requestIds.scope !== undefined
|
|
566
|
+
&& requested.requestIds.scope !== "connection"
|
|
567
|
+
&& requested.requestIds.scope !== "process"
|
|
568
|
+
&& requested.requestIds.scope !== "none"))
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
if (Object.hasOwn(requested, "multiplexing")) {
|
|
572
|
+
if (!isRecord(requested.multiplexing)
|
|
573
|
+
|| !optionalBoolean(requested.multiplexing.unary)
|
|
574
|
+
|| !optionalBoolean(requested.multiplexing.streams))
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
if (Object.hasOwn(requested, "cancellation")) {
|
|
578
|
+
if (!isRecord(requested.cancellation)
|
|
579
|
+
|| !optionalBoolean(requested.cancellation.supported)
|
|
580
|
+
|| !optionalBoolean(requested.cancellation.requests)
|
|
581
|
+
|| !optionalBoolean(requested.cancellation.streams))
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
if (Object.hasOwn(requested, "tabs")) {
|
|
585
|
+
if (!isRecord(requested.tabs)
|
|
586
|
+
|| !optionalBoolean(requested.tabs.stableProviderIdentity)
|
|
587
|
+
|| !optionalBoolean(requested.tabs.stableBrowserIdentity)
|
|
588
|
+
|| !optionalBoolean(requested.tabs.stableTabIdentity)
|
|
589
|
+
|| (requested.tabs.coordinationScope !== undefined
|
|
590
|
+
&& requested.tabs.coordinationScope !== "none"
|
|
591
|
+
&& requested.tabs.coordinationScope !== "process"
|
|
592
|
+
&& requested.tabs.coordinationScope !== "provider")
|
|
593
|
+
|| !optionalBoolean(requested.tabs.authoritativeClaim)
|
|
594
|
+
|| !optionalBoolean(requested.tabs.fencing)
|
|
595
|
+
|| !optionalBoolean(requested.tabs.concurrentTabs)
|
|
596
|
+
|| !optionalBoolean(requested.tabs.stableIdentity)
|
|
597
|
+
|| !optionalBoolean(requested.tabs.coordination)
|
|
598
|
+
|| !optionalBoolean(requested.tabs.concurrent))
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
function optionalStringArray(value) {
|
|
604
|
+
return value === undefined || (Array.isArray(value) && value.every(item => typeof item === "string"));
|
|
605
|
+
}
|
|
606
|
+
function optionalBoolean(value) {
|
|
607
|
+
return value === undefined || typeof value === "boolean";
|
|
608
|
+
}
|
|
609
|
+
function optionalIdentityString(value) {
|
|
610
|
+
return value === undefined
|
|
611
|
+
|| (typeof value === "string"
|
|
612
|
+
&& value.length > 0
|
|
613
|
+
&& value.length <= MAX_IDENTITY_FIELD_LENGTH
|
|
614
|
+
&& value.trim() === value
|
|
615
|
+
&& !/[\u0000-\u001f\u007f]/u.test(value));
|
|
616
|
+
}
|
|
617
|
+
function requestedDeprecatedTabAliasesConsistent(tabs) {
|
|
618
|
+
const hasStableFields = ["stableProviderIdentity", "stableBrowserIdentity", "stableTabIdentity"]
|
|
619
|
+
.every(field => Object.hasOwn(tabs, field));
|
|
620
|
+
const expectedStableIdentity = hasStableFields
|
|
621
|
+
&& tabs.stableProviderIdentity === true
|
|
622
|
+
&& tabs.stableBrowserIdentity === true
|
|
623
|
+
&& tabs.stableTabIdentity === true;
|
|
624
|
+
const expectedCoordination = tabs.coordinationScope !== undefined && tabs.coordinationScope !== "none";
|
|
625
|
+
const expectedConcurrent = tabs.concurrentTabs === true;
|
|
626
|
+
return (!Object.hasOwn(tabs, "stableIdentity")
|
|
627
|
+
|| !hasStableFields
|
|
628
|
+
|| tabs.stableIdentity === expectedStableIdentity)
|
|
629
|
+
&& (!Object.hasOwn(tabs, "coordination")
|
|
630
|
+
|| tabs.coordination === expectedCoordination)
|
|
631
|
+
&& (!Object.hasOwn(tabs, "concurrent")
|
|
632
|
+
|| tabs.concurrent === expectedConcurrent);
|
|
633
|
+
}
|
|
634
|
+
function includesString(value, expected) {
|
|
635
|
+
return Array.isArray(value) && value.includes(expected);
|
|
636
|
+
}
|
|
637
|
+
function backendRuntimeIdentity(rawOverrides = {}) {
|
|
638
|
+
const overrides = validateIdentityOverrides(rawOverrides);
|
|
639
|
+
return {
|
|
640
|
+
backendSessionId: identityString(overrides.backendSessionId ?? PROCESS_BACKEND_SESSION_ID, "backendSessionId"),
|
|
641
|
+
packageName: identityString(overrides.packageName ?? process.env.CHATGPT_BROWSER_CONTROL_PACKAGE_NAME ?? "codex-chatgpt-control", "packageName"),
|
|
642
|
+
packageVersion: identityString(overrides.packageVersion ?? process.env.CHATGPT_BROWSER_CONTROL_PACKAGE_VERSION ?? "unknown", "packageVersion"),
|
|
643
|
+
runtime: "node",
|
|
644
|
+
runtimeVersion: identityString(overrides.runtimeVersion ?? process.env.CHATGPT_BROWSER_CONTROL_RUNTIME_VERSION ?? process.version, "runtimeVersion"),
|
|
645
|
+
buildDigest: identityString(overrides.buildDigest
|
|
646
|
+
?? process.env.CHATGPT_BROWSER_CONTROL_BUILD_DIGEST
|
|
647
|
+
?? process.env.CHATGPT_BROWSER_CONTROL_BUILD_SHA
|
|
648
|
+
?? "unknown", "buildDigest"),
|
|
649
|
+
protocolVersion: BACKEND_REQUEST_SCHEMA_VERSION
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function validateIdentityOverrides(value) {
|
|
653
|
+
if (value === undefined)
|
|
654
|
+
return {};
|
|
655
|
+
if (!isRecord(value))
|
|
656
|
+
throw new TypeError("backendIdentity must be an object when provided.");
|
|
657
|
+
const allowed = new Set(["backendSessionId", "packageName", "packageVersion", "runtimeVersion", "buildDigest"]);
|
|
658
|
+
if (Object.keys(value).some(key => !allowed.has(key))) {
|
|
659
|
+
throw new TypeError("backendIdentity contains unsupported fields.");
|
|
660
|
+
}
|
|
661
|
+
for (const [key, field] of Object.entries(value)) {
|
|
662
|
+
identityString(field, key);
|
|
663
|
+
}
|
|
664
|
+
return value;
|
|
665
|
+
}
|
|
666
|
+
function identityString(value, label) {
|
|
667
|
+
if (typeof value !== "string"
|
|
668
|
+
|| value.length === 0
|
|
669
|
+
|| value.length > MAX_IDENTITY_FIELD_LENGTH
|
|
670
|
+
|| value.trim() !== value
|
|
671
|
+
|| /[\u0000-\u001f\u007f]/u.test(value)) {
|
|
672
|
+
throw new TypeError(`backend identity ${label} must be a bounded, non-empty string.`);
|
|
673
|
+
}
|
|
674
|
+
return value;
|
|
675
|
+
}
|
|
205
676
|
function agentConfig(payload) {
|
|
206
677
|
return requiredRecord(payload, "agent");
|
|
207
678
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Readable, Writable } from "node:stream";
|
|
2
|
-
import { BackendSession } from "./session.js";
|
|
2
|
+
import { BackendSession, type BackendSessionOptions } from "./session.js";
|
|
3
3
|
export type BackendStdioServerOptions = {
|
|
4
4
|
input: Readable;
|
|
5
5
|
output: Writable;
|
|
6
6
|
error?: Writable;
|
|
7
7
|
session?: BackendSession;
|
|
8
|
+
backendIdentity?: BackendSessionOptions["backendIdentity"];
|
|
9
|
+
maxInFlight?: number;
|
|
10
|
+
frameLimitBytes?: number;
|
|
8
11
|
};
|
|
9
12
|
export declare function runBackendStdioServer(options: BackendStdioServerOptions): Promise<void>;
|