@kapeta/local-cluster-service 0.51.0 → 0.51.2
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 +15 -0
- package/dist/cjs/src/storm/codegen.d.ts +0 -1
- package/dist/cjs/src/storm/codegen.js +25 -11
- package/dist/cjs/src/storm/events.d.ts +10 -4
- package/dist/cjs/src/storm/stormClient.js +4 -3
- package/dist/esm/src/storm/codegen.d.ts +0 -1
- package/dist/esm/src/storm/codegen.js +25 -11
- package/dist/esm/src/storm/events.d.ts +10 -4
- package/dist/esm/src/storm/stormClient.js +4 -3
- package/package.json +1 -1
- package/src/storm/codegen.ts +36 -19
- package/src/storm/events.ts +11 -4
- package/src/storm/stormClient.ts +4 -3
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## [0.51.2](https://github.com/kapetacom/local-cluster-service/compare/v0.51.1...v0.51.2) (2024-06-06)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* collect generated screens & write these ([50fa728](https://github.com/kapetacom/local-cluster-service/commit/50fa728fea26c0baad2c37b821602b3ca3c46679))
|
7
|
+
* merge errors ([92fae09](https://github.com/kapetacom/local-cluster-service/commit/92fae09bc226e7c6128a0a7ae4123ffe810ebe04))
|
8
|
+
|
9
|
+
## [0.51.1](https://github.com/kapetacom/local-cluster-service/compare/v0.51.0...v0.51.1) (2024-06-05)
|
10
|
+
|
11
|
+
|
12
|
+
### Bug Fixes
|
13
|
+
|
14
|
+
* Add line numbers to chunks ([a60688e](https://github.com/kapetacom/local-cluster-service/commit/a60688e0341238160c6779ae43cae876a62e622d))
|
15
|
+
|
1
16
|
# [0.51.0](https://github.com/kapetacom/local-cluster-service/compare/v0.50.0...v0.51.0) (2024-06-05)
|
2
17
|
|
3
18
|
|
@@ -27,7 +27,6 @@ export declare class StormCodegen {
|
|
27
27
|
private processBlockCode;
|
28
28
|
private verifyAndFixCode;
|
29
29
|
removePrefix(prefix: string, str: string): string;
|
30
|
-
writeToFile(fileName: string, code: Promise<string>): Promise<void>;
|
31
30
|
/**
|
32
31
|
* Sends the code to the AI for a fix
|
33
32
|
*/
|
@@ -42,6 +42,7 @@ const path_1 = __importStar(require("path"));
|
|
42
42
|
const node_os_1 = __importDefault(require("node:os"));
|
43
43
|
const fs_1 = require("fs");
|
44
44
|
const path_2 = __importDefault(require("path"));
|
45
|
+
const yaml_1 = __importDefault(require("yaml"));
|
45
46
|
const SIMULATED_DELAY = 1000;
|
46
47
|
class SimulatedFileDelay {
|
47
48
|
file;
|
@@ -66,6 +67,7 @@ class SimulatedFileDelay {
|
|
66
67
|
});
|
67
68
|
const lines = this.file.payload.content.split('\n');
|
68
69
|
const delayPerLine = SIMULATED_DELAY / lines.length;
|
70
|
+
let lineNumber = 0;
|
69
71
|
for (const line of lines) {
|
70
72
|
await new Promise((resolve) => {
|
71
73
|
setTimeout(() => {
|
@@ -76,6 +78,7 @@ class SimulatedFileDelay {
|
|
76
78
|
payload: {
|
77
79
|
...commonPayload,
|
78
80
|
content: line,
|
81
|
+
lineNumber: lineNumber++,
|
79
82
|
},
|
80
83
|
});
|
81
84
|
resolve();
|
@@ -179,7 +182,7 @@ class StormCodegen {
|
|
179
182
|
});
|
180
183
|
break;
|
181
184
|
case 'FILE_DONE':
|
182
|
-
this.handleFileDoneOutput(blockUri, blockName, data);
|
185
|
+
return this.handleFileDoneOutput(blockUri, blockName, data);
|
183
186
|
break;
|
184
187
|
}
|
185
188
|
}
|
@@ -269,6 +272,7 @@ class StormCodegen {
|
|
269
272
|
}
|
270
273
|
const relevantFiles = allFiles.filter((file) => file.type !== codegen_1.AIFileTypes.IGNORE && file.type !== codegen_1.AIFileTypes.WEB_SCREEN);
|
271
274
|
const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
|
275
|
+
const screenFiles = [];
|
272
276
|
if (uiTemplates.length > 0) {
|
273
277
|
const uiStream = await stormClient_1.stormClient.createUIImplementation({
|
274
278
|
events: this.events,
|
@@ -278,7 +282,10 @@ class StormCodegen {
|
|
278
282
|
prompt: this.userPrompt,
|
279
283
|
});
|
280
284
|
uiStream.on('data', (evt) => {
|
281
|
-
this.handleUiOutput((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, evt);
|
285
|
+
const uiFile = this.handleUiOutput((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, evt);
|
286
|
+
if (uiFile != undefined) {
|
287
|
+
screenFiles.push(uiFile);
|
288
|
+
}
|
282
289
|
});
|
283
290
|
this.out.on('aborted', () => {
|
284
291
|
uiStream.abort();
|
@@ -307,11 +314,23 @@ class StormCodegen {
|
|
307
314
|
const filePath = (0, path_1.join)(basePath, serviceFile.filename);
|
308
315
|
await (0, promises_1.writeFile)(filePath, serviceFile.content);
|
309
316
|
}
|
310
|
-
|
311
|
-
|
312
|
-
|
317
|
+
const kapetaYmlPath = (0, path_1.join)(basePath, 'kapeta.yml');
|
318
|
+
await (0, promises_1.writeFile)(kapetaYmlPath, yaml_1.default.stringify(block.content));
|
319
|
+
for (const screenFile of screenFiles) {
|
320
|
+
const filePath = (0, path_1.join)(basePath, screenFile.payload.filename);
|
321
|
+
await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
|
313
322
|
}
|
314
|
-
const
|
323
|
+
const screenFilesConverted = screenFiles.map(screenFile => {
|
324
|
+
return {
|
325
|
+
filename: screenFile.payload.filename,
|
326
|
+
content: screenFile.payload.content,
|
327
|
+
mode: codegen_1.MODE_CREATE_ONLY,
|
328
|
+
permissions: '0644',
|
329
|
+
type: codegen_1.AIFileTypes.WEB_SCREEN,
|
330
|
+
};
|
331
|
+
});
|
332
|
+
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
333
|
+
allFiles.push(...screenFilesConverted);
|
315
334
|
const codeGenerator = new codegen_1.BlockCodeGenerator(block.content);
|
316
335
|
await this.verifyAndFixCode(codeGenerator, basePath, filesToBeFixed, allFiles);
|
317
336
|
const blockRef = block.uri;
|
@@ -390,11 +409,6 @@ class StormCodegen {
|
|
390
409
|
}
|
391
410
|
return str;
|
392
411
|
}
|
393
|
-
async writeToFile(fileName, code) {
|
394
|
-
console.log(`writing the fixed code to ${fileName}`);
|
395
|
-
const resolvedCode = await code;
|
396
|
-
(0, fs_1.writeFileSync)(fileName, resolvedCode);
|
397
|
-
}
|
398
412
|
/**
|
399
413
|
* Sends the code to the AI for a fix
|
400
414
|
*/
|
@@ -172,13 +172,19 @@ export interface StormEventFileState extends StormEventFileBase {
|
|
172
172
|
state: string;
|
173
173
|
};
|
174
174
|
}
|
175
|
-
export interface
|
176
|
-
type: 'FILE_DONE'
|
175
|
+
export interface StormEventFileDone extends StormEventFileBase {
|
176
|
+
type: 'FILE_DONE';
|
177
177
|
payload: StormEventFileBasePayload & {
|
178
178
|
content: string;
|
179
179
|
};
|
180
180
|
}
|
181
|
-
export
|
181
|
+
export interface StormEventFileChunk extends StormEventFileBase {
|
182
|
+
type: 'FILE_CHUNK';
|
183
|
+
payload: StormEventFileBasePayload & {
|
184
|
+
content: string;
|
185
|
+
lineNumber: number;
|
186
|
+
};
|
187
|
+
}
|
182
188
|
export interface StormEventBlockReady {
|
183
189
|
type: 'BLOCK_READY';
|
184
190
|
reason: string;
|
@@ -212,4 +218,4 @@ export interface StormEventPhases {
|
|
212
218
|
phaseType: StormEventPhaseType;
|
213
219
|
};
|
214
220
|
}
|
215
|
-
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState |
|
221
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventBlockReady | StormEventPhases;
|
@@ -20,14 +20,15 @@ class StormClient {
|
|
20
20
|
constructor() {
|
21
21
|
this._baseUrl = (0, utils_1.getRemoteUrl)('ai-service', 'https://ai.kapeta.com');
|
22
22
|
}
|
23
|
-
createOptions(path, method, body) {
|
23
|
+
async createOptions(path, method, body) {
|
24
24
|
const url = `${this._baseUrl}${path}`;
|
25
25
|
const headers = {
|
26
26
|
'Content-Type': 'application/json',
|
27
27
|
};
|
28
28
|
const api = new nodejs_api_client_1.KapetaAPI();
|
29
29
|
if (api.hasToken()) {
|
30
|
-
|
30
|
+
const token = await api.getAccessToken();
|
31
|
+
headers['Authorization'] = `Bearer ${token}`;
|
31
32
|
}
|
32
33
|
if (body.conversationId) {
|
33
34
|
headers[exports.ConversationIdHeader] = body.conversationId;
|
@@ -42,7 +43,7 @@ class StormClient {
|
|
42
43
|
}
|
43
44
|
async send(path, body, method = 'POST') {
|
44
45
|
const stringPrompt = typeof body.prompt === 'string' ? body.prompt : JSON.stringify(body.prompt);
|
45
|
-
const options = this.createOptions(path, method, {
|
46
|
+
const options = await this.createOptions(path, method, {
|
46
47
|
prompt: stringPrompt,
|
47
48
|
conversationId: body.conversationId,
|
48
49
|
});
|
@@ -27,7 +27,6 @@ export declare class StormCodegen {
|
|
27
27
|
private processBlockCode;
|
28
28
|
private verifyAndFixCode;
|
29
29
|
removePrefix(prefix: string, str: string): string;
|
30
|
-
writeToFile(fileName: string, code: Promise<string>): Promise<void>;
|
31
30
|
/**
|
32
31
|
* Sends the code to the AI for a fix
|
33
32
|
*/
|
@@ -42,6 +42,7 @@ const path_1 = __importStar(require("path"));
|
|
42
42
|
const node_os_1 = __importDefault(require("node:os"));
|
43
43
|
const fs_1 = require("fs");
|
44
44
|
const path_2 = __importDefault(require("path"));
|
45
|
+
const yaml_1 = __importDefault(require("yaml"));
|
45
46
|
const SIMULATED_DELAY = 1000;
|
46
47
|
class SimulatedFileDelay {
|
47
48
|
file;
|
@@ -66,6 +67,7 @@ class SimulatedFileDelay {
|
|
66
67
|
});
|
67
68
|
const lines = this.file.payload.content.split('\n');
|
68
69
|
const delayPerLine = SIMULATED_DELAY / lines.length;
|
70
|
+
let lineNumber = 0;
|
69
71
|
for (const line of lines) {
|
70
72
|
await new Promise((resolve) => {
|
71
73
|
setTimeout(() => {
|
@@ -76,6 +78,7 @@ class SimulatedFileDelay {
|
|
76
78
|
payload: {
|
77
79
|
...commonPayload,
|
78
80
|
content: line,
|
81
|
+
lineNumber: lineNumber++,
|
79
82
|
},
|
80
83
|
});
|
81
84
|
resolve();
|
@@ -179,7 +182,7 @@ class StormCodegen {
|
|
179
182
|
});
|
180
183
|
break;
|
181
184
|
case 'FILE_DONE':
|
182
|
-
this.handleFileDoneOutput(blockUri, blockName, data);
|
185
|
+
return this.handleFileDoneOutput(blockUri, blockName, data);
|
183
186
|
break;
|
184
187
|
}
|
185
188
|
}
|
@@ -269,6 +272,7 @@ class StormCodegen {
|
|
269
272
|
}
|
270
273
|
const relevantFiles = allFiles.filter((file) => file.type !== codegen_1.AIFileTypes.IGNORE && file.type !== codegen_1.AIFileTypes.WEB_SCREEN);
|
271
274
|
const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
|
275
|
+
const screenFiles = [];
|
272
276
|
if (uiTemplates.length > 0) {
|
273
277
|
const uiStream = await stormClient_1.stormClient.createUIImplementation({
|
274
278
|
events: this.events,
|
@@ -278,7 +282,10 @@ class StormCodegen {
|
|
278
282
|
prompt: this.userPrompt,
|
279
283
|
});
|
280
284
|
uiStream.on('data', (evt) => {
|
281
|
-
this.handleUiOutput((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, evt);
|
285
|
+
const uiFile = this.handleUiOutput((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, evt);
|
286
|
+
if (uiFile != undefined) {
|
287
|
+
screenFiles.push(uiFile);
|
288
|
+
}
|
282
289
|
});
|
283
290
|
this.out.on('aborted', () => {
|
284
291
|
uiStream.abort();
|
@@ -307,11 +314,23 @@ class StormCodegen {
|
|
307
314
|
const filePath = (0, path_1.join)(basePath, serviceFile.filename);
|
308
315
|
await (0, promises_1.writeFile)(filePath, serviceFile.content);
|
309
316
|
}
|
310
|
-
|
311
|
-
|
312
|
-
|
317
|
+
const kapetaYmlPath = (0, path_1.join)(basePath, 'kapeta.yml');
|
318
|
+
await (0, promises_1.writeFile)(kapetaYmlPath, yaml_1.default.stringify(block.content));
|
319
|
+
for (const screenFile of screenFiles) {
|
320
|
+
const filePath = (0, path_1.join)(basePath, screenFile.payload.filename);
|
321
|
+
await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
|
313
322
|
}
|
314
|
-
const
|
323
|
+
const screenFilesConverted = screenFiles.map(screenFile => {
|
324
|
+
return {
|
325
|
+
filename: screenFile.payload.filename,
|
326
|
+
content: screenFile.payload.content,
|
327
|
+
mode: codegen_1.MODE_CREATE_ONLY,
|
328
|
+
permissions: '0644',
|
329
|
+
type: codegen_1.AIFileTypes.WEB_SCREEN,
|
330
|
+
};
|
331
|
+
});
|
332
|
+
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
333
|
+
allFiles.push(...screenFilesConverted);
|
315
334
|
const codeGenerator = new codegen_1.BlockCodeGenerator(block.content);
|
316
335
|
await this.verifyAndFixCode(codeGenerator, basePath, filesToBeFixed, allFiles);
|
317
336
|
const blockRef = block.uri;
|
@@ -390,11 +409,6 @@ class StormCodegen {
|
|
390
409
|
}
|
391
410
|
return str;
|
392
411
|
}
|
393
|
-
async writeToFile(fileName, code) {
|
394
|
-
console.log(`writing the fixed code to ${fileName}`);
|
395
|
-
const resolvedCode = await code;
|
396
|
-
(0, fs_1.writeFileSync)(fileName, resolvedCode);
|
397
|
-
}
|
398
412
|
/**
|
399
413
|
* Sends the code to the AI for a fix
|
400
414
|
*/
|
@@ -172,13 +172,19 @@ export interface StormEventFileState extends StormEventFileBase {
|
|
172
172
|
state: string;
|
173
173
|
};
|
174
174
|
}
|
175
|
-
export interface
|
176
|
-
type: 'FILE_DONE'
|
175
|
+
export interface StormEventFileDone extends StormEventFileBase {
|
176
|
+
type: 'FILE_DONE';
|
177
177
|
payload: StormEventFileBasePayload & {
|
178
178
|
content: string;
|
179
179
|
};
|
180
180
|
}
|
181
|
-
export
|
181
|
+
export interface StormEventFileChunk extends StormEventFileBase {
|
182
|
+
type: 'FILE_CHUNK';
|
183
|
+
payload: StormEventFileBasePayload & {
|
184
|
+
content: string;
|
185
|
+
lineNumber: number;
|
186
|
+
};
|
187
|
+
}
|
182
188
|
export interface StormEventBlockReady {
|
183
189
|
type: 'BLOCK_READY';
|
184
190
|
reason: string;
|
@@ -212,4 +218,4 @@ export interface StormEventPhases {
|
|
212
218
|
phaseType: StormEventPhaseType;
|
213
219
|
};
|
214
220
|
}
|
215
|
-
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState |
|
221
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventBlockReady | StormEventPhases;
|
@@ -20,14 +20,15 @@ class StormClient {
|
|
20
20
|
constructor() {
|
21
21
|
this._baseUrl = (0, utils_1.getRemoteUrl)('ai-service', 'https://ai.kapeta.com');
|
22
22
|
}
|
23
|
-
createOptions(path, method, body) {
|
23
|
+
async createOptions(path, method, body) {
|
24
24
|
const url = `${this._baseUrl}${path}`;
|
25
25
|
const headers = {
|
26
26
|
'Content-Type': 'application/json',
|
27
27
|
};
|
28
28
|
const api = new nodejs_api_client_1.KapetaAPI();
|
29
29
|
if (api.hasToken()) {
|
30
|
-
|
30
|
+
const token = await api.getAccessToken();
|
31
|
+
headers['Authorization'] = `Bearer ${token}`;
|
31
32
|
}
|
32
33
|
if (body.conversationId) {
|
33
34
|
headers[exports.ConversationIdHeader] = body.conversationId;
|
@@ -42,7 +43,7 @@ class StormClient {
|
|
42
43
|
}
|
43
44
|
async send(path, body, method = 'POST') {
|
44
45
|
const stringPrompt = typeof body.prompt === 'string' ? body.prompt : JSON.stringify(body.prompt);
|
45
|
-
const options = this.createOptions(path, method, {
|
46
|
+
const options = await this.createOptions(path, method, {
|
46
47
|
prompt: stringPrompt,
|
47
48
|
conversationId: body.conversationId,
|
48
49
|
});
|
package/package.json
CHANGED
package/src/storm/codegen.ts
CHANGED
@@ -11,11 +11,12 @@ import {
|
|
11
11
|
CodeWriter,
|
12
12
|
GeneratedFile,
|
13
13
|
GeneratedResult,
|
14
|
+
MODE_CREATE_ONLY,
|
14
15
|
} from '@kapeta/codegen';
|
15
16
|
import { BlockDefinition } from '@kapeta/schemas';
|
16
17
|
import { codeGeneratorManager } from '../codeGeneratorManager';
|
17
18
|
import { STORM_ID, stormClient } from './stormClient';
|
18
|
-
import { StormEvent,
|
19
|
+
import { StormEvent, StormEventFileChunk, StormEventFileDone, StormEventFileLogical } from './events';
|
19
20
|
import { BlockDefinitionInfo, StormEventParser } from './event-parser';
|
20
21
|
import { StormFileImplementationPrompt, StormFileInfo, StormStream } from './stream';
|
21
22
|
import { KapetaURI, parseKapetaUri } from '@kapeta/nodejs-utils';
|
@@ -24,15 +25,16 @@ import path, { join } from 'path';
|
|
24
25
|
import os from 'node:os';
|
25
26
|
import { readFile, readFileSync, writeFileSync } from 'fs';
|
26
27
|
import Path from 'path';
|
28
|
+
import YAML from "yaml";
|
27
29
|
|
28
30
|
type ImplementationGenerator = (prompt: StormFileImplementationPrompt, conversationId?: string) => Promise<StormStream>;
|
29
31
|
|
30
32
|
const SIMULATED_DELAY = 1000;
|
31
33
|
|
32
34
|
class SimulatedFileDelay {
|
33
|
-
private readonly file:
|
35
|
+
private readonly file: StormEventFileDone;
|
34
36
|
public readonly stream;
|
35
|
-
constructor(file:
|
37
|
+
constructor(file: StormEventFileDone, stream: StormStream) {
|
36
38
|
this.file = file;
|
37
39
|
this.stream = stream;
|
38
40
|
}
|
@@ -54,6 +56,7 @@ class SimulatedFileDelay {
|
|
54
56
|
|
55
57
|
const lines = this.file.payload.content.split('\n');
|
56
58
|
const delayPerLine = SIMULATED_DELAY / lines.length;
|
59
|
+
let lineNumber = 0;
|
57
60
|
for (const line of lines) {
|
58
61
|
await new Promise<void>((resolve) => {
|
59
62
|
setTimeout(() => {
|
@@ -64,8 +67,9 @@ class SimulatedFileDelay {
|
|
64
67
|
payload: {
|
65
68
|
...commonPayload,
|
66
69
|
content: line,
|
70
|
+
lineNumber: lineNumber++,
|
67
71
|
},
|
68
|
-
} satisfies
|
72
|
+
} satisfies StormEventFileChunk);
|
69
73
|
resolve();
|
70
74
|
}, delayPerLine);
|
71
75
|
});
|
@@ -126,7 +130,7 @@ export class StormCodegen {
|
|
126
130
|
}
|
127
131
|
}
|
128
132
|
|
129
|
-
private handleUiOutput(blockUri: KapetaURI, blockName: string, data: StormEvent) {
|
133
|
+
private handleUiOutput(blockUri: KapetaURI, blockName: string, data: StormEvent): StormEventFileDone | undefined {
|
130
134
|
const blockRef = blockUri.toNormalizedString();
|
131
135
|
const instanceId = StormEventParser.toInstanceIdFromRef(blockRef);
|
132
136
|
|
@@ -183,7 +187,7 @@ export class StormCodegen {
|
|
183
187
|
});
|
184
188
|
break;
|
185
189
|
case 'FILE_DONE':
|
186
|
-
this.handleFileDoneOutput(blockUri, blockName, data);
|
190
|
+
return this.handleFileDoneOutput(blockUri, blockName, data);
|
187
191
|
break;
|
188
192
|
}
|
189
193
|
}
|
@@ -250,7 +254,7 @@ export class StormCodegen {
|
|
250
254
|
blockRef: ref,
|
251
255
|
instanceId: StormEventParser.toInstanceIdFromRef(ref),
|
252
256
|
},
|
253
|
-
} as
|
257
|
+
} as StormEventFileDone;
|
254
258
|
}
|
255
259
|
}
|
256
260
|
|
@@ -284,6 +288,7 @@ export class StormCodegen {
|
|
284
288
|
(file) => file.type !== AIFileTypes.IGNORE && file.type !== AIFileTypes.WEB_SCREEN
|
285
289
|
);
|
286
290
|
const uiTemplates: StormFileInfo[] = allFiles.filter((file) => file.type === AIFileTypes.WEB_SCREEN);
|
291
|
+
const screenFiles: StormEventFileDone[] = [];
|
287
292
|
if (uiTemplates.length > 0) {
|
288
293
|
const uiStream = await stormClient.createUIImplementation({
|
289
294
|
events: this.events,
|
@@ -294,7 +299,10 @@ export class StormCodegen {
|
|
294
299
|
});
|
295
300
|
|
296
301
|
uiStream.on('data', (evt) => {
|
297
|
-
this.handleUiOutput(parseKapetaUri(block.uri), block.aiName, evt);
|
302
|
+
const uiFile = this.handleUiOutput(parseKapetaUri(block.uri), block.aiName, evt);
|
303
|
+
if (uiFile != undefined) {
|
304
|
+
screenFiles.push(uiFile);
|
305
|
+
}
|
298
306
|
});
|
299
307
|
|
300
308
|
this.out.on('aborted', () => {
|
@@ -341,12 +349,25 @@ export class StormCodegen {
|
|
341
349
|
await writeFile(filePath, serviceFile.content);
|
342
350
|
}
|
343
351
|
|
344
|
-
|
345
|
-
|
346
|
-
|
352
|
+
const kapetaYmlPath = join(basePath, 'kapeta.yml');
|
353
|
+
await writeFile(kapetaYmlPath, YAML.stringify(block.content as BlockDefinition));
|
354
|
+
|
355
|
+
for (const screenFile of screenFiles) {
|
356
|
+
const filePath = join(basePath, screenFile.payload.filename);
|
357
|
+
await writeFile(filePath, screenFile.payload.content);
|
347
358
|
}
|
348
359
|
|
349
|
-
const
|
360
|
+
const screenFilesConverted = screenFiles.map(screenFile => {
|
361
|
+
return {
|
362
|
+
filename: screenFile.payload.filename,
|
363
|
+
content: screenFile.payload.content,
|
364
|
+
mode: MODE_CREATE_ONLY,
|
365
|
+
permissions: '0644',
|
366
|
+
type: AIFileTypes.WEB_SCREEN,
|
367
|
+
};
|
368
|
+
});
|
369
|
+
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
370
|
+
allFiles.push(...screenFilesConverted);
|
350
371
|
const codeGenerator = new BlockCodeGenerator(block.content as BlockDefinition);
|
351
372
|
await this.verifyAndFixCode(codeGenerator, basePath, filesToBeFixed, allFiles);
|
352
373
|
|
@@ -437,11 +458,7 @@ export class StormCodegen {
|
|
437
458
|
}
|
438
459
|
return str;
|
439
460
|
}
|
440
|
-
|
441
|
-
console.log(`writing the fixed code to ${fileName}`);
|
442
|
-
const resolvedCode = await code;
|
443
|
-
writeFileSync(fileName, resolvedCode);
|
444
|
-
}
|
461
|
+
|
445
462
|
/**
|
446
463
|
* Sends the code to the AI for a fix
|
447
464
|
*/
|
@@ -486,7 +503,7 @@ export class StormCodegen {
|
|
486
503
|
|
487
504
|
const basePath = this.getBasePath(uri.fullName);
|
488
505
|
const ref = uri.toNormalizedString();
|
489
|
-
const fileEvent:
|
506
|
+
const fileEvent: StormEventFileDone = {
|
490
507
|
type: 'FILE_DONE',
|
491
508
|
reason: 'File generated',
|
492
509
|
created: Date.now(),
|
@@ -526,7 +543,7 @@ export class StormCodegen {
|
|
526
543
|
blockRef: ref,
|
527
544
|
instanceId: StormEventParser.toInstanceIdFromRef(ref),
|
528
545
|
},
|
529
|
-
} satisfies
|
546
|
+
} satisfies StormEventFileDone);
|
530
547
|
}
|
531
548
|
|
532
549
|
/**
|
package/src/storm/events.ts
CHANGED
@@ -208,14 +208,20 @@ export interface StormEventFileState extends StormEventFileBase {
|
|
208
208
|
};
|
209
209
|
}
|
210
210
|
|
211
|
-
export interface
|
212
|
-
type: 'FILE_DONE'
|
211
|
+
export interface StormEventFileDone extends StormEventFileBase {
|
212
|
+
type: 'FILE_DONE';
|
213
213
|
payload: StormEventFileBasePayload & {
|
214
214
|
content: string;
|
215
215
|
};
|
216
216
|
}
|
217
217
|
|
218
|
-
export
|
218
|
+
export interface StormEventFileChunk extends StormEventFileBase {
|
219
|
+
type: 'FILE_CHUNK';
|
220
|
+
payload: StormEventFileBasePayload & {
|
221
|
+
content: string;
|
222
|
+
lineNumber: number;
|
223
|
+
};
|
224
|
+
}
|
219
225
|
|
220
226
|
export interface StormEventBlockReady {
|
221
227
|
type: 'BLOCK_READY';
|
@@ -268,7 +274,8 @@ export type StormEvent =
|
|
268
274
|
| StormEventScreenCandidate
|
269
275
|
| StormEventFileLogical
|
270
276
|
| StormEventFileState
|
271
|
-
|
|
277
|
+
| StormEventFileDone
|
278
|
+
| StormEventFileChunk
|
272
279
|
| StormEventDone
|
273
280
|
| StormEventDefinitionChange
|
274
281
|
| StormEventErrorClassifier
|
package/src/storm/stormClient.ts
CHANGED
@@ -26,14 +26,15 @@ class StormClient {
|
|
26
26
|
this._baseUrl = getRemoteUrl('ai-service', 'https://ai.kapeta.com');
|
27
27
|
}
|
28
28
|
|
29
|
-
private createOptions(path: string, method: string, body: StormContextRequest): RequestInit & { url: string } {
|
29
|
+
private async createOptions(path: string, method: string, body: StormContextRequest): Promise<RequestInit & { url: string }> {
|
30
30
|
const url = `${this._baseUrl}${path}`;
|
31
31
|
const headers: { [k: string]: string } = {
|
32
32
|
'Content-Type': 'application/json',
|
33
33
|
};
|
34
34
|
const api = new KapetaAPI();
|
35
35
|
if (api.hasToken()) {
|
36
|
-
|
36
|
+
const token = await api.getAccessToken();
|
37
|
+
headers['Authorization'] = `Bearer ${token}`;
|
37
38
|
}
|
38
39
|
|
39
40
|
if (body.conversationId) {
|
@@ -56,7 +57,7 @@ class StormClient {
|
|
56
57
|
): Promise<StormStream> {
|
57
58
|
const stringPrompt = typeof body.prompt === 'string' ? body.prompt : JSON.stringify(body.prompt);
|
58
59
|
|
59
|
-
const options = this.createOptions(path, method, {
|
60
|
+
const options = await this.createOptions(path, method, {
|
60
61
|
prompt: stringPrompt,
|
61
62
|
conversationId: body.conversationId,
|
62
63
|
});
|