agl 22.0.4 → 23.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.
@@ -3,6 +3,7 @@ import * as interfaces from '../ts_interfaces/index.js';
3
3
 
4
4
  const controllerEventTypes: ReadonlySet<string> = new Set(interfaces.controllerEventTypes);
5
5
  const controllerRequestTimeoutMs = 35_000;
6
+ const textEncoder = new TextEncoder();
6
7
 
7
8
  const isQualifiedRuntimeId = (
8
9
  valueArg: unknown,
@@ -16,7 +17,7 @@ const isQualifiedRuntimeId = (
16
17
  && allowedHarnessIdsArg.has(candidate.harnessId as interfaces.TControllerHarnessId)
17
18
  && typeof candidate.nativeId === 'string'
18
19
  && candidate.nativeId.length > 0
19
- && new TextEncoder().encode(candidate.nativeId).byteLength <= 512
20
+ && textEncoder.encode(candidate.nativeId).byteLength <= 512
20
21
  );
21
22
  };
22
23
 
@@ -36,6 +37,14 @@ const textUpdateKeys = new Set([
36
37
  'sessionId', 'messageId', 'partId', 'text', 'status', 'order',
37
38
  'sourceUpdatedAt', 'revision', 'streamEpoch',
38
39
  ]);
40
+ const messageDeltaKeys = new Set([
41
+ 'sessionId', 'messageId', 'partId', 'delta', 'baseTextUtf8Bytes', 'textUtf8Bytes',
42
+ 'order', 'sourceUpdatedAt', 'revision', 'streamEpoch',
43
+ ]);
44
+ const messageDeltaRequiredKeys = [
45
+ 'sessionId', 'messageId', 'partId', 'delta', 'baseTextUtf8Bytes', 'textUtf8Bytes',
46
+ 'sourceUpdatedAt', 'revision', 'streamEpoch',
47
+ ] as const;
39
48
 
40
49
  const isOptionalFiniteNumber = (valueArg: unknown): boolean => (
41
50
  valueArg === undefined || (typeof valueArg === 'number' && Number.isFinite(valueArg))
@@ -53,12 +62,26 @@ const isTranscriptOrder = (valueArg: unknown): boolean => {
53
62
 
54
63
  const serializedBytesWithin = (valueArg: unknown, byteLimitArg: number): boolean => {
55
64
  try {
56
- return new TextEncoder().encode(JSON.stringify(valueArg)).byteLength <= byteLimitArg;
65
+ return textEncoder.encode(JSON.stringify(valueArg)).byteLength <= byteLimitArg;
57
66
  } catch {
58
67
  return false;
59
68
  }
60
69
  };
61
70
 
71
+ const hasExactDeltaUtf8Coordinates = (
72
+ deltaArg: string,
73
+ baseTextUtf8BytesArg: number,
74
+ textUtf8BytesArg: number,
75
+ ): boolean => {
76
+ const encodedDeltaBytes = textEncoder.encode(deltaArg).byteLength;
77
+ const increment = textUtf8BytesArg - baseTextUtf8BytesArg;
78
+ if (increment === encodedDeltaBytes) return true;
79
+ const firstCodeUnit = deltaArg.charCodeAt(0);
80
+ return firstCodeUnit >= 0xDC00
81
+ && firstCodeUnit <= 0xDFFF
82
+ && increment === encodedDeltaBytes - 2;
83
+ };
84
+
62
85
  const isDraftAttachment = (valueArg: unknown): valueArg is interfaces.IControllerDraftAttachment => {
63
86
  if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) return false;
64
87
  const candidate = valueArg as Partial<interfaces.IControllerDraftAttachment>;
@@ -68,13 +91,13 @@ const isDraftAttachment = (valueArg: unknown): valueArg is interfaces.IControlle
68
91
  ))
69
92
  || typeof candidate.id !== 'string'
70
93
  || candidate.id.length === 0
71
- || new TextEncoder().encode(candidate.id).byteLength > 512
94
+ || textEncoder.encode(candidate.id).byteLength > 512
72
95
  || typeof candidate.name !== 'string'
73
96
  || candidate.name.length === 0
74
- || new TextEncoder().encode(candidate.name).byteLength > 255
97
+ || textEncoder.encode(candidate.name).byteLength > 255
75
98
  || typeof candidate.mediaType !== 'string'
76
99
  || candidate.mediaType.length === 0
77
- || new TextEncoder().encode(candidate.mediaType).byteLength > 129
100
+ || textEncoder.encode(candidate.mediaType).byteLength > 129
78
101
  || !Number.isSafeInteger(candidate.size)
79
102
  || (candidate.size ?? -1) < 0
80
103
  || (candidate.size ?? 0) > interfaces.controllerMaxDraftAttachmentBytes
@@ -101,7 +124,7 @@ const isSessionDraftUpdate = (
101
124
  || (candidate.text === undefined && candidate.attachments === undefined)
102
125
  || (candidate.text !== undefined && (
103
126
  typeof candidate.text !== 'string'
104
- || new TextEncoder().encode(candidate.text).byteLength > interfaces.controllerMaxDraftTextBytes
127
+ || textEncoder.encode(candidate.text).byteLength > interfaces.controllerMaxDraftTextBytes
105
128
  ))
106
129
  || (candidate.attachments !== undefined && (
107
130
  !Array.isArray(candidate.attachments)
@@ -130,7 +153,7 @@ const isControllerToolExecution = (
130
153
  && isQualifiedRuntimeId(candidate.callId, executionHarnessIds)
131
154
  && typeof candidate.toolName === 'string'
132
155
  && candidate.toolName.length > 0
133
- && new TextEncoder().encode(candidate.toolName).byteLength <= 2048
156
+ && textEncoder.encode(candidate.toolName).byteLength <= 2048
134
157
  && ['pending', 'running', 'completed', 'error'].includes(candidate.status ?? '')
135
158
  && (candidate.exitCode === undefined
136
159
  || (Number.isSafeInteger(candidate.exitCode) && candidate.exitCode >= 0))
@@ -166,7 +189,7 @@ const isControllerReasoningUpdate = (
166
189
  && isQualifiedRuntimeId(candidate.messageId, harnessIds)
167
190
  && isQualifiedRuntimeId(candidate.partId, harnessIds)
168
191
  && typeof candidate.text === 'string'
169
- && new TextEncoder().encode(candidate.text).byteLength
192
+ && textEncoder.encode(candidate.text).byteLength
170
193
  <= interfaces.controllerMaxLiveMessageEventBytes
171
194
  && ['running', 'completed', 'cancelled'].includes(candidate.status ?? '')
172
195
  && (candidate.order === undefined || isTranscriptOrder(candidate.order))
@@ -193,7 +216,7 @@ const isControllerTextUpdate = (
193
216
  && isQualifiedRuntimeId(candidate.messageId, harnessIds)
194
217
  && isQualifiedRuntimeId(candidate.partId, harnessIds)
195
218
  && typeof candidate.text === 'string'
196
- && new TextEncoder().encode(candidate.text).byteLength
219
+ && textEncoder.encode(candidate.text).byteLength
197
220
  <= interfaces.controllerMaxLiveMessageEventBytes
198
221
  && ['running', 'completed'].includes(candidate.status ?? '')
199
222
  && (candidate.order === undefined || isTranscriptOrder(candidate.order))
@@ -207,6 +230,48 @@ const isControllerTextUpdate = (
207
230
  && (candidate.streamEpoch ?? -1) >= 0;
208
231
  };
209
232
 
233
+ const isControllerMessageDelta = (
234
+ valueArg: unknown,
235
+ ): valueArg is interfaces.IControllerReasoningDelta | interfaces.IControllerTextDelta => {
236
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) return false;
237
+ const candidate = valueArg as Partial<interfaces.IControllerReasoningDelta>;
238
+ if (!isQualifiedRuntimeId(candidate.sessionId, sessionHarnessIds)) return false;
239
+ const harnessIds: ReadonlySet<interfaces.TControllerHarnessId> = new Set([
240
+ candidate.sessionId.harnessId,
241
+ ]);
242
+ const keys = Object.keys(candidate);
243
+ const hasOrder = Object.prototype.hasOwnProperty.call(candidate, 'order');
244
+ return keys.length === messageDeltaRequiredKeys.length + (hasOrder ? 1 : 0)
245
+ && keys.every((key) => messageDeltaKeys.has(key))
246
+ && messageDeltaRequiredKeys.every((key) => (
247
+ Object.prototype.hasOwnProperty.call(candidate, key)
248
+ ))
249
+ && isQualifiedRuntimeId(candidate.messageId, harnessIds)
250
+ && isQualifiedRuntimeId(candidate.partId, harnessIds)
251
+ && typeof candidate.delta === 'string'
252
+ && candidate.delta.length > 0
253
+ && textEncoder.encode(candidate.delta).byteLength
254
+ <= interfaces.controllerMaxLiveMessageEventBytes
255
+ && Number.isSafeInteger(candidate.baseTextUtf8Bytes)
256
+ && (candidate.baseTextUtf8Bytes ?? -1) >= 0
257
+ && Number.isSafeInteger(candidate.textUtf8Bytes)
258
+ && (candidate.textUtf8Bytes ?? -1) > (candidate.baseTextUtf8Bytes ?? -1)
259
+ && hasExactDeltaUtf8Coordinates(
260
+ candidate.delta,
261
+ candidate.baseTextUtf8Bytes!,
262
+ candidate.textUtf8Bytes!,
263
+ )
264
+ && (!hasOrder || isTranscriptOrder(candidate.order))
265
+ && (candidate.sessionId.harnessId !== 'flex' || hasOrder)
266
+ && (candidate.sessionId.harnessId !== 'opencode' || !hasOrder)
267
+ && typeof candidate.sourceUpdatedAt === 'number'
268
+ && Number.isFinite(candidate.sourceUpdatedAt)
269
+ && Number.isSafeInteger(candidate.revision)
270
+ && (candidate.revision ?? -1) >= 0
271
+ && Number.isSafeInteger(candidate.streamEpoch)
272
+ && (candidate.streamEpoch ?? -1) >= 0;
273
+ };
274
+
210
275
  export interface IControllerSocketClientOptions {
211
276
  onStatus: (status: plugins.typedsocket.TConnectionStatus) => void;
212
277
  onControllerEvent: (event: interfaces.IControllerEvent) => void | Promise<void>;
@@ -240,9 +305,18 @@ export const isControllerEvent = (valueArg: unknown): valueArg is interfaces.ICo
240
305
  const hasSessionMarker = candidate.sessionStatus !== undefined || candidate.sessionError !== undefined;
241
306
  const hasToolExecution = candidate.toolExecution !== undefined;
242
307
  const hasReasoningUpdate = candidate.reasoningUpdate !== undefined;
308
+ const hasReasoningDelta = candidate.reasoningDelta !== undefined;
243
309
  const hasTextUpdate = candidate.textUpdate !== undefined;
310
+ const hasTextDelta = candidate.textDelta !== undefined;
244
311
  const hasDraftUpdate = candidate.sessionDraftUpdate !== undefined;
245
312
  const hasUpgrade = candidate.upgrade !== undefined;
313
+ const livePayloadCount = [
314
+ hasToolExecution,
315
+ hasReasoningUpdate,
316
+ hasReasoningDelta,
317
+ hasTextUpdate,
318
+ hasTextDelta,
319
+ ].filter(Boolean).length;
246
320
  return (
247
321
  typeof candidate.type === 'string'
248
322
  && controllerEventTypes.has(candidate.type as interfaces.TControllerEventType)
@@ -269,14 +343,19 @@ export const isControllerEvent = (valueArg: unknown): valueArg is interfaces.ICo
269
343
  && (candidate.toolExecution === undefined || isControllerToolExecution(candidate.toolExecution))
270
344
  && (candidate.reasoningUpdate === undefined
271
345
  || isControllerReasoningUpdate(candidate.reasoningUpdate))
346
+ && (candidate.reasoningDelta === undefined
347
+ || isControllerMessageDelta(candidate.reasoningDelta))
272
348
  && (candidate.textUpdate === undefined || isControllerTextUpdate(candidate.textUpdate))
349
+ && (candidate.textDelta === undefined || isControllerMessageDelta(candidate.textDelta))
273
350
  && (candidate.sessionDraftUpdate === undefined
274
351
  || isSessionDraftUpdate(candidate.sessionDraftUpdate))
352
+ && livePayloadCount <= 1
275
353
  && (!hasToolExecution || serializedBytesWithin(
276
354
  candidate,
277
355
  interfaces.controllerMaxToolEventBytes,
278
356
  ))
279
- && (!(hasReasoningUpdate || hasTextUpdate) || serializedBytesWithin(
357
+ && (!(hasReasoningUpdate || hasReasoningDelta || hasTextUpdate || hasTextDelta)
358
+ || serializedBytesWithin(
280
359
  candidate,
281
360
  interfaces.controllerMaxLiveMessageEventBytes,
282
361
  ))
@@ -312,6 +391,16 @@ export const isControllerEvent = (valueArg: unknown): valueArg is interfaces.ICo
312
391
  === interfaces.controllerRuntimeIdKey(candidate.reasoningUpdate!.sessionId)
313
392
  ))
314
393
  && (hasReasoningUpdate || candidate.type !== 'session.reasoning.updated')
394
+ && (!hasReasoningDelta || (
395
+ candidate.type === 'session.reasoning.delta'
396
+ && (candidate.harnessId === 'opencode' || candidate.harnessId === 'flex')
397
+ && typeof candidate.projectId === 'string'
398
+ && isQualifiedRuntimeId(candidate.sessionId, sessionHarnessIds)
399
+ && candidate.harnessId === candidate.reasoningDelta!.sessionId.harnessId
400
+ && interfaces.controllerRuntimeIdKey(candidate.sessionId)
401
+ === interfaces.controllerRuntimeIdKey(candidate.reasoningDelta!.sessionId)
402
+ ))
403
+ && (hasReasoningDelta || candidate.type !== 'session.reasoning.delta')
315
404
  && (!hasTextUpdate || (
316
405
  candidate.type === 'session.text.updated'
317
406
  && (candidate.harnessId === 'opencode' || candidate.harnessId === 'flex')
@@ -322,6 +411,16 @@ export const isControllerEvent = (valueArg: unknown): valueArg is interfaces.ICo
322
411
  === interfaces.controllerRuntimeIdKey(candidate.textUpdate!.sessionId)
323
412
  ))
324
413
  && (hasTextUpdate || candidate.type !== 'session.text.updated')
414
+ && (!hasTextDelta || (
415
+ candidate.type === 'session.text.delta'
416
+ && (candidate.harnessId === 'opencode' || candidate.harnessId === 'flex')
417
+ && typeof candidate.projectId === 'string'
418
+ && isQualifiedRuntimeId(candidate.sessionId, sessionHarnessIds)
419
+ && candidate.harnessId === candidate.textDelta!.sessionId.harnessId
420
+ && interfaces.controllerRuntimeIdKey(candidate.sessionId)
421
+ === interfaces.controllerRuntimeIdKey(candidate.textDelta!.sessionId)
422
+ ))
423
+ && (hasTextDelta || candidate.type !== 'session.text.delta')
325
424
  && (!hasDraftUpdate || (
326
425
  candidate.type === 'session.draft.changed'
327
426
  && typeof candidate.projectId === 'string'
@@ -337,7 +436,9 @@ export const isControllerEvent = (valueArg: unknown): valueArg is interfaces.ICo
337
436
  candidate.type === 'harness.changed'
338
437
  && (candidate.harnessId === 'opencode' || candidate.harnessId === 'flex')
339
438
  && !hasReasoningUpdate
439
+ && !hasReasoningDelta
340
440
  && !hasTextUpdate
441
+ && !hasTextDelta
341
442
  ))
342
443
  && (candidate.upgrade === undefined || (
343
444
  typeof candidate.upgrade === 'object'
@@ -345,10 +446,10 @@ export const isControllerEvent = (valueArg: unknown): valueArg is interfaces.ICo
345
446
  && Object.keys(candidate.upgrade).length === 3
346
447
  && typeof candidate.upgrade.fromVersion === 'string'
347
448
  && candidate.upgrade.fromVersion.length > 0
348
- && new TextEncoder().encode(candidate.upgrade.fromVersion).byteLength <= 128
449
+ && textEncoder.encode(candidate.upgrade.fromVersion).byteLength <= 128
349
450
  && typeof candidate.upgrade.toVersion === 'string'
350
451
  && candidate.upgrade.toVersion.length > 0
351
- && new TextEncoder().encode(candidate.upgrade.toVersion).byteLength <= 128
452
+ && textEncoder.encode(candidate.upgrade.toVersion).byteLength <= 128
352
453
  && ['preparing', 'pausing', 'installing', 'restarting', 'continuing', 'completed', 'failed']
353
454
  .includes(candidate.upgrade.phase)
354
455
  ))