@kapeta/local-cluster-service 0.54.0 → 0.54.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 +7 -0
- package/dist/cjs/src/storm/codegen.js +73 -56
- package/dist/cjs/src/storm/stormClient.d.ts +1 -0
- package/dist/cjs/src/storm/stormClient.js +6 -0
- package/dist/esm/src/storm/codegen.js +73 -56
- package/dist/esm/src/storm/stormClient.d.ts +1 -0
- package/dist/esm/src/storm/stormClient.js +6 -0
- package/package.json +1 -1
- package/src/storm/codegen.ts +100 -73
- package/src/storm/stormClient.ts +7 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## [0.54.1](https://github.com/kapetacom/local-cluster-service/compare/v0.54.0...v0.54.1) (2024-06-19)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* handle screen events by adding a meta-file to context + routes ([#180](https://github.com/kapetacom/local-cluster-service/issues/180)) ([69d67f8](https://github.com/kapetacom/local-cluster-service/commit/69d67f84fd7a373d49f5c20ff9057d8b2baa620a))
|
7
|
+
|
1
8
|
# [0.54.0](https://github.com/kapetacom/local-cluster-service/compare/v0.53.5...v0.54.0) (2024-06-17)
|
2
9
|
|
3
10
|
|
@@ -242,7 +242,6 @@ class StormCodegen {
|
|
242
242
|
file.type !== codegen_1.AIFileTypes.WEB_SCREEN &&
|
243
243
|
file.type !== codegen_1.AIFileTypes.WEB_ROUTER);
|
244
244
|
const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
|
245
|
-
const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
|
246
245
|
const screenFiles = [];
|
247
246
|
let filteredEvents = [];
|
248
247
|
for (const event of this.events) {
|
@@ -252,65 +251,63 @@ class StormCodegen {
|
|
252
251
|
}
|
253
252
|
}
|
254
253
|
const screenEvents = [];
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
prompt: this.userPrompt,
|
262
|
-
});
|
263
|
-
screenStream.on('data', (evt) => {
|
264
|
-
if (evt.type === 'SCREEN') {
|
265
|
-
screenEvents.push(evt);
|
266
|
-
}
|
267
|
-
this.handleUiOutput(blockUri, block.aiName, evt);
|
254
|
+
const getScreenEventsFile = () => ({
|
255
|
+
content: JSON.stringify(screenEvents),
|
256
|
+
filename: '<screens>.json',
|
257
|
+
type: codegen_1.AIFileTypes.CONFIG,
|
258
|
+
mode: codegen_1.MODE_WRITE_NEVER,
|
259
|
+
permissions: '0644',
|
268
260
|
});
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
// screenfiles
|
274
|
-
const screenTemplates = screenEvents
|
275
|
-
.map((screenEvent) => ({
|
276
|
-
...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
|
277
|
-
filename: screenEvent.payload.filename,
|
278
|
-
}))
|
279
|
-
.filter((tpl) => !!tpl.content);
|
280
|
-
await Promise.all(screenTemplates.concat(webRouters).map(async (template) => {
|
281
|
-
const payload = {
|
261
|
+
const uiEvents = [];
|
262
|
+
// generate screens
|
263
|
+
if (uiTemplates.length) {
|
264
|
+
const screenStream = await stormClient_1.stormClient.listScreens({
|
282
265
|
events: filteredEvents,
|
266
|
+
templates: uiTemplates,
|
267
|
+
context: relevantFiles,
|
283
268
|
blockName: block.aiName,
|
284
|
-
filename: template.filename,
|
285
|
-
template: template,
|
286
|
-
context: relevantFiles.concat([
|
287
|
-
{
|
288
|
-
type: codegen_1.AIFileTypes.INSTRUCTIONS,
|
289
|
-
mode: codegen_1.MODE_CREATE_ONLY,
|
290
|
-
permissions: '0644',
|
291
|
-
filename: '<screens>.md',
|
292
|
-
content: `
|
293
|
-
# Generated screens
|
294
|
-
|
295
|
-
${JSON.stringify({ screenEvents })}
|
296
|
-
|
297
|
-
`,
|
298
|
-
},
|
299
|
-
]),
|
300
269
|
prompt: this.userPrompt,
|
301
|
-
};
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
if (uiFile != undefined) {
|
306
|
-
screenFiles.push(uiFile);
|
270
|
+
});
|
271
|
+
screenStream.on('data', (evt) => {
|
272
|
+
if (evt.type === 'SCREEN') {
|
273
|
+
screenEvents.push(evt);
|
307
274
|
}
|
275
|
+
this.handleUiOutput(blockUri, block.aiName, evt);
|
308
276
|
});
|
309
277
|
this.out.on('aborted', () => {
|
310
|
-
|
278
|
+
screenStream.abort();
|
311
279
|
});
|
312
|
-
await
|
313
|
-
|
280
|
+
await screenStream.waitForDone();
|
281
|
+
// screenfiles
|
282
|
+
const screenTemplates = screenEvents
|
283
|
+
.map((screenEvent) => ({
|
284
|
+
...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
|
285
|
+
filename: screenEvent.payload.filename,
|
286
|
+
}))
|
287
|
+
.filter((tpl) => !!tpl.content);
|
288
|
+
await Promise.all(screenTemplates.map(async (template) => {
|
289
|
+
const payload = {
|
290
|
+
events: filteredEvents,
|
291
|
+
blockName: block.aiName,
|
292
|
+
filename: template.filename,
|
293
|
+
template: template,
|
294
|
+
context: relevantFiles.concat([getScreenEventsFile()]),
|
295
|
+
prompt: this.userPrompt,
|
296
|
+
};
|
297
|
+
const uiStream = await stormClient_1.stormClient.createUIImplementation(payload);
|
298
|
+
uiStream.on('data', (evt) => {
|
299
|
+
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
300
|
+
if (uiFile != undefined) {
|
301
|
+
screenFiles.push(uiFile);
|
302
|
+
}
|
303
|
+
uiEvents.push(evt);
|
304
|
+
});
|
305
|
+
this.out.on('aborted', () => {
|
306
|
+
uiStream.abort();
|
307
|
+
});
|
308
|
+
await uiStream.waitForDone();
|
309
|
+
}));
|
310
|
+
}
|
314
311
|
if (this.isAborted()) {
|
315
312
|
return;
|
316
313
|
}
|
@@ -324,6 +321,24 @@ ${JSON.stringify({ screenEvents })}
|
|
324
321
|
type: codegen_1.AIFileTypes.WEB_SCREEN,
|
325
322
|
};
|
326
323
|
});
|
324
|
+
allFiles.push(...screenFilesConverted);
|
325
|
+
const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
|
326
|
+
await Promise.all(webRouters.map(async (webRouter) => {
|
327
|
+
const payload = {
|
328
|
+
filename: webRouter.filename,
|
329
|
+
template: webRouter,
|
330
|
+
context: screenFilesConverted.concat([getScreenEventsFile()]),
|
331
|
+
prompt: this.userPrompt,
|
332
|
+
};
|
333
|
+
const stream = await stormClient_1.stormClient.generateCode(payload);
|
334
|
+
stream.on('data', (evt) => {
|
335
|
+
this.handleTemplateFileOutput(blockUri, block.aiName, webRouter, evt);
|
336
|
+
});
|
337
|
+
this.out.on('aborted', () => {
|
338
|
+
stream.abort();
|
339
|
+
});
|
340
|
+
await stream.waitForDone();
|
341
|
+
}));
|
327
342
|
// Gather the context files for implementation. These will be all be passed to the AI
|
328
343
|
const contextFiles = relevantFiles.filter((file) => ![codegen_1.AIFileTypes.SERVICE, codegen_1.AIFileTypes.WEB_SCREEN, codegen_1.AIFileTypes.WEB_ROUTER].includes(file.type));
|
329
344
|
// Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
|
@@ -335,6 +350,7 @@ ${JSON.stringify({ screenEvents })}
|
|
335
350
|
return;
|
336
351
|
}
|
337
352
|
for (const screenFile of screenFilesConverted) {
|
353
|
+
// this.emitFile(blockUri, block.aiName, screenFile.filename, screenFile.content);
|
338
354
|
const filePath = (0, path_2.join)(basePath, screenFile.filename);
|
339
355
|
await (0, promises_1.writeFile)(filePath, screenFile.content);
|
340
356
|
}
|
@@ -346,12 +362,13 @@ ${JSON.stringify({ screenEvents })}
|
|
346
362
|
const filePath = (0, path_2.join)(basePath, serviceFile.filename);
|
347
363
|
await (0, promises_1.writeFile)(filePath, serviceFile.content);
|
348
364
|
}
|
365
|
+
// Write again after modifications
|
366
|
+
for (const webRouterFile of webRouters) {
|
367
|
+
const filePath = (0, path_2.join)(basePath, webRouterFile.filename);
|
368
|
+
await (0, promises_1.writeFile)(filePath, webRouterFile.content);
|
369
|
+
}
|
349
370
|
const kapetaYmlPath = (0, path_2.join)(basePath, 'kapeta.yml');
|
350
371
|
await (0, promises_1.writeFile)(kapetaYmlPath, yaml_1.default.stringify(block.content));
|
351
|
-
for (const screenFile of screenFiles) {
|
352
|
-
const filePath = (0, path_2.join)(basePath, screenFile.payload.filename);
|
353
|
-
await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
|
354
|
-
}
|
355
372
|
const blockRef = block.uri;
|
356
373
|
this.emitBlockStatus(blockUri, block.aiName, events_1.StormEventBlockStatusType.QA);
|
357
374
|
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
@@ -13,6 +13,7 @@ declare class StormClient {
|
|
13
13
|
createErrorClassification(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
14
14
|
createCodeFix(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
15
15
|
createErrorDetails(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
16
|
+
generateCode(prompt: StormFileImplementationPrompt, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
16
17
|
}
|
17
18
|
export declare const stormClient: StormClient;
|
18
19
|
export {};
|
@@ -116,5 +116,11 @@ class StormClient {
|
|
116
116
|
prompt,
|
117
117
|
});
|
118
118
|
}
|
119
|
+
generateCode(prompt, history, conversationId) {
|
120
|
+
return this.send('/v2/code/generate', {
|
121
|
+
conversationId: conversationId,
|
122
|
+
prompt,
|
123
|
+
});
|
124
|
+
}
|
119
125
|
}
|
120
126
|
exports.stormClient = new StormClient();
|
@@ -242,7 +242,6 @@ class StormCodegen {
|
|
242
242
|
file.type !== codegen_1.AIFileTypes.WEB_SCREEN &&
|
243
243
|
file.type !== codegen_1.AIFileTypes.WEB_ROUTER);
|
244
244
|
const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
|
245
|
-
const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
|
246
245
|
const screenFiles = [];
|
247
246
|
let filteredEvents = [];
|
248
247
|
for (const event of this.events) {
|
@@ -252,65 +251,63 @@ class StormCodegen {
|
|
252
251
|
}
|
253
252
|
}
|
254
253
|
const screenEvents = [];
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
prompt: this.userPrompt,
|
262
|
-
});
|
263
|
-
screenStream.on('data', (evt) => {
|
264
|
-
if (evt.type === 'SCREEN') {
|
265
|
-
screenEvents.push(evt);
|
266
|
-
}
|
267
|
-
this.handleUiOutput(blockUri, block.aiName, evt);
|
254
|
+
const getScreenEventsFile = () => ({
|
255
|
+
content: JSON.stringify(screenEvents),
|
256
|
+
filename: '<screens>.json',
|
257
|
+
type: codegen_1.AIFileTypes.CONFIG,
|
258
|
+
mode: codegen_1.MODE_WRITE_NEVER,
|
259
|
+
permissions: '0644',
|
268
260
|
});
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
// screenfiles
|
274
|
-
const screenTemplates = screenEvents
|
275
|
-
.map((screenEvent) => ({
|
276
|
-
...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
|
277
|
-
filename: screenEvent.payload.filename,
|
278
|
-
}))
|
279
|
-
.filter((tpl) => !!tpl.content);
|
280
|
-
await Promise.all(screenTemplates.concat(webRouters).map(async (template) => {
|
281
|
-
const payload = {
|
261
|
+
const uiEvents = [];
|
262
|
+
// generate screens
|
263
|
+
if (uiTemplates.length) {
|
264
|
+
const screenStream = await stormClient_1.stormClient.listScreens({
|
282
265
|
events: filteredEvents,
|
266
|
+
templates: uiTemplates,
|
267
|
+
context: relevantFiles,
|
283
268
|
blockName: block.aiName,
|
284
|
-
filename: template.filename,
|
285
|
-
template: template,
|
286
|
-
context: relevantFiles.concat([
|
287
|
-
{
|
288
|
-
type: codegen_1.AIFileTypes.INSTRUCTIONS,
|
289
|
-
mode: codegen_1.MODE_CREATE_ONLY,
|
290
|
-
permissions: '0644',
|
291
|
-
filename: '<screens>.md',
|
292
|
-
content: `
|
293
|
-
# Generated screens
|
294
|
-
|
295
|
-
${JSON.stringify({ screenEvents })}
|
296
|
-
|
297
|
-
`,
|
298
|
-
},
|
299
|
-
]),
|
300
269
|
prompt: this.userPrompt,
|
301
|
-
};
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
if (uiFile != undefined) {
|
306
|
-
screenFiles.push(uiFile);
|
270
|
+
});
|
271
|
+
screenStream.on('data', (evt) => {
|
272
|
+
if (evt.type === 'SCREEN') {
|
273
|
+
screenEvents.push(evt);
|
307
274
|
}
|
275
|
+
this.handleUiOutput(blockUri, block.aiName, evt);
|
308
276
|
});
|
309
277
|
this.out.on('aborted', () => {
|
310
|
-
|
278
|
+
screenStream.abort();
|
311
279
|
});
|
312
|
-
await
|
313
|
-
|
280
|
+
await screenStream.waitForDone();
|
281
|
+
// screenfiles
|
282
|
+
const screenTemplates = screenEvents
|
283
|
+
.map((screenEvent) => ({
|
284
|
+
...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
|
285
|
+
filename: screenEvent.payload.filename,
|
286
|
+
}))
|
287
|
+
.filter((tpl) => !!tpl.content);
|
288
|
+
await Promise.all(screenTemplates.map(async (template) => {
|
289
|
+
const payload = {
|
290
|
+
events: filteredEvents,
|
291
|
+
blockName: block.aiName,
|
292
|
+
filename: template.filename,
|
293
|
+
template: template,
|
294
|
+
context: relevantFiles.concat([getScreenEventsFile()]),
|
295
|
+
prompt: this.userPrompt,
|
296
|
+
};
|
297
|
+
const uiStream = await stormClient_1.stormClient.createUIImplementation(payload);
|
298
|
+
uiStream.on('data', (evt) => {
|
299
|
+
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
300
|
+
if (uiFile != undefined) {
|
301
|
+
screenFiles.push(uiFile);
|
302
|
+
}
|
303
|
+
uiEvents.push(evt);
|
304
|
+
});
|
305
|
+
this.out.on('aborted', () => {
|
306
|
+
uiStream.abort();
|
307
|
+
});
|
308
|
+
await uiStream.waitForDone();
|
309
|
+
}));
|
310
|
+
}
|
314
311
|
if (this.isAborted()) {
|
315
312
|
return;
|
316
313
|
}
|
@@ -324,6 +321,24 @@ ${JSON.stringify({ screenEvents })}
|
|
324
321
|
type: codegen_1.AIFileTypes.WEB_SCREEN,
|
325
322
|
};
|
326
323
|
});
|
324
|
+
allFiles.push(...screenFilesConverted);
|
325
|
+
const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
|
326
|
+
await Promise.all(webRouters.map(async (webRouter) => {
|
327
|
+
const payload = {
|
328
|
+
filename: webRouter.filename,
|
329
|
+
template: webRouter,
|
330
|
+
context: screenFilesConverted.concat([getScreenEventsFile()]),
|
331
|
+
prompt: this.userPrompt,
|
332
|
+
};
|
333
|
+
const stream = await stormClient_1.stormClient.generateCode(payload);
|
334
|
+
stream.on('data', (evt) => {
|
335
|
+
this.handleTemplateFileOutput(blockUri, block.aiName, webRouter, evt);
|
336
|
+
});
|
337
|
+
this.out.on('aborted', () => {
|
338
|
+
stream.abort();
|
339
|
+
});
|
340
|
+
await stream.waitForDone();
|
341
|
+
}));
|
327
342
|
// Gather the context files for implementation. These will be all be passed to the AI
|
328
343
|
const contextFiles = relevantFiles.filter((file) => ![codegen_1.AIFileTypes.SERVICE, codegen_1.AIFileTypes.WEB_SCREEN, codegen_1.AIFileTypes.WEB_ROUTER].includes(file.type));
|
329
344
|
// Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
|
@@ -335,6 +350,7 @@ ${JSON.stringify({ screenEvents })}
|
|
335
350
|
return;
|
336
351
|
}
|
337
352
|
for (const screenFile of screenFilesConverted) {
|
353
|
+
// this.emitFile(blockUri, block.aiName, screenFile.filename, screenFile.content);
|
338
354
|
const filePath = (0, path_2.join)(basePath, screenFile.filename);
|
339
355
|
await (0, promises_1.writeFile)(filePath, screenFile.content);
|
340
356
|
}
|
@@ -346,12 +362,13 @@ ${JSON.stringify({ screenEvents })}
|
|
346
362
|
const filePath = (0, path_2.join)(basePath, serviceFile.filename);
|
347
363
|
await (0, promises_1.writeFile)(filePath, serviceFile.content);
|
348
364
|
}
|
365
|
+
// Write again after modifications
|
366
|
+
for (const webRouterFile of webRouters) {
|
367
|
+
const filePath = (0, path_2.join)(basePath, webRouterFile.filename);
|
368
|
+
await (0, promises_1.writeFile)(filePath, webRouterFile.content);
|
369
|
+
}
|
349
370
|
const kapetaYmlPath = (0, path_2.join)(basePath, 'kapeta.yml');
|
350
371
|
await (0, promises_1.writeFile)(kapetaYmlPath, yaml_1.default.stringify(block.content));
|
351
|
-
for (const screenFile of screenFiles) {
|
352
|
-
const filePath = (0, path_2.join)(basePath, screenFile.payload.filename);
|
353
|
-
await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
|
354
|
-
}
|
355
372
|
const blockRef = block.uri;
|
356
373
|
this.emitBlockStatus(blockUri, block.aiName, events_1.StormEventBlockStatusType.QA);
|
357
374
|
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
@@ -13,6 +13,7 @@ declare class StormClient {
|
|
13
13
|
createErrorClassification(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
14
14
|
createCodeFix(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
15
15
|
createErrorDetails(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
16
|
+
generateCode(prompt: StormFileImplementationPrompt, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
|
16
17
|
}
|
17
18
|
export declare const stormClient: StormClient;
|
18
19
|
export {};
|
@@ -116,5 +116,11 @@ class StormClient {
|
|
116
116
|
prompt,
|
117
117
|
});
|
118
118
|
}
|
119
|
+
generateCode(prompt, history, conversationId) {
|
120
|
+
return this.send('/v2/code/generate', {
|
121
|
+
conversationId: conversationId,
|
122
|
+
prompt,
|
123
|
+
});
|
124
|
+
}
|
119
125
|
}
|
120
126
|
exports.stormClient = new StormClient();
|
package/package.json
CHANGED
package/src/storm/codegen.ts
CHANGED
@@ -12,6 +12,7 @@ import {
|
|
12
12
|
GeneratedFile,
|
13
13
|
GeneratedResult,
|
14
14
|
MODE_CREATE_ONLY,
|
15
|
+
MODE_WRITE_NEVER,
|
15
16
|
} from '@kapeta/codegen';
|
16
17
|
|
17
18
|
import { BlockDefinition } from '@kapeta/schemas';
|
@@ -277,7 +278,6 @@ export class StormCodegen {
|
|
277
278
|
file.type !== AIFileTypes.WEB_ROUTER
|
278
279
|
);
|
279
280
|
const uiTemplates = allFiles.filter((file) => file.type === AIFileTypes.WEB_SCREEN);
|
280
|
-
const webRouters = allFiles.filter((file) => file.type === AIFileTypes.WEB_ROUTER);
|
281
281
|
const screenFiles: StormEventFileDone[] = [];
|
282
282
|
let filteredEvents = [] as StormEvent[];
|
283
283
|
for (const event of this.events) {
|
@@ -288,75 +288,74 @@ export class StormCodegen {
|
|
288
288
|
}
|
289
289
|
|
290
290
|
const screenEvents: StormEventScreen[] = [];
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
prompt: this.userPrompt,
|
298
|
-
});
|
299
|
-
screenStream.on('data', (evt) => {
|
300
|
-
if (evt.type === 'SCREEN') {
|
301
|
-
screenEvents.push(evt);
|
302
|
-
}
|
303
|
-
this.handleUiOutput(blockUri, block.aiName, evt);
|
304
|
-
});
|
305
|
-
|
306
|
-
this.out.on('aborted', () => {
|
307
|
-
screenStream.abort();
|
291
|
+
const getScreenEventsFile = () => ({
|
292
|
+
content: JSON.stringify(screenEvents),
|
293
|
+
filename: '<screens>.json',
|
294
|
+
type: AIFileTypes.CONFIG,
|
295
|
+
mode: MODE_WRITE_NEVER,
|
296
|
+
permissions: '0644',
|
308
297
|
});
|
298
|
+
const uiEvents = [];
|
309
299
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
filename: template.filename,
|
326
|
-
template: template,
|
327
|
-
context: relevantFiles.concat([
|
328
|
-
{
|
329
|
-
type: AIFileTypes.INSTRUCTIONS,
|
330
|
-
mode: MODE_CREATE_ONLY,
|
331
|
-
permissions: '0644',
|
332
|
-
filename: '<screens>.md',
|
333
|
-
content: `
|
334
|
-
# Generated screens
|
335
|
-
|
336
|
-
${JSON.stringify({ screenEvents })}
|
337
|
-
|
338
|
-
`,
|
339
|
-
},
|
340
|
-
]),
|
341
|
-
prompt: this.userPrompt,
|
342
|
-
};
|
343
|
-
|
344
|
-
const uiStream = await stormClient.createUIImplementation(payload);
|
345
|
-
|
346
|
-
uiStream.on('data', (evt) => {
|
347
|
-
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
348
|
-
if (uiFile != undefined) {
|
349
|
-
screenFiles.push(uiFile);
|
350
|
-
}
|
351
|
-
});
|
300
|
+
// generate screens
|
301
|
+
if (uiTemplates.length) {
|
302
|
+
const screenStream = await stormClient.listScreens({
|
303
|
+
events: filteredEvents,
|
304
|
+
templates: uiTemplates,
|
305
|
+
context: relevantFiles,
|
306
|
+
blockName: block.aiName,
|
307
|
+
prompt: this.userPrompt,
|
308
|
+
});
|
309
|
+
screenStream.on('data', (evt) => {
|
310
|
+
if (evt.type === 'SCREEN') {
|
311
|
+
screenEvents.push(evt);
|
312
|
+
}
|
313
|
+
this.handleUiOutput(blockUri, block.aiName, evt);
|
314
|
+
});
|
352
315
|
|
353
|
-
|
354
|
-
|
355
|
-
|
316
|
+
this.out.on('aborted', () => {
|
317
|
+
screenStream.abort();
|
318
|
+
});
|
356
319
|
|
357
|
-
|
358
|
-
|
359
|
-
|
320
|
+
await screenStream.waitForDone();
|
321
|
+
|
322
|
+
// screenfiles
|
323
|
+
const screenTemplates = screenEvents
|
324
|
+
.map((screenEvent) => ({
|
325
|
+
...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
|
326
|
+
filename: screenEvent.payload.filename,
|
327
|
+
}))
|
328
|
+
.filter((tpl): tpl is StormFileInfo => !!tpl.content);
|
329
|
+
|
330
|
+
await Promise.all(
|
331
|
+
screenTemplates.map(async (template) => {
|
332
|
+
const payload = {
|
333
|
+
events: filteredEvents,
|
334
|
+
blockName: block.aiName,
|
335
|
+
filename: template.filename,
|
336
|
+
template: template,
|
337
|
+
context: relevantFiles.concat([getScreenEventsFile()]),
|
338
|
+
prompt: this.userPrompt,
|
339
|
+
};
|
340
|
+
|
341
|
+
const uiStream = await stormClient.createUIImplementation(payload);
|
342
|
+
|
343
|
+
uiStream.on('data', (evt) => {
|
344
|
+
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
345
|
+
if (uiFile != undefined) {
|
346
|
+
screenFiles.push(uiFile);
|
347
|
+
}
|
348
|
+
uiEvents.push(evt);
|
349
|
+
});
|
350
|
+
|
351
|
+
this.out.on('aborted', () => {
|
352
|
+
uiStream.abort();
|
353
|
+
});
|
354
|
+
|
355
|
+
await uiStream.waitForDone();
|
356
|
+
})
|
357
|
+
);
|
358
|
+
}
|
360
359
|
|
361
360
|
if (this.isAborted()) {
|
362
361
|
return;
|
@@ -372,6 +371,31 @@ ${JSON.stringify({ screenEvents })}
|
|
372
371
|
type: AIFileTypes.WEB_SCREEN,
|
373
372
|
};
|
374
373
|
});
|
374
|
+
allFiles.push(...screenFilesConverted);
|
375
|
+
|
376
|
+
const webRouters = allFiles.filter((file) => file.type === AIFileTypes.WEB_ROUTER);
|
377
|
+
await Promise.all(
|
378
|
+
webRouters.map(async (webRouter) => {
|
379
|
+
const payload = {
|
380
|
+
filename: webRouter.filename,
|
381
|
+
template: webRouter,
|
382
|
+
context: screenFilesConverted.concat([getScreenEventsFile()]),
|
383
|
+
prompt: this.userPrompt,
|
384
|
+
};
|
385
|
+
|
386
|
+
const stream = await stormClient.generateCode(payload);
|
387
|
+
|
388
|
+
stream.on('data', (evt) => {
|
389
|
+
this.handleTemplateFileOutput(blockUri, block.aiName, webRouter, evt);
|
390
|
+
});
|
391
|
+
|
392
|
+
this.out.on('aborted', () => {
|
393
|
+
stream.abort();
|
394
|
+
});
|
395
|
+
|
396
|
+
await stream.waitForDone();
|
397
|
+
})
|
398
|
+
);
|
375
399
|
|
376
400
|
// Gather the context files for implementation. These will be all be passed to the AI
|
377
401
|
const contextFiles: StormFileInfo[] = relevantFiles.filter(
|
@@ -395,6 +419,7 @@ ${JSON.stringify({ screenEvents })}
|
|
395
419
|
}
|
396
420
|
|
397
421
|
for (const screenFile of screenFilesConverted) {
|
422
|
+
// this.emitFile(blockUri, block.aiName, screenFile.filename, screenFile.content);
|
398
423
|
const filePath = join(basePath, screenFile.filename);
|
399
424
|
await writeFile(filePath, screenFile.content);
|
400
425
|
}
|
@@ -409,20 +434,21 @@ ${JSON.stringify({ screenEvents })}
|
|
409
434
|
await writeFile(filePath, serviceFile.content);
|
410
435
|
}
|
411
436
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
const filePath = join(basePath, screenFile.payload.filename);
|
417
|
-
await writeFile(filePath, screenFile.payload.content);
|
437
|
+
// Write again after modifications
|
438
|
+
for (const webRouterFile of webRouters) {
|
439
|
+
const filePath = join(basePath, webRouterFile.filename);
|
440
|
+
await writeFile(filePath, webRouterFile.content);
|
418
441
|
}
|
419
442
|
|
443
|
+
const kapetaYmlPath = join(basePath, 'kapeta.yml');
|
444
|
+
await writeFile(kapetaYmlPath, YAML.stringify(block.content));
|
445
|
+
|
420
446
|
const blockRef = block.uri;
|
421
447
|
|
422
448
|
this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.QA);
|
423
449
|
|
424
450
|
const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
|
425
|
-
const codeGenerator = new BlockCodeGenerator(block.content
|
451
|
+
const codeGenerator = new BlockCodeGenerator(block.content);
|
426
452
|
|
427
453
|
this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.BUILDING);
|
428
454
|
await this.verifyAndFixCode(blockUri, block.aiName, codeGenerator, basePath, filesToBeFixed, allFiles);
|
@@ -881,6 +907,7 @@ ${JSON.stringify({ screenEvents })}
|
|
881
907
|
type,
|
882
908
|
};
|
883
909
|
});
|
910
|
+
|
884
911
|
return allFiles;
|
885
912
|
}
|
886
913
|
|
package/src/storm/stormClient.ts
CHANGED
@@ -154,6 +154,13 @@ class StormClient {
|
|
154
154
|
prompt,
|
155
155
|
});
|
156
156
|
}
|
157
|
+
|
158
|
+
public generateCode(prompt: StormFileImplementationPrompt, history?: ConversationItem[], conversationId?: string) {
|
159
|
+
return this.send('/v2/code/generate', {
|
160
|
+
conversationId: conversationId,
|
161
|
+
prompt,
|
162
|
+
});
|
163
|
+
}
|
157
164
|
}
|
158
165
|
|
159
166
|
export const stormClient = new StormClient();
|