@kapeta/local-cluster-service 0.52.3 → 0.53.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.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/src/storm/codegen.d.ts +1 -0
- package/dist/cjs/src/storm/codegen.js +101 -95
- package/dist/cjs/src/storm/event-parser.js +5 -4
- package/dist/cjs/src/storm/events.d.ts +23 -5
- package/dist/cjs/src/storm/events.js +10 -1
- package/dist/cjs/src/storm/stormClient.js +6 -2
- package/dist/cjs/src/storm/stream.d.ts +1 -0
- package/dist/cjs/src/storm/stream.js +8 -2
- package/dist/esm/src/storm/codegen.d.ts +1 -0
- package/dist/esm/src/storm/codegen.js +101 -95
- package/dist/esm/src/storm/event-parser.js +5 -4
- package/dist/esm/src/storm/events.d.ts +23 -5
- package/dist/esm/src/storm/events.js +10 -1
- package/dist/esm/src/storm/stormClient.js +6 -2
- package/dist/esm/src/storm/stream.d.ts +1 -0
- package/dist/esm/src/storm/stream.js +8 -2
- package/package.json +1 -1
- package/src/storm/codegen.ts +181 -118
- package/src/storm/event-parser.ts +7 -5
- package/src/storm/events.ts +26 -5
- package/src/storm/stormClient.ts +10 -3
- package/src/storm/stream.ts +8 -2
package/src/storm/codegen.ts
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
5
|
|
6
|
-
import {Definition} from '@kapeta/local-cluster-config';
|
6
|
+
import { Definition } from '@kapeta/local-cluster-config';
|
7
7
|
import {
|
8
8
|
AIFileTypes,
|
9
9
|
BlockCodeGenerator,
|
@@ -13,27 +13,27 @@ import {
|
|
13
13
|
GeneratedResult,
|
14
14
|
MODE_CREATE_ONLY,
|
15
15
|
} from '@kapeta/codegen';
|
16
|
-
import {BlockDefinition} from '@kapeta/schemas';
|
17
|
-
import {codeGeneratorManager} from '../codeGeneratorManager';
|
18
|
-
import {STORM_ID, stormClient} from './stormClient';
|
16
|
+
import { BlockDefinition } from '@kapeta/schemas';
|
17
|
+
import { codeGeneratorManager } from '../codeGeneratorManager';
|
18
|
+
import { STORM_ID, stormClient } from './stormClient';
|
19
19
|
import {
|
20
20
|
StormEvent,
|
21
|
+
StormEventBlockStatusType,
|
21
22
|
StormEventErrorDetailsFile,
|
22
23
|
StormEventFileChunk,
|
23
24
|
StormEventFileDone,
|
24
|
-
StormEventFileLogical
|
25
|
+
StormEventFileLogical,
|
25
26
|
} from './events';
|
26
|
-
import {BlockDefinitionInfo, StormEventParser} from './event-parser';
|
27
|
-
import {ConversationItem, StormFileImplementationPrompt, StormFileInfo, StormStream} from './stream';
|
28
|
-
import {KapetaURI, parseKapetaUri} from '@kapeta/nodejs-utils';
|
29
|
-
import {writeFile} from 'fs/promises';
|
27
|
+
import { BlockDefinitionInfo, StormEventParser } from './event-parser';
|
28
|
+
import { ConversationItem, StormFileImplementationPrompt, StormFileInfo, StormStream } from './stream';
|
29
|
+
import { KapetaURI, parseKapetaUri } from '@kapeta/nodejs-utils';
|
30
|
+
import { writeFile } from 'fs/promises';
|
30
31
|
import path from 'path';
|
31
|
-
import Path, {join} from 'path';
|
32
|
+
import Path, { join } from 'path';
|
32
33
|
import os from 'node:os';
|
33
|
-
import {readFileSync, writeFileSync} from 'fs';
|
34
|
-
import YAML from
|
35
|
-
import * as fs from
|
36
|
-
import {v4 as uuidv4} from 'uuid';
|
34
|
+
import { readFileSync, writeFileSync } from 'fs';
|
35
|
+
import YAML from 'yaml';
|
36
|
+
import * as fs from 'node:fs';
|
37
37
|
|
38
38
|
type ImplementationGenerator = (prompt: StormFileImplementationPrompt, conversationId?: string) => Promise<StormStream>;
|
39
39
|
|
@@ -44,7 +44,7 @@ interface ErrorClassification {
|
|
44
44
|
}
|
45
45
|
|
46
46
|
const SIMULATED_DELAY = 1000;
|
47
|
-
|
47
|
+
const ENABLE_SIMULATED_DELAY = false;
|
48
48
|
class SimulatedFileDelay {
|
49
49
|
private readonly file: StormEventFileDone;
|
50
50
|
public readonly stream;
|
@@ -166,43 +166,8 @@ export class StormCodegen {
|
|
166
166
|
},
|
167
167
|
});
|
168
168
|
break;
|
169
|
-
case 'FILE_START':
|
170
|
-
case 'FILE_CHUNK_RESET':
|
171
|
-
this.out.emit('data', {
|
172
|
-
...data,
|
173
|
-
payload: {
|
174
|
-
...data.payload,
|
175
|
-
blockName,
|
176
|
-
blockRef,
|
177
|
-
instanceId,
|
178
|
-
},
|
179
|
-
});
|
180
|
-
break;
|
181
|
-
case 'FILE_CHUNK':
|
182
|
-
this.out.emit('data', {
|
183
|
-
...data,
|
184
|
-
payload: {
|
185
|
-
...data.payload,
|
186
|
-
blockName,
|
187
|
-
blockRef,
|
188
|
-
instanceId,
|
189
|
-
},
|
190
|
-
});
|
191
|
-
break;
|
192
|
-
case 'FILE_STATE':
|
193
|
-
this.out.emit('data', {
|
194
|
-
...data,
|
195
|
-
payload: {
|
196
|
-
...data.payload,
|
197
|
-
blockName,
|
198
|
-
blockRef,
|
199
|
-
instanceId,
|
200
|
-
},
|
201
|
-
});
|
202
|
-
break;
|
203
169
|
case 'FILE_DONE':
|
204
170
|
return this.handleFileDoneOutput(blockUri, blockName, data);
|
205
|
-
break;
|
206
171
|
}
|
207
172
|
}
|
208
173
|
|
@@ -298,6 +263,8 @@ export class StormCodegen {
|
|
298
263
|
return;
|
299
264
|
}
|
300
265
|
|
266
|
+
const blockUri = parseKapetaUri(block.uri);
|
267
|
+
|
301
268
|
const relevantFiles: StormFileInfo[] = allFiles.filter(
|
302
269
|
(file) => file.type !== AIFileTypes.IGNORE && file.type !== AIFileTypes.WEB_SCREEN
|
303
270
|
);
|
@@ -313,7 +280,7 @@ export class StormCodegen {
|
|
313
280
|
});
|
314
281
|
|
315
282
|
uiStream.on('data', (evt) => {
|
316
|
-
const uiFile = this.handleUiOutput(
|
283
|
+
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
317
284
|
if (uiFile != undefined) {
|
318
285
|
screenFiles.push(uiFile);
|
319
286
|
}
|
@@ -339,7 +306,7 @@ export class StormCodegen {
|
|
339
306
|
const serviceFiles: StormFileInfo[] = allFiles.filter((file) => file.type === AIFileTypes.SERVICE);
|
340
307
|
if (serviceFiles.length > 0) {
|
341
308
|
await this.processTemplates(
|
342
|
-
|
309
|
+
blockUri,
|
343
310
|
block.aiName,
|
344
311
|
stormClient.createServiceImplementation.bind(stormClient),
|
345
312
|
serviceFiles,
|
@@ -371,7 +338,7 @@ export class StormCodegen {
|
|
371
338
|
await writeFile(filePath, screenFile.payload.content);
|
372
339
|
}
|
373
340
|
|
374
|
-
const screenFilesConverted = screenFiles.map(screenFile => {
|
341
|
+
const screenFilesConverted = screenFiles.map((screenFile) => {
|
375
342
|
return {
|
376
343
|
filename: screenFile.payload.filename,
|
377
344
|
content: screenFile.payload.content,
|
@@ -381,12 +348,16 @@ export class StormCodegen {
|
|
381
348
|
};
|
382
349
|
});
|
383
350
|
allFiles.push(...screenFilesConverted);
|
351
|
+
const blockRef = block.uri;
|
352
|
+
|
353
|
+
this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.QA);
|
384
354
|
|
385
355
|
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
386
356
|
const codeGenerator = new BlockCodeGenerator(block.content as BlockDefinition);
|
387
|
-
await this.verifyAndFixCode(codeGenerator, basePath, filesToBeFixed, allFiles);
|
388
357
|
|
389
|
-
|
358
|
+
this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.BUILDING);
|
359
|
+
await this.verifyAndFixCode(blockUri, block.aiName, codeGenerator, basePath, filesToBeFixed, allFiles);
|
360
|
+
|
390
361
|
this.out.emit('data', {
|
391
362
|
type: 'BLOCK_READY',
|
392
363
|
reason: 'Block ready',
|
@@ -400,7 +371,23 @@ export class StormCodegen {
|
|
400
371
|
} satisfies StormEvent);
|
401
372
|
}
|
402
373
|
|
374
|
+
private emitBlockStatus(blockUri: KapetaURI, blockName: string, status: StormEventBlockStatusType) {
|
375
|
+
this.out.emit('data', {
|
376
|
+
type: 'BLOCK_STATUS',
|
377
|
+
reason: status,
|
378
|
+
created: Date.now(),
|
379
|
+
payload: {
|
380
|
+
status,
|
381
|
+
blockName,
|
382
|
+
blockRef: blockUri.toNormalizedString(),
|
383
|
+
instanceId: StormEventParser.toInstanceIdFromRef(blockUri.toNormalizedString()),
|
384
|
+
},
|
385
|
+
} satisfies StormEvent);
|
386
|
+
}
|
387
|
+
|
403
388
|
private async verifyAndFixCode(
|
389
|
+
blockUri: KapetaURI,
|
390
|
+
blockName: string,
|
404
391
|
codeGenerator: CodeGenerator,
|
405
392
|
basePath: string,
|
406
393
|
filesToBeFixed: StormFileInfo[],
|
@@ -421,11 +408,30 @@ export class StormCodegen {
|
|
421
408
|
if (result && !result.valid) {
|
422
409
|
console.debug('Validation error:', result);
|
423
410
|
|
411
|
+
this.emitBlockStatus(blockUri, blockName, StormEventBlockStatusType.PLANNING_FIX);
|
412
|
+
|
424
413
|
const errors = await this.classifyErrors(result.error, basePath);
|
425
|
-
|
426
|
-
|
427
|
-
|
414
|
+
|
415
|
+
if (errors.size > 0) {
|
416
|
+
this.emitBlockStatus(blockUri, blockName, StormEventBlockStatusType.FIXING);
|
417
|
+
|
418
|
+
const promises = Array.from(errors.entries()).map(([filename, fileErrors]) => {
|
419
|
+
// todo: only try to fix file if it is part of filesToBeFixed
|
420
|
+
return this.tryToFixFile(
|
421
|
+
blockUri,
|
422
|
+
blockName,
|
423
|
+
basePath,
|
424
|
+
filename,
|
425
|
+
fileErrors,
|
426
|
+
allFiles,
|
427
|
+
codeGenerator
|
428
|
+
);
|
429
|
+
});
|
430
|
+
|
431
|
+
await Promise.all(promises);
|
428
432
|
}
|
433
|
+
|
434
|
+
this.emitBlockStatus(blockUri, blockName, StormEventBlockStatusType.FIX_DONE);
|
429
435
|
}
|
430
436
|
} catch (e) {
|
431
437
|
console.error('Error:', e);
|
@@ -439,33 +445,57 @@ export class StormCodegen {
|
|
439
445
|
}
|
440
446
|
}
|
441
447
|
|
442
|
-
private async tryToFixFile(
|
448
|
+
private async tryToFixFile(
|
449
|
+
blockUri: KapetaURI,
|
450
|
+
blockName: string,
|
451
|
+
basePath: string,
|
452
|
+
filename: string,
|
453
|
+
fileErrors: ErrorClassification[],
|
454
|
+
allFiles: StormFileInfo[],
|
455
|
+
codeGenerator: CodeGenerator
|
456
|
+
) {
|
443
457
|
console.log(`Processing ${filename}`);
|
444
458
|
const language = await codeGenerator.language();
|
445
|
-
const relevantFiles = allFiles.filter(file => file.type != AIFileTypes.IGNORE);
|
459
|
+
const relevantFiles = allFiles.filter((file) => file.type != AIFileTypes.IGNORE);
|
446
460
|
|
447
|
-
for (let attempts = 1;
|
461
|
+
for (let attempts = 1; attempts <= 5; attempts++) {
|
448
462
|
if (fileErrors.length == 0) {
|
449
463
|
console.log(`No more errors for ${filename}`);
|
450
464
|
return;
|
451
465
|
}
|
452
466
|
|
453
467
|
console.log(`Errors in ${filename} - requesting error details`);
|
454
|
-
const filesForContext = await this.getErrorDetailsForFile(
|
468
|
+
const filesForContext = await this.getErrorDetailsForFile(
|
469
|
+
basePath,
|
470
|
+
filename,
|
471
|
+
fileErrors[0],
|
472
|
+
relevantFiles,
|
473
|
+
language
|
474
|
+
);
|
455
475
|
console.log(`Get error details for ${filename} requesting code fixes`);
|
456
476
|
|
457
|
-
const fix = this.createFixRequestForFile(
|
458
|
-
|
477
|
+
const fix = this.createFixRequestForFile(
|
478
|
+
basePath,
|
479
|
+
filename,
|
480
|
+
fileErrors[0],
|
481
|
+
filesForContext,
|
482
|
+
relevantFiles,
|
483
|
+
language
|
484
|
+
);
|
485
|
+
const codeFixFile = await this.codeFix(blockUri, blockName, fix);
|
459
486
|
console.log(`Got fixed code for ${filename}`);
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
487
|
+
const filePath =
|
488
|
+
codeFixFile.filename.indexOf(basePath) > -1
|
489
|
+
? codeFixFile.filename
|
490
|
+
: join(basePath, codeFixFile.filename);
|
491
|
+
const existing = readFileSync(filePath);
|
492
|
+
if (
|
493
|
+
existing.toString().replace(/(\r\n|\r|\n)+$/, '') == codeFixFile.content.replace(/(\r\n|\r|\n)+$/, '')
|
494
|
+
) {
|
495
|
+
console.log(`${filename} not changed by gemini`);
|
496
|
+
continue;
|
468
497
|
}
|
498
|
+
writeFileSync(filePath, codeFixFile.content);
|
469
499
|
|
470
500
|
const result = await codeGenerator.validateForTarget(basePath);
|
471
501
|
if (result && result.valid) {
|
@@ -488,7 +518,11 @@ export class StormCodegen {
|
|
488
518
|
errorStream.on('data', (evt) => {
|
489
519
|
if (evt.type === 'ERROR_CLASSIFIER') {
|
490
520
|
const eventFileName = this.removePrefix(basePath + '/', evt.payload.filename);
|
491
|
-
const fix = {
|
521
|
+
const fix = {
|
522
|
+
error: evt.payload.error,
|
523
|
+
lineNumber: evt.payload.lineNumber,
|
524
|
+
column: evt.payload.column,
|
525
|
+
};
|
492
526
|
|
493
527
|
let existingFixes = fixes.get(eventFileName);
|
494
528
|
if (existingFixes) {
|
@@ -504,17 +538,23 @@ export class StormCodegen {
|
|
504
538
|
return fixes;
|
505
539
|
}
|
506
540
|
|
507
|
-
private async getErrorDetailsForFile(
|
541
|
+
private async getErrorDetailsForFile(
|
542
|
+
basePath: string,
|
543
|
+
filename: string,
|
544
|
+
error: ErrorClassification,
|
545
|
+
allFiles: StormFileInfo[],
|
546
|
+
language: string
|
547
|
+
): Promise<string[]> {
|
508
548
|
const filePath = filename.indexOf(basePath) > -1 ? filename : join(basePath, filename); // to compensate when compiler returns absolute path
|
509
549
|
return new Promise<string[]>(async (resolve, reject) => {
|
510
550
|
const request = {
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
551
|
+
language: language,
|
552
|
+
sourceFile: {
|
553
|
+
filename: filename,
|
554
|
+
content: readFileSync(filePath, 'utf8'),
|
515
555
|
},
|
516
|
-
|
517
|
-
|
556
|
+
error: error,
|
557
|
+
projectFiles: allFiles.map((f) => f.filename),
|
518
558
|
};
|
519
559
|
|
520
560
|
const detailsStream = await stormClient.createErrorDetails(JSON.stringify(request), []);
|
@@ -522,11 +562,11 @@ export class StormCodegen {
|
|
522
562
|
if (evt.type === 'ERROR_DETAILS') {
|
523
563
|
resolve(evt.payload.files);
|
524
564
|
}
|
525
|
-
reject(new Error(
|
565
|
+
reject(new Error('Error details: Unexpected event [' + evt.type + ']'));
|
526
566
|
});
|
527
567
|
this.out.on('aborted', () => {
|
528
568
|
detailsStream.abort();
|
529
|
-
reject(
|
569
|
+
reject(new Error('aborted'));
|
530
570
|
});
|
531
571
|
detailsStream.on('error', (err) => {
|
532
572
|
reject(err);
|
@@ -535,20 +575,25 @@ export class StormCodegen {
|
|
535
575
|
});
|
536
576
|
}
|
537
577
|
|
538
|
-
private createFixRequestForFile(
|
578
|
+
private createFixRequestForFile(
|
579
|
+
basePath: string,
|
580
|
+
filename: string,
|
581
|
+
error: ErrorClassification,
|
582
|
+
filesForContext: string[],
|
583
|
+
allFiles: StormFileInfo[],
|
584
|
+
language: string
|
585
|
+
): string {
|
539
586
|
const files = new Set(filesForContext);
|
540
587
|
files.add(filename);
|
541
588
|
|
542
|
-
const requestedFiles = Array.from(files).flatMap(file => {
|
589
|
+
const requestedFiles = Array.from(files).flatMap((file) => {
|
543
590
|
if (fs.existsSync(file)) {
|
544
591
|
return file;
|
545
592
|
}
|
546
593
|
|
547
594
|
// file does not exist - look for similar
|
548
595
|
const candidateName = file.split('/').pop();
|
549
|
-
return allFiles
|
550
|
-
.filter(file => file.filename.split('/').pop() === candidateName)
|
551
|
-
.map(f => f.filename);
|
596
|
+
return allFiles.filter((file) => file.filename.split('/').pop() === candidateName).map((f) => f.filename);
|
552
597
|
});
|
553
598
|
|
554
599
|
const filePath = filename.indexOf(basePath) > -1 ? filename : join(basePath, filename);
|
@@ -556,31 +601,26 @@ export class StormCodegen {
|
|
556
601
|
const affectedLine = this.getErrorLine(error, content);
|
557
602
|
|
558
603
|
const fixRequest = {
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
604
|
+
language: language,
|
605
|
+
filename: filename,
|
606
|
+
error: error.error,
|
607
|
+
affectedLine: affectedLine,
|
608
|
+
projectFiles: requestedFiles.map((filename) => {
|
564
609
|
const filePath = filename.indexOf(basePath) > -1 ? filename : join(basePath, filename);
|
565
610
|
const content = readFileSync(filePath, 'utf8');
|
566
611
|
return { filename: filename, content: content };
|
567
612
|
}),
|
568
|
-
"conversationId": this.conversationId,
|
569
|
-
"sessionId": uuidv4()
|
570
613
|
};
|
571
614
|
|
572
615
|
return JSON.stringify(fixRequest);
|
573
616
|
}
|
574
617
|
|
575
|
-
private getErrorLine(
|
576
|
-
errorDetails: ErrorClassification,
|
577
|
-
sourceCode: string
|
578
|
-
): string {
|
618
|
+
private getErrorLine(errorDetails: ErrorClassification, sourceCode: string): string {
|
579
619
|
const lines = sourceCode.split('\n');
|
580
620
|
const errorLine = lines[errorDetails.lineNumber - 1];
|
581
621
|
|
582
622
|
if (!errorLine) {
|
583
|
-
return
|
623
|
+
return 'Error: Line number out of range.';
|
584
624
|
}
|
585
625
|
|
586
626
|
return errorLine;
|
@@ -596,24 +636,41 @@ export class StormCodegen {
|
|
596
636
|
/**
|
597
637
|
* Sends the code to the AI for a fix
|
598
638
|
*/
|
599
|
-
private async codeFix(
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
fixStream.
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
639
|
+
private async codeFix(
|
640
|
+
blockUri: KapetaURI,
|
641
|
+
blockName: string,
|
642
|
+
fix: string,
|
643
|
+
history?: ConversationItem[]
|
644
|
+
): Promise<StormEventErrorDetailsFile> {
|
645
|
+
return new Promise<StormEventErrorDetailsFile>(async (resolve, reject) => {
|
646
|
+
try {
|
647
|
+
const fixStream = await stormClient.createCodeFix(fix, history, this.conversationId);
|
648
|
+
let resolved = false;
|
649
|
+
fixStream.on('data', (evt) => {
|
650
|
+
if (this.handleFileEvents(blockUri, blockName, evt)) {
|
651
|
+
return;
|
652
|
+
}
|
653
|
+
|
654
|
+
if (evt.type === 'CODE_FIX') {
|
655
|
+
resolved = true;
|
656
|
+
resolve(evt.payload);
|
657
|
+
}
|
658
|
+
});
|
659
|
+
this.out.on('aborted', () => {
|
660
|
+
fixStream.abort();
|
661
|
+
reject(new Error('aborted'));
|
662
|
+
});
|
663
|
+
fixStream.on('error', (err) => {
|
664
|
+
reject(err);
|
665
|
+
});
|
666
|
+
fixStream.on('end', () => {
|
667
|
+
if (!resolved) {
|
668
|
+
reject(new Error('Code fix never returned a valid event'));
|
669
|
+
}
|
670
|
+
});
|
671
|
+
} catch (e) {
|
672
|
+
reject(e);
|
673
|
+
}
|
617
674
|
});
|
618
675
|
}
|
619
676
|
|
@@ -653,7 +710,13 @@ export class StormCodegen {
|
|
653
710
|
instanceId: StormEventParser.toInstanceIdFromRef(ref),
|
654
711
|
},
|
655
712
|
};
|
656
|
-
|
713
|
+
|
714
|
+
if (ENABLE_SIMULATED_DELAY) {
|
715
|
+
// Simulate a delay when sending the file
|
716
|
+
return new SimulatedFileDelay(fileEvent, this.out).start();
|
717
|
+
} else {
|
718
|
+
this.out.emit('data', fileEvent);
|
719
|
+
}
|
657
720
|
});
|
658
721
|
|
659
722
|
return Promise.all(promises);
|
@@ -181,10 +181,10 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
181
181
|
|
182
182
|
return {
|
183
183
|
serviceKind: normalizeKapetaUri(`${blockTypeService.definition.metadata.name}:${blockTypeService.version}`),
|
184
|
-
serviceLanguage: normalizeKapetaUri(
|
184
|
+
serviceLanguage: normalizeKapetaUri(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
|
185
185
|
|
186
186
|
frontendKind: normalizeKapetaUri(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
187
|
-
frontendLanguage: normalizeKapetaUri(
|
187
|
+
frontendLanguage: normalizeKapetaUri(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
188
188
|
|
189
189
|
cliKind: normalizeKapetaUri(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
190
190
|
cliLanguage: normalizeKapetaUri(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
@@ -270,7 +270,6 @@ export class StormEventParser {
|
|
270
270
|
public processEvent(handle: string, evt: StormEvent): StormDefinitions {
|
271
271
|
let blockInfo;
|
272
272
|
this.events.push(evt);
|
273
|
-
console.log('Processing event: %s', evt.type);
|
274
273
|
switch (evt.type) {
|
275
274
|
case 'CREATE_PLAN_PROPERTIES':
|
276
275
|
this.planName = evt.payload.name;
|
@@ -431,9 +430,12 @@ export class StormEventParser {
|
|
431
430
|
}
|
432
431
|
|
433
432
|
const clientTypes = DSLDataTypeParser.parse(
|
434
|
-
clientConsumerBlock.content.spec.entities.source!.value,
|
433
|
+
clientConsumerBlock.content.spec.entities.source!.value,
|
434
|
+
{ ignoreSemantics: true }
|
435
435
|
);
|
436
|
-
const apiTypes = DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, {
|
436
|
+
const apiTypes = DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, {
|
437
|
+
ignoreSemantics: true,
|
438
|
+
});
|
437
439
|
|
438
440
|
apiTypes.forEach((apiType) => {
|
439
441
|
if (clientTypes.some((clientType) => clientType.name === apiType.name)) {
|
package/src/storm/events.ts
CHANGED
@@ -139,9 +139,8 @@ export interface StormEventCodeFix {
|
|
139
139
|
reason: string;
|
140
140
|
created: number;
|
141
141
|
payload: {
|
142
|
-
|
143
|
-
|
144
|
-
}
|
142
|
+
filename: string;
|
143
|
+
content: string;
|
145
144
|
};
|
146
145
|
}
|
147
146
|
|
@@ -162,7 +161,7 @@ export interface StormEventErrorDetails {
|
|
162
161
|
reason: string;
|
163
162
|
created: number;
|
164
163
|
payload: {
|
165
|
-
files: string[]
|
164
|
+
files: string[];
|
166
165
|
};
|
167
166
|
}
|
168
167
|
|
@@ -252,6 +251,26 @@ export interface StormEventBlockReady {
|
|
252
251
|
};
|
253
252
|
}
|
254
253
|
|
254
|
+
export enum StormEventBlockStatusType {
|
255
|
+
QA = 'QA',
|
256
|
+
FIXING = 'FIXING',
|
257
|
+
PLANNING_FIX = 'PLANNING_FIX',
|
258
|
+
FIX_DONE = 'FIX_DONE',
|
259
|
+
BUILDING = 'BUILDING',
|
260
|
+
}
|
261
|
+
|
262
|
+
export interface StormEventBlockStatus {
|
263
|
+
type: 'BLOCK_STATUS';
|
264
|
+
reason: string;
|
265
|
+
created: number;
|
266
|
+
payload: {
|
267
|
+
status: StormEventBlockStatusType;
|
268
|
+
blockName: string;
|
269
|
+
blockRef: string;
|
270
|
+
instanceId: string;
|
271
|
+
};
|
272
|
+
}
|
273
|
+
|
255
274
|
export interface StormEventDone {
|
256
275
|
type: 'DONE';
|
257
276
|
created: number;
|
@@ -268,6 +287,7 @@ export enum StormEventPhaseType {
|
|
268
287
|
META = 'META',
|
269
288
|
DEFINITIONS = 'DEFINITIONS',
|
270
289
|
IMPLEMENTATION = 'IMPLEMENTATION',
|
290
|
+
QA = 'QA',
|
271
291
|
}
|
272
292
|
|
273
293
|
export interface StormEventPhases {
|
@@ -299,4 +319,5 @@ export type StormEvent =
|
|
299
319
|
| StormEventCodeFix
|
300
320
|
| StormEventErrorDetails
|
301
321
|
| StormEventBlockReady
|
302
|
-
| StormEventPhases
|
322
|
+
| StormEventPhases
|
323
|
+
| StormEventBlockStatus;
|
package/src/storm/stormClient.ts
CHANGED
@@ -26,7 +26,11 @@ class StormClient {
|
|
26
26
|
this._baseUrl = getRemoteUrl('ai-service', 'https://ai.kapeta.com');
|
27
27
|
}
|
28
28
|
|
29
|
-
private async createOptions(
|
29
|
+
private async createOptions(
|
30
|
+
path: string,
|
31
|
+
method: string,
|
32
|
+
body: StormContextRequest
|
33
|
+
): Promise<RequestInit & { url: string }> {
|
30
34
|
const url = `${this._baseUrl}${path}`;
|
31
35
|
const headers: { [k: string]: string } = {
|
32
36
|
'Content-Type': 'application/json',
|
@@ -39,7 +43,6 @@ class StormClient {
|
|
39
43
|
|
40
44
|
if (body.conversationId) {
|
41
45
|
headers[ConversationIdHeader] = body.conversationId;
|
42
|
-
console.log('Setting ConversationIdHeader', headers[ConversationIdHeader]);
|
43
46
|
}
|
44
47
|
|
45
48
|
return {
|
@@ -92,7 +95,11 @@ class StormClient {
|
|
92
95
|
});
|
93
96
|
|
94
97
|
out.on('aborted', () => {
|
95
|
-
|
98
|
+
try {
|
99
|
+
abort.abort();
|
100
|
+
} catch (e) {
|
101
|
+
console.warn('Error aborting stream', e);
|
102
|
+
}
|
96
103
|
});
|
97
104
|
|
98
105
|
return out;
|
package/src/storm/stream.ts
CHANGED
@@ -11,6 +11,7 @@ export class StormStream extends EventEmitter {
|
|
11
11
|
private conversationId: string = '';
|
12
12
|
private lines: string[] = [];
|
13
13
|
private aborted: boolean = false;
|
14
|
+
private done: boolean = false;
|
14
15
|
|
15
16
|
constructor(prompt: string = '', conversationId?: string | null) {
|
16
17
|
super();
|
@@ -39,6 +40,7 @@ export class StormStream extends EventEmitter {
|
|
39
40
|
}
|
40
41
|
|
41
42
|
end() {
|
43
|
+
this.done = true;
|
42
44
|
this.emit('end');
|
43
45
|
}
|
44
46
|
|
@@ -59,6 +61,9 @@ export class StormStream extends EventEmitter {
|
|
59
61
|
}
|
60
62
|
|
61
63
|
waitForDone() {
|
64
|
+
if (this.done) {
|
65
|
+
return Promise.resolve();
|
66
|
+
}
|
62
67
|
return new Promise<void>((resolve, reject) => {
|
63
68
|
const errorHandler = (err: any) => {
|
64
69
|
this.removeListener('error', errorHandler);
|
@@ -70,8 +75,8 @@ export class StormStream extends EventEmitter {
|
|
70
75
|
this.removeListener('end', endHandler);
|
71
76
|
resolve();
|
72
77
|
};
|
73
|
-
this.
|
74
|
-
this.
|
78
|
+
this.on('error', errorHandler);
|
79
|
+
this.on('end', endHandler);
|
75
80
|
});
|
76
81
|
}
|
77
82
|
|
@@ -80,6 +85,7 @@ export class StormStream extends EventEmitter {
|
|
80
85
|
return;
|
81
86
|
}
|
82
87
|
this.aborted = true;
|
88
|
+
this.done = true;
|
83
89
|
this.emit('aborted');
|
84
90
|
}
|
85
91
|
}
|