@kapeta/local-cluster-service 0.45.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/src/storm/codegen.d.ts +5 -1
- package/dist/cjs/src/storm/codegen.js +68 -18
- package/dist/cjs/src/storm/event-parser.d.ts +5 -5
- package/dist/cjs/src/storm/event-parser.js +50 -33
- package/dist/cjs/src/storm/events.d.ts +8 -2
- package/dist/cjs/src/storm/events.js +0 -4
- package/dist/cjs/src/storm/routes.js +20 -29
- package/dist/cjs/src/storm/stormClient.d.ts +2 -2
- package/dist/cjs/src/storm/stormClient.js +0 -7
- package/dist/cjs/src/storm/stream.d.ts +7 -0
- package/dist/cjs/test/storm/event-parser.test.d.ts +5 -0
- package/dist/cjs/test/storm/event-parser.test.js +169 -0
- package/dist/esm/src/storm/codegen.d.ts +5 -1
- package/dist/esm/src/storm/codegen.js +68 -18
- package/dist/esm/src/storm/event-parser.d.ts +5 -5
- package/dist/esm/src/storm/event-parser.js +50 -33
- package/dist/esm/src/storm/events.d.ts +8 -2
- package/dist/esm/src/storm/events.js +0 -4
- package/dist/esm/src/storm/routes.js +20 -29
- package/dist/esm/src/storm/stormClient.d.ts +2 -2
- package/dist/esm/src/storm/stormClient.js +0 -7
- package/dist/esm/src/storm/stream.d.ts +7 -0
- package/dist/esm/test/storm/event-parser.test.d.ts +5 -0
- package/dist/esm/test/storm/event-parser.test.js +169 -0
- package/package.json +3 -1
- package/src/storm/codegen.ts +83 -27
- package/src/storm/event-parser.ts +68 -47
- package/src/storm/events.ts +10 -2
- package/src/storm/routes.ts +42 -59
- package/src/storm/stormClient.ts +3 -11
- package/src/storm/stream.ts +8 -0
- package/test/storm/event-parser.test.ts +190 -0
@@ -21,17 +21,17 @@ router.post('/:handle/all', async (req, res) => {
|
|
21
21
|
try {
|
22
22
|
const stormOptions = await (0, event_parser_1.resolveOptions)();
|
23
23
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
24
|
-
console.log('Got prompt', req.stringBody);
|
25
24
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
26
25
|
const metaStream = await stormClient_1.stormClient.createMetadata(aiRequest.prompt, aiRequest.history);
|
27
26
|
res.set('Content-Type', 'application/x-ndjson');
|
28
27
|
metaStream.on('data', (data) => {
|
29
|
-
eventParser.addEvent(data);
|
28
|
+
const result = eventParser.addEvent(req.params.handle, data);
|
29
|
+
sendDefinitions(res, result);
|
30
30
|
});
|
31
31
|
await streamStormPartialResponse(metaStream, res);
|
32
32
|
if (!eventParser.isValid()) {
|
33
33
|
// We can't continue if the meta stream is invalid
|
34
|
-
res
|
34
|
+
sendEvent(res, {
|
35
35
|
type: 'ERROR_INTERNAL',
|
36
36
|
payload: { error: eventParser.getError() },
|
37
37
|
reason: 'Failed to generate system',
|
@@ -41,8 +41,8 @@ router.post('/:handle/all', async (req, res) => {
|
|
41
41
|
return;
|
42
42
|
}
|
43
43
|
const result = eventParser.toResult(handle);
|
44
|
-
|
45
|
-
const stormCodegen = new codegen_1.StormCodegen(aiRequest.prompt, result.blocks);
|
44
|
+
sendDefinitions(res, result);
|
45
|
+
const stormCodegen = new codegen_1.StormCodegen(aiRequest.prompt, result.blocks, eventParser.getEvents());
|
46
46
|
const codegenStream = streamStormPartialResponse(stormCodegen.getStream(), res);
|
47
47
|
await stormCodegen.process();
|
48
48
|
await codegenStream;
|
@@ -52,42 +52,30 @@ router.post('/:handle/all', async (req, res) => {
|
|
52
52
|
sendError(err, res);
|
53
53
|
}
|
54
54
|
});
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
const result = await stormClient_1.stormClient.createServiceImplementation(aiRequest.prompt, aiRequest.history);
|
63
|
-
await streamStormResponse(result, res);
|
64
|
-
});
|
65
|
-
router.post('/ui/implement', async (req, res) => {
|
66
|
-
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
67
|
-
const result = await stormClient_1.stormClient.createUIImplementation(aiRequest.prompt, aiRequest.history);
|
68
|
-
await streamStormResponse(result, res);
|
69
|
-
});
|
70
|
-
async function streamStormResponse(result, res) {
|
71
|
-
res.set('Content-Type', 'application/x-ndjson');
|
72
|
-
await streamStormPartialResponse(result, res);
|
73
|
-
sendDone(res);
|
55
|
+
function sendDefinitions(res, result) {
|
56
|
+
sendEvent(res, {
|
57
|
+
type: 'DEFINITION_CHANGE',
|
58
|
+
payload: result,
|
59
|
+
reason: 'Updates to definition',
|
60
|
+
created: Date.now(),
|
61
|
+
});
|
74
62
|
}
|
75
63
|
function sendDone(res) {
|
76
|
-
res
|
64
|
+
sendEvent(res, {
|
77
65
|
type: 'DONE',
|
78
66
|
created: Date.now(),
|
79
|
-
})
|
67
|
+
});
|
80
68
|
res.end();
|
81
69
|
}
|
82
70
|
function sendError(err, res) {
|
83
71
|
console.error('Failed to send prompt', err);
|
84
72
|
if (res.headersSent) {
|
85
|
-
res
|
73
|
+
sendEvent(res, {
|
86
74
|
type: 'ERROR_INTERNAL',
|
87
75
|
created: Date.now(),
|
88
76
|
payload: { error: err.message },
|
89
77
|
reason: 'Failed while sending prompt',
|
90
|
-
})
|
78
|
+
});
|
91
79
|
}
|
92
80
|
else {
|
93
81
|
res.status(400).send({ error: err.message });
|
@@ -96,7 +84,7 @@ function sendError(err, res) {
|
|
96
84
|
function streamStormPartialResponse(result, res) {
|
97
85
|
return new Promise((resolve, reject) => {
|
98
86
|
result.on('data', (data) => {
|
99
|
-
res
|
87
|
+
sendEvent(res, data);
|
100
88
|
});
|
101
89
|
result.on('error', (err) => {
|
102
90
|
reject(err);
|
@@ -106,4 +94,7 @@ function streamStormPartialResponse(result, res) {
|
|
106
94
|
});
|
107
95
|
});
|
108
96
|
}
|
97
|
+
function sendEvent(res, evt) {
|
98
|
+
res.write(JSON.stringify(evt) + '\n');
|
99
|
+
}
|
109
100
|
exports.default = router;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ConversationItem, StormFileImplementationPrompt, StormStream } from './stream';
|
1
|
+
import { ConversationItem, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt } from './stream';
|
2
2
|
export declare const STORM_ID = "storm";
|
3
3
|
declare class StormClient {
|
4
4
|
private readonly _baseUrl;
|
@@ -6,7 +6,7 @@ declare class StormClient {
|
|
6
6
|
private createOptions;
|
7
7
|
private send;
|
8
8
|
createMetadata(prompt: string, history?: ConversationItem[]): Promise<StormStream>;
|
9
|
-
createUIImplementation(prompt:
|
9
|
+
createUIImplementation(prompt: StormUIImplementationPrompt, history?: ConversationItem[]): Promise<StormStream>;
|
10
10
|
createServiceImplementation(prompt: StormFileImplementationPrompt, history?: ConversationItem[]): Promise<StormStream>;
|
11
11
|
}
|
12
12
|
export declare const stormClient: StormClient;
|
@@ -53,12 +53,6 @@ class StormClient {
|
|
53
53
|
jsonLStream.on('error', (error) => {
|
54
54
|
out.emit('error', error);
|
55
55
|
});
|
56
|
-
jsonLStream.on('pause', () => {
|
57
|
-
console.log('paused');
|
58
|
-
});
|
59
|
-
jsonLStream.on('resume', () => {
|
60
|
-
console.log('resumed');
|
61
|
-
});
|
62
56
|
jsonLStream.on('close', () => {
|
63
57
|
out.end();
|
64
58
|
});
|
@@ -77,7 +71,6 @@ class StormClient {
|
|
77
71
|
});
|
78
72
|
}
|
79
73
|
createServiceImplementation(prompt, history) {
|
80
|
-
console.log('SENDING SERVICE PROMPT', JSON.stringify(prompt, null, 2));
|
81
74
|
return this.send('/v2/services/merge', {
|
82
75
|
history: history ?? [],
|
83
76
|
prompt,
|
@@ -36,3 +36,10 @@ export interface StormFileImplementationPrompt {
|
|
36
36
|
template: StormFileInfo;
|
37
37
|
prompt: string;
|
38
38
|
}
|
39
|
+
export interface StormUIImplementationPrompt {
|
40
|
+
events: StormEvent[];
|
41
|
+
templates: StormFileInfo[];
|
42
|
+
context: StormFileInfo[];
|
43
|
+
blockName: string;
|
44
|
+
prompt: string;
|
45
|
+
}
|
@@ -0,0 +1,169 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* Copyright 2023 Kapeta Inc.
|
4
|
+
* SPDX-License-Identifier: BUSL-1.1
|
5
|
+
*/
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
7
|
+
const event_parser_1 = require("../../src/storm/event-parser");
|
8
|
+
const parserOptions = {
|
9
|
+
serviceKind: 'kapeta/block-service:local',
|
10
|
+
serviceLanguage: 'kapeta/language-target-nodejs-ts:local',
|
11
|
+
frontendKind: 'kapeta/block-type-frontend:local',
|
12
|
+
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
13
|
+
cliKind: 'kapeta/block-type-cli:local',
|
14
|
+
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|
15
|
+
desktopKind: 'kapeta/block-type-desktop:local',
|
16
|
+
desktopLanguage: 'kapeta/language-target-electron-ts:local',
|
17
|
+
gatewayKind: 'kapeta/block-type-gateway:local',
|
18
|
+
mqKind: 'kapeta/block-type-mq:local',
|
19
|
+
exchangeKind: 'kapeta/resource-type-exchange:local',
|
20
|
+
queueKind: 'kapeta/resource-type-queue:local',
|
21
|
+
publisherKind: 'kapeta/resource-type-publisher:local',
|
22
|
+
subscriberKind: 'kapeta/resource-type-subscriber:local',
|
23
|
+
databaseKind: 'kapeta/block-type-database:local',
|
24
|
+
apiKind: 'kapeta/block-type-api:local',
|
25
|
+
clientKind: 'kapeta/block-type-client:local',
|
26
|
+
webPageKind: 'kapeta/block-type-web-page:local',
|
27
|
+
webFragmentKind: 'kapeta/block-type-web-fragment:local',
|
28
|
+
jwtProviderKind: 'kapeta/resource-type-jwt-provider:local',
|
29
|
+
jwtConsumerKind: 'kapeta/resource-type-jwt-consumer:local',
|
30
|
+
smtpKind: 'kapeta/resource-type-smtp:local',
|
31
|
+
externalApiKind: 'kapeta/resource-type-external-api:local',
|
32
|
+
};
|
33
|
+
const events = [
|
34
|
+
{
|
35
|
+
type: 'CREATE_PLAN_PROPERTIES',
|
36
|
+
created: Date.now(),
|
37
|
+
reason: 'create plan properties',
|
38
|
+
payload: {
|
39
|
+
name: 'my-plan',
|
40
|
+
description: 'my plan description',
|
41
|
+
},
|
42
|
+
},
|
43
|
+
{
|
44
|
+
type: 'CREATE_BLOCK',
|
45
|
+
reason: 'create backend',
|
46
|
+
created: Date.now(),
|
47
|
+
payload: {
|
48
|
+
name: 'service',
|
49
|
+
description: 'A service block',
|
50
|
+
type: 'BACKEND',
|
51
|
+
resources: [
|
52
|
+
{
|
53
|
+
name: 'entities',
|
54
|
+
type: 'DATABASE',
|
55
|
+
description: 'A database resource',
|
56
|
+
},
|
57
|
+
{
|
58
|
+
type: 'API',
|
59
|
+
name: 'entities',
|
60
|
+
description: 'An API resource',
|
61
|
+
},
|
62
|
+
],
|
63
|
+
},
|
64
|
+
},
|
65
|
+
{
|
66
|
+
type: 'CREATE_BLOCK',
|
67
|
+
reason: 'create frontend',
|
68
|
+
created: Date.now(),
|
69
|
+
payload: {
|
70
|
+
name: 'ui',
|
71
|
+
description: 'A frontend block',
|
72
|
+
type: 'FRONTEND',
|
73
|
+
resources: [
|
74
|
+
{
|
75
|
+
name: 'web',
|
76
|
+
type: 'WEBPAGE',
|
77
|
+
description: 'A web page',
|
78
|
+
},
|
79
|
+
{
|
80
|
+
type: 'CLIENT',
|
81
|
+
name: 'entities',
|
82
|
+
description: 'Client for backend',
|
83
|
+
},
|
84
|
+
],
|
85
|
+
},
|
86
|
+
},
|
87
|
+
{
|
88
|
+
type: 'CREATE_CONNECTION',
|
89
|
+
created: Date.now(),
|
90
|
+
reason: 'connect service to ui',
|
91
|
+
payload: {
|
92
|
+
fromComponent: 'service',
|
93
|
+
fromResource: 'entities',
|
94
|
+
fromResourceType: 'API',
|
95
|
+
toComponent: 'ui',
|
96
|
+
toResource: 'entities',
|
97
|
+
toResourceType: 'CLIENT',
|
98
|
+
},
|
99
|
+
},
|
100
|
+
{
|
101
|
+
type: 'CREATE_API',
|
102
|
+
reason: 'create api',
|
103
|
+
created: Date.now(),
|
104
|
+
payload: {
|
105
|
+
blockName: 'service',
|
106
|
+
content: `controller Entities('/entities') {
|
107
|
+
@GET('/')
|
108
|
+
list(): string[]
|
109
|
+
}`,
|
110
|
+
},
|
111
|
+
},
|
112
|
+
{
|
113
|
+
type: 'CREATE_MODEL',
|
114
|
+
created: Date.now(),
|
115
|
+
reason: 'create model',
|
116
|
+
payload: {
|
117
|
+
blockName: 'service',
|
118
|
+
content: `type Entity {
|
119
|
+
@Id
|
120
|
+
id: string
|
121
|
+
|
122
|
+
name: string
|
123
|
+
}`,
|
124
|
+
},
|
125
|
+
},
|
126
|
+
];
|
127
|
+
describe('event-parser', () => {
|
128
|
+
it('it can parse events into a plan and blocks with proper layout', () => {
|
129
|
+
const parser = new event_parser_1.StormEventParser(parserOptions);
|
130
|
+
events.forEach((event) => parser.addEvent('kapeta', event));
|
131
|
+
const result = parser.toResult('kapeta');
|
132
|
+
expect(result.plan.metadata.name).toBe('kapeta/my-plan');
|
133
|
+
expect(result.plan.metadata.description).toBe('my plan description');
|
134
|
+
expect(result.blocks.length).toBe(2);
|
135
|
+
expect(result.blocks[0].content.metadata.name).toBe('kapeta/service');
|
136
|
+
expect(result.blocks[1].content.metadata.name).toBe('kapeta/ui');
|
137
|
+
const dbResource = result.blocks[0].content.spec.consumers?.[0];
|
138
|
+
const apiResource = result.blocks[0].content.spec.providers?.[0];
|
139
|
+
const clientResource = result.blocks[1].content.spec.consumers?.[0];
|
140
|
+
const pageResource = result.blocks[1].content.spec.providers?.[0];
|
141
|
+
expect(apiResource).toBeDefined();
|
142
|
+
expect(clientResource).toBeDefined();
|
143
|
+
expect(dbResource).toBeDefined();
|
144
|
+
expect(pageResource).toBeDefined();
|
145
|
+
expect(apiResource?.kind).toBe(parserOptions.apiKind);
|
146
|
+
expect(clientResource?.kind).toBe(parserOptions.clientKind);
|
147
|
+
expect(dbResource?.kind).toBe(parserOptions.databaseKind);
|
148
|
+
expect(pageResource?.kind).toBe(parserOptions.webPageKind);
|
149
|
+
expect(apiResource?.spec).toEqual(clientResource?.spec);
|
150
|
+
expect(dbResource?.spec.source.value).toContain('type Entity');
|
151
|
+
const serviceBlockInstance = result.plan.spec.blocks[0];
|
152
|
+
expect(serviceBlockInstance.name).toBe('service');
|
153
|
+
expect(serviceBlockInstance.dimensions.width).toBe(150);
|
154
|
+
expect(serviceBlockInstance.dimensions.height).toBe(200);
|
155
|
+
expect(serviceBlockInstance.dimensions.top).toBe(3);
|
156
|
+
expect(serviceBlockInstance.dimensions.left).toBe(6);
|
157
|
+
const uiBlockInstance = result.plan.spec.blocks[1];
|
158
|
+
expect(uiBlockInstance.name).toBe('ui');
|
159
|
+
expect(uiBlockInstance.dimensions.width).toBe(150);
|
160
|
+
expect(uiBlockInstance.dimensions.height).toBe(200);
|
161
|
+
expect(uiBlockInstance.dimensions.top).toBe(107);
|
162
|
+
expect(uiBlockInstance.dimensions.left).toBe(112);
|
163
|
+
expect(result.plan.spec.connections.length).toBe(1);
|
164
|
+
expect(result.plan.spec.connections[0].consumer.blockId).toBe(uiBlockInstance.id);
|
165
|
+
expect(result.plan.spec.connections[0].consumer.resourceName).toBe(clientResource?.metadata.name);
|
166
|
+
expect(result.plan.spec.connections[0].provider.blockId).toBe(serviceBlockInstance.id);
|
167
|
+
expect(result.plan.spec.connections[0].provider.resourceName).toBe(apiResource?.metadata.name);
|
168
|
+
});
|
169
|
+
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.47.0",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -74,6 +74,8 @@
|
|
74
74
|
"gunzip-maybe": "^1.4.2",
|
75
75
|
"lodash": "^4.17.15",
|
76
76
|
"md5": "2.2.1",
|
77
|
+
"ngraph.forcelayout": "^3.3.1",
|
78
|
+
"ngraph.graph": "^20.0.1",
|
77
79
|
"node-cache": "^5.1.2",
|
78
80
|
"node-uuid": "^1.4.8",
|
79
81
|
"parse-data-uri": "^0.2.0",
|
package/src/storm/codegen.ts
CHANGED
@@ -8,7 +8,7 @@ import { AIFileTypes, BlockCodeGenerator, GeneratedFile, GeneratedResult } from
|
|
8
8
|
import { BlockDefinition } from '@kapeta/schemas';
|
9
9
|
import { codeGeneratorManager } from '../codeGeneratorManager';
|
10
10
|
import { STORM_ID, stormClient } from './stormClient';
|
11
|
-
import { ScreenTemplate, StormEvent, StormEventFile } from './events';
|
11
|
+
import { ScreenTemplate, StormEvent, StormEventFile, StormEventScreen } from './events';
|
12
12
|
import { BlockDefinitionInfo } from './event-parser';
|
13
13
|
import { ConversationItem, StormFileImplementationPrompt, StormFileInfo, StormStream } from './stream';
|
14
14
|
import { KapetaURI } from '@kapeta/nodejs-utils';
|
@@ -22,15 +22,15 @@ export class StormCodegen {
|
|
22
22
|
private readonly userPrompt: string;
|
23
23
|
private readonly blocks: BlockDefinitionInfo[];
|
24
24
|
private readonly out = new StormStream();
|
25
|
+
private readonly events: StormEvent[];
|
25
26
|
|
26
|
-
constructor(userPrompt: string, blocks: BlockDefinitionInfo[]) {
|
27
|
+
constructor(userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[]) {
|
27
28
|
this.userPrompt = userPrompt;
|
28
29
|
this.blocks = blocks;
|
30
|
+
this.events = events;
|
29
31
|
}
|
30
32
|
|
31
33
|
public async process() {
|
32
|
-
console.log('Processing blocks', this.blocks.length);
|
33
|
-
|
34
34
|
for (const block of this.blocks) {
|
35
35
|
await this.processBlockCode(block);
|
36
36
|
}
|
@@ -42,13 +42,44 @@ export class StormCodegen {
|
|
42
42
|
return this.out;
|
43
43
|
}
|
44
44
|
|
45
|
-
private
|
45
|
+
private handleTemplateFileOutput(blockUri: KapetaURI, template: StormFileInfo, data: StormEvent) {
|
46
46
|
switch (data.type) {
|
47
47
|
case 'FILE':
|
48
48
|
template.filename = data.payload.filename;
|
49
49
|
template.content = data.payload.content;
|
50
|
+
return this.handleFileOutput(blockUri, data);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
private handleUiOutput(blockUri: KapetaURI, data: StormEvent) {
|
55
|
+
switch (data.type) {
|
56
|
+
case 'SCREEN':
|
57
|
+
this.out.emit('data', {
|
58
|
+
type: 'SCREEN',
|
59
|
+
reason: data.reason,
|
60
|
+
created: Date.now(),
|
61
|
+
payload: {
|
62
|
+
...data.payload,
|
63
|
+
blockName: blockUri.toNormalizedString(),
|
64
|
+
},
|
65
|
+
});
|
66
|
+
case 'FILE':
|
67
|
+
return this.handleFileOutput(blockUri, data);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
private handleFileOutput(blockUri: KapetaURI, data: StormEvent) {
|
72
|
+
switch (data.type) {
|
73
|
+
case 'FILE':
|
50
74
|
this.emitFile(blockUri, data.payload.filename, data.payload.content, data.reason);
|
51
|
-
|
75
|
+
return {
|
76
|
+
type: 'FILE',
|
77
|
+
created: Date.now(),
|
78
|
+
payload: {
|
79
|
+
filename: data.payload.filename,
|
80
|
+
content: data.payload.content,
|
81
|
+
},
|
82
|
+
} as StormEventFile;
|
52
83
|
}
|
53
84
|
}
|
54
85
|
|
@@ -57,9 +88,8 @@ export class StormCodegen {
|
|
57
88
|
*/
|
58
89
|
private async processBlockCode(block: BlockDefinitionInfo) {
|
59
90
|
// Generate the code for the block using the standard codegen templates
|
60
|
-
const generatedResult = await this.generateBlock(block.content
|
91
|
+
const generatedResult = await this.generateBlock(block.content);
|
61
92
|
if (!generatedResult) {
|
62
|
-
console.warn('No generated result for block', block.uri);
|
63
93
|
return;
|
64
94
|
}
|
65
95
|
|
@@ -68,24 +98,41 @@ export class StormCodegen {
|
|
68
98
|
// Send all the non-ai files to the stream
|
69
99
|
this.emitFiles(block.uri, allFiles);
|
70
100
|
|
71
|
-
const
|
101
|
+
const relevantFiles: StormFileInfo[] = allFiles.filter(
|
102
|
+
(file) => file.type !== AIFileTypes.IGNORE && file.type !== AIFileTypes.WEB_SCREEN
|
103
|
+
);
|
104
|
+
const uiTemplates: StormFileInfo[] = allFiles.filter((file) => file.type === AIFileTypes.WEB_SCREEN);
|
105
|
+
if (uiTemplates.length > 0) {
|
106
|
+
const uiStream = await stormClient.createUIImplementation({
|
107
|
+
events: this.events,
|
108
|
+
templates: uiTemplates,
|
109
|
+
context: relevantFiles,
|
110
|
+
blockName: block.aiName,
|
111
|
+
prompt: this.userPrompt,
|
112
|
+
});
|
113
|
+
|
114
|
+
uiStream.on('data', (evt) => {
|
115
|
+
this.handleUiOutput(block.uri, evt);
|
116
|
+
});
|
117
|
+
|
118
|
+
await uiStream.waitForDone();
|
119
|
+
}
|
72
120
|
|
73
|
-
// Gather the context files. These will be all be passed to the AI
|
74
|
-
const contextFiles: StormFileInfo[] =
|
75
|
-
(file) =>
|
121
|
+
// Gather the context files for implementation. These will be all be passed to the AI
|
122
|
+
const contextFiles: StormFileInfo[] = relevantFiles.filter(
|
123
|
+
(file) => ![AIFileTypes.SERVICE, AIFileTypes.WEB_SCREEN].includes(file.type)
|
76
124
|
);
|
77
125
|
|
78
126
|
// Send the service and UI templates to the AI. These will be send one-by-one in addition to the context files
|
79
127
|
const serviceFiles: StormFileInfo[] = allFiles.filter((file) => file.type === AIFileTypes.SERVICE);
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
//await this.processTemplates(stormClient.createUIImplementation, uiTemplates, contextFiles);
|
128
|
+
if (serviceFiles.length > 0) {
|
129
|
+
await this.processTemplates(
|
130
|
+
block.uri,
|
131
|
+
stormClient.createServiceImplementation.bind(stormClient),
|
132
|
+
serviceFiles,
|
133
|
+
contextFiles
|
134
|
+
);
|
135
|
+
}
|
89
136
|
}
|
90
137
|
|
91
138
|
/**
|
@@ -129,7 +176,7 @@ export class StormCodegen {
|
|
129
176
|
/**
|
130
177
|
* Sends the template to the AI and processes the response
|
131
178
|
*/
|
132
|
-
private processTemplates(
|
179
|
+
private async processTemplates(
|
133
180
|
blockUri: KapetaURI,
|
134
181
|
generator: ImplementationGenerator,
|
135
182
|
templates: StormFileInfo[],
|
@@ -142,12 +189,22 @@ export class StormCodegen {
|
|
142
189
|
prompt: this.userPrompt,
|
143
190
|
});
|
144
191
|
|
145
|
-
|
192
|
+
const files: StormEventFile[] = [];
|
146
193
|
|
147
|
-
|
194
|
+
stream.on('data', (evt) => {
|
195
|
+
const file = this.handleTemplateFileOutput(blockUri, templateFile, evt);
|
196
|
+
if (file) {
|
197
|
+
files.push(file);
|
198
|
+
}
|
199
|
+
});
|
200
|
+
|
201
|
+
await stream.waitForDone();
|
202
|
+
return files;
|
148
203
|
});
|
149
204
|
|
150
|
-
|
205
|
+
const fileChunks = await Promise.all(promises);
|
206
|
+
|
207
|
+
return fileChunks.flat();
|
151
208
|
}
|
152
209
|
|
153
210
|
/**
|
@@ -191,7 +248,7 @@ export class StormCodegen {
|
|
191
248
|
/**
|
192
249
|
* Generates the code using codegen for a given block.
|
193
250
|
*/
|
194
|
-
private async generateBlock(yamlContent: Definition
|
251
|
+
private async generateBlock(yamlContent: Definition) {
|
195
252
|
if (!yamlContent.spec.target?.kind) {
|
196
253
|
//Not all block types have targets
|
197
254
|
return;
|
@@ -203,7 +260,6 @@ export class StormCodegen {
|
|
203
260
|
|
204
261
|
const codeGenerator = new BlockCodeGenerator(yamlContent as BlockDefinition);
|
205
262
|
codeGenerator.withOption('AIContext', STORM_ID);
|
206
|
-
codeGenerator.withOption('AIScreens', screens ?? []);
|
207
263
|
|
208
264
|
return codeGenerator.generate();
|
209
265
|
}
|