@opengeni/runtime 3.1.3-canary.38890816741001 → 3.3.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.
@@ -67,6 +67,7 @@ export interface SelfhostedConnectionBinding {
67
67
  operationResourcePolicySupported: boolean;
68
68
  operationCpuQuotaSupported: boolean;
69
69
  transactionalFsWriteSupported?: boolean;
70
+ browserControlHttpSupported?: boolean;
70
71
  }
71
72
 
72
73
  export interface ActiveBackendResolverDeps {
@@ -406,6 +407,7 @@ export function makeActiveBackendResolver(
406
407
  operationResourcePolicySupported: connection.operationResourcePolicySupported,
407
408
  operationCpuQuotaSupported: connection.operationCpuQuotaSupported,
408
409
  transactionalFsWriteSupported: connection.transactionalFsWriteSupported === true,
410
+ browserControlHttpSupported: connection.browserControlHttpSupported === true,
409
411
  // The routing proxy caches this session by sandbox+epoch, but command
410
412
  // policy and runner authority are mutable. Re-read one coherent DB
411
413
  // snapshot only when a new exec/Git is admitted.
@@ -45,6 +45,11 @@ import {
45
45
  import { Manifest } from "@openai/agents/sandbox";
46
46
  import { formatExecResponse } from "@openai/agents-core/sandbox/internal";
47
47
  import type { ExposedPortEndpoint } from "../stream-port";
48
+ import {
49
+ BROWSER_CONTROL_HTTP_REPLY_GRACE_MS,
50
+ type BrowserControlHttpCall,
51
+ type BrowserControlHttpOutcome,
52
+ } from "../browser-control-http";
48
53
  import {
49
54
  agentErrorToControlError,
50
55
  drainingExhaustedError,
@@ -285,6 +290,8 @@ export interface SelfhostedBackgroundCommandAdoption {
285
290
  * every exec/Git admission; retries and already-started operations retain it. */
286
291
  export interface SelfhostedOperationAdmission {
287
292
  transactionalFsWriteSupported?: boolean;
293
+ /** The live runner serves in-process browser/computer controller requests. */
294
+ browserControlHttpSupported?: boolean;
288
295
  /** Workspace segment of the physical agent/relay route. Personal machines may
289
296
  * originate in a different same-organization workspace than the session. */
290
297
  workspaceId?: string;
@@ -309,6 +316,9 @@ export interface SelfhostedOperationAdmission {
309
316
  export interface SelfhostedSessionDeps {
310
317
  /** Exact live daemon capability; absent preserves legacy small-file writes. */
311
318
  transactionalFsWriteSupported?: boolean;
319
+ /** Exact live daemon capability; absent keeps controller requests on the
320
+ * command transport. */
321
+ browserControlHttpSupported?: boolean;
312
322
  /** Authorization/session workspace. */
313
323
  workspaceId: string;
314
324
  /** Physical control-plane workspace. Defaults to workspaceId for legacy and
@@ -521,6 +531,7 @@ export class SelfhostedSession {
521
531
  private readonly resourcePolicySupported: boolean;
522
532
  private readonly operationCpuQuotaSupported: boolean;
523
533
  private readonly transactionalFsWriteSupported: boolean;
534
+ private readonly browserControlHttpSupported: boolean;
524
535
  private readonly defaultOpStream: SelfhostedOpStreamDeps | undefined;
525
536
  private readonly connectionInstanceId: string;
526
537
  private readonly resolveOperationAdmission:
@@ -594,6 +605,7 @@ export class SelfhostedSession {
594
605
  this.resourcePolicySupported = deps.operationResourcePolicySupported === true;
595
606
  this.operationCpuQuotaSupported = deps.operationCpuQuotaSupported === true;
596
607
  this.transactionalFsWriteSupported = deps.transactionalFsWriteSupported === true;
608
+ this.browserControlHttpSupported = deps.browserControlHttpSupported === true;
597
609
  this.defaultOpStream = deps.opStream;
598
610
  this.connectionInstanceId = deps.connectionInstanceId;
599
611
  this.resolveOperationAdmission = deps.resolveOperationAdmission;
@@ -612,6 +624,7 @@ export class SelfhostedSession {
612
624
  resourcePolicy: this.resourcePolicy,
613
625
  opStream: deps.opStream,
614
626
  transactionalFsWriteSupported: this.transactionalFsWriteSupported,
627
+ browserControlHttpSupported: this.browserControlHttpSupported,
615
628
  })
616
629
  : undefined;
617
630
  // A valid Manifest whose root is the machine's actual effective root. There
@@ -680,6 +693,7 @@ export class SelfhostedSession {
680
693
 
681
694
  private async admitOperation(commandPolicy: boolean): Promise<{
682
695
  transactionalFsWriteSupported: boolean;
696
+ browserControlHttpSupported: boolean;
683
697
  controlWorkspaceId: string;
684
698
  connectionInstanceId: string;
685
699
  subject: string;
@@ -701,6 +715,7 @@ export class SelfhostedSession {
701
715
  resourcePolicy: commandPolicy ? this.resourcePolicy : undefined,
702
716
  opStream: this.defaultOpStream,
703
717
  transactionalFsWriteSupported: this.transactionalFsWriteSupported,
718
+ browserControlHttpSupported: this.browserControlHttpSupported,
704
719
  };
705
720
  }
706
721
 
@@ -736,6 +751,7 @@ export class SelfhostedSession {
736
751
  resourcePolicy: commandPolicy ? resourcePolicy : undefined,
737
752
  opStream: resolved.opStream,
738
753
  transactionalFsWriteSupported: resolved.transactionalFsWriteSupported === true,
754
+ browserControlHttpSupported: resolved.browserControlHttpSupported === true,
739
755
  };
740
756
  }
741
757
 
@@ -1955,6 +1971,99 @@ export class SelfhostedSession {
1955
1971
  return result.browserControlEnsure;
1956
1972
  }
1957
1973
 
1974
+ /** Send one request to the agent-owned controller of an exact authority
1975
+ * scope, served inside the runner over loopback without starting a process.
1976
+ * `unsupported` means this connection's runner does not serve it and nothing
1977
+ * was sent. `controller_absent` means no controller for that scope and
1978
+ * generation accepted the request, so it was not delivered and the caller may
1979
+ * ensure the controller and send again. A body too large for one reply is
1980
+ * drained from the runner's spool; the request is never repeated. */
1981
+ async browserControlHttp(request: BrowserControlHttpCall): Promise<BrowserControlHttpOutcome> {
1982
+ const admission = await this.admitOperation(false);
1983
+ if (!admission.browserControlHttpSupported) return { kind: "unsupported" };
1984
+ // The runner bounds the request by timeoutMs; allow the reply to arrive.
1985
+ const rpcTimeoutMs = request.timeoutMs + BROWSER_CONTROL_HTTP_REPLY_GRACE_MS;
1986
+ let result: NonNullable<ControlResponse["result"]>;
1987
+ try {
1988
+ result = await this.call(
1989
+ {
1990
+ $case: "browserControlHttp",
1991
+ browserControlHttp: {
1992
+ scopeId: request.scopeId,
1993
+ scopeGeneration: request.scopeGeneration,
1994
+ method: request.method,
1995
+ path: request.path,
1996
+ bearerToken: request.bearerToken,
1997
+ body: request.body ?? new Uint8Array(),
1998
+ hasBody: request.body !== undefined,
1999
+ timeoutMs: request.timeoutMs,
2000
+ maxResponseBytes: String(request.maxResponseBytes),
2001
+ },
2002
+ },
2003
+ rpcTimeoutMs,
2004
+ admission,
2005
+ );
2006
+ } catch (error) {
2007
+ if (
2008
+ error instanceof SelfhostedControlError &&
2009
+ error.code === ErrorCode.ERROR_CODE_NOT_FOUND
2010
+ ) {
2011
+ return { kind: "controller_absent" };
2012
+ }
2013
+ throw error;
2014
+ }
2015
+ if (result.$case !== "browserControlHttp") {
2016
+ throw new Error(`selfhosted browserControlHttp: unexpected result ${result.$case}`);
2017
+ }
2018
+ const response = result.browserControlHttp;
2019
+ const totalBytes = Number(response.totalBytes);
2020
+ if (
2021
+ !Number.isSafeInteger(totalBytes) ||
2022
+ totalBytes < response.body.byteLength ||
2023
+ totalBytes > request.maxResponseBytes
2024
+ ) {
2025
+ throw new Error("selfhosted browserControlHttp: response length is invalid");
2026
+ }
2027
+ let body = response.body;
2028
+ if (response.spoolId) {
2029
+ const complete = new Uint8Array(totalBytes);
2030
+ complete.set(response.body, 0);
2031
+ let offset = response.body.byteLength;
2032
+ for (;;) {
2033
+ const read = await this.call(
2034
+ {
2035
+ $case: "browserControlHttpRead",
2036
+ browserControlHttpRead: { spoolId: response.spoolId, offset: String(offset) },
2037
+ },
2038
+ this.timeoutMs,
2039
+ admission,
2040
+ );
2041
+ if (read.$case !== "browserControlHttpRead") {
2042
+ throw new Error(`selfhosted browserControlHttpRead: unexpected result ${read.$case}`);
2043
+ }
2044
+ const part = read.browserControlHttpRead;
2045
+ if (offset + part.data.byteLength > totalBytes) {
2046
+ throw new Error("selfhosted browserControlHttpRead: response exceeds its length");
2047
+ }
2048
+ complete.set(part.data, offset);
2049
+ offset += part.data.byteLength;
2050
+ if (part.done) break;
2051
+ if (part.data.byteLength === 0) {
2052
+ throw new Error("selfhosted browserControlHttpRead: spool made no progress");
2053
+ }
2054
+ }
2055
+ if (offset !== totalBytes) {
2056
+ throw new Error("selfhosted browserControlHttpRead: response is incomplete");
2057
+ }
2058
+ body = complete;
2059
+ } else if (response.body.byteLength !== totalBytes) {
2060
+ throw new Error("selfhosted browserControlHttp: response is incomplete");
2061
+ }
2062
+ const headers = new Map<string, string>();
2063
+ for (const header of response.headers) headers.set(header.name.toLowerCase(), header.value);
2064
+ return { kind: "response", status: response.status, headers, body };
2065
+ }
2066
+
1958
2067
  /** Open one browser-native frame producer and return its canonical relay
1959
2068
  * endpoint. This does not route through `resolveExposedPort`: that legacy
1960
2069
  * method allocates PTY/desktop resources based on fixed ports, while this op
@@ -2145,6 +2254,7 @@ export class SelfhostedSandboxClient {
2145
2254
  private readonly operationResourcePolicySupported: boolean | undefined;
2146
2255
  private readonly operationCpuQuotaSupported: boolean | undefined;
2147
2256
  private readonly transactionalFsWriteSupported: boolean | undefined;
2257
+ private readonly browserControlHttpSupported: boolean | undefined;
2148
2258
  private readonly resolveOperationAdmission:
2149
2259
  | (() => Promise<SelfhostedOperationAdmission | null>)
2150
2260
  | undefined;
@@ -2186,6 +2296,7 @@ export class SelfhostedSandboxClient {
2186
2296
  operationResourcePolicySupported?: boolean;
2187
2297
  operationCpuQuotaSupported?: boolean;
2188
2298
  transactionalFsWriteSupported?: boolean;
2299
+ browserControlHttpSupported?: boolean;
2189
2300
  resolveOperationAdmission?: () => Promise<SelfhostedOperationAdmission | null>;
2190
2301
  adoptBackgroundCommand?: SelfhostedSessionDeps["adoptBackgroundCommand"];
2191
2302
  settleBackgroundCommand?: SelfhostedSessionDeps["settleBackgroundCommand"];
@@ -2218,6 +2329,7 @@ export class SelfhostedSandboxClient {
2218
2329
  this.operationResourcePolicySupported = opts.operationResourcePolicySupported;
2219
2330
  this.operationCpuQuotaSupported = opts.operationCpuQuotaSupported;
2220
2331
  this.transactionalFsWriteSupported = opts.transactionalFsWriteSupported;
2332
+ this.browserControlHttpSupported = opts.browserControlHttpSupported;
2221
2333
  this.resolveOperationAdmission = opts.resolveOperationAdmission;
2222
2334
  this.adoptBackgroundCommand = opts.adoptBackgroundCommand;
2223
2335
  this.settleBackgroundCommand = opts.settleBackgroundCommand;
@@ -2262,6 +2374,7 @@ export class SelfhostedSandboxClient {
2262
2374
  ? { operationCpuQuotaSupported: this.operationCpuQuotaSupported }
2263
2375
  : {}),
2264
2376
  transactionalFsWriteSupported: this.transactionalFsWriteSupported === true,
2377
+ browserControlHttpSupported: this.browserControlHttpSupported === true,
2265
2378
  ...(this.resolveOperationAdmission !== undefined
2266
2379
  ? { resolveOperationAdmission: this.resolveOperationAdmission }
2267
2380
  : {}),
@@ -2382,6 +2495,8 @@ export interface SelfhostedSessionBuild {
2382
2495
  /** Exact live CPU enforcement capability paired with the initial snapshot. */
2383
2496
  operationCpuQuotaSupported?: boolean;
2384
2497
  transactionalFsWriteSupported?: boolean;
2498
+ /** Exact live runner capability for in-process controller requests. */
2499
+ browserControlHttpSupported?: boolean;
2385
2500
  /** Live last-boundary operation admission resolver; see SelfhostedSessionDeps. */
2386
2501
  resolveOperationAdmission?: () => Promise<SelfhostedOperationAdmission | null>;
2387
2502
  adoptBackgroundCommand?: SelfhostedSessionDeps["adoptBackgroundCommand"];
@@ -2438,6 +2553,7 @@ export async function buildSelfhostedBackendSession(
2438
2553
  ? { operationCpuQuotaSupported: deps.operationCpuQuotaSupported }
2439
2554
  : {}),
2440
2555
  transactionalFsWriteSupported: deps.transactionalFsWriteSupported === true,
2556
+ browserControlHttpSupported: deps.browserControlHttpSupported === true,
2441
2557
  ...(deps.resolveOperationAdmission !== undefined
2442
2558
  ? { resolveOperationAdmission: deps.resolveOperationAdmission }
2443
2559
  : {}),