@opengeni/runtime 4.0.1 → 4.0.3-canary.36199476632001

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.
Files changed (61) hide show
  1. package/dist/{agent-RJQLKFIW.js → agent-ME6HT4DH.js} +2 -2
  2. package/dist/assets/codemode-client.json +1 -1
  3. package/dist/browser-action-json-schema.d.ts +4 -0
  4. package/dist/{chunk-J5AR5XAJ.js → chunk-FAFZCSN7.js} +695 -210
  5. package/dist/chunk-FAFZCSN7.js.map +1 -0
  6. package/dist/{chunk-ZG2YH25H.js → chunk-JAYHA6BF.js} +2 -2
  7. package/dist/{chunk-UNICCRW5.js → chunk-LZIXCZUV.js} +6 -3
  8. package/dist/{chunk-UNICCRW5.js.map → chunk-LZIXCZUV.js.map} +1 -1
  9. package/dist/{chunk-J6J3VYFW.js → chunk-P4V7JGQ2.js} +1037 -105
  10. package/dist/chunk-P4V7JGQ2.js.map +1 -0
  11. package/dist/{chunk-SPT3PLMX.js → chunk-PRHMSM6C.js} +2 -2
  12. package/dist/codex-tool-search.d.ts +12 -0
  13. package/dist/context-compaction.d.ts +4 -2
  14. package/dist/index.d.ts +27 -8
  15. package/dist/index.js +23 -7
  16. package/dist/interaction-tools.d.ts +1 -1
  17. package/dist/{lazy-manifest-OEYEHNVY.js → lazy-manifest-GCGUFIWP.js} +3 -3
  18. package/dist/{localSources-TWHTEKGO.js → localSources-FDH65AFI.js} +4 -4
  19. package/dist/metrics.d.ts +17 -0
  20. package/dist/model-provider-routing.d.ts +14 -0
  21. package/dist/operational-instructions.d.ts +1 -1
  22. package/dist/provider-quota.d.ts +76 -0
  23. package/dist/sandbox/browser-control-client.d.ts +28 -1
  24. package/dist/sandbox/channel-a.d.ts +43 -0
  25. package/dist/sandbox/index.d.ts +3 -3
  26. package/dist/sandbox/index.js +10 -6
  27. package/dist/sandbox/providers/modal-command-router-wire.d.ts +8 -0
  28. package/dist/sandbox/providers/modal.d.ts +5 -6
  29. package/dist/workspace-tool-gateway.js +5 -5
  30. package/package.json +11 -11
  31. package/src/browser-action-json-schema.ts +10 -0
  32. package/src/bundled_artifact_skills/opengeni-documents/SKILL.md +4 -1
  33. package/src/bundled_artifact_skills/opengeni-documents/references/api.md +20 -0
  34. package/src/bundled_default_skills/opengeni-client/SKILL.md +4 -1
  35. package/src/bundled_default_skills/opengeni-client/references/discovery-and-autonomy.md +31 -0
  36. package/src/bundled_default_skills/opengeni-client/references/runtime-profile-and-verification.md +32 -0
  37. package/src/codex-tool-search.ts +54 -6
  38. package/src/context-compaction.ts +19 -3
  39. package/src/index.ts +285 -56
  40. package/src/interaction-tools.ts +656 -48
  41. package/src/lazy-tool-transport.ts +4 -0
  42. package/src/metrics.ts +26 -0
  43. package/src/model-context-inspector.ts +1 -0
  44. package/src/model-provider-client.ts +37 -16
  45. package/src/model-provider-routing.ts +32 -6
  46. package/src/operational-instructions.ts +1 -1
  47. package/src/provider-quota.ts +412 -0
  48. package/src/sandbox/browser-control-client.ts +241 -26
  49. package/src/sandbox/channel-a.ts +370 -0
  50. package/src/sandbox/index.ts +6 -1
  51. package/src/sandbox/providers/modal-command-control.ts +7 -1
  52. package/src/sandbox/providers/modal-command-router-wire.ts +47 -6
  53. package/src/sandbox/providers/modal.ts +16 -24
  54. package/src/sandbox/routing/routing-session.ts +29 -6
  55. package/dist/chunk-J5AR5XAJ.js.map +0 -1
  56. package/dist/chunk-J6J3VYFW.js.map +0 -1
  57. /package/dist/{agent-RJQLKFIW.js.map → agent-ME6HT4DH.js.map} +0 -0
  58. /package/dist/{chunk-ZG2YH25H.js.map → chunk-JAYHA6BF.js.map} +0 -0
  59. /package/dist/{chunk-SPT3PLMX.js.map → chunk-PRHMSM6C.js.map} +0 -0
  60. /package/dist/{lazy-manifest-OEYEHNVY.js.map → lazy-manifest-GCGUFIWP.js.map} +0 -0
  61. /package/dist/{localSources-TWHTEKGO.js.map → localSources-FDH65AFI.js.map} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { posix as posixPath } from "node:path";
3
+ import { parseBrowserFrameMetadata, type BrowserFrameMetadata } from "@opengeni/sdk";
3
4
  import {
4
5
  BROWSER_CONTROL_MAX_JSON_BYTES,
5
6
  BROWSER_CONTROL_PORT,
@@ -14,6 +15,8 @@ import {
14
15
  BrowserDownloadExportReceipt,
15
16
  BrowserDownloadExportRequest,
16
17
  BrowserDownloadListResponse,
18
+ BrowserDomReadRequest,
19
+ BrowserDomReadResponse,
17
20
  BrowserExternalAuthCommand,
18
21
  BrowserExternalAuthResult,
19
22
  BrowserObservation,
@@ -21,6 +24,7 @@ import {
21
24
  BrowserProtectedAuthFillReceipt,
22
25
  BrowserRevisionMaterialization,
23
26
  BrowserTarget,
27
+ BrowserTargetState,
24
28
  BrowserWorkspaceFileStageRequest,
25
29
  BrowserWorkspaceFileStageResponse,
26
30
  ComputerActionCommand,
@@ -40,6 +44,8 @@ import {
40
44
  type BrowserDownloadExportReceipt as BrowserDownloadExportReceiptValue,
41
45
  type BrowserDownloadExportRequest as BrowserDownloadExportRequestValue,
42
46
  type BrowserDownloadListResponse as BrowserDownloadListResponseValue,
47
+ type BrowserDomReadRequest as BrowserDomReadRequestValue,
48
+ type BrowserDomReadResponse as BrowserDomReadResponseValue,
43
49
  type BrowserExternalAuthCommand as BrowserExternalAuthCommandValue,
44
50
  type BrowserExternalAuthResult as BrowserExternalAuthResultValue,
45
51
  type BrowserDiagnosticKind,
@@ -48,6 +54,7 @@ import {
48
54
  type BrowserProtectedAuthFillReceipt as BrowserProtectedAuthFillReceiptValue,
49
55
  type BrowserRevisionMaterialization as BrowserRevisionMaterializationValue,
50
56
  type BrowserTarget as BrowserTargetValue,
57
+ type BrowserTargetState as BrowserTargetStateValue,
51
58
  type BrowserWorkspaceFileStageRequest as BrowserWorkspaceFileStageRequestValue,
52
59
  type BrowserWorkspaceFileStageResponse as BrowserWorkspaceFileStageResponseValue,
53
60
  type ComputerActionCommand as ComputerActionCommandValue,
@@ -165,6 +172,35 @@ export type ComputerControlFrame = {
165
172
  metadata: ComputerControlFrameMetadata;
166
173
  };
167
174
 
175
+ export type BrowserControlFrame = {
176
+ data: Uint8Array;
177
+ mediaType: "image/jpeg" | "image/png";
178
+ metadataHeader: string;
179
+ metadata: BrowserFrameMetadata;
180
+ };
181
+
182
+ export type BrowserControlScreenshotOptions = {
183
+ fullPage?: boolean;
184
+ format?: "jpeg" | "png";
185
+ quality?: number;
186
+ };
187
+
188
+ type ExpectedBrowserFrameEvidence = {
189
+ browserSessionId: string;
190
+ controllerGeneration: string;
191
+ targetId: string;
192
+ };
193
+
194
+ type FrameRequest = {
195
+ method: "GET";
196
+ path: string;
197
+ token: string;
198
+ timeoutMs?: number;
199
+ } & (
200
+ | { surface: "browser"; expectedFrameEvidence: ExpectedBrowserFrameEvidence }
201
+ | { surface: "computer"; expectedFrameEvidence: ExpectedComputerFrameEvidence }
202
+ );
203
+
168
204
  export type ComputerControlFrameMetadata = {
169
205
  frameId: string;
170
206
  computerSessionId: string;
@@ -947,7 +983,17 @@ export class BrowserControlClient {
947
983
  expectedFrameEvidence: ExpectedComputerFrameEvidence;
948
984
  timeoutMs?: number;
949
985
  }): Promise<ComputerControlFrame> {
950
- return await this.requestBytes(input);
986
+ return (await this.requestBytes({ ...input, surface: "computer" })) as ComputerControlFrame;
987
+ }
988
+
989
+ async requestBrowserBytesForSession(input: {
990
+ method: "GET";
991
+ path: string;
992
+ token: string;
993
+ expectedFrameEvidence: ExpectedBrowserFrameEvidence;
994
+ timeoutMs?: number;
995
+ }): Promise<BrowserControlFrame> {
996
+ return (await this.requestBytes({ ...input, surface: "browser" })) as BrowserControlFrame;
951
997
  }
952
998
 
953
999
  private async requestJson(
@@ -1124,15 +1170,9 @@ export class BrowserControlClient {
1124
1170
  }
1125
1171
 
1126
1172
  private async requestBytes(
1127
- input: {
1128
- method: "GET";
1129
- path: string;
1130
- token: string;
1131
- expectedFrameEvidence: ExpectedComputerFrameEvidence;
1132
- timeoutMs?: number;
1133
- },
1173
+ input: FrameRequest,
1134
1174
  retryNativeEndpoint = true,
1135
- ): Promise<ComputerControlFrame> {
1175
+ ): Promise<ComputerControlFrame | BrowserControlFrame> {
1136
1176
  const requireHostFetch = this.session.requireHostFetchController === true;
1137
1177
  if (this.session.resolveExposedPort && !this.session.ensureBrowserControl) {
1138
1178
  try {
@@ -1247,10 +1287,10 @@ export class BrowserControlClient {
1247
1287
  const data = await readBytes(
1248
1288
  this.session,
1249
1289
  responsePath,
1250
- COMPUTER_SCREENSHOT_MAX_BYTES,
1290
+ input.surface === "browser" ? 24 * 1024 * 1024 : COMPUTER_SCREENSHOT_MAX_BYTES,
1251
1291
  timeoutMs,
1252
1292
  );
1253
- return computerControlFrame(data, headers, input.expectedFrameEvidence);
1293
+ return controllerImageFrame(data, headers, input);
1254
1294
  } catch (error) {
1255
1295
  if (
1256
1296
  error instanceof BrowserControlRequestError ||
@@ -1432,6 +1472,104 @@ export class BrowserControlSessionClient {
1432
1472
  );
1433
1473
  }
1434
1474
 
1475
+ async targetState(targetId: string): Promise<BrowserTargetStateValue> {
1476
+ let state: BrowserTargetStateValue;
1477
+ try {
1478
+ state = BrowserTargetState.parse(
1479
+ await this.parent.requestForSession({
1480
+ method: "GET",
1481
+ path: this.targetPath(targetId, "state"),
1482
+ token: this.viewToken,
1483
+ }),
1484
+ );
1485
+ } catch (error) {
1486
+ // Active Connected Machines can run an older browserd during an API rollout.
1487
+ // Only its exact unknown-route response permits the existing observation path.
1488
+ // A missing session or target must keep its original error.
1489
+ if (
1490
+ !(error instanceof BrowserControlRequestError) ||
1491
+ error.status !== 404 ||
1492
+ error.error.code !== "resource_not_found" ||
1493
+ error.error.message !== "route not found"
1494
+ ) {
1495
+ throw error;
1496
+ }
1497
+ const observation = await this.observe(targetId);
1498
+ state = BrowserTargetState.parse({
1499
+ browserSessionId: observation.browserSessionId,
1500
+ controllerGeneration: observation.target.controllerGeneration,
1501
+ targetId: observation.target.id,
1502
+ targetGeneration: observation.target.targetGeneration,
1503
+ documentGeneration: observation.target.documentGeneration,
1504
+ frameId: observation.frameId,
1505
+ });
1506
+ }
1507
+ if (
1508
+ state.browserSessionId !== this.reference.browserSessionId ||
1509
+ state.controllerGeneration !== this.reference.controllerGeneration ||
1510
+ state.targetId !== targetId
1511
+ ) {
1512
+ throw new BrowserControlProtocolError("browser target state belongs to another binding");
1513
+ }
1514
+ return state;
1515
+ }
1516
+
1517
+ async readDom(
1518
+ targetId: string,
1519
+ requestInput: BrowserDomReadRequestValue,
1520
+ ): Promise<BrowserDomReadResponseValue> {
1521
+ const request = BrowserDomReadRequest.parse(requestInput);
1522
+ const result = BrowserDomReadResponse.parse(
1523
+ await this.parent.requestForSession({
1524
+ method: "POST",
1525
+ path: this.targetPath(targetId, "dom-read"),
1526
+ token: this.viewToken,
1527
+ body: request,
1528
+ }),
1529
+ );
1530
+ if (
1531
+ result.browserSessionId !== this.reference.browserSessionId ||
1532
+ result.controllerGeneration !== this.reference.controllerGeneration ||
1533
+ result.targetId !== targetId ||
1534
+ result.targetGeneration !== request.expectedTargetGeneration ||
1535
+ result.documentGeneration !== request.expectedDocumentGeneration ||
1536
+ result.frameId !== request.expectedFrameId ||
1537
+ result.kind !== request.kind
1538
+ ) {
1539
+ throw new BrowserControlProtocolError("browser DOM read belongs to another binding");
1540
+ }
1541
+ return result;
1542
+ }
1543
+
1544
+ async capture(
1545
+ targetId: string,
1546
+ options: BrowserControlScreenshotOptions = {},
1547
+ ): Promise<BrowserControlFrame> {
1548
+ const query = new URLSearchParams({
1549
+ format: options.format ?? "jpeg",
1550
+ quality: String(boundedInteger(options.quality ?? 55, 1, 100, "browser screenshot quality")),
1551
+ });
1552
+ if (options.format !== undefined && options.format !== "jpeg" && options.format !== "png") {
1553
+ throw new RangeError("browser screenshot format is invalid");
1554
+ }
1555
+ if (options.fullPage !== undefined) {
1556
+ if (typeof options.fullPage !== "boolean") {
1557
+ throw new RangeError("browser screenshot fullPage is invalid");
1558
+ }
1559
+ query.set("fullPage", String(options.fullPage));
1560
+ }
1561
+ return await this.parent.requestBrowserBytesForSession({
1562
+ method: "GET",
1563
+ path: this.targetPath(targetId, `screenshot?${query}`),
1564
+ token: this.viewToken,
1565
+ expectedFrameEvidence: {
1566
+ browserSessionId: this.reference.browserSessionId,
1567
+ controllerGeneration: this.reference.controllerGeneration,
1568
+ targetId: requireOpaqueId(targetId, "browser target id"),
1569
+ },
1570
+ });
1571
+ }
1572
+
1435
1573
  async readClipboard(): Promise<BrowserClipboardValue> {
1436
1574
  return BrowserClipboard.parse(
1437
1575
  await this.parent.requestForSession({
@@ -1840,15 +1978,9 @@ async function requestExposedController(
1840
1978
 
1841
1979
  async function requestExposedControllerBytes(
1842
1980
  endpoint: ExposedPortEndpoint,
1843
- input: {
1844
- method: "GET";
1845
- path: string;
1846
- token: string;
1847
- expectedFrameEvidence: ExpectedComputerFrameEvidence;
1848
- timeoutMs?: number;
1849
- },
1981
+ input: FrameRequest,
1850
1982
  defaultTimeoutMs: number,
1851
- ): Promise<ComputerControlFrame> {
1983
+ ): Promise<ComputerControlFrame | BrowserControlFrame> {
1852
1984
  const token = requireToken(input.token, "browser controller token");
1853
1985
  const timeoutMs = boundedTimeout(input.timeoutMs ?? defaultTimeoutMs);
1854
1986
  const streamUrl = exposedControllerUrl(endpoint, input.path);
@@ -1872,12 +2004,91 @@ async function requestExposedControllerBytes(
1872
2004
  throw new BrowserControlProtocolError("browser controller image response is invalid");
1873
2005
  }
1874
2006
  const declaredLength = Number(response.headers.get("content-length"));
1875
- if (Number.isFinite(declaredLength) && declaredLength > COMPUTER_SCREENSHOT_MAX_BYTES) {
1876
- await response.body?.cancel("computer frame exceeds its byte bound").catch(() => undefined);
1877
- throw new RangeError("computer frame exceeds its byte bound");
2007
+ const maxBytes = input.surface === "browser" ? 24 * 1024 * 1024 : COMPUTER_SCREENSHOT_MAX_BYTES;
2008
+ if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {
2009
+ await response.body?.cancel("frame exceeds its byte bound").catch(() => undefined);
2010
+ throw new RangeError("frame exceeds its byte bound");
2011
+ }
2012
+ const data = await readBoundedFrameResponse(response, maxBytes);
2013
+ return controllerImageFrame(data, response.headers, input);
2014
+ }
2015
+
2016
+ async function readBoundedFrameResponse(response: Response, maxBytes: number): Promise<Uint8Array> {
2017
+ if (!response.body) throw new BrowserControlProtocolError("browser controller image is empty");
2018
+ const reader = response.body.getReader();
2019
+ const chunks: Uint8Array[] = [];
2020
+ let size = 0;
2021
+ try {
2022
+ for (;;) {
2023
+ const { done, value } = await reader.read();
2024
+ if (done) break;
2025
+ size += value.byteLength;
2026
+ if (size > maxBytes) {
2027
+ await reader.cancel("frame exceeds its byte bound").catch(() => undefined);
2028
+ throw new RangeError("frame exceeds its byte bound");
2029
+ }
2030
+ chunks.push(value);
2031
+ }
2032
+ } finally {
2033
+ reader.releaseLock();
1878
2034
  }
1879
- const data = new Uint8Array(await response.arrayBuffer());
1880
- return computerControlFrame(data, response.headers, input.expectedFrameEvidence);
2035
+ const data = new Uint8Array(size);
2036
+ let offset = 0;
2037
+ for (const chunk of chunks) {
2038
+ data.set(chunk, offset);
2039
+ offset += chunk.byteLength;
2040
+ }
2041
+ return data;
2042
+ }
2043
+
2044
+ function controllerImageFrame(
2045
+ data: Uint8Array,
2046
+ headers: { get(name: string): string | null | undefined },
2047
+ input: FrameRequest,
2048
+ ): ComputerControlFrame | BrowserControlFrame {
2049
+ return input.surface === "browser"
2050
+ ? browserControlFrame(data, headers, input.expectedFrameEvidence)
2051
+ : computerControlFrame(data, headers, input.expectedFrameEvidence);
2052
+ }
2053
+
2054
+ function browserControlFrame(
2055
+ data: Uint8Array,
2056
+ headers: { get(name: string): string | null | undefined },
2057
+ expected: ExpectedBrowserFrameEvidence,
2058
+ ): BrowserControlFrame {
2059
+ if (data.byteLength < 1 || data.byteLength > 24 * 1024 * 1024) {
2060
+ throw new RangeError("browser frame exceeds its byte bound");
2061
+ }
2062
+ const get = (name: string): string | null => headers.get(name.toLowerCase()) ?? null;
2063
+ const mediaType = get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
2064
+ if (mediaType !== "image/jpeg" && mediaType !== "image/png") {
2065
+ throw new BrowserControlProtocolError("browser frame media type is invalid");
2066
+ }
2067
+ const metadataHeader = get("x-opengeni-browser-frame");
2068
+ if (
2069
+ !metadataHeader ||
2070
+ metadataHeader.length > 64 * 1024 ||
2071
+ !/^[A-Za-z0-9_-]+$/u.test(metadataHeader)
2072
+ ) {
2073
+ throw new BrowserControlProtocolError("browser frame metadata is invalid");
2074
+ }
2075
+ let metadata: BrowserFrameMetadata;
2076
+ try {
2077
+ metadata = parseBrowserFrameMetadata(
2078
+ JSON.parse(Buffer.from(metadataHeader, "base64url").toString("utf8")),
2079
+ );
2080
+ } catch {
2081
+ throw new BrowserControlProtocolError("browser frame metadata is invalid");
2082
+ }
2083
+ if (
2084
+ metadata.browserSessionId !== expected.browserSessionId ||
2085
+ metadata.controllerGeneration !== expected.controllerGeneration ||
2086
+ metadata.targetId !== expected.targetId ||
2087
+ metadata.mediaType !== mediaType
2088
+ ) {
2089
+ throw new BrowserControlProtocolError("browser frame evidence does not match its request");
2090
+ }
2091
+ return { data, mediaType, metadataHeader, metadata };
1881
2092
  }
1882
2093
 
1883
2094
  function computerControlFrame(
@@ -2764,7 +2975,11 @@ async function readBytes(
2764
2975
  timeoutMs: number,
2765
2976
  ): Promise<Uint8Array> {
2766
2977
  const privatePath = absolutePrivatePath(path, "browser private binary response path");
2767
- if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > COMPUTER_SCREENSHOT_MAX_BYTES) {
2978
+ if (
2979
+ !Number.isSafeInteger(maxBytes) ||
2980
+ maxBytes < 1 ||
2981
+ maxBytes > Math.max(24 * 1024 * 1024, COMPUTER_SCREENSHOT_MAX_BYTES)
2982
+ ) {
2768
2983
  throw new RangeError("browser private binary response limit is invalid");
2769
2984
  }
2770
2985
  const sizeMarker = `OPENGENI_BROWSER_PRIVATE_SIZE_${randomUUID()}`;
@@ -2783,7 +2998,7 @@ async function readBytes(
2783
2998
  "browser private binary response size",
2784
2999
  );
2785
3000
  if (size < 1 || size > maxBytes) {
2786
- throw new RangeError("computer frame exceeds its byte bound");
3001
+ throw new RangeError("frame exceeds its byte bound");
2787
3002
  }
2788
3003
  const chunks: Buffer[] = [];
2789
3004
  for (let offset = 0; offset < size; offset += PRIVATE_READ_CHUNK_BYTES) {