agl 40.5.1 → 41.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 (137) hide show
  1. package/changelog.md +43 -0
  2. package/dist_serve/bundle.js +3514 -3357
  3. package/dist_serve/bundle.js.map +2 -2
  4. package/dist_serve/bundle.js.third-party-notices.json +58 -32
  5. package/dist_serve/bundle.js.third-party-notices.txt +108 -33
  6. package/dist_ts/00_commitinfo_data.js +1 -1
  7. package/dist_ts/aglapi/aglapisurface.document.js +64 -37
  8. package/dist_ts/classes.aglhome.d.ts +5 -0
  9. package/dist_ts/classes.aglhome.js +2 -1
  10. package/dist_ts/classes.authstore.js +5 -1
  11. package/dist_ts/classes.controller.d.ts +8 -0
  12. package/dist_ts/classes.controller.js +119 -22
  13. package/dist_ts/classes.controllereventdelivery.d.ts +72 -0
  14. package/dist_ts/classes.controllereventdelivery.js +233 -0
  15. package/dist_ts/classes.flexmodels.public.js +4 -1
  16. package/dist_ts/classes.flexprojectionreader.d.ts +6 -0
  17. package/dist_ts/classes.flexprojectionreader.js +29 -5
  18. package/dist_ts/classes.flexservice.d.ts +2 -1
  19. package/dist_ts/classes.flexservice.js +34 -6
  20. package/dist_ts/classes.flexstore.d.ts +41 -4
  21. package/dist_ts/classes.flexstore.js +266 -203
  22. package/dist_ts/classes.inferencegateway.d.ts +35 -1
  23. package/dist_ts/classes.inferencegateway.js +86 -26
  24. package/dist_ts/classes.inferenceservice.d.ts +4 -2
  25. package/dist_ts/classes.inferenceservice.js +5 -4
  26. package/dist_ts/classes.proxycontrol.d.ts +58 -4
  27. package/dist_ts/classes.proxycontrol.js +23 -44
  28. package/dist_ts/classes.proxycontrolclient.d.ts +15 -5
  29. package/dist_ts/classes.proxycontrolclient.js +67 -17
  30. package/dist_ts/classes.proxydaemon.d.ts +22 -3
  31. package/dist_ts/classes.proxydaemon.js +73 -12
  32. package/dist_ts/classes.proxyleaseholder.d.ts +43 -14
  33. package/dist_ts/classes.proxyleaseholder.js +66 -22
  34. package/dist_ts/classes.proxystore.d.ts +9 -0
  35. package/dist_ts/classes.proxystore.js +15 -7
  36. package/dist_ts/classes.ticketnotifier.js +4 -2
  37. package/dist_ts/classes.ticketstore.d.ts +50 -2
  38. package/dist_ts/classes.ticketstore.js +195 -78
  39. package/dist_ts/classes.workercallerbindings.d.ts +66 -0
  40. package/dist_ts/classes.workercallerbindings.js +211 -0
  41. package/dist_ts/classes.workercallers.d.ts +63 -2
  42. package/dist_ts/classes.workercallers.js +430 -65
  43. package/dist_ts/driver/classes.drivereventrelay.d.ts +13 -1
  44. package/dist_ts/driver/classes.drivereventrelay.js +99 -6
  45. package/dist_ts/driver/functions.driverinstructions.d.ts +1 -1
  46. package/dist_ts/driver/functions.driverinstructions.js +1 -1
  47. package/dist_ts/driver/functions.drivertools.d.ts +11 -2
  48. package/dist_ts/driver/functions.drivertools.js +19 -9
  49. package/dist_ts/fleet/classes.boardpump.d.ts +8 -2
  50. package/dist_ts/fleet/classes.boardpump.js +38 -20
  51. package/dist_ts/fleet/classes.ticketeffects.d.ts +17 -2
  52. package/dist_ts/fleet/classes.ticketeffects.js +16 -10
  53. package/dist_ts/fleet/classes.workerlaunches.d.ts +12 -5
  54. package/dist_ts/fleet/classes.workerlaunches.js +25 -19
  55. package/dist_ts/fleet/classes.workers.d.ts +21 -0
  56. package/dist_ts/fleet/classes.workers.js +110 -17
  57. package/dist_ts/fleet/functions.workervalidation.js +2 -2
  58. package/dist_ts/functions.flexprivatesnapshot.d.ts +102 -0
  59. package/dist_ts/functions.flexprivatesnapshot.js +461 -0
  60. package/dist_ts/functions.inferencecli.d.ts +3 -2
  61. package/dist_ts/functions.inferencecli.js +67 -5
  62. package/dist_ts/functions.inferencecliarguments.d.ts +6 -2
  63. package/dist_ts/functions.inferencecliarguments.js +29 -2
  64. package/dist_ts/functions.inferencelaunch.d.ts +24 -0
  65. package/dist_ts/functions.inferencelaunch.js +42 -2
  66. package/dist_ts/functions.mcptickettools.d.ts +3 -0
  67. package/dist_ts/functions.mcptickettools.js +2 -2
  68. package/dist_ts/functions.proxycontract.d.ts +11 -0
  69. package/dist_ts/functions.proxycontract.js +12 -1
  70. package/dist_ts/functions.proxysocket.d.ts +6 -0
  71. package/dist_ts/functions.proxysocket.js +46 -0
  72. package/dist_ts/functions.ticketcli.d.ts +1 -1
  73. package/dist_ts/functions.ticketcli.js +8 -4
  74. package/dist_ts/functions.ticketvalidation.d.ts +3 -0
  75. package/dist_ts/functions.ticketvalidation.js +7 -4
  76. package/dist_ts/functions.workerprocessproof.d.ts +6 -0
  77. package/dist_ts/functions.workerprocessproof.js +28 -4
  78. package/dist_ts/interfaces.flexipc.d.ts +21 -2
  79. package/dist_ts/interfaces.flexipc.js +33 -16
  80. package/dist_ts_interfaces/fleetworkers.d.ts +6 -0
  81. package/dist_ts_interfaces/interfaces.d.ts +1 -1
  82. package/dist_ts_interfaces/interfaces.js +1 -1
  83. package/dist_ts_interfaces/requests.tickets.d.ts +8 -12
  84. package/dist_ts_interfaces/tickets.d.ts +37 -9
  85. package/dist_ts_interfaces/tickets.js +7 -1
  86. package/dist_ts_interfaces/workercallers.d.ts +43 -4
  87. package/package.json +7 -7
  88. package/readme.md +156 -23
  89. package/ts/00_commitinfo_data.ts +1 -1
  90. package/ts/aglapi/aglapisurface.document.ts +63 -36
  91. package/ts/classes.aglhome.ts +6 -0
  92. package/ts/classes.authstore.ts +4 -0
  93. package/ts/classes.controller.ts +141 -32
  94. package/ts/classes.controllereventdelivery.ts +289 -0
  95. package/ts/classes.flexmodels.public.ts +10 -0
  96. package/ts/classes.flexprojectionreader.ts +30 -3
  97. package/ts/classes.flexservice.ts +33 -5
  98. package/ts/classes.flexstore.ts +381 -246
  99. package/ts/classes.inferencegateway.ts +104 -23
  100. package/ts/classes.inferenceservice.ts +6 -3
  101. package/ts/classes.proxycontrol.ts +76 -39
  102. package/ts/classes.proxycontrolclient.ts +72 -20
  103. package/ts/classes.proxydaemon.ts +85 -15
  104. package/ts/classes.proxyleaseholder.ts +84 -28
  105. package/ts/classes.proxystore.ts +16 -5
  106. package/ts/classes.ticketnotifier.ts +3 -1
  107. package/ts/classes.ticketstore.ts +201 -75
  108. package/ts/classes.workercallerbindings.ts +147 -0
  109. package/ts/classes.workercallers.ts +410 -59
  110. package/ts/driver/classes.drivereventrelay.ts +89 -4
  111. package/ts/driver/functions.driverinstructions.ts +1 -1
  112. package/ts/driver/functions.drivertools.ts +22 -8
  113. package/ts/fleet/classes.boardpump.ts +51 -19
  114. package/ts/fleet/classes.ticketeffects.ts +25 -11
  115. package/ts/fleet/classes.workerlaunches.ts +23 -15
  116. package/ts/fleet/classes.workers.ts +79 -17
  117. package/ts/fleet/functions.workervalidation.ts +1 -1
  118. package/ts/functions.flexprivatesnapshot.ts +601 -0
  119. package/ts/functions.inferencecli.ts +61 -7
  120. package/ts/functions.inferencecliarguments.ts +32 -1
  121. package/ts/functions.inferencelaunch.ts +49 -2
  122. package/ts/functions.mcptickettools.ts +1 -1
  123. package/ts/functions.proxycontract.ts +12 -0
  124. package/ts/functions.proxysocket.ts +39 -0
  125. package/ts/functions.ticketcli.ts +7 -3
  126. package/ts/functions.ticketvalidation.ts +7 -3
  127. package/ts/functions.workerprocessproof.ts +27 -4
  128. package/ts/interfaces.flexipc.ts +50 -21
  129. package/ts_interfaces/fleetworkers.ts +6 -0
  130. package/ts_interfaces/interfaces.ts +1 -1
  131. package/ts_interfaces/requests.tickets.ts +9 -6
  132. package/ts_interfaces/tickets.ts +32 -1
  133. package/ts_interfaces/workercallers.ts +32 -4
  134. package/ts_web/00_commitinfo_data.ts +1 -1
  135. package/ts_web/elements.harnesscontrollerapp.ts +19 -8
  136. package/ts_web/elements.ticketboard.ts +16 -4
  137. package/ts_web/settings.general.ts +10 -4
@@ -1,9 +1,9 @@
1
1
  import * as plugins from '../plugins.js';
2
- import { controllerRuntimeIdKey } from '../../ts_interfaces/index.js';
3
- import type { IFleetWorker, IFleetWorkerProfile, IFleetWorkerJob, IFleetNativeMessageReceipt, TFleetEventKind, TFleetWorkerAction, TFleetWorkerRequest, TFleetWorkerResponse, TFleetWorkerJobAction, IFleetWorkerReport, IFleetWorkerDispatchHolder } from '../../ts_interfaces/fleetworkers.js';
2
+ import { controllerRuntimeIdKey, type IWorkerClaudeJobRequest, type TWorkerClaudeJobObservation } from '../../ts_interfaces/index.js';
3
+ import type { IFleetEvent, IFleetWorker, IFleetWorkerProfile, IFleetWorkerJob, IFleetNativeMessageReceipt, TFleetEventKind, TFleetWorkerAction, TFleetWorkerRequest, TFleetWorkerResponse, TFleetWorkerJobAction, IFleetWorkerReport, IFleetWorkerDispatchHolder } from '../../ts_interfaces/fleetworkers.js';
4
4
  import type { IFleetConfiguration, IFleetOperation, IFleetTicketSync } from '../../ts_interfaces/fleet.js';
5
5
  import type { ITicketActor } from '../../ts_interfaces/tickets.js';
6
- import type { FleetTicketEffects } from './classes.ticketeffects.js';
6
+ import type { FleetTicketEffects, IFleetTicketReport } from './classes.ticketeffects.js';
7
7
  import type { IControllerSystemMetrics, IControllerFleetWorkerView, IReq_ControllerFleetWorkerRead, IControllerPermission, IControllerQuestion, TControllerPermissionReply } from '../../ts_interfaces/index.js';
8
8
  import { FleetWorkerStore, type IFleetWorkerStore, type IFleetWorkerDocument } from './classes.workerstore.js';
9
9
  import { FleetEvents } from './classes.events.js';
@@ -14,6 +14,7 @@ import { FleetDispatchError, fleetMessageDigest, fleetReportMarker, type IFleetW
14
14
  import { assertFleetWorkerRequest, validateFleetWorkerProfiles } from './functions.workervalidation.js';
15
15
  import { readControllerProcessIdentity, controllerProcessIdentityIsLive } from '../classes.processinspection.js';
16
16
  import { ticketActorSchema } from '../functions.ticketvalidation.js';
17
+ import { isWorkerCallerProofRefusal, readWorkerProcessSnapshot } from '../functions.workerprocessproof.js';
17
18
 
18
19
  /** A binding that stayed on `workerName` though its native session lives on `nextName` now. */
19
20
  export interface IFleetSessionBindingFailure { workerName: string; nextName: string; error: string }
@@ -80,6 +81,10 @@ export class FleetWorkers {
80
81
  private lastLoad = 0;
81
82
  private readonly controllerId = plugins.crypto.randomUUID();
82
83
  private holder?: Promise<IFleetWorkerDispatchHolder>;
84
+ /** The chain the caller job re-proofs read their inventories on, one at a time. */
85
+ private callerJobs: Promise<unknown> = Promise.resolve();
86
+ /** Set once the controller began to stop: no new worker job is admitted. */
87
+ private admissionClosed = false;
83
88
  constructor(private readonly options: IFleetWorkersOptions = {}) {
84
89
  this.store = options.store ?? new FleetWorkerStore(); this.events = options.events ?? new FleetEvents();
85
90
  this.backends = options.backends ?? { claude: new FleetClaudeWorkers(this.abort.signal, undefined, undefined, options.callers, options.claudeReleases),
@@ -110,15 +115,21 @@ export class FleetWorkers {
110
115
  try {
111
116
  const backend = this.backends[worker.harness], observed = backend.observed?.(worker), excerpt = backend.observedExcerpt?.(worker);
112
117
  const events = await this.backends[worker.harness].poll(worker, worker.profile);
118
+ const ticketed = this.options.ticketEffects && worker.ticketKey && worker.ticketActor;
113
119
  for (const { nativeId: _nativeId, ...event } of events) {
114
- this.events.publish({ ...event, workerId: worker.id, workerName: worker.name, ...(worker.ticketKey ? { ticketKey: worker.ticketKey } : {}) }, owner);
115
- if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) {
116
- if (event.kind === 'worker.report.mid_turn' && event.text && event.reportId) await this.reportTicket(owner, worker, { reportId: event.reportId, text: event.text, truncated: event.truncated ?? false });
117
- else if (event.kind === 'worker.turn.ended') {
118
- const report = await this.backends[worker.harness].observe(worker, worker.profile);
119
- if (report.reportId && report.text.trim()) await this.reportTicket(owner, worker, report);
120
- }
120
+ const published = { ...event, workerId: worker.id, workerName: worker.name, ...(worker.ticketKey ? { ticketKey: worker.ticketKey } : {}) };
121
+ if (ticketed && event.kind === 'worker.report.mid_turn' && event.text && event.reportId) {
122
+ await this.reportTicket(owner, worker, { reportId: event.reportId, text: event.text, truncated: event.truncated ?? false }, published);
123
+ continue;
124
+ }
125
+ if (ticketed && event.kind === 'worker.turn.ended') {
126
+ let report: IFleetWorkerReport;
127
+ // The turn's end is published whether or not its report can be observed.
128
+ try { report = await this.backends[worker.harness].observe(worker, worker.profile); }
129
+ catch (error) { this.events.publish(published, owner); throw error; }
130
+ if (report.reportId && report.text.trim()) { await this.reportTicket(owner, worker, report, published); continue; }
121
131
  }
132
+ this.events.publish(published, owner);
122
133
  }
123
134
  if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) {
124
135
  const baseline = `${worker.id}:${worker.nativeId}:${worker.ticketKey}`;
@@ -157,8 +168,9 @@ export class FleetWorkers {
157
168
  let report: IFleetWorkerReport;
158
169
  try { report = await backend.observe(worker, worker.profile); } catch { return; }
159
170
  if (!report.reportId || !report.text.trim() || !fleetReportMarker.test(report.text)) return;
160
- this.events.publish({ kind: 'worker.report.mid_turn', workerId: worker.id, workerName: worker.name, ...ticket, reportId: report.reportId, text: report.text, truncated: report.truncated, status: report.status }, owner);
161
- if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) await this.reportTicket(owner, worker, report);
171
+ const event: Omit<IFleetEvent, 'id' | 'occurredAt'> = { kind: 'worker.report.mid_turn', workerId: worker.id, workerName: worker.name, ...ticket, reportId: report.reportId, text: report.text, truncated: report.truncated, status: report.status };
172
+ if (this.options.ticketEffects && worker.ticketKey && worker.ticketActor) await this.reportTicket(owner, worker, report, event);
173
+ else this.events.publish(event, owner);
162
174
  }
163
175
  public releaseEvent(operation: IFleetOperation, owner: string, repo?: string): void {
164
176
  if (operation.operation !== 'release' || !['succeeded', 'failed'].includes(operation.state)) return;
@@ -170,11 +182,16 @@ export class FleetWorkers {
170
182
  this.events.publish({ kind: ticketSync.state === 'applied' ? 'ticket.applied' : ticketSync.state === 'failed' ? 'ticket.failed' : 'ticket.unknown',
171
183
  ticketKey, ticketSync, ...(workerId ? { workerId } : {}), ...(operationId ? { operationId } : {}) }, owner);
172
184
  }
173
- private async reportTicket(owner: string, worker: IFleetWorker, report: { reportId?: string; text: string; truncated: boolean }): Promise<IFleetTicketSync> {
174
- let sync: IFleetTicketSync;
175
- try { sync = await this.options.ticketEffects!.report(owner, worker.ticketKey!, worker.ticketActor!, worker, report, this.abort.signal); }
176
- catch (error) { sync = { state: 'unknown', effects: [], error: this.error(error) }; }
177
- this.ticketEvent(owner, worker.ticketKey!, sync, worker.id); return sync;
185
+ /**
186
+ * Comments the report on the worker's ticket first, then publishes `event`, naming the comment that holds its whole
187
+ * text when the board wrote it, and then the comment's ticket event.
188
+ */
189
+ private async reportTicket(owner: string, worker: IFleetWorker, report: { reportId?: string; text: string; truncated: boolean }, event?: Omit<IFleetEvent, 'id' | 'occurredAt'>): Promise<IFleetTicketSync> {
190
+ let written: IFleetTicketReport;
191
+ try { written = await this.options.ticketEffects!.report(owner, worker.ticketKey!, worker.ticketActor!, worker, report, this.abort.signal); }
192
+ catch (error) { written = { sync: { state: 'unknown', effects: [], error: this.error(error) } }; }
193
+ if (event) this.events.publish({ ...event, ...(written.commentId ? { commentId: written.commentId } : {}) }, owner);
194
+ this.ticketEvent(owner, worker.ticketKey!, written.sync, worker.id); return written.sync;
178
195
  }
179
196
  /** `reportsTo` names the direct report whose session asks; a worker it starts or adopts reports to it. */
180
197
  public async execute<T extends TFleetWorkerAction>(action: T, request: TFleetWorkerRequest<T>, configuration: IFleetConfiguration, owner: string, signal?: AbortSignal, actor?: ITicketActor, reportsTo?: string): Promise<TFleetWorkerResponse<T>> {
@@ -298,11 +315,43 @@ export class FleetWorkers {
298
315
  public async nativeAgents(home: string | undefined, maxAgeMs: number): Promise<IFleetNativeAgent[]> {
299
316
  return await this.backends.claude.inventory?.(home, plugins.os.homedir(), maxAgeMs) ?? [];
300
317
  }
318
+ /**
319
+ * What a fresh inventory shows of the Claude background job a worker's caller launch is bound to, for the controller
320
+ * to prove the job's next process. One read at a time, however many bridges ask.
321
+ */
322
+ public observeCallerJob(request: IWorkerClaudeJobRequest): Promise<TWorkerClaudeJobObservation> {
323
+ const task = this.callerJobs.then(() => this.readCallerJob(request));
324
+ this.callerJobs = task.then(() => undefined, () => undefined);
325
+ return task;
326
+ }
327
+ private async readCallerJob(request: IWorkerClaudeJobRequest): Promise<TWorkerClaudeJobObservation> {
328
+ if (this.abort.signal.aborted) return { state: 'unproven', reason: 'the fleet is closing' };
329
+ if (!request.workerId.startsWith(`${request.projectId}:`)) return { state: 'ended', reason: 'its launch names no worker of its project' };
330
+ let worker: IFleetWorker | undefined;
331
+ try { worker = (await this.store.list(request.projectId)).find((doc) => doc.id === request.workerId)?.worker; }
332
+ catch (error) { return { state: 'unproven', reason: `the fleet registry could not be read (${this.error(error)})` }; }
333
+ if (!worker || worker.state === 'archived') return { state: 'ended', reason: `fleet worker ${request.workerId} is ${worker ? 'archived' : 'gone'}` };
334
+ if (worker.harness !== 'claude' || worker.nativeId !== request.nativeSessionId) return { state: 'ended', reason: 'its worker continues in another session' };
335
+ let agents: IFleetNativeAgent[] | undefined;
336
+ try { agents = await this.backends.claude.inventory?.(worker.profile.home, plugins.os.homedir(), 0); }
337
+ catch (error) { return { state: 'unproven', reason: `the Claude inventory could not be read (${this.error(error)})` }; }
338
+ const listed = (agents ?? []).filter((agent) => agent.sessionId === request.nativeSessionId);
339
+ if (listed.length !== 1) return { state: 'unproven', reason: `the Claude inventory lists its session ${listed.length ? 'more than once' : 'nowhere'}` };
340
+ const agent = listed[0]!;
341
+ if (agent.kind !== 'background' || agent.id !== request.jobId) return { state: 'ended', reason: 'its session continues as another Claude job' };
342
+ if (agent.pid === undefined) return { state: 'settled' };
343
+ try { return { state: 'running', process: { jobId: request.jobId, pid: agent.pid, startTicks: (await readWorkerProcessSnapshot(agent.pid)).startTicks } }; }
344
+ catch (error) {
345
+ if (!isWorkerCallerProofRefusal(error)) throw error;
346
+ return { state: 'unproven', reason: 'the process of its Claude job could not be read' };
347
+ }
348
+ }
301
349
  /** The newest root threads on the host's shared Codex app-server, read at most `maxAgeMs` ago. */
302
350
  public async nativeThreads(maxAgeMs: number): Promise<IFleetNativeThread[]> {
303
351
  return await this.backends.codex.threads?.(plugins.os.homedir(), maxAgeMs) ?? [];
304
352
  }
305
353
  private admitJob(): void {
354
+ if (this.admissionClosed || this.abort.signal.aborted) throw new Error('The fleet is closing and admits no new worker job.');
306
355
  if (this.jobs.size < 512) return;
307
356
  for (const [id, job] of this.jobs) if (['succeeded', 'failed'].includes(job.snapshot.state)) { this.jobs.delete(id); break; }
308
357
  if (this.jobs.size >= 512) throw new Error('Fleet worker job capacity reached.');
@@ -779,6 +828,19 @@ export class FleetWorkers {
779
828
  throw error;
780
829
  }
781
830
  }
831
+ /**
832
+ * Admits no new worker job and lets the running ones finish, for at most `waitMs`; the ones still running then are
833
+ * aborted and settle. The controller calls it before it tears down the caller hooks the jobs prepare, bind and
834
+ * revoke launches through, so no job meets them gone.
835
+ */
836
+ public async closeAdmission(waitMs = 10_000): Promise<void> {
837
+ this.admissionClosed = true;
838
+ const settled = Promise.allSettled([...this.jobs.values()].map((job) => job.completion));
839
+ let timer: NodeJS.Timeout | undefined;
840
+ const waited = await Promise.race([settled.then(() => true), new Promise<false>((resolve) => { timer = setTimeout(() => resolve(false), waitMs); })]);
841
+ if (timer) clearTimeout(timer);
842
+ if (!waited) { this.abort.abort(); await settled; }
843
+ }
782
844
  public async close(): Promise<void> {
783
845
  if (this.pollTimer) clearInterval(this.pollTimer); this.abort.abort(); this.events.close(); this.viewListeners.clear();
784
846
  await Promise.allSettled([...this.jobs.values()].map((job) => job.completion)); await Promise.allSettled([this.polling]);
@@ -117,7 +117,7 @@ const job = plugins.z.object({ id: text, action: plugins.z.enum(['start', 'adopt
117
117
  const event = plugins.z.object({ id: plugins.z.number().int().positive(),
118
118
  kind: plugins.z.enum(['worker.changed', 'worker.turn.ended', 'worker.report.mid_turn', 'worker.reaped', 'worker.credential.failed', 'worker.observation.failed', 'release.finished', 'release.failed', 'ticket.applied', 'ticket.failed', 'ticket.unknown',
119
119
  'ticket.changed', 'ticket.notified', 'ticket.notification.failed', 'ticket.stalled', 'harness.release.discovered', 'host.load']),
120
- occurredAt: text, workerId: text.optional(), workerName: name.optional(), sessionId: text.optional(), reportId: text.optional(), turnId: text.optional(), status: text.optional(),
120
+ occurredAt: text, workerId: text.optional(), workerName: name.optional(), sessionId: text.optional(), reportId: text.optional(), commentId: text.optional(), turnId: text.optional(), status: text.optional(),
121
121
  ticketKey: ticketKey.optional(),
122
122
  ticketSync: ticketSync.optional(),
123
123
  text: plugins.z.string().max(64 * 1024).optional(), truncated: plugins.z.boolean().optional(), error: plugins.z.string().max(4096).optional(),