@kapeta/local-cluster-service 0.70.6 → 0.70.8
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/PageGenerator.js +32 -0
- package/dist/cjs/src/storm/codegen.d.ts +2 -1
- package/dist/cjs/src/storm/codegen.js +7 -1
- package/dist/cjs/src/storm/event-parser.d.ts +3 -1
- package/dist/cjs/src/storm/event-parser.js +5 -2
- package/dist/cjs/src/storm/routes.js +11 -2
- package/dist/cjs/test/storm/event-parser.test.d.ts +1 -0
- package/dist/cjs/test/storm/event-parser.test.js +1 -0
- package/dist/esm/src/storm/PageGenerator.js +32 -0
- package/dist/esm/src/storm/codegen.d.ts +2 -1
- package/dist/esm/src/storm/codegen.js +7 -1
- package/dist/esm/src/storm/event-parser.d.ts +3 -1
- package/dist/esm/src/storm/event-parser.js +5 -2
- package/dist/esm/src/storm/routes.js +11 -2
- package/dist/esm/test/storm/event-parser.test.d.ts +1 -0
- package/dist/esm/test/storm/event-parser.test.js +1 -0
- package/package.json +3 -1
- package/src/storm/PageGenerator.ts +10 -0
- package/src/storm/codegen.ts +16 -3
- package/src/storm/event-parser.ts +10 -3
- package/src/storm/routes.ts +14 -2
- package/test/storm/event-parser.test.ts +1 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## [0.70.8](https://github.com/kapetacom/local-cluster-service/compare/v0.70.7...v0.70.8) (2024-09-12)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* use language-target-html if pre-existing systemId is specified ([0a38e0c](https://github.com/kapetacom/local-cluster-service/commit/0a38e0cb384a0954269c1b00ee1ef6660f979e42))
|
7
|
+
|
8
|
+
## [0.70.7](https://github.com/kapetacom/local-cluster-service/compare/v0.70.6...v0.70.7) (2024-09-12)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* add missing error handlers to pagegen ([56a3ab5](https://github.com/kapetacom/local-cluster-service/commit/56a3ab576f011ed29ce8074c53e025b347fb4e8a))
|
14
|
+
* skip unknown mimetypes in image gen ([3076367](https://github.com/kapetacom/local-cluster-service/commit/307636771c46a99f555c4c3e944c61fcffa16adc))
|
15
|
+
|
1
16
|
## [0.70.6](https://github.com/kapetacom/local-cluster-service/compare/v0.70.5...v0.70.6) (2024-09-11)
|
2
17
|
|
3
18
|
|
@@ -3,6 +3,29 @@
|
|
3
3
|
* Copyright 2023 Kapeta Inc.
|
4
4
|
* SPDX-License-Identifier: BUSL-1.1
|
5
5
|
*/
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
7
|
+
if (k2 === undefined) k2 = k;
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
11
|
+
}
|
12
|
+
Object.defineProperty(o, k2, desc);
|
13
|
+
}) : (function(o, m, k, k2) {
|
14
|
+
if (k2 === undefined) k2 = k;
|
15
|
+
o[k2] = m[k];
|
16
|
+
}));
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
19
|
+
}) : function(o, v) {
|
20
|
+
o["default"] = v;
|
21
|
+
});
|
22
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
23
|
+
if (mod && mod.__esModule) return mod;
|
24
|
+
var result = {};
|
25
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
26
|
+
__setModuleDefault(result, mod);
|
27
|
+
return result;
|
28
|
+
};
|
6
29
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
7
30
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
8
31
|
};
|
@@ -13,6 +36,7 @@ const stormClient_1 = require("./stormClient");
|
|
13
36
|
const node_events_1 = require("node:events");
|
14
37
|
const p_queue_1 = __importDefault(require("p-queue"));
|
15
38
|
const page_utils_1 = require("./page-utils");
|
39
|
+
const mimetypes = __importStar(require("mime-types"));
|
16
40
|
class PageQueue extends node_events_1.EventEmitter {
|
17
41
|
queue;
|
18
42
|
eventQueue;
|
@@ -208,6 +232,14 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
208
232
|
//console.log('Ignoring duplicate image prompt', prompt);
|
209
233
|
return;
|
210
234
|
}
|
235
|
+
// Add safeguard to avoid generating images for nonsense URLs
|
236
|
+
// Sometimes we get entries for Base URLs that will then cause issues on the filesystem
|
237
|
+
// Example: https://www.kapeta.com/images/
|
238
|
+
const mimeType = mimetypes.lookup(prompt.url);
|
239
|
+
if (!mimeType || !mimeType.startsWith('image/')) {
|
240
|
+
console.warn('Skipping image reference of type %s for url %s', mimeType, prompt.url);
|
241
|
+
return;
|
242
|
+
}
|
211
243
|
this.images.set(prompt.url, prompt.description);
|
212
244
|
const prefix = this.getPrefix();
|
213
245
|
const result = await stormClient_1.stormClient.createImage(prefix + `Create an image for the url "${prompt.url}" with this description: ${prompt.description}`.trim());
|
@@ -12,7 +12,8 @@ export declare class StormCodegen {
|
|
12
12
|
private readonly events;
|
13
13
|
private tmpDir;
|
14
14
|
private readonly conversationId;
|
15
|
-
|
15
|
+
private readonly uiSystemId?;
|
16
|
+
constructor(conversationId: string, userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[], uiSystemId?: string);
|
16
17
|
setTmpDir(tmpDir: string): void;
|
17
18
|
process(): Promise<void>;
|
18
19
|
isAborted(): boolean;
|
@@ -47,6 +47,7 @@ const yaml_1 = __importDefault(require("yaml"));
|
|
47
47
|
const predefined_1 = require("./predefined");
|
48
48
|
const archetype_1 = require("./archetype");
|
49
49
|
const lodash_1 = __importDefault(require("lodash"));
|
50
|
+
const page_utils_1 = require("./page-utils");
|
50
51
|
const SIMULATED_DELAY = 1000;
|
51
52
|
const ENABLE_SIMULATED_DELAY = false;
|
52
53
|
class SimulatedFileDelay {
|
@@ -100,12 +101,14 @@ class StormCodegen {
|
|
100
101
|
events;
|
101
102
|
tmpDir;
|
102
103
|
conversationId;
|
103
|
-
|
104
|
+
uiSystemId;
|
105
|
+
constructor(conversationId, userPrompt, blocks, events, uiSystemId) {
|
104
106
|
this.userPrompt = userPrompt;
|
105
107
|
this.blocks = blocks;
|
106
108
|
this.events = events;
|
107
109
|
this.tmpDir = path_2.default.join(node_os_1.default.tmpdir(), conversationId);
|
108
110
|
this.conversationId = conversationId;
|
111
|
+
this.uiSystemId = uiSystemId;
|
109
112
|
}
|
110
113
|
setTmpDir(tmpDir) {
|
111
114
|
this.tmpDir = tmpDir;
|
@@ -794,6 +797,9 @@ class StormCodegen {
|
|
794
797
|
const basePath = this.getBasePath(yamlContent.metadata.name);
|
795
798
|
const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
|
796
799
|
codeGenerator.withOption('AIContext', stormClient_1.STORM_ID);
|
800
|
+
if (this.uiSystemId) {
|
801
|
+
codeGenerator.withOption('AIStaticFiles', (0, page_utils_1.getSystemBaseDir)(this.uiSystemId));
|
802
|
+
}
|
797
803
|
const generatedResult = await codeGenerator.generate();
|
798
804
|
new codegen_1.CodeWriter(basePath).write(generatedResult);
|
799
805
|
return generatedResult;
|
@@ -26,6 +26,7 @@ export interface StormOptions {
|
|
26
26
|
serviceLanguage: string;
|
27
27
|
frontendKind: string;
|
28
28
|
frontendLanguage: string;
|
29
|
+
htmlLanguage: string;
|
29
30
|
exchangeKind: string;
|
30
31
|
queueKind: string;
|
31
32
|
publisherKind: string;
|
@@ -39,7 +40,8 @@ export interface StormOptions {
|
|
39
40
|
desktopKind: string;
|
40
41
|
desktopLanguage: string;
|
41
42
|
gatewayKind: string;
|
42
|
-
|
43
|
+
systemId?: string;
|
44
|
+
[key: string]: string | undefined;
|
43
45
|
}
|
44
46
|
export declare function createPhaseStartEvent(type: StormEventPhaseType): StormEventPhases;
|
45
47
|
export declare function createPhaseEndEvent(type: StormEventPhaseType): StormEventPhases;
|
@@ -67,6 +67,7 @@ async function resolveOptions() {
|
|
67
67
|
const javaLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
68
68
|
const reactLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
69
69
|
const nodejsLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
70
|
+
const htmlLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-html');
|
70
71
|
const blockTypePubsub = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
71
72
|
const resourceTypePubsubSubscriber = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscriber');
|
72
73
|
const resourceTypePubsubSubscription = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscription');
|
@@ -83,6 +84,7 @@ async function resolveOptions() {
|
|
83
84
|
!postgresResource ||
|
84
85
|
!javaLanguage ||
|
85
86
|
!reactLanguage ||
|
87
|
+
!htmlLanguage ||
|
86
88
|
!webPageResource ||
|
87
89
|
!restApiResource ||
|
88
90
|
!restClientResource ||
|
@@ -105,6 +107,7 @@ async function resolveOptions() {
|
|
105
107
|
serviceLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
|
106
108
|
frontendKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
107
109
|
frontendLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
110
|
+
htmlLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${htmlLanguage.definition.metadata.name}:${htmlLanguage.version}`),
|
108
111
|
cliKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
109
112
|
cliLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
110
113
|
desktopKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeDesktop.definition.metadata.name}:${blockTypeDesktop.version}`),
|
@@ -770,7 +773,7 @@ class StormEventParser {
|
|
770
773
|
case 'CLI':
|
771
774
|
return this.options.cliLanguage;
|
772
775
|
case 'FRONTEND':
|
773
|
-
return this.options.frontendLanguage;
|
776
|
+
return this.options.systemId ? this.options.htmlLanguage : this.options.frontendLanguage;
|
774
777
|
case 'DESKTOP':
|
775
778
|
return this.options.desktopLanguage;
|
776
779
|
}
|
@@ -791,7 +794,7 @@ class StormEventParser {
|
|
791
794
|
for (const prop in options) {
|
792
795
|
if (options.hasOwnProperty(prop)) {
|
793
796
|
const value = options[prop];
|
794
|
-
if (value.indexOf(kind) > 0) {
|
797
|
+
if (typeof value === 'string' && value.indexOf(kind) > 0) {
|
795
798
|
return value;
|
796
799
|
}
|
797
800
|
}
|
@@ -380,6 +380,10 @@ router.post('/:handle/ui', async (req, res) => {
|
|
380
380
|
queue.on('event', (screenData) => {
|
381
381
|
sendEvent(res, screenData);
|
382
382
|
});
|
383
|
+
queue.on('error', (err) => {
|
384
|
+
console.error('Failed to process page', err);
|
385
|
+
sendError(err, res);
|
386
|
+
});
|
383
387
|
for (const screen of Object.values(uniqueUserJourneyScreens)) {
|
384
388
|
queue
|
385
389
|
.addPrompt({
|
@@ -435,6 +439,10 @@ router.post('/ui/edit', async (req, res) => {
|
|
435
439
|
sendEvent(res, data);
|
436
440
|
}
|
437
441
|
});
|
442
|
+
queue.on('error', (err) => {
|
443
|
+
console.error('Failed to process page', err);
|
444
|
+
sendError(err, res);
|
445
|
+
});
|
438
446
|
const pages = aiRequest.prompt.pages.filter((page) => page.conversationId);
|
439
447
|
if (pages.length === 0) {
|
440
448
|
console.log('No pages to update', aiRequest.prompt.pages);
|
@@ -493,8 +501,9 @@ router.post('/ui/get-vote', async (req, res) => {
|
|
493
501
|
});
|
494
502
|
router.post('/:handle/all', async (req, res) => {
|
495
503
|
const handle = req.params.handle;
|
504
|
+
const systemId = req.query.systemId ?? undefined;
|
496
505
|
try {
|
497
|
-
const stormOptions = await (0, event_parser_1.resolveOptions)();
|
506
|
+
const stormOptions = { ...(await (0, event_parser_1.resolveOptions)()), systemId: systemId };
|
498
507
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
499
508
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
500
509
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
@@ -563,7 +572,7 @@ router.post('/:handle/all', async (req, res) => {
|
|
563
572
|
if (!req.query.skipCodegen) {
|
564
573
|
try {
|
565
574
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENTATION));
|
566
|
-
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents());
|
575
|
+
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents(), systemId);
|
567
576
|
onRequestAborted(req, res, () => {
|
568
577
|
stormCodegen.abort();
|
569
578
|
});
|
@@ -19,6 +19,7 @@ exports.parserOptions = {
|
|
19
19
|
serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
|
20
20
|
frontendKind: 'kapeta/block-type-frontend:local',
|
21
21
|
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
22
|
+
htmlLanguage: 'kapeta/language-target-html:local',
|
22
23
|
cliKind: 'kapeta/block-type-cli:local',
|
23
24
|
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|
24
25
|
desktopKind: 'kapeta/block-type-desktop:local',
|
@@ -3,6 +3,29 @@
|
|
3
3
|
* Copyright 2023 Kapeta Inc.
|
4
4
|
* SPDX-License-Identifier: BUSL-1.1
|
5
5
|
*/
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
7
|
+
if (k2 === undefined) k2 = k;
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
11
|
+
}
|
12
|
+
Object.defineProperty(o, k2, desc);
|
13
|
+
}) : (function(o, m, k, k2) {
|
14
|
+
if (k2 === undefined) k2 = k;
|
15
|
+
o[k2] = m[k];
|
16
|
+
}));
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
19
|
+
}) : function(o, v) {
|
20
|
+
o["default"] = v;
|
21
|
+
});
|
22
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
23
|
+
if (mod && mod.__esModule) return mod;
|
24
|
+
var result = {};
|
25
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
26
|
+
__setModuleDefault(result, mod);
|
27
|
+
return result;
|
28
|
+
};
|
6
29
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
7
30
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
8
31
|
};
|
@@ -13,6 +36,7 @@ const stormClient_1 = require("./stormClient");
|
|
13
36
|
const node_events_1 = require("node:events");
|
14
37
|
const p_queue_1 = __importDefault(require("p-queue"));
|
15
38
|
const page_utils_1 = require("./page-utils");
|
39
|
+
const mimetypes = __importStar(require("mime-types"));
|
16
40
|
class PageQueue extends node_events_1.EventEmitter {
|
17
41
|
queue;
|
18
42
|
eventQueue;
|
@@ -208,6 +232,14 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
208
232
|
//console.log('Ignoring duplicate image prompt', prompt);
|
209
233
|
return;
|
210
234
|
}
|
235
|
+
// Add safeguard to avoid generating images for nonsense URLs
|
236
|
+
// Sometimes we get entries for Base URLs that will then cause issues on the filesystem
|
237
|
+
// Example: https://www.kapeta.com/images/
|
238
|
+
const mimeType = mimetypes.lookup(prompt.url);
|
239
|
+
if (!mimeType || !mimeType.startsWith('image/')) {
|
240
|
+
console.warn('Skipping image reference of type %s for url %s', mimeType, prompt.url);
|
241
|
+
return;
|
242
|
+
}
|
211
243
|
this.images.set(prompt.url, prompt.description);
|
212
244
|
const prefix = this.getPrefix();
|
213
245
|
const result = await stormClient_1.stormClient.createImage(prefix + `Create an image for the url "${prompt.url}" with this description: ${prompt.description}`.trim());
|
@@ -12,7 +12,8 @@ export declare class StormCodegen {
|
|
12
12
|
private readonly events;
|
13
13
|
private tmpDir;
|
14
14
|
private readonly conversationId;
|
15
|
-
|
15
|
+
private readonly uiSystemId?;
|
16
|
+
constructor(conversationId: string, userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[], uiSystemId?: string);
|
16
17
|
setTmpDir(tmpDir: string): void;
|
17
18
|
process(): Promise<void>;
|
18
19
|
isAborted(): boolean;
|
@@ -47,6 +47,7 @@ const yaml_1 = __importDefault(require("yaml"));
|
|
47
47
|
const predefined_1 = require("./predefined");
|
48
48
|
const archetype_1 = require("./archetype");
|
49
49
|
const lodash_1 = __importDefault(require("lodash"));
|
50
|
+
const page_utils_1 = require("./page-utils");
|
50
51
|
const SIMULATED_DELAY = 1000;
|
51
52
|
const ENABLE_SIMULATED_DELAY = false;
|
52
53
|
class SimulatedFileDelay {
|
@@ -100,12 +101,14 @@ class StormCodegen {
|
|
100
101
|
events;
|
101
102
|
tmpDir;
|
102
103
|
conversationId;
|
103
|
-
|
104
|
+
uiSystemId;
|
105
|
+
constructor(conversationId, userPrompt, blocks, events, uiSystemId) {
|
104
106
|
this.userPrompt = userPrompt;
|
105
107
|
this.blocks = blocks;
|
106
108
|
this.events = events;
|
107
109
|
this.tmpDir = path_2.default.join(node_os_1.default.tmpdir(), conversationId);
|
108
110
|
this.conversationId = conversationId;
|
111
|
+
this.uiSystemId = uiSystemId;
|
109
112
|
}
|
110
113
|
setTmpDir(tmpDir) {
|
111
114
|
this.tmpDir = tmpDir;
|
@@ -794,6 +797,9 @@ class StormCodegen {
|
|
794
797
|
const basePath = this.getBasePath(yamlContent.metadata.name);
|
795
798
|
const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
|
796
799
|
codeGenerator.withOption('AIContext', stormClient_1.STORM_ID);
|
800
|
+
if (this.uiSystemId) {
|
801
|
+
codeGenerator.withOption('AIStaticFiles', (0, page_utils_1.getSystemBaseDir)(this.uiSystemId));
|
802
|
+
}
|
797
803
|
const generatedResult = await codeGenerator.generate();
|
798
804
|
new codegen_1.CodeWriter(basePath).write(generatedResult);
|
799
805
|
return generatedResult;
|
@@ -26,6 +26,7 @@ export interface StormOptions {
|
|
26
26
|
serviceLanguage: string;
|
27
27
|
frontendKind: string;
|
28
28
|
frontendLanguage: string;
|
29
|
+
htmlLanguage: string;
|
29
30
|
exchangeKind: string;
|
30
31
|
queueKind: string;
|
31
32
|
publisherKind: string;
|
@@ -39,7 +40,8 @@ export interface StormOptions {
|
|
39
40
|
desktopKind: string;
|
40
41
|
desktopLanguage: string;
|
41
42
|
gatewayKind: string;
|
42
|
-
|
43
|
+
systemId?: string;
|
44
|
+
[key: string]: string | undefined;
|
43
45
|
}
|
44
46
|
export declare function createPhaseStartEvent(type: StormEventPhaseType): StormEventPhases;
|
45
47
|
export declare function createPhaseEndEvent(type: StormEventPhaseType): StormEventPhases;
|
@@ -67,6 +67,7 @@ async function resolveOptions() {
|
|
67
67
|
const javaLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
68
68
|
const reactLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
69
69
|
const nodejsLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
70
|
+
const htmlLanguage = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/language-target-html');
|
70
71
|
const blockTypePubsub = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
71
72
|
const resourceTypePubsubSubscriber = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscriber');
|
72
73
|
const resourceTypePubsubSubscription = await definitionsManager_1.definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-subscription');
|
@@ -83,6 +84,7 @@ async function resolveOptions() {
|
|
83
84
|
!postgresResource ||
|
84
85
|
!javaLanguage ||
|
85
86
|
!reactLanguage ||
|
87
|
+
!htmlLanguage ||
|
86
88
|
!webPageResource ||
|
87
89
|
!restApiResource ||
|
88
90
|
!restClientResource ||
|
@@ -105,6 +107,7 @@ async function resolveOptions() {
|
|
105
107
|
serviceLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
|
106
108
|
frontendKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
107
109
|
frontendLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
110
|
+
htmlLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${htmlLanguage.definition.metadata.name}:${htmlLanguage.version}`),
|
108
111
|
cliKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
109
112
|
cliLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
110
113
|
desktopKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeDesktop.definition.metadata.name}:${blockTypeDesktop.version}`),
|
@@ -770,7 +773,7 @@ class StormEventParser {
|
|
770
773
|
case 'CLI':
|
771
774
|
return this.options.cliLanguage;
|
772
775
|
case 'FRONTEND':
|
773
|
-
return this.options.frontendLanguage;
|
776
|
+
return this.options.systemId ? this.options.htmlLanguage : this.options.frontendLanguage;
|
774
777
|
case 'DESKTOP':
|
775
778
|
return this.options.desktopLanguage;
|
776
779
|
}
|
@@ -791,7 +794,7 @@ class StormEventParser {
|
|
791
794
|
for (const prop in options) {
|
792
795
|
if (options.hasOwnProperty(prop)) {
|
793
796
|
const value = options[prop];
|
794
|
-
if (value.indexOf(kind) > 0) {
|
797
|
+
if (typeof value === 'string' && value.indexOf(kind) > 0) {
|
795
798
|
return value;
|
796
799
|
}
|
797
800
|
}
|
@@ -380,6 +380,10 @@ router.post('/:handle/ui', async (req, res) => {
|
|
380
380
|
queue.on('event', (screenData) => {
|
381
381
|
sendEvent(res, screenData);
|
382
382
|
});
|
383
|
+
queue.on('error', (err) => {
|
384
|
+
console.error('Failed to process page', err);
|
385
|
+
sendError(err, res);
|
386
|
+
});
|
383
387
|
for (const screen of Object.values(uniqueUserJourneyScreens)) {
|
384
388
|
queue
|
385
389
|
.addPrompt({
|
@@ -435,6 +439,10 @@ router.post('/ui/edit', async (req, res) => {
|
|
435
439
|
sendEvent(res, data);
|
436
440
|
}
|
437
441
|
});
|
442
|
+
queue.on('error', (err) => {
|
443
|
+
console.error('Failed to process page', err);
|
444
|
+
sendError(err, res);
|
445
|
+
});
|
438
446
|
const pages = aiRequest.prompt.pages.filter((page) => page.conversationId);
|
439
447
|
if (pages.length === 0) {
|
440
448
|
console.log('No pages to update', aiRequest.prompt.pages);
|
@@ -493,8 +501,9 @@ router.post('/ui/get-vote', async (req, res) => {
|
|
493
501
|
});
|
494
502
|
router.post('/:handle/all', async (req, res) => {
|
495
503
|
const handle = req.params.handle;
|
504
|
+
const systemId = req.query.systemId ?? undefined;
|
496
505
|
try {
|
497
|
-
const stormOptions = await (0, event_parser_1.resolveOptions)();
|
506
|
+
const stormOptions = { ...(await (0, event_parser_1.resolveOptions)()), systemId: systemId };
|
498
507
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
499
508
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
500
509
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
@@ -563,7 +572,7 @@ router.post('/:handle/all', async (req, res) => {
|
|
563
572
|
if (!req.query.skipCodegen) {
|
564
573
|
try {
|
565
574
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENTATION));
|
566
|
-
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents());
|
575
|
+
const stormCodegen = new codegen_1.StormCodegen(metaStream.getConversationId(), aiRequest.prompt, result.blocks, eventParser.getEvents(), systemId);
|
567
576
|
onRequestAborted(req, res, () => {
|
568
577
|
stormCodegen.abort();
|
569
578
|
});
|
@@ -19,6 +19,7 @@ exports.parserOptions = {
|
|
19
19
|
serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
|
20
20
|
frontendKind: 'kapeta/block-type-frontend:local',
|
21
21
|
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
22
|
+
htmlLanguage: 'kapeta/language-target-html:local',
|
22
23
|
cliKind: 'kapeta/block-type-cli:local',
|
23
24
|
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|
24
25
|
desktopKind: 'kapeta/block-type-desktop:local',
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.70.
|
3
|
+
"version": "0.70.8",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -76,6 +76,7 @@
|
|
76
76
|
"js-yaml": "^4.1.0",
|
77
77
|
"lodash": "^4.17.15",
|
78
78
|
"md5": "2.2.1",
|
79
|
+
"mime-types": "^2.1.35",
|
79
80
|
"node-cache": "^5.1.2",
|
80
81
|
"node-fetch": "^3.3.2",
|
81
82
|
"node-uuid": "^1.4.8",
|
@@ -104,6 +105,7 @@
|
|
104
105
|
"@types/js-yaml": "^4.0.9",
|
105
106
|
"@types/lodash": "^4.14.195",
|
106
107
|
"@types/md5": "^2.3.2",
|
108
|
+
"@types/mime-types": "^2.1.4",
|
107
109
|
"@types/node": "^20.5.8",
|
108
110
|
"@types/node-fetch": "^2.6.11",
|
109
111
|
"@types/node-uuid": "^0.0.29",
|
@@ -10,6 +10,7 @@ import { EventEmitter } from 'node:events';
|
|
10
10
|
import PQueue from 'p-queue';
|
11
11
|
|
12
12
|
import { hasPageOnDisk, normalizePath } from './page-utils';
|
13
|
+
import * as mimetypes from 'mime-types';
|
13
14
|
|
14
15
|
export interface ImagePrompt {
|
15
16
|
name: string;
|
@@ -255,6 +256,15 @@ export class PageQueue extends EventEmitter {
|
|
255
256
|
//console.log('Ignoring duplicate image prompt', prompt);
|
256
257
|
return;
|
257
258
|
}
|
259
|
+
// Add safeguard to avoid generating images for nonsense URLs
|
260
|
+
// Sometimes we get entries for Base URLs that will then cause issues on the filesystem
|
261
|
+
// Example: https://www.kapeta.com/images/
|
262
|
+
const mimeType = mimetypes.lookup(prompt.url) as string | false;
|
263
|
+
if (!mimeType || !mimeType.startsWith('image/')) {
|
264
|
+
console.warn('Skipping image reference of type %s for url %s', mimeType, prompt.url);
|
265
|
+
return;
|
266
|
+
}
|
267
|
+
|
258
268
|
this.images.set(prompt.url, prompt.description);
|
259
269
|
const prefix = this.getPrefix();
|
260
270
|
const result = await stormClient.createImage(
|
package/src/storm/codegen.ts
CHANGED
@@ -39,6 +39,7 @@ import YAML from 'yaml';
|
|
39
39
|
import { PREDEFINED_BLOCKS } from './predefined';
|
40
40
|
import { Archetype } from './archetype';
|
41
41
|
import _ from 'lodash';
|
42
|
+
import { getSystemBaseDir } from './page-utils';
|
42
43
|
|
43
44
|
type ImplementationGenerator<T = StormFileImplementationPrompt> = (
|
44
45
|
prompt: T,
|
@@ -108,13 +109,21 @@ export class StormCodegen {
|
|
108
109
|
private readonly events: StormEvent[];
|
109
110
|
private tmpDir: string;
|
110
111
|
private readonly conversationId: string;
|
111
|
-
|
112
|
-
|
112
|
+
private readonly uiSystemId?: string;
|
113
|
+
|
114
|
+
constructor(
|
115
|
+
conversationId: string,
|
116
|
+
userPrompt: string,
|
117
|
+
blocks: BlockDefinitionInfo[],
|
118
|
+
events: StormEvent[],
|
119
|
+
uiSystemId?: string
|
120
|
+
) {
|
113
121
|
this.userPrompt = userPrompt;
|
114
122
|
this.blocks = blocks;
|
115
123
|
this.events = events;
|
116
124
|
this.tmpDir = Path.join(os.tmpdir(), conversationId);
|
117
125
|
this.conversationId = conversationId;
|
126
|
+
this.uiSystemId = uiSystemId;
|
118
127
|
}
|
119
128
|
|
120
129
|
public setTmpDir(tmpDir: string) {
|
@@ -488,7 +497,6 @@ export class StormCodegen {
|
|
488
497
|
await writeFile(filePath, webRouterFile.content);
|
489
498
|
}
|
490
499
|
|
491
|
-
|
492
500
|
const blockRef = block.uri;
|
493
501
|
|
494
502
|
this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.QA);
|
@@ -1009,6 +1017,11 @@ export class StormCodegen {
|
|
1009
1017
|
|
1010
1018
|
const codeGenerator = new BlockCodeGenerator(yamlContent as BlockDefinition);
|
1011
1019
|
codeGenerator.withOption('AIContext', STORM_ID);
|
1020
|
+
|
1021
|
+
if (this.uiSystemId) {
|
1022
|
+
codeGenerator.withOption('AIStaticFiles', getSystemBaseDir(this.uiSystemId));
|
1023
|
+
}
|
1024
|
+
|
1012
1025
|
const generatedResult = await codeGenerator.generate();
|
1013
1026
|
new CodeWriter(basePath).write(generatedResult);
|
1014
1027
|
return generatedResult;
|
@@ -67,6 +67,7 @@ export interface StormOptions {
|
|
67
67
|
serviceLanguage: string;
|
68
68
|
frontendKind: string;
|
69
69
|
frontendLanguage: string;
|
70
|
+
htmlLanguage: string;
|
70
71
|
exchangeKind: string;
|
71
72
|
queueKind: string;
|
72
73
|
publisherKind: string;
|
@@ -80,7 +81,10 @@ export interface StormOptions {
|
|
80
81
|
desktopKind: string;
|
81
82
|
desktopLanguage: string;
|
82
83
|
gatewayKind: string;
|
83
|
-
|
84
|
+
|
85
|
+
systemId?: string;
|
86
|
+
|
87
|
+
[key: string]: string | undefined;
|
84
88
|
}
|
85
89
|
|
86
90
|
function prettifyKaplang(source: string) {
|
@@ -143,6 +147,7 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
143
147
|
const javaLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
144
148
|
const reactLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
145
149
|
const nodejsLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
150
|
+
const htmlLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-html');
|
146
151
|
|
147
152
|
const blockTypePubsub = await definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
148
153
|
const resourceTypePubsubSubscriber = await definitionsManager.getLatestDefinition(
|
@@ -170,6 +175,7 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
170
175
|
!postgresResource ||
|
171
176
|
!javaLanguage ||
|
172
177
|
!reactLanguage ||
|
178
|
+
!htmlLanguage ||
|
173
179
|
!webPageResource ||
|
174
180
|
!restApiResource ||
|
175
181
|
!restClientResource ||
|
@@ -195,6 +201,7 @@ export async function resolveOptions(): Promise<StormOptions> {
|
|
195
201
|
|
196
202
|
frontendKind: normalizeKapetaUri(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
197
203
|
frontendLanguage: normalizeKapetaUri(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
204
|
+
htmlLanguage: normalizeKapetaUri(`${htmlLanguage.definition.metadata.name}:${htmlLanguage.version}`),
|
198
205
|
|
199
206
|
cliKind: normalizeKapetaUri(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
200
207
|
cliLanguage: normalizeKapetaUri(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
@@ -997,7 +1004,7 @@ export class StormEventParser {
|
|
997
1004
|
case 'CLI':
|
998
1005
|
return this.options.cliLanguage;
|
999
1006
|
case 'FRONTEND':
|
1000
|
-
return this.options.frontendLanguage;
|
1007
|
+
return this.options.systemId ? this.options.htmlLanguage : this.options.frontendLanguage;
|
1001
1008
|
case 'DESKTOP':
|
1002
1009
|
return this.options.desktopLanguage;
|
1003
1010
|
}
|
@@ -1027,7 +1034,7 @@ export class StormEventParser {
|
|
1027
1034
|
for (const prop in options) {
|
1028
1035
|
if (options.hasOwnProperty(prop)) {
|
1029
1036
|
const value = options[prop];
|
1030
|
-
if (value.indexOf(kind) > 0) {
|
1037
|
+
if (typeof value === 'string' && value.indexOf(kind) > 0) {
|
1031
1038
|
return value;
|
1032
1039
|
}
|
1033
1040
|
}
|
package/src/storm/routes.ts
CHANGED
@@ -474,6 +474,11 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
474
474
|
sendEvent(res, screenData);
|
475
475
|
});
|
476
476
|
|
477
|
+
queue.on('error', (err) => {
|
478
|
+
console.error('Failed to process page', err);
|
479
|
+
sendError(err as any, res);
|
480
|
+
});
|
481
|
+
|
477
482
|
for (const screen of Object.values(uniqueUserJourneyScreens)) {
|
478
483
|
queue
|
479
484
|
.addPrompt({
|
@@ -538,6 +543,11 @@ router.post('/ui/edit', async (req: KapetaBodyRequest, res: Response) => {
|
|
538
543
|
}
|
539
544
|
});
|
540
545
|
|
546
|
+
queue.on('error', (err) => {
|
547
|
+
console.error('Failed to process page', err);
|
548
|
+
sendError(err as any, res);
|
549
|
+
});
|
550
|
+
|
541
551
|
const pages = aiRequest.prompt.pages.filter((page) => page.conversationId);
|
542
552
|
if (pages.length === 0) {
|
543
553
|
console.log('No pages to update', aiRequest.prompt.pages);
|
@@ -604,9 +614,10 @@ router.post('/ui/get-vote', async (req: KapetaBodyRequest, res: Response) => {
|
|
604
614
|
|
605
615
|
router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
|
606
616
|
const handle = req.params.handle as string;
|
617
|
+
const systemId = (req.query.systemId as string) ?? undefined;
|
607
618
|
|
608
619
|
try {
|
609
|
-
const stormOptions = await resolveOptions();
|
620
|
+
const stormOptions = { ...(await resolveOptions()), systemId: systemId };
|
610
621
|
|
611
622
|
const eventParser = new StormEventParser(stormOptions);
|
612
623
|
|
@@ -693,7 +704,8 @@ router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
|
|
693
704
|
metaStream.getConversationId(),
|
694
705
|
aiRequest.prompt,
|
695
706
|
result.blocks,
|
696
|
-
eventParser.getEvents()
|
707
|
+
eventParser.getEvents(),
|
708
|
+
systemId
|
697
709
|
);
|
698
710
|
|
699
711
|
onRequestAborted(req, res, () => {
|
@@ -17,6 +17,7 @@ export const parserOptions = {
|
|
17
17
|
|
18
18
|
frontendKind: 'kapeta/block-type-frontend:local',
|
19
19
|
frontendLanguage: 'kapeta/language-target-react-ts:local',
|
20
|
+
htmlLanguage: 'kapeta/language-target-html:local',
|
20
21
|
|
21
22
|
cliKind: 'kapeta/block-type-cli:local',
|
22
23
|
cliLanguage: 'kapeta/language-target-nodejs-ts:local',
|