agl 23.0.0 → 24.0.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.
Files changed (35) hide show
  1. package/changelog.md +11 -0
  2. package/dist_serve/bundle.js +811 -808
  3. package/dist_serve/bundle.js.map +1 -0
  4. package/dist_ts/00_commitinfo_data.js +1 -1
  5. package/dist_ts/classes.authstore.js +2 -2
  6. package/dist_ts/classes.browserresourcehost.d.ts +1 -0
  7. package/dist_ts/classes.browserresourcehost.js +7 -1
  8. package/dist_ts/classes.controller.d.ts +35 -5
  9. package/dist_ts/classes.controller.js +994 -229
  10. package/dist_ts/classes.validation.d.ts +9 -1
  11. package/dist_ts/classes.validation.js +62 -7
  12. package/dist_ts_interfaces/browsertransport.d.ts +72 -0
  13. package/dist_ts_interfaces/browsertransport.js +47 -0
  14. package/dist_ts_interfaces/index.d.ts +1 -0
  15. package/dist_ts_interfaces/index.js +2 -1
  16. package/dist_ts_interfaces/interfaces.d.ts +10 -6
  17. package/dist_ts_interfaces/interfaces.js +2 -3
  18. package/dist_ts_interfaces/requests.d.ts +20 -21
  19. package/package.json +5 -5
  20. package/readme.md +7 -3
  21. package/ts/00_commitinfo_data.ts +1 -1
  22. package/ts/classes.authstore.ts +1 -1
  23. package/ts/classes.browserresourcehost.ts +7 -0
  24. package/ts/classes.controller.ts +1367 -279
  25. package/ts/classes.validation.ts +77 -6
  26. package/ts_interfaces/browsertransport.ts +126 -0
  27. package/ts_interfaces/index.ts +1 -0
  28. package/ts_interfaces/interfaces.ts +11 -11
  29. package/ts_interfaces/requests.ts +23 -30
  30. package/ts_web/00_commitinfo_data.ts +1 -1
  31. package/ts_web/classes.browserviewtransport.ts +532 -0
  32. package/ts_web/classes.controllersocketclient.ts +6 -17
  33. package/ts_web/elements.harnesscontrollerapp.ts +450 -115
  34. package/ts_web/index.ts +1 -0
  35. package/ts_web/plugins.ts +2 -0
@@ -5,6 +5,7 @@ import {
5
5
  controllerMaxDraftAttachmentTotalBytes,
6
6
  controllerMaxDraftAttachments,
7
7
  controllerMaxDraftTextBytes,
8
+ controllerBrowserTransportProtocol,
8
9
  controllerRuntimeIdKey,
9
10
  controllerSessionHarnessIds,
10
11
  } from '../ts_interfaces/index.js';
@@ -1065,7 +1066,7 @@ const assertBrowserViewport = (
1065
1066
  || typeof value.deviceScaleFactor !== 'number'
1066
1067
  || !Number.isFinite(value.deviceScaleFactor)
1067
1068
  || value.deviceScaleFactor < 0.25
1068
- || value.deviceScaleFactor > 4
1069
+ || value.deviceScaleFactor > 3
1069
1070
  ) throw new Error(`${nameArg} is invalid.`);
1070
1071
  return value as unknown as interfaces.IControllerBrowserViewport;
1071
1072
  };
@@ -1121,21 +1122,50 @@ export const assertBrowserViewCloseRequest = (
1121
1122
  valueArg: unknown,
1122
1123
  ): interfaces.IReq_ControllerBrowserViewClose['request'] => {
1123
1124
  const value = assertObject(valueArg, 'browser view close request');
1124
- assertKeys(value, ['viewId']);
1125
- return { viewId: assertIdentifier(value.viewId, 'viewId') };
1125
+ assertKeys(value, ['viewId', 'expectedStreamGeneration']);
1126
+ return {
1127
+ viewId: assertIdentifier(value.viewId, 'viewId'),
1128
+ expectedStreamGeneration: assertBrowserStreamGeneration(value.expectedStreamGeneration),
1129
+ };
1126
1130
  };
1127
1131
 
1128
1132
  export const assertBrowserViewActivateRequest = (
1129
1133
  valueArg: unknown,
1130
1134
  ): interfaces.IReq_ControllerBrowserViewActivate['request'] => {
1131
1135
  const value = assertObject(valueArg, 'browser view activation request');
1132
- assertKeys(value, ['viewId']);
1133
- return { viewId: assertIdentifier(value.viewId, 'viewId') };
1136
+ assertKeys(value, ['viewId', 'streamGeneration']);
1137
+ return {
1138
+ viewId: assertIdentifier(value.viewId, 'viewId'),
1139
+ streamGeneration: assertBrowserStreamGeneration(value.streamGeneration),
1140
+ };
1141
+ };
1142
+
1143
+ const assertBrowserStreamGeneration = (valueArg: unknown): number => {
1144
+ if (!Number.isSafeInteger(valueArg) || (valueArg as number) < 1) {
1145
+ throw new Error('streamGeneration is invalid.');
1146
+ }
1147
+ return valueArg as number;
1134
1148
  };
1135
1149
 
1150
+ export const assertBrowserViewRecoverRequest = (
1151
+ valueArg: unknown,
1152
+ ): interfaces.IReq_ControllerBrowserViewRecover['request'] => {
1153
+ const value = assertObject(valueArg, 'browser view recovery request');
1154
+ assertKeys(value, ['viewId', 'expectedStreamGeneration']);
1155
+ return {
1156
+ viewId: assertIdentifier(value.viewId, 'viewId'),
1157
+ expectedStreamGeneration: assertBrowserStreamGeneration(value.expectedStreamGeneration),
1158
+ };
1159
+ };
1160
+
1161
+ interface IBrowserViewOperationEnvelope {
1162
+ viewId: string;
1163
+ operation: interfaces.TControllerBrowserViewOperation;
1164
+ }
1165
+
1136
1166
  export const assertBrowserViewOperateRequest = (
1137
1167
  valueArg: unknown,
1138
- ): interfaces.IReq_ControllerBrowserViewOperate['request'] => {
1168
+ ): IBrowserViewOperationEnvelope => {
1139
1169
  const value = assertObject(valueArg, 'browser view operation request');
1140
1170
  assertKeys(value, ['viewId', 'operation']);
1141
1171
  const operation = assertObject(value.operation, 'operation');
@@ -1304,6 +1334,47 @@ export const assertBrowserViewOperateRequest = (
1304
1334
  throw new Error('operation.type is unsupported.');
1305
1335
  };
1306
1336
 
1337
+ export const assertBrowserViewOperation = (
1338
+ valueArg: unknown,
1339
+ ): interfaces.TControllerBrowserViewOperation => assertBrowserViewOperateRequest({
1340
+ viewId: 'browser-operation',
1341
+ operation: valueArg,
1342
+ }).operation;
1343
+
1344
+ export const assertControllerBrowserClientPacket = (
1345
+ valueArg: unknown,
1346
+ ): interfaces.TControllerBrowserClientPacket => {
1347
+ const value = assertObject(valueArg, 'browser transport packet');
1348
+ if (value.protocol !== controllerBrowserTransportProtocol) {
1349
+ throw new Error('browser transport protocol is invalid.');
1350
+ }
1351
+ const streamGeneration = assertBrowserStreamGeneration(value.streamGeneration);
1352
+ if (!Number.isSafeInteger(value.operationId) || (value.operationId as number) < 1) {
1353
+ throw new Error('operationId is invalid.');
1354
+ }
1355
+ const operationId = value.operationId as number;
1356
+ if (value.type === 'operation') {
1357
+ assertKeys(value, ['protocol', 'streamGeneration', 'type', 'operationId', 'operation']);
1358
+ return {
1359
+ protocol: controllerBrowserTransportProtocol,
1360
+ streamGeneration,
1361
+ type: 'operation',
1362
+ operationId,
1363
+ operation: assertBrowserViewOperation(value.operation),
1364
+ };
1365
+ }
1366
+ if (value.type === 'cancel') {
1367
+ assertKeys(value, ['protocol', 'streamGeneration', 'type', 'operationId']);
1368
+ return {
1369
+ protocol: controllerBrowserTransportProtocol,
1370
+ streamGeneration,
1371
+ type: 'cancel',
1372
+ operationId,
1373
+ };
1374
+ }
1375
+ throw new Error('browser transport packet type is unsupported.');
1376
+ };
1377
+
1307
1378
  export const assertTerminalCreateRequest = (
1308
1379
  valueArg: unknown,
1309
1380
  ): interfaces.IReq_ControllerTerminalCreate['request'] => {
@@ -0,0 +1,126 @@
1
+ import type {
2
+ IControllerBrowserFrameMetadata,
3
+ IControllerBrowserViewState,
4
+ TControllerBrowserViewOperation,
5
+ } from './interfaces.js';
6
+
7
+ export const controllerBrowserTransportProtocol = 'agl-browser-v24' as const;
8
+ export const controllerBrowserTransportEventContentType =
9
+ 'application/vnd.agl.browser-events.v24' as const;
10
+ export const controllerBrowserTransportOperationContentType =
11
+ 'application/vnd.agl.browser-operations.v24' as const;
12
+ export const controllerBrowserTransportMaximumJsonBytes = 64 * 1024;
13
+ export const controllerBrowserTransportMaximumFrameBytes = 4 * 1024 * 1024;
14
+ export const controllerBrowserTransportPairOpenTimeoutMs = 9_000;
15
+ export const controllerBrowserTransportRecoveryGraceMs = 15_000;
16
+ export const controllerBrowserTransportMaximumRecoveryAttempts = 3;
17
+ export const controllerBrowserTransportMaximumPendingOperations = 64;
18
+ export const controllerBrowserTransportMaximumQueuedOperationBytes = 256 * 1024;
19
+ export const controllerBrowserTransportMaximumActiveAcknowledgements = 16;
20
+ export const controllerBrowserTransportMaximumPendingEvents = 16;
21
+ export const controllerBrowserTransportMaximumPendingEventBytes = 16 * 1024 * 1024;
22
+
23
+ interface IControllerBrowserTransportPacketBase {
24
+ protocol: typeof controllerBrowserTransportProtocol;
25
+ streamGeneration: number;
26
+ }
27
+
28
+ export interface IControllerBrowserOperationPacket extends IControllerBrowserTransportPacketBase {
29
+ type: 'operation';
30
+ operationId: number;
31
+ operation: TControllerBrowserViewOperation;
32
+ }
33
+
34
+ export interface IControllerBrowserCancelPacket extends IControllerBrowserTransportPacketBase {
35
+ type: 'cancel';
36
+ operationId: number;
37
+ }
38
+
39
+ export type TControllerBrowserClientPacket =
40
+ | IControllerBrowserOperationPacket
41
+ | IControllerBrowserCancelPacket;
42
+
43
+ export type TControllerBrowserOperationResult =
44
+ | {
45
+ status: 'succeeded';
46
+ accepted?: boolean;
47
+ state?: IControllerBrowserViewState;
48
+ }
49
+ | { status: 'failed'; error: { code: string; message: string } }
50
+ | { status: 'cancelled' }
51
+ | { status: 'superseded' };
52
+
53
+ export interface IControllerBrowserStatePacket extends IControllerBrowserTransportPacketBase {
54
+ type: 'state';
55
+ state: IControllerBrowserViewState;
56
+ }
57
+
58
+ export interface IControllerBrowserErrorPacket extends IControllerBrowserTransportPacketBase {
59
+ type: 'error';
60
+ error: { code: string; message: string; fatal: boolean; tabId?: string };
61
+ }
62
+
63
+ export interface IControllerBrowserOperationResultPacket
64
+ extends IControllerBrowserTransportPacketBase {
65
+ type: 'operationResult';
66
+ operationId: number;
67
+ result: TControllerBrowserOperationResult;
68
+ }
69
+
70
+ export interface IControllerBrowserFramePacket extends IControllerBrowserTransportPacketBase {
71
+ type: 'frame';
72
+ frame: IControllerBrowserFrameMetadata;
73
+ }
74
+
75
+ export type TControllerBrowserServerPacket =
76
+ | IControllerBrowserStatePacket
77
+ | IControllerBrowserErrorPacket
78
+ | IControllerBrowserOperationResultPacket
79
+ | IControllerBrowserFramePacket;
80
+
81
+ export class ControllerBrowserTransportProtocolError extends Error {
82
+ constructor(messageArg: string, optionsArg?: ErrorOptions) {
83
+ super(messageArg, optionsArg);
84
+ this.name = 'ControllerBrowserTransportProtocolError';
85
+ }
86
+ }
87
+
88
+ const textEncoder = new TextEncoder();
89
+ const textDecoder = new TextDecoder('utf-8', { fatal: true });
90
+
91
+ export const encodeControllerBrowserTransportPacket = (
92
+ packetArg: TControllerBrowserClientPacket | TControllerBrowserServerPacket,
93
+ ): Uint8Array => {
94
+ let serialized: string;
95
+ try {
96
+ serialized = JSON.stringify(packetArg);
97
+ } catch (errorArg) {
98
+ throw new ControllerBrowserTransportProtocolError(
99
+ 'The browser transport packet is not JSON serializable.',
100
+ { cause: errorArg },
101
+ );
102
+ }
103
+ const bytes = textEncoder.encode(serialized);
104
+ if (bytes.byteLength > controllerBrowserTransportMaximumJsonBytes) {
105
+ throw new ControllerBrowserTransportProtocolError(
106
+ 'The browser transport packet exceeds the JSON byte limit.',
107
+ );
108
+ }
109
+ return bytes;
110
+ };
111
+
112
+ export const decodeControllerBrowserTransportPacket = (bytesArg: Uint8Array): unknown => {
113
+ if (bytesArg.byteLength > controllerBrowserTransportMaximumJsonBytes) {
114
+ throw new ControllerBrowserTransportProtocolError(
115
+ 'The browser transport packet exceeds the JSON byte limit.',
116
+ );
117
+ }
118
+ try {
119
+ return JSON.parse(textDecoder.decode(bytesArg));
120
+ } catch (errorArg) {
121
+ throw new ControllerBrowserTransportProtocolError(
122
+ 'The browser transport packet is not valid UTF-8 JSON.',
123
+ { cause: errorArg },
124
+ );
125
+ }
126
+ };
@@ -1,2 +1,3 @@
1
1
  export * from './interfaces.js';
2
+ export * from './browsertransport.js';
2
3
  export * from './requests.js';
@@ -1,6 +1,4 @@
1
- import * as plugins from './plugins.js';
2
-
3
- export const controllerProtocolVersion = 23 as const;
1
+ export const controllerProtocolVersion = 24 as const;
4
2
  export const controllerUpgradeManagementVersion = 2 as const;
5
3
  export const controllerPackageName = 'agl' as const;
6
4
  export const controllerMaxToolEventBytes = 48 * 1024;
@@ -223,6 +221,8 @@ export interface IControllerBrowserTabState {
223
221
  }
224
222
 
225
223
  export interface IControllerBrowserViewState {
224
+ /** Monotonic for the complete lifetime of one browser view. */
225
+ revision: number;
226
226
  status: 'stopped' | 'starting' | 'running' | 'stopping';
227
227
  activeTabId: string | null;
228
228
  viewportRevision: number;
@@ -231,9 +231,7 @@ export interface IControllerBrowserViewState {
231
231
  lastError?: { code: string; message: string; fatal: boolean; tabId?: string };
232
232
  }
233
233
 
234
- export interface IControllerBrowserFrame<
235
- TDirection extends plugins.typedrequestInterfaces.TVirtualStreamDirection,
236
- > {
234
+ export interface IControllerBrowserFrameMetadata {
237
235
  tabId: string;
238
236
  sequence: number;
239
237
  generation: number;
@@ -252,14 +250,16 @@ export interface IControllerBrowserFrame<
252
250
  scrollOffsetY: number;
253
251
  timestamp?: number;
254
252
  };
255
- dataStream: plugins.typedrequestInterfaces.TVirtualStream<TDirection>;
253
+ dataByteLength: number;
254
+ }
255
+
256
+ export interface IControllerBrowserFrame extends Omit<IControllerBrowserFrameMetadata, 'dataByteLength'> {
257
+ data: Uint8Array;
256
258
  }
257
259
 
258
- export type TControllerBrowserViewEvent<
259
- TDirection extends plugins.typedrequestInterfaces.TVirtualStreamDirection,
260
- > =
260
+ export type TControllerBrowserViewEvent =
261
261
  | { type: 'state'; state: IControllerBrowserViewState }
262
- | { type: 'frame'; frame: IControllerBrowserFrame<TDirection> }
262
+ | { type: 'frame'; frame: IControllerBrowserFrame }
263
263
  | { type: 'error'; error: { code: string; message: string; fatal: boolean; tabId?: string } };
264
264
 
265
265
  export interface IControllerBrowserFrameAcknowledgement {
@@ -10,8 +10,6 @@ import type {
10
10
  TControllerResource,
11
11
  TControllerResourceKind,
12
12
  IControllerBrowserViewState,
13
- TControllerBrowserViewEvent,
14
- TControllerBrowserViewOperation,
15
13
  IControllerProvider,
16
14
  IControllerProviderAccountRateLimits,
17
15
  IControllerProviderConnection,
@@ -927,6 +925,9 @@ export interface IReq_ControllerBrowserViewOpen extends plugins.typedrequestInte
927
925
  viewId: string;
928
926
  resourceId: string;
929
927
  attachmentRevision: number;
928
+ streamGeneration: number;
929
+ events: plugins.typedrequestInterfaces.TVirtualStream<'receive'>;
930
+ operations: plugins.typedrequestInterfaces.TVirtualStream<'send'>;
930
931
  state: IControllerBrowserViewState;
931
932
  };
932
933
  }
@@ -936,41 +937,34 @@ export interface IReq_ControllerBrowserViewActivate extends plugins.typedrequest
936
937
  IReq_ControllerBrowserViewActivate
937
938
  > {
938
939
  method: 'controller.browser.view.activate';
939
- request: { viewId: string };
940
+ request: { viewId: string; streamGeneration: number };
940
941
  response: { activated: true };
941
942
  }
942
943
 
943
- export interface IReq_ControllerBrowserViewClose extends plugins.typedrequestInterfaces.implementsTR<
944
- plugins.typedrequestInterfaces.ITypedRequest,
945
- IReq_ControllerBrowserViewClose
946
- > {
947
- method: 'controller.browser.view.close';
948
- request: { viewId: string };
949
- response: { closed: true };
950
- }
951
-
952
- export interface IReq_ControllerBrowserViewOperate extends plugins.typedrequestInterfaces.implementsTR<
953
- plugins.typedrequestInterfaces.ITypedRequest,
954
- IReq_ControllerBrowserViewOperate
955
- > {
956
- method: 'controller.browser.view.operate';
957
- request: { viewId: string; operation: TControllerBrowserViewOperation };
958
- response: { accepted: boolean; state: IControllerBrowserViewState };
959
- }
960
-
961
- /** Server to client push for one exact human browser view. */
962
- export interface IReq_ControllerBrowserViewEvent extends plugins.typedrequestInterfaces.implementsTR<
944
+ export interface IReq_ControllerBrowserViewRecover extends plugins.typedrequestInterfaces.implementsTR<
963
945
  plugins.typedrequestInterfaces.ITypedRequest,
964
- IReq_ControllerBrowserViewEvent
946
+ IReq_ControllerBrowserViewRecover
965
947
  > {
966
- method: 'controller.browser.view.event';
967
- request: {
948
+ method: 'controller.browser.view.recover';
949
+ request: { viewId: string; expectedStreamGeneration: number };
950
+ response: {
968
951
  viewId: string;
969
952
  resourceId: string;
970
953
  attachmentRevision: number;
971
- event: TControllerBrowserViewEvent<'send'>;
954
+ streamGeneration: number;
955
+ events: plugins.typedrequestInterfaces.TVirtualStream<'receive'>;
956
+ operations: plugins.typedrequestInterfaces.TVirtualStream<'send'>;
957
+ state: IControllerBrowserViewState;
972
958
  };
973
- response: Record<string, never>;
959
+ }
960
+
961
+ export interface IReq_ControllerBrowserViewClose extends plugins.typedrequestInterfaces.implementsTR<
962
+ plugins.typedrequestInterfaces.ITypedRequest,
963
+ IReq_ControllerBrowserViewClose
964
+ > {
965
+ method: 'controller.browser.view.close';
966
+ request: { viewId: string; expectedStreamGeneration: number };
967
+ response: { closed: boolean };
974
968
  }
975
969
 
976
970
  export interface IReq_ControllerTerminalCreate extends plugins.typedrequestInterfaces.implementsTR<
@@ -1171,8 +1165,8 @@ export type TControllerRequest =
1171
1165
  | IReq_ControllerResourceStop
1172
1166
  | IReq_ControllerBrowserViewOpen
1173
1167
  | IReq_ControllerBrowserViewActivate
1168
+ | IReq_ControllerBrowserViewRecover
1174
1169
  | IReq_ControllerBrowserViewClose
1175
- | IReq_ControllerBrowserViewOperate
1176
1170
  | IReq_ControllerTerminalList
1177
1171
  | IReq_ControllerTerminalCreate
1178
1172
  | IReq_ControllerTerminalRename
@@ -1182,5 +1176,4 @@ export type TControllerRequest =
1182
1176
  | IReq_ControllerTerminalInput
1183
1177
  | IReq_ControllerTerminalResize
1184
1178
  | IReq_ControllerTerminalOutput
1185
- | IReq_ControllerBrowserViewEvent
1186
1179
  | IReq_ControllerEvent;
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: 'agl',
6
- version: '23.0.0',
6
+ version: '24.0.0',
7
7
  description: 'Agent Gateway Layer for OpenCode and FlexHarness sessions'
8
8
  }