@kapeta/local-cluster-service 0.75.0 → 0.76.1

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.
@@ -42,7 +42,6 @@ const promises_1 = require("fs/promises");
42
42
  const path_1 = __importDefault(require("path"));
43
43
  const path_2 = __importStar(require("path"));
44
44
  const node_os_1 = __importDefault(require("node:os"));
45
- const fs_1 = require("fs");
46
45
  const yaml_1 = __importDefault(require("yaml"));
47
46
  const predefined_1 = require("./predefined");
48
47
  const archetype_1 = require("./archetype");
@@ -311,7 +310,7 @@ class StormCodegen {
311
310
  permissions: '0644',
312
311
  });
313
312
  const uiEvents = [];
314
- const stormClient = new stormClient_1.StormClient(this.uiSystemId);
313
+ const stormClient = new stormClient_1.StormClient(blockUri.handle, this.uiSystemId);
315
314
  // generate screens
316
315
  if (uiTemplates.length) {
317
316
  const screenStream = await stormClient.listScreens({
@@ -439,212 +438,12 @@ class StormCodegen {
439
438
  },
440
439
  });
441
440
  }
442
- async verifyAndFixCode(blockUri, blockName, codeGenerator, basePath, filesToBeFixed, allFiles) {
443
- let attempts = 0;
444
- let validCode = false;
445
- for (let i = 0; i <= 3; i++) {
446
- attempts++;
447
- try {
448
- console.log(`Validating the code in ${basePath} attempt #${attempts}`);
449
- const result = await codeGenerator.validateForTarget(basePath);
450
- if (result && result.valid) {
451
- validCode = true;
452
- break;
453
- }
454
- if (result && !result.valid) {
455
- console.debug('Validation error:', result);
456
- this.emitBlockStatus(blockUri, blockName, events_1.StormEventBlockStatusType.PLANNING_FIX);
457
- const errors = await this.classifyErrors(result.error, basePath);
458
- if (errors.size > 0) {
459
- this.emitBlockStatus(blockUri, blockName, events_1.StormEventBlockStatusType.FIXING);
460
- const promises = Array.from(errors.entries()).map(([filename, fileErrors]) => {
461
- if (filesToBeFixed.some((file) => file.filename === filename)) {
462
- return this.tryToFixFile(blockUri, blockName, basePath, filename, fileErrors, allFiles, codeGenerator);
463
- }
464
- });
465
- await Promise.all(promises);
466
- }
467
- this.emitBlockStatus(blockUri, blockName, events_1.StormEventBlockStatusType.FIX_DONE);
468
- }
469
- }
470
- catch (e) {
471
- console.error('Error:', e);
472
- }
473
- }
474
- if (validCode) {
475
- console.log(`Validation successful after ${attempts} attempts`);
476
- }
477
- else {
478
- console.error(`Validation failed for ${basePath} after ${attempts} attempts`);
479
- }
480
- }
481
- async tryToFixFile(blockUri, blockName, basePath, filename, fileErrors, allFiles, codeGenerator) {
482
- console.log(`Processing ${filename}`);
483
- const language = await codeGenerator.language();
484
- const relevantFiles = allFiles.filter((file) => file.type != codegen_1.AIFileTypes.IGNORE);
485
- for (let attempts = 1; attempts <= 5; attempts++) {
486
- if (fileErrors.length == 0) {
487
- console.log(`No more errors for ${filename}`);
488
- return;
489
- }
490
- console.log(`Errors in ${filename} - requesting error details`);
491
- const filesForContext = await this.getErrorDetailsForFile(basePath, filename, fileErrors[0], relevantFiles, language);
492
- console.log(`Get error details for ${filename} requesting code fixes`);
493
- const fix = this.createFixRequestForFile(basePath, filename, fileErrors[0], filesForContext, relevantFiles, language);
494
- const codeFixFile = await this.codeFix(blockUri, blockName, fix);
495
- console.log(`Got fixed code for ${filename}`);
496
- const filePath = codeFixFile.filename.indexOf(basePath) > -1
497
- ? codeFixFile.filename
498
- : (0, path_2.join)(basePath, codeFixFile.filename);
499
- const existing = (0, fs_1.readFileSync)(filePath);
500
- if (existing.toString().replace(/(\r\n|\r|\n)+$/, '') == codeFixFile.content.replace(/(\r\n|\r|\n)+$/, '')) {
501
- console.log(`${filename} not changed by gemini`);
502
- continue;
503
- }
504
- (0, fs_1.writeFileSync)(filePath, codeFixFile.content);
505
- const result = await codeGenerator.validateForTarget(basePath);
506
- if (result && result.valid) {
507
- return;
508
- }
509
- const errors = await this.classifyErrors(result.error, basePath);
510
- fileErrors = errors.get(filename) ?? [];
511
- }
512
- }
513
- async classifyErrors(errors, basePath) {
514
- const stormClient = new stormClient_1.StormClient(this.uiSystemId);
515
- const errorStream = await stormClient.createErrorClassification(errors, []);
516
- const fixes = new Map();
517
- this.out.on('aborted', () => {
518
- errorStream.abort();
519
- });
520
- errorStream.on('data', (evt) => {
521
- if (evt.type === 'ERROR_CLASSIFIER') {
522
- const eventFileName = this.removePrefix(basePath + '/', evt.payload.filename);
523
- const fix = {
524
- error: evt.payload.error,
525
- lineNumber: evt.payload.lineNumber,
526
- column: evt.payload.column,
527
- };
528
- let existingFixes = fixes.get(eventFileName);
529
- if (existingFixes) {
530
- existingFixes.push(fix);
531
- }
532
- else {
533
- fixes.set(eventFileName, [fix]);
534
- }
535
- }
536
- });
537
- await errorStream.waitForDone();
538
- return fixes;
539
- }
540
- async getErrorDetailsForFile(basePath, filename, error, allFiles, language) {
541
- const filePath = filename.indexOf(basePath) > -1 ? filename : (0, path_2.join)(basePath, filename); // to compensate when compiler returns absolute path
542
- return new Promise(async (resolve, reject) => {
543
- const request = {
544
- language: language,
545
- sourceFile: {
546
- filename: filename,
547
- content: (0, fs_1.readFileSync)(filePath, 'utf8'),
548
- },
549
- error: error,
550
- projectFiles: allFiles.map((f) => f.filename),
551
- };
552
- const stormClient = new stormClient_1.StormClient(this.uiSystemId);
553
- const detailsStream = await stormClient.createErrorDetails(JSON.stringify(request), []);
554
- detailsStream.on('data', (evt) => {
555
- if (evt.type === 'ERROR_DETAILS') {
556
- resolve(evt.payload.files);
557
- }
558
- reject(new Error('Error details: Unexpected event [' + evt.type + ']'));
559
- });
560
- this.out.on('aborted', () => {
561
- detailsStream.abort();
562
- reject(new Error('aborted'));
563
- });
564
- detailsStream.on('error', (err) => {
565
- reject(err);
566
- });
567
- await detailsStream.waitForDone();
568
- });
569
- }
570
- createFixRequestForFile(basePath, filename, error, filesForContext, allFiles, language) {
571
- const files = new Set(filesForContext);
572
- files.add(filename);
573
- const requestedFiles = Array.from(files).flatMap((file) => {
574
- if ((0, fs_1.existsSync)(file)) {
575
- return file;
576
- }
577
- // file does not exist - look for similar
578
- const candidateName = file.split('/').pop();
579
- return allFiles.filter((file) => file.filename.split('/').pop() === candidateName).map((f) => f.filename);
580
- });
581
- const filePath = filename.indexOf(basePath) > -1 ? filename : (0, path_2.join)(basePath, filename);
582
- const content = (0, fs_1.readFileSync)(filePath, 'utf8');
583
- const affectedLine = this.getErrorLine(error, content);
584
- const fixRequest = {
585
- language: language,
586
- filename: filename,
587
- error: error.error,
588
- affectedLine: affectedLine,
589
- projectFiles: requestedFiles.map((filename) => {
590
- const filePath = filename.indexOf(basePath) > -1 ? filename : (0, path_2.join)(basePath, filename);
591
- const content = (0, fs_1.readFileSync)(filePath, 'utf8');
592
- return { filename: filename, content: content };
593
- }),
594
- };
595
- return JSON.stringify(fixRequest);
596
- }
597
- getErrorLine(errorDetails, sourceCode) {
598
- const lines = sourceCode.split('\n');
599
- const errorLine = lines[errorDetails.lineNumber - 1];
600
- if (!errorLine) {
601
- return 'Error: Line number out of range.';
602
- }
603
- return errorLine;
604
- }
605
441
  removePrefix(prefix, str) {
606
442
  if (str.startsWith(prefix)) {
607
443
  return str.slice(prefix.length);
608
444
  }
609
445
  return str;
610
446
  }
611
- /**
612
- * Sends the code to the AI for a fix
613
- */
614
- async codeFix(blockUri, blockName, fix, history) {
615
- return new Promise(async (resolve, reject) => {
616
- try {
617
- const stormClient = new stormClient_1.StormClient(this.uiSystemId);
618
- const fixStream = await stormClient.createCodeFix(fix, history, this.conversationId);
619
- let resolved = false;
620
- fixStream.on('data', (evt) => {
621
- if (this.handleFileEvents(blockUri, blockName, evt)) {
622
- return;
623
- }
624
- this.handleFileDoneOutput(blockUri, blockName, evt);
625
- if (evt.type === 'CODE_FIX') {
626
- resolved = true;
627
- resolve(evt.payload);
628
- }
629
- });
630
- this.out.on('aborted', () => {
631
- fixStream.abort();
632
- reject(new Error('aborted'));
633
- });
634
- fixStream.on('error', (err) => {
635
- reject(err);
636
- });
637
- fixStream.on('end', () => {
638
- if (!resolved) {
639
- reject(new Error('Code fix never returned a valid event'));
640
- }
641
- });
642
- }
643
- catch (e) {
644
- reject(e);
645
- }
646
- });
647
- }
648
447
  /**
649
448
  * Emits the text-based files to the stream
650
449
  */
@@ -110,6 +110,7 @@ router.post('/ui/conversations/:systemId/append', async (req, res) => {
110
110
  });
111
111
  router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
112
112
  const systemId = req.params.systemId;
113
+ const handle = req.params.handle;
113
114
  const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
114
115
  const destDir = (0, page_utils_1.getSystemBaseImplDir)(systemId);
115
116
  res.set('Content-Type', 'application/x-ndjson');
@@ -117,7 +118,7 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
117
118
  res.set(stormClient_1.ConversationIdHeader, systemId);
118
119
  sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
119
120
  const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
120
- const client = new stormClient_1.StormClient(systemId);
121
+ const client = new stormClient_1.StormClient(handle, systemId);
121
122
  const pagesWithImplementation = await client.replaceMockWithAPICall({
122
123
  pages: pagesFromDisk,
123
124
  systemId: systemId,
@@ -151,7 +152,7 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
151
152
  //res.set('Access-Control-Expose-Headers', ConversationIdHeader);
152
153
  //res.set(ConversationIdHeader, systemId);
153
154
  //sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
154
- const client = new stormClient_1.StormClient(systemId);
155
+ const client = new stormClient_1.StormClient(handle, systemId);
155
156
  try {
156
157
  const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
157
158
  const pagesWithImplementation = await client.replaceMockWithAPICall({
@@ -225,8 +226,9 @@ router.delete('/ui/serve/:systemId', async (req, res) => {
225
226
  }
226
227
  res.status(200).json({ status: 'ok' });
227
228
  });
228
- router.post('/ui/screen', async (req, res) => {
229
+ router.post('/:handle/ui/screen', async (req, res) => {
229
230
  try {
231
+ const handle = req.params.handle;
230
232
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
231
233
  const systemId = req.headers[page_utils_1.SystemIdHeader.toLowerCase()];
232
234
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
@@ -235,7 +237,7 @@ router.post('/ui/screen', async (req, res) => {
235
237
  res.set('Access-Control-Expose-Headers', stormClient_1.ConversationIdHeader);
236
238
  res.set(stormClient_1.ConversationIdHeader, conversationId);
237
239
  const parentConversationId = systemId ?? '';
238
- const queue = new PageGenerator_1.PageQueue(parentConversationId, '', 5);
240
+ const queue = new PageGenerator_1.PageQueue(handle, parentConversationId, '', 5);
239
241
  onRequestAborted(req, res, () => {
240
242
  queue.cancel();
241
243
  });
@@ -270,7 +272,7 @@ router.post('/:handle/ui/iterative', async (req, res) => {
270
272
  try {
271
273
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
272
274
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
273
- const client = new stormClient_1.StormClient(conversationId); //todo is this correct we are using the landing page getConversationId down below as well
275
+ const client = new stormClient_1.StormClient(handle, conversationId); //todo is this correct we are using the landing page getConversationId down below as well
274
276
  const landingPagesStream = await client.createUILandingPages(aiRequest, conversationId);
275
277
  onRequestAborted(req, res, () => {
276
278
  landingPagesStream.abort();
@@ -325,7 +327,7 @@ router.post('/:handle/ui/iterative', async (req, res) => {
325
327
  waitForStormStream(landingPagesStream).then(() => {
326
328
  systemPrompt.resolve(aiRequest.prompt);
327
329
  });
328
- const pageQueue = new PageGenerator_1.PageQueue(systemId, await systemPrompt.promise, 5);
330
+ const pageQueue = new PageGenerator_1.PageQueue(handle, systemId, await systemPrompt.promise, 5);
329
331
  onRequestAborted(req, res, () => {
330
332
  pageQueue.cancel();
331
333
  });
@@ -360,7 +362,7 @@ router.post('/:handle/ui', async (req, res) => {
360
362
  try {
361
363
  const outerConversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()] || (0, crypto_1.randomUUID)();
362
364
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
363
- const stormClient = new stormClient_1.StormClient(outerConversationId);
365
+ const stormClient = new stormClient_1.StormClient(handle, outerConversationId);
364
366
  // Get user journeys
365
367
  const userJourneysStream = await stormClient.createUIUserJourneys(aiRequest, outerConversationId);
366
368
  onRequestAborted(req, res, () => {
@@ -458,7 +460,7 @@ router.post('/:handle/ui', async (req, res) => {
458
460
  onRequestAborted(req, res, () => {
459
461
  shellsStream.abort();
460
462
  });
461
- const queue = new PageGenerator_1.PageQueue(outerConversationId, systemPrompt, 5);
463
+ const queue = new PageGenerator_1.PageQueue(handle, outerConversationId, systemPrompt, 5);
462
464
  queue.setUiTheme(theme);
463
465
  shellsStream.on('data', (data) => {
464
466
  //console.log('Processing shell event', data);
@@ -538,13 +540,14 @@ router.post('/:handle/ui', async (req, res) => {
538
540
  }
539
541
  }
540
542
  });
541
- router.post('/ui/edit', async (req, res) => {
543
+ router.post('/:handle/ui/edit', async (req, res) => {
542
544
  try {
545
+ const handle = req.params.handle;
543
546
  const systemId = (req.headers[page_utils_1.SystemIdHeader.toLowerCase()] ||
544
547
  req.headers[stormClient_1.ConversationIdHeader.toLowerCase()]);
545
548
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
546
549
  const storagePrefix = systemId ? systemId + '_' : 'mock_';
547
- const queue = new PageGenerator_1.PageQueue(systemId, '', 5);
550
+ const queue = new PageGenerator_1.PageQueue(handle, systemId, '', 5);
548
551
  onRequestAborted(req, res, () => {
549
552
  queue.cancel();
550
553
  });
@@ -604,7 +607,7 @@ router.post('/ui/vote', async (req, res) => {
604
607
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
605
608
  const { topic, vote, mainConversationId } = aiRequest;
606
609
  try {
607
- const stormClient = new stormClient_1.StormClient(mainConversationId);
610
+ const stormClient = new stormClient_1.StormClient("", mainConversationId);
608
611
  await stormClient.voteUIPage(topic, conversationId, vote, mainConversationId);
609
612
  }
610
613
  catch (e) {
@@ -616,7 +619,7 @@ router.post('/ui/get-vote', async (req, res) => {
616
619
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
617
620
  const { topic, mainConversationId } = aiRequest;
618
621
  try {
619
- const stormClient = new stormClient_1.StormClient(mainConversationId);
622
+ const stormClient = new stormClient_1.StormClient("", mainConversationId);
620
623
  const vote = await stormClient.getVoteUIPage(topic, conversationId, mainConversationId);
621
624
  res.send({ vote });
622
625
  }
@@ -641,7 +644,7 @@ async function handleAll(req, res) {
641
644
  const eventParser = new event_parser_1.StormEventParser(stormOptions);
642
645
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
643
646
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
644
- const stormClient = new stormClient_1.StormClient(systemId);
647
+ const stormClient = new stormClient_1.StormClient(handle, systemId);
645
648
  const metaStream = await stormClient.createMetadata(aiRequest, conversationId);
646
649
  onRequestAborted(req, res, () => {
647
650
  metaStream.abort();
@@ -5,6 +5,7 @@ import { Page, StormEventPageUrl } from './events';
5
5
  export declare const STORM_ID = "storm";
6
6
  export declare const ConversationIdHeader = "Conversation-Id";
7
7
  export declare const SystemIdHeader = "System-Id";
8
+ export declare const HandleHeader = "Handle";
8
9
  export interface UIShellsPrompt {
9
10
  theme?: string;
10
11
  pages: {
@@ -59,7 +60,8 @@ export interface BasePromptRequest {
59
60
  export declare class StormClient {
60
61
  private readonly _baseUrl;
61
62
  private readonly _systemId;
62
- constructor(systemId?: string);
63
+ private readonly _handle;
64
+ constructor(handle: string, systemId?: string);
63
65
  private createOptions;
64
66
  private send;
65
67
  createMetadata(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StormClient = exports.SystemIdHeader = exports.ConversationIdHeader = exports.STORM_ID = void 0;
6
+ exports.StormClient = exports.HandleHeader = exports.SystemIdHeader = exports.ConversationIdHeader = exports.STORM_ID = void 0;
7
7
  /**
8
8
  * Copyright 2023 Kapeta Inc.
9
9
  * SPDX-License-Identifier: BUSL-1.1
@@ -18,12 +18,15 @@ const fetchWithRetries = (0, fetch_retry_1.default)(global.fetch, { retries: 5,
18
18
  exports.STORM_ID = 'storm';
19
19
  exports.ConversationIdHeader = 'Conversation-Id';
20
20
  exports.SystemIdHeader = 'System-Id';
21
+ exports.HandleHeader = 'Handle';
21
22
  class StormClient {
22
23
  _baseUrl;
23
24
  _systemId;
24
- constructor(systemId) {
25
+ _handle;
26
+ constructor(handle, systemId) {
25
27
  this._baseUrl = (0, utils_1.getRemoteUrl)('ai-service', 'https://ai.kapeta.com');
26
28
  this._systemId = systemId || "";
29
+ this._handle = handle;
27
30
  }
28
31
  async createOptions(path, method, body) {
29
32
  const url = `${this._baseUrl}${path}`;
@@ -41,6 +44,9 @@ class StormClient {
41
44
  if (this._systemId) {
42
45
  headers[exports.SystemIdHeader] = this._systemId;
43
46
  }
47
+ if (this._handle) {
48
+ headers[exports.HandleHeader] = this._handle;
49
+ }
44
50
  return {
45
51
  url,
46
52
  method: method,
@@ -147,6 +153,7 @@ class StormClient {
147
153
  body: JSON.stringify(prompt.pages),
148
154
  headers: {
149
155
  'systemId': prompt.systemId,
156
+ 'conversationId': prompt.systemId,
150
157
  },
151
158
  });
152
159
  return (await response.json());
@@ -138,13 +138,13 @@ class StormService {
138
138
  gzip: true,
139
139
  filter: (entry) => !entry.includes(tarballName),
140
140
  }, ['.']);
141
- const stormClient = new stormClient_1.StormClient(systemId);
141
+ const stormClient = new stormClient_1.StormClient(handle, systemId);
142
142
  await stormClient.uploadSystem(handle, systemId, await promises_1.default.readFile(tarballFile));
143
143
  }
144
144
  async installProjectById(handle, systemId) {
145
145
  const tarballFile = this.getConversationTarball(systemId);
146
146
  const destDir = path_1.default.dirname(tarballFile);
147
- const stormClient = new stormClient_1.StormClient(systemId);
147
+ const stormClient = new stormClient_1.StormClient(handle, systemId);
148
148
  const buffer = await stormClient.downloadSystem(handle, systemId);
149
149
  await promises_1.default.mkdir(destDir, { recursive: true });
150
150
  await promises_1.default.writeFile(tarballFile, buffer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.75.0",
3
+ "version": "0.76.1",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -31,6 +31,7 @@ type PagePrompt = InitialPrompt & { conversationId: string; id: string };
31
31
  export class PageQueue extends EventEmitter {
32
32
  private readonly queue: PQueue;
33
33
  private readonly eventQueue: PQueue;
34
+ private readonly handle: string;
34
35
  private readonly systemId: string;
35
36
  private readonly systemPrompt: string;
36
37
  private readonly references: Map<string, boolean> = new Map();
@@ -39,8 +40,9 @@ export class PageQueue extends EventEmitter {
39
40
  private uiShells: UIShell[] = [];
40
41
  private theme = '';
41
42
 
42
- constructor(systemId: string, systemPrompt: string, concurrency: number = 5) {
43
+ constructor(handle: string, systemId: string, systemPrompt: string, concurrency: number = 5) {
43
44
  super();
45
+ this.handle = handle;
44
46
  this.systemId = systemId;
45
47
  this.systemPrompt = systemPrompt;
46
48
  this.queue = new PQueue({ concurrency });
@@ -272,7 +274,7 @@ export class PageQueue extends EventEmitter {
272
274
  return;
273
275
  }
274
276
 
275
- const client = new StormClient(this.systemId);
277
+ const client = new StormClient(this.handle, this.systemId);
276
278
  this.images.set(prompt.url, prompt.description);
277
279
  const result = await client.createImage(
278
280
  `Create an image for the url "${prompt.url}" with this description: ${prompt.description}`.trim()
@@ -295,7 +297,7 @@ export class PageQueue extends EventEmitter {
295
297
  }
296
298
 
297
299
  public async generate(prompt: UIPagePrompt, conversationId: string) {
298
- const client = new StormClient(this.systemId);
300
+ const client = new StormClient(this.handle, this.systemId);
299
301
  const screenStream = await client.createUIPage(prompt, conversationId);
300
302
  let pageEvent: StormEventPage | null = null;
301
303
  screenStream.on('data', (event: StormEvent) => {
@@ -315,7 +317,7 @@ export class PageQueue extends EventEmitter {
315
317
  }
316
318
 
317
319
  private async resolveReferences(content: string): Promise<ReferenceClassification[]> {
318
- const client = new StormClient(this.systemId);
320
+ const client = new StormClient(this.handle, this.systemId);
319
321
  const referenceStream = await client.classifyUIReferences(content);
320
322
 
321
323
  const references: ReferenceClassification[] = [];