@kapeta/local-cluster-service 0.71.4 → 0.71.6
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 +16 -0
- package/dist/cjs/src/storm/events.d.ts +10 -1
- package/dist/cjs/src/storm/events.js +1 -0
- package/dist/cjs/src/storm/routes.js +41 -1
- package/dist/cjs/src/storm/stormClient.d.ts +3 -2
- package/dist/cjs/src/storm/stormClient.js +14 -2
- package/dist/cjs/src/storm/stream.d.ts +10 -2
- package/dist/cjs/src/storm/stream.js +6 -1
- package/dist/cjs/src/storm/utils.d.ts +2 -2
- package/dist/cjs/src/storm/utils.js +14 -4
- package/dist/esm/src/storm/events.d.ts +10 -1
- package/dist/esm/src/storm/events.js +1 -0
- package/dist/esm/src/storm/routes.js +41 -1
- package/dist/esm/src/storm/stormClient.d.ts +3 -2
- package/dist/esm/src/storm/stormClient.js +14 -2
- package/dist/esm/src/storm/stream.d.ts +10 -2
- package/dist/esm/src/storm/stream.js +6 -1
- package/dist/esm/src/storm/utils.d.ts +2 -2
- package/dist/esm/src/storm/utils.js +14 -4
- package/package.json +1 -1
- package/src/storm/events.ts +12 -1
- package/src/storm/routes.ts +64 -11
- package/src/storm/stormClient.ts +17 -3
- package/src/storm/stream.ts +13 -3
- package/src/storm/utils.ts +14 -6
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## [0.71.6](https://github.com/kapetacom/local-cluster-service/compare/v0.71.5...v0.71.6) (2024-09-19)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Change to simple json response for now ([#256](https://github.com/kapetacom/local-cluster-service/issues/256)) ([7d8ae48](https://github.com/kapetacom/local-cluster-service/commit/7d8ae4813b78f478a0f719195ea33dc2890f1d2a))
|
7
|
+
|
8
|
+
## [0.71.5](https://github.com/kapetacom/local-cluster-service/compare/v0.71.4...v0.71.5) (2024-09-19)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* adds create-system-simple route ([fea005a](https://github.com/kapetacom/local-cluster-service/commit/fea005a183b45a2caf6811ae6d0d7019386a21ef))
|
14
|
+
* review comments ([17f8192](https://github.com/kapetacom/local-cluster-service/commit/17f819237efff8bb57dfdb9b2f53431d5dc44021))
|
15
|
+
* send html + images etc. to endpoint ([bdb5e81](https://github.com/kapetacom/local-cluster-service/commit/bdb5e818d66fff6983f126d872fdf228e97bc5d1))
|
16
|
+
|
1
17
|
## [0.71.4](https://github.com/kapetacom/local-cluster-service/compare/v0.71.3...v0.71.4) (2024-09-19)
|
2
18
|
|
3
19
|
|
@@ -273,6 +273,7 @@ export interface StormEventDefinitionChange {
|
|
273
273
|
export declare enum StormEventPhaseType {
|
274
274
|
IMPLEMENT_APIS = "IMPLEMENT_APIS",// Implement APIs in the html pages
|
275
275
|
COMPOSE_SYSTEM_PROMPT = "COMPOSE_SYSTEM_PROMPT",// Compose system prompt for bottom-up approach
|
276
|
+
COMPOSE_SYSTEM = "COMPOSE_SYSTEM",
|
276
277
|
META = "META",
|
277
278
|
DEFINITIONS = "DEFINITIONS",
|
278
279
|
IMPLEMENTATION = "IMPLEMENTATION",
|
@@ -395,5 +396,13 @@ export interface StormEventUIStarted {
|
|
395
396
|
resetUrl: string;
|
396
397
|
};
|
397
398
|
}
|
398
|
-
export
|
399
|
+
export interface StormEventSystemReady {
|
400
|
+
type: 'SYSTEM_READY';
|
401
|
+
reason: string;
|
402
|
+
created: number;
|
403
|
+
payload: {
|
404
|
+
systemUrl: string;
|
405
|
+
};
|
406
|
+
}
|
407
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileFailed | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventErrorDetails | StormEventBlockReady | StormEventPhases | StormEventBlockStatus | StormEventCreateDSLRetry | StormEventUserJourney | StormEventUIShell | StormEventPage | StormEventPageUrl | StormEventPromptImprove | StormEventLandingPage | StormEventReferenceClassification | StormEventApiBase | StormEventUIStarted | StormImage | StormEventSystemReady;
|
399
408
|
export {};
|
@@ -13,6 +13,7 @@ var StormEventPhaseType;
|
|
13
13
|
(function (StormEventPhaseType) {
|
14
14
|
StormEventPhaseType["IMPLEMENT_APIS"] = "IMPLEMENT_APIS";
|
15
15
|
StormEventPhaseType["COMPOSE_SYSTEM_PROMPT"] = "COMPOSE_SYSTEM_PROMPT";
|
16
|
+
StormEventPhaseType["COMPOSE_SYSTEM"] = "COMPOSE_SYSTEM";
|
16
17
|
StormEventPhaseType["META"] = "META";
|
17
18
|
StormEventPhaseType["DEFINITIONS"] = "DEFINITIONS";
|
18
19
|
StormEventPhaseType["IMPLEMENTATION"] = "IMPLEMENTATION";
|
@@ -13,6 +13,7 @@ const path_1 = __importDefault(require("path"));
|
|
13
13
|
const lodash_1 = __importDefault(require("lodash"));
|
14
14
|
const cors_1 = require("../middleware/cors");
|
15
15
|
const stringBody_1 = require("../middleware/stringBody");
|
16
|
+
const stream_1 = require("./stream");
|
16
17
|
const stormClient_1 = require("./stormClient");
|
17
18
|
const events_1 = require("./events");
|
18
19
|
const event_parser_1 = require("./event-parser");
|
@@ -82,7 +83,7 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
82
83
|
});
|
83
84
|
await (0, utils_1.copyDirectory)(srcDir, destDir, (fileName, content) => {
|
84
85
|
// find the page from result1 and write the content to the file
|
85
|
-
const page = pagesWithImplementation.find((p) => p.
|
86
|
+
const page = pagesWithImplementation.find((p) => p.fileName === fileName);
|
86
87
|
return page ? page.content : content;
|
87
88
|
});
|
88
89
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
@@ -101,6 +102,45 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
101
102
|
req.stringBody = JSON.stringify(promptRequest);
|
102
103
|
await handleAll(req, res);
|
103
104
|
});
|
105
|
+
router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
106
|
+
const handle = req.params.handle;
|
107
|
+
const systemId = req.params.systemId;
|
108
|
+
const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
|
109
|
+
//res.set('Content-Type', 'application/x-ndjson');
|
110
|
+
//res.set('Access-Control-Expose-Headers', ConversationIdHeader);
|
111
|
+
//res.set(ConversationIdHeader, systemId);
|
112
|
+
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
113
|
+
try {
|
114
|
+
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
115
|
+
const pagesWithImplementation = await stormClient_1.stormClient.replaceMockWithAPICall({
|
116
|
+
pages: pagesFromDisk,
|
117
|
+
});
|
118
|
+
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
119
|
+
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
120
|
+
const allFiles = (0, utils_1.readFilesAndContent)(srcDir, false).map((page) => {
|
121
|
+
if (page.encoding == stream_1.HTMLPageEncoding.TEXT) {
|
122
|
+
const matchingFile = pagesWithImplementation.find((pageWithImpl) => pageWithImpl.fileName === page.fileName);
|
123
|
+
if (matchingFile) {
|
124
|
+
return matchingFile;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
return page;
|
128
|
+
});
|
129
|
+
const systemUrl = await stormClient_1.stormClient.createSimpleBackend(handle, systemId, { pages: allFiles });
|
130
|
+
//sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
131
|
+
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
132
|
+
//sendDone(res);
|
133
|
+
res.json({ url: systemUrl });
|
134
|
+
}
|
135
|
+
catch (err) {
|
136
|
+
res.status(500).json({ error: err.message });
|
137
|
+
}
|
138
|
+
finally {
|
139
|
+
if (!res.closed) {
|
140
|
+
res.end();
|
141
|
+
}
|
142
|
+
}
|
143
|
+
});
|
104
144
|
router.delete('/ui/serve/:systemId', async (req, res) => {
|
105
145
|
const systemId = req.params.systemId;
|
106
146
|
if (!systemId) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/// <reference types="node" />
|
2
|
-
import { ConversationItem, ImplementAPIClients, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
2
|
+
import { ConversationItem, CreateSimpleBackendRequest, HTMLPage, ImplementAPIClients, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
3
3
|
import { Page, StormEventPageUrl } from './events';
|
4
4
|
export declare const STORM_ID = "storm";
|
5
5
|
export declare const ConversationIdHeader = "Conversation-Id";
|
@@ -70,8 +70,9 @@ declare class StormClient {
|
|
70
70
|
getVoteUIPage(topic: string, conversationId: string, mainConversationId?: string): Promise<{
|
71
71
|
vote: -1 | 0 | 1;
|
72
72
|
}>;
|
73
|
-
replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<
|
73
|
+
replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<HTMLPage[]>;
|
74
74
|
generatePrompt(pages: string[]): Promise<string>;
|
75
|
+
createSimpleBackend(handle: string, systemId: string, input: CreateSimpleBackendRequest): Promise<string>;
|
75
76
|
classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
|
76
77
|
editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
|
77
78
|
listScreens(prompt: StormUIListPrompt, conversationId?: string): Promise<StormStream>;
|
@@ -139,8 +139,7 @@ class StormClient {
|
|
139
139
|
method: 'POST',
|
140
140
|
body: JSON.stringify(prompt.pages),
|
141
141
|
});
|
142
|
-
|
143
|
-
return data;
|
142
|
+
return await response.json();
|
144
143
|
}
|
145
144
|
async generatePrompt(pages) {
|
146
145
|
const u = `${this._baseUrl}/v2/ui/prompt`;
|
@@ -152,6 +151,19 @@ class StormClient {
|
|
152
151
|
});
|
153
152
|
return await response.text();
|
154
153
|
}
|
154
|
+
async createSimpleBackend(handle, systemId, input) {
|
155
|
+
const u = `${this._baseUrl}/v2/create-simple-backend/${handle}/${systemId}`;
|
156
|
+
const response = await fetch(u, {
|
157
|
+
method: 'POST',
|
158
|
+
body: JSON.stringify({
|
159
|
+
pages: input.pages,
|
160
|
+
}),
|
161
|
+
});
|
162
|
+
if (!response.ok) {
|
163
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
164
|
+
}
|
165
|
+
return await response.text();
|
166
|
+
}
|
155
167
|
classifyUIReferences(prompt, conversationId) {
|
156
168
|
return this.send('/v2/ui/references', {
|
157
169
|
prompt: prompt,
|
@@ -72,10 +72,18 @@ export interface StormUIListPrompt {
|
|
72
72
|
blockName: string;
|
73
73
|
prompt: string;
|
74
74
|
}
|
75
|
+
export declare enum HTMLPageEncoding {
|
76
|
+
TEXT = "TEXT",
|
77
|
+
BINARY = "BINARY"
|
78
|
+
}
|
75
79
|
export interface ImplementAPIClients {
|
76
|
-
pages:
|
80
|
+
pages: HTMLPage[];
|
77
81
|
}
|
78
|
-
export interface
|
82
|
+
export interface HTMLPage {
|
79
83
|
fileName: string;
|
80
84
|
content: string;
|
85
|
+
encoding: HTMLPageEncoding;
|
86
|
+
}
|
87
|
+
export interface CreateSimpleBackendRequest {
|
88
|
+
pages: HTMLPage[];
|
81
89
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.StormStream = void 0;
|
3
|
+
exports.HTMLPageEncoding = exports.StormStream = void 0;
|
4
4
|
/**
|
5
5
|
* Copyright 2023 Kapeta Inc.
|
6
6
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -74,3 +74,8 @@ class StormStream extends node_events_1.EventEmitter {
|
|
74
74
|
}
|
75
75
|
}
|
76
76
|
exports.StormStream = StormStream;
|
77
|
+
var HTMLPageEncoding;
|
78
|
+
(function (HTMLPageEncoding) {
|
79
|
+
HTMLPageEncoding["TEXT"] = "TEXT";
|
80
|
+
HTMLPageEncoding["BINARY"] = "BINARY";
|
81
|
+
})(HTMLPageEncoding || (exports.HTMLPageEncoding = HTMLPageEncoding = {}));
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import {
|
1
|
+
import { HTMLPage } from './stream';
|
2
2
|
export declare function copyDirectory(src: string, dest: string, modifyHtml: (fileName: string, content: string) => string): Promise<void>;
|
3
|
-
export declare function readFilesAndContent(directoryPath: string):
|
3
|
+
export declare function readFilesAndContent(directoryPath: string, htmlExclusive?: boolean): HTMLPage[];
|
4
4
|
export declare function createFuture<T = void>(): {
|
5
5
|
promise: Promise<T>;
|
6
6
|
resolve: (value: T | PromiseLike<T>) => void;
|
@@ -10,6 +10,7 @@ exports.createFuture = exports.readFilesAndContent = exports.copyDirectory = voi
|
|
10
10
|
*/
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
12
|
const path_1 = __importDefault(require("path"));
|
13
|
+
const stream_1 = require("./stream");
|
13
14
|
async function copyDirectory(src, dest, modifyHtml) {
|
14
15
|
await fs_extra_1.default.promises.mkdir(dest, { recursive: true });
|
15
16
|
const entries = await fs_extra_1.default.promises.readdir(src, { withFileTypes: true });
|
@@ -29,19 +30,28 @@ async function copyDirectory(src, dest, modifyHtml) {
|
|
29
30
|
}
|
30
31
|
}
|
31
32
|
exports.copyDirectory = copyDirectory;
|
32
|
-
function readFilesAndContent(directoryPath) {
|
33
|
+
function readFilesAndContent(directoryPath, htmlExclusive = true) {
|
33
34
|
const htmlFiles = [];
|
34
35
|
function traverseDirectory(currentPath) {
|
35
36
|
const files = fs_extra_1.default.readdirSync(currentPath);
|
36
37
|
for (const file of files) {
|
37
38
|
const fileName = path_1.default.join(currentPath, file);
|
39
|
+
const relativeFilename = path_1.default.relative(directoryPath, fileName);
|
38
40
|
const stats = fs_extra_1.default.statSync(fileName);
|
39
41
|
if (stats.isDirectory()) {
|
40
42
|
traverseDirectory(fileName);
|
41
43
|
}
|
42
|
-
else if (stats.isFile()
|
43
|
-
|
44
|
-
|
44
|
+
else if (stats.isFile()) {
|
45
|
+
if (path_1.default.extname(fileName) === '.html') {
|
46
|
+
const content = fs_extra_1.default.readFileSync(fileName, 'utf8');
|
47
|
+
htmlFiles.push({ fileName: relativeFilename, content: content, encoding: stream_1.HTMLPageEncoding.TEXT });
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
if (!htmlExclusive) {
|
51
|
+
const content = fs_extra_1.default.readFileSync(fileName);
|
52
|
+
htmlFiles.push({ fileName: relativeFilename, content: content.toString('base64'), encoding: stream_1.HTMLPageEncoding.BINARY });
|
53
|
+
}
|
54
|
+
}
|
45
55
|
}
|
46
56
|
}
|
47
57
|
}
|
@@ -273,6 +273,7 @@ export interface StormEventDefinitionChange {
|
|
273
273
|
export declare enum StormEventPhaseType {
|
274
274
|
IMPLEMENT_APIS = "IMPLEMENT_APIS",// Implement APIs in the html pages
|
275
275
|
COMPOSE_SYSTEM_PROMPT = "COMPOSE_SYSTEM_PROMPT",// Compose system prompt for bottom-up approach
|
276
|
+
COMPOSE_SYSTEM = "COMPOSE_SYSTEM",
|
276
277
|
META = "META",
|
277
278
|
DEFINITIONS = "DEFINITIONS",
|
278
279
|
IMPLEMENTATION = "IMPLEMENTATION",
|
@@ -395,5 +396,13 @@ export interface StormEventUIStarted {
|
|
395
396
|
resetUrl: string;
|
396
397
|
};
|
397
398
|
}
|
398
|
-
export
|
399
|
+
export interface StormEventSystemReady {
|
400
|
+
type: 'SYSTEM_READY';
|
401
|
+
reason: string;
|
402
|
+
created: number;
|
403
|
+
payload: {
|
404
|
+
systemUrl: string;
|
405
|
+
};
|
406
|
+
}
|
407
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileFailed | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventErrorDetails | StormEventBlockReady | StormEventPhases | StormEventBlockStatus | StormEventCreateDSLRetry | StormEventUserJourney | StormEventUIShell | StormEventPage | StormEventPageUrl | StormEventPromptImprove | StormEventLandingPage | StormEventReferenceClassification | StormEventApiBase | StormEventUIStarted | StormImage | StormEventSystemReady;
|
399
408
|
export {};
|
@@ -13,6 +13,7 @@ var StormEventPhaseType;
|
|
13
13
|
(function (StormEventPhaseType) {
|
14
14
|
StormEventPhaseType["IMPLEMENT_APIS"] = "IMPLEMENT_APIS";
|
15
15
|
StormEventPhaseType["COMPOSE_SYSTEM_PROMPT"] = "COMPOSE_SYSTEM_PROMPT";
|
16
|
+
StormEventPhaseType["COMPOSE_SYSTEM"] = "COMPOSE_SYSTEM";
|
16
17
|
StormEventPhaseType["META"] = "META";
|
17
18
|
StormEventPhaseType["DEFINITIONS"] = "DEFINITIONS";
|
18
19
|
StormEventPhaseType["IMPLEMENTATION"] = "IMPLEMENTATION";
|
@@ -13,6 +13,7 @@ const path_1 = __importDefault(require("path"));
|
|
13
13
|
const lodash_1 = __importDefault(require("lodash"));
|
14
14
|
const cors_1 = require("../middleware/cors");
|
15
15
|
const stringBody_1 = require("../middleware/stringBody");
|
16
|
+
const stream_1 = require("./stream");
|
16
17
|
const stormClient_1 = require("./stormClient");
|
17
18
|
const events_1 = require("./events");
|
18
19
|
const event_parser_1 = require("./event-parser");
|
@@ -82,7 +83,7 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
82
83
|
});
|
83
84
|
await (0, utils_1.copyDirectory)(srcDir, destDir, (fileName, content) => {
|
84
85
|
// find the page from result1 and write the content to the file
|
85
|
-
const page = pagesWithImplementation.find((p) => p.
|
86
|
+
const page = pagesWithImplementation.find((p) => p.fileName === fileName);
|
86
87
|
return page ? page.content : content;
|
87
88
|
});
|
88
89
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
@@ -101,6 +102,45 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
101
102
|
req.stringBody = JSON.stringify(promptRequest);
|
102
103
|
await handleAll(req, res);
|
103
104
|
});
|
105
|
+
router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
106
|
+
const handle = req.params.handle;
|
107
|
+
const systemId = req.params.systemId;
|
108
|
+
const srcDir = (0, page_utils_1.getSystemBaseDir)(systemId);
|
109
|
+
//res.set('Content-Type', 'application/x-ndjson');
|
110
|
+
//res.set('Access-Control-Expose-Headers', ConversationIdHeader);
|
111
|
+
//res.set(ConversationIdHeader, systemId);
|
112
|
+
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
113
|
+
try {
|
114
|
+
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
115
|
+
const pagesWithImplementation = await stormClient_1.stormClient.replaceMockWithAPICall({
|
116
|
+
pages: pagesFromDisk,
|
117
|
+
});
|
118
|
+
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
119
|
+
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
120
|
+
const allFiles = (0, utils_1.readFilesAndContent)(srcDir, false).map((page) => {
|
121
|
+
if (page.encoding == stream_1.HTMLPageEncoding.TEXT) {
|
122
|
+
const matchingFile = pagesWithImplementation.find((pageWithImpl) => pageWithImpl.fileName === page.fileName);
|
123
|
+
if (matchingFile) {
|
124
|
+
return matchingFile;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
return page;
|
128
|
+
});
|
129
|
+
const systemUrl = await stormClient_1.stormClient.createSimpleBackend(handle, systemId, { pages: allFiles });
|
130
|
+
//sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
131
|
+
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
132
|
+
//sendDone(res);
|
133
|
+
res.json({ url: systemUrl });
|
134
|
+
}
|
135
|
+
catch (err) {
|
136
|
+
res.status(500).json({ error: err.message });
|
137
|
+
}
|
138
|
+
finally {
|
139
|
+
if (!res.closed) {
|
140
|
+
res.end();
|
141
|
+
}
|
142
|
+
}
|
143
|
+
});
|
104
144
|
router.delete('/ui/serve/:systemId', async (req, res) => {
|
105
145
|
const systemId = req.params.systemId;
|
106
146
|
if (!systemId) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/// <reference types="node" />
|
2
|
-
import { ConversationItem, ImplementAPIClients, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
2
|
+
import { ConversationItem, CreateSimpleBackendRequest, HTMLPage, ImplementAPIClients, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
3
3
|
import { Page, StormEventPageUrl } from './events';
|
4
4
|
export declare const STORM_ID = "storm";
|
5
5
|
export declare const ConversationIdHeader = "Conversation-Id";
|
@@ -70,8 +70,9 @@ declare class StormClient {
|
|
70
70
|
getVoteUIPage(topic: string, conversationId: string, mainConversationId?: string): Promise<{
|
71
71
|
vote: -1 | 0 | 1;
|
72
72
|
}>;
|
73
|
-
replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<
|
73
|
+
replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<HTMLPage[]>;
|
74
74
|
generatePrompt(pages: string[]): Promise<string>;
|
75
|
+
createSimpleBackend(handle: string, systemId: string, input: CreateSimpleBackendRequest): Promise<string>;
|
75
76
|
classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
|
76
77
|
editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
|
77
78
|
listScreens(prompt: StormUIListPrompt, conversationId?: string): Promise<StormStream>;
|
@@ -139,8 +139,7 @@ class StormClient {
|
|
139
139
|
method: 'POST',
|
140
140
|
body: JSON.stringify(prompt.pages),
|
141
141
|
});
|
142
|
-
|
143
|
-
return data;
|
142
|
+
return await response.json();
|
144
143
|
}
|
145
144
|
async generatePrompt(pages) {
|
146
145
|
const u = `${this._baseUrl}/v2/ui/prompt`;
|
@@ -152,6 +151,19 @@ class StormClient {
|
|
152
151
|
});
|
153
152
|
return await response.text();
|
154
153
|
}
|
154
|
+
async createSimpleBackend(handle, systemId, input) {
|
155
|
+
const u = `${this._baseUrl}/v2/create-simple-backend/${handle}/${systemId}`;
|
156
|
+
const response = await fetch(u, {
|
157
|
+
method: 'POST',
|
158
|
+
body: JSON.stringify({
|
159
|
+
pages: input.pages,
|
160
|
+
}),
|
161
|
+
});
|
162
|
+
if (!response.ok) {
|
163
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
164
|
+
}
|
165
|
+
return await response.text();
|
166
|
+
}
|
155
167
|
classifyUIReferences(prompt, conversationId) {
|
156
168
|
return this.send('/v2/ui/references', {
|
157
169
|
prompt: prompt,
|
@@ -72,10 +72,18 @@ export interface StormUIListPrompt {
|
|
72
72
|
blockName: string;
|
73
73
|
prompt: string;
|
74
74
|
}
|
75
|
+
export declare enum HTMLPageEncoding {
|
76
|
+
TEXT = "TEXT",
|
77
|
+
BINARY = "BINARY"
|
78
|
+
}
|
75
79
|
export interface ImplementAPIClients {
|
76
|
-
pages:
|
80
|
+
pages: HTMLPage[];
|
77
81
|
}
|
78
|
-
export interface
|
82
|
+
export interface HTMLPage {
|
79
83
|
fileName: string;
|
80
84
|
content: string;
|
85
|
+
encoding: HTMLPageEncoding;
|
86
|
+
}
|
87
|
+
export interface CreateSimpleBackendRequest {
|
88
|
+
pages: HTMLPage[];
|
81
89
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.StormStream = void 0;
|
3
|
+
exports.HTMLPageEncoding = exports.StormStream = void 0;
|
4
4
|
/**
|
5
5
|
* Copyright 2023 Kapeta Inc.
|
6
6
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -74,3 +74,8 @@ class StormStream extends node_events_1.EventEmitter {
|
|
74
74
|
}
|
75
75
|
}
|
76
76
|
exports.StormStream = StormStream;
|
77
|
+
var HTMLPageEncoding;
|
78
|
+
(function (HTMLPageEncoding) {
|
79
|
+
HTMLPageEncoding["TEXT"] = "TEXT";
|
80
|
+
HTMLPageEncoding["BINARY"] = "BINARY";
|
81
|
+
})(HTMLPageEncoding || (exports.HTMLPageEncoding = HTMLPageEncoding = {}));
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import {
|
1
|
+
import { HTMLPage } from './stream';
|
2
2
|
export declare function copyDirectory(src: string, dest: string, modifyHtml: (fileName: string, content: string) => string): Promise<void>;
|
3
|
-
export declare function readFilesAndContent(directoryPath: string):
|
3
|
+
export declare function readFilesAndContent(directoryPath: string, htmlExclusive?: boolean): HTMLPage[];
|
4
4
|
export declare function createFuture<T = void>(): {
|
5
5
|
promise: Promise<T>;
|
6
6
|
resolve: (value: T | PromiseLike<T>) => void;
|
@@ -10,6 +10,7 @@ exports.createFuture = exports.readFilesAndContent = exports.copyDirectory = voi
|
|
10
10
|
*/
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
12
|
const path_1 = __importDefault(require("path"));
|
13
|
+
const stream_1 = require("./stream");
|
13
14
|
async function copyDirectory(src, dest, modifyHtml) {
|
14
15
|
await fs_extra_1.default.promises.mkdir(dest, { recursive: true });
|
15
16
|
const entries = await fs_extra_1.default.promises.readdir(src, { withFileTypes: true });
|
@@ -29,19 +30,28 @@ async function copyDirectory(src, dest, modifyHtml) {
|
|
29
30
|
}
|
30
31
|
}
|
31
32
|
exports.copyDirectory = copyDirectory;
|
32
|
-
function readFilesAndContent(directoryPath) {
|
33
|
+
function readFilesAndContent(directoryPath, htmlExclusive = true) {
|
33
34
|
const htmlFiles = [];
|
34
35
|
function traverseDirectory(currentPath) {
|
35
36
|
const files = fs_extra_1.default.readdirSync(currentPath);
|
36
37
|
for (const file of files) {
|
37
38
|
const fileName = path_1.default.join(currentPath, file);
|
39
|
+
const relativeFilename = path_1.default.relative(directoryPath, fileName);
|
38
40
|
const stats = fs_extra_1.default.statSync(fileName);
|
39
41
|
if (stats.isDirectory()) {
|
40
42
|
traverseDirectory(fileName);
|
41
43
|
}
|
42
|
-
else if (stats.isFile()
|
43
|
-
|
44
|
-
|
44
|
+
else if (stats.isFile()) {
|
45
|
+
if (path_1.default.extname(fileName) === '.html') {
|
46
|
+
const content = fs_extra_1.default.readFileSync(fileName, 'utf8');
|
47
|
+
htmlFiles.push({ fileName: relativeFilename, content: content, encoding: stream_1.HTMLPageEncoding.TEXT });
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
if (!htmlExclusive) {
|
51
|
+
const content = fs_extra_1.default.readFileSync(fileName);
|
52
|
+
htmlFiles.push({ fileName: relativeFilename, content: content.toString('base64'), encoding: stream_1.HTMLPageEncoding.BINARY });
|
53
|
+
}
|
54
|
+
}
|
45
55
|
}
|
46
56
|
}
|
47
57
|
}
|
package/package.json
CHANGED
package/src/storm/events.ts
CHANGED
@@ -331,6 +331,7 @@ export interface StormEventDefinitionChange {
|
|
331
331
|
export enum StormEventPhaseType {
|
332
332
|
IMPLEMENT_APIS = 'IMPLEMENT_APIS', // Implement APIs in the html pages
|
333
333
|
COMPOSE_SYSTEM_PROMPT = 'COMPOSE_SYSTEM_PROMPT', // Compose system prompt for bottom-up approach
|
334
|
+
COMPOSE_SYSTEM = 'COMPOSE_SYSTEM',
|
334
335
|
META = 'META',
|
335
336
|
DEFINITIONS = 'DEFINITIONS',
|
336
337
|
IMPLEMENTATION = 'IMPLEMENTATION',
|
@@ -473,6 +474,15 @@ export interface StormEventUIStarted {
|
|
473
474
|
};
|
474
475
|
}
|
475
476
|
|
477
|
+
export interface StormEventSystemReady {
|
478
|
+
type: 'SYSTEM_READY';
|
479
|
+
reason: string;
|
480
|
+
created: number;
|
481
|
+
payload: {
|
482
|
+
systemUrl: string;
|
483
|
+
}
|
484
|
+
}
|
485
|
+
|
476
486
|
export type StormEvent =
|
477
487
|
| StormEventCreateBlock
|
478
488
|
| StormEventCreateConnection
|
@@ -507,4 +517,5 @@ export type StormEvent =
|
|
507
517
|
| StormEventReferenceClassification
|
508
518
|
| StormEventApiBase
|
509
519
|
| StormEventUIStarted
|
510
|
-
| StormImage
|
520
|
+
| StormImage
|
521
|
+
| StormEventSystemReady;
|
package/src/storm/routes.ts
CHANGED
@@ -11,7 +11,13 @@ import _ from 'lodash';
|
|
11
11
|
import { corsHandler } from '../middleware/cors';
|
12
12
|
import { stringBody } from '../middleware/stringBody';
|
13
13
|
import { KapetaBodyRequest } from '../types';
|
14
|
-
import {
|
14
|
+
import {
|
15
|
+
HTMLPageEncoding,
|
16
|
+
StormCodegenRequest,
|
17
|
+
StormContextRequest,
|
18
|
+
StormCreateBlockRequest,
|
19
|
+
StormStream,
|
20
|
+
} from './stream';
|
15
21
|
|
16
22
|
import {
|
17
23
|
ConversationIdHeader,
|
@@ -22,7 +28,7 @@ import {
|
|
22
28
|
UIPageVoteRequest,
|
23
29
|
UIPageGetVoteRequest,
|
24
30
|
} from './stormClient';
|
25
|
-
import {
|
31
|
+
import { StormEvent, StormEventPage, StormEventPhaseType, UserJourneyScreen } from './events';
|
26
32
|
|
27
33
|
import {
|
28
34
|
createPhaseEndEvent,
|
@@ -43,7 +49,7 @@ import {
|
|
43
49
|
} from './page-utils';
|
44
50
|
import { UIServer } from './UIServer';
|
45
51
|
import { randomUUID } from 'crypto';
|
46
|
-
import {
|
52
|
+
import { PageQueue } from './PageGenerator';
|
47
53
|
import { copyDirectory, createFuture, readFilesAndContent } from './utils';
|
48
54
|
|
49
55
|
const UI_SERVERS: { [key: string]: UIServer } = {};
|
@@ -109,26 +115,24 @@ router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest
|
|
109
115
|
|
110
116
|
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
111
117
|
|
112
|
-
const pagesFromDisk =
|
118
|
+
const pagesFromDisk = readFilesAndContent(srcDir);
|
113
119
|
const pagesWithImplementation = await stormClient.replaceMockWithAPICall({
|
114
|
-
|
115
|
-
|
116
|
-
);
|
120
|
+
pages: pagesFromDisk,
|
121
|
+
});
|
117
122
|
await copyDirectory(srcDir, destDir, (fileName, content) => {
|
118
123
|
// find the page from result1 and write the content to the file
|
119
|
-
const page = pagesWithImplementation.find((p) => p.
|
124
|
+
const page = pagesWithImplementation.find((p) => p.fileName === fileName);
|
120
125
|
return page ? page.content : content;
|
121
126
|
});
|
122
127
|
|
123
|
-
|
124
128
|
sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
125
129
|
|
126
130
|
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
127
131
|
|
128
132
|
// get the content of the pages
|
129
133
|
const pageContents = pagesWithImplementation.map((page) => {
|
130
|
-
return page.content
|
131
|
-
})
|
134
|
+
return page.content;
|
135
|
+
});
|
132
136
|
|
133
137
|
const prompt = await stormClient.generatePrompt(pageContents);
|
134
138
|
|
@@ -143,6 +147,55 @@ router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest
|
|
143
147
|
await handleAll(req, res);
|
144
148
|
});
|
145
149
|
|
150
|
+
router.post('/ui/create-system-simple/:handle/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
151
|
+
const handle = req.params.handle as string;
|
152
|
+
const systemId = req.params.systemId as string;
|
153
|
+
const srcDir = getSystemBaseDir(systemId);
|
154
|
+
|
155
|
+
//res.set('Content-Type', 'application/x-ndjson');
|
156
|
+
//res.set('Access-Control-Expose-Headers', ConversationIdHeader);
|
157
|
+
//res.set(ConversationIdHeader, systemId);
|
158
|
+
|
159
|
+
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
160
|
+
|
161
|
+
try {
|
162
|
+
const pagesFromDisk = readFilesAndContent(srcDir);
|
163
|
+
const pagesWithImplementation = await stormClient.replaceMockWithAPICall({
|
164
|
+
pages: pagesFromDisk,
|
165
|
+
});
|
166
|
+
|
167
|
+
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
168
|
+
|
169
|
+
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
170
|
+
|
171
|
+
const allFiles = readFilesAndContent(srcDir, false).map((page) => {
|
172
|
+
if (page.encoding == HTMLPageEncoding.TEXT) {
|
173
|
+
const matchingFile = pagesWithImplementation.find(
|
174
|
+
(pageWithImpl) => pageWithImpl.fileName === page.fileName
|
175
|
+
);
|
176
|
+
if (matchingFile) {
|
177
|
+
return matchingFile;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
return page;
|
181
|
+
});
|
182
|
+
|
183
|
+
const systemUrl = await stormClient.createSimpleBackend(handle, systemId, { pages: allFiles });
|
184
|
+
//sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
185
|
+
|
186
|
+
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
187
|
+
|
188
|
+
//sendDone(res);
|
189
|
+
res.json({ url: systemUrl });
|
190
|
+
} catch (err: any) {
|
191
|
+
res.status(500).json({ error: err.message });
|
192
|
+
} finally {
|
193
|
+
if (!res.closed) {
|
194
|
+
res.end();
|
195
|
+
}
|
196
|
+
}
|
197
|
+
});
|
198
|
+
|
146
199
|
router.delete('/ui/serve/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
147
200
|
const systemId = req.params.systemId as string | undefined;
|
148
201
|
if (!systemId) {
|
package/src/storm/stormClient.ts
CHANGED
@@ -8,6 +8,7 @@ import readLine from 'node:readline/promises';
|
|
8
8
|
import { Readable } from 'node:stream';
|
9
9
|
import {
|
10
10
|
ConversationItem,
|
11
|
+
CreateSimpleBackendRequest, HTMLPage,
|
11
12
|
ImplementAPIClients,
|
12
13
|
StormContextRequest,
|
13
14
|
StormFileImplementationPrompt,
|
@@ -238,14 +239,13 @@ class StormClient {
|
|
238
239
|
return response.json() as Promise<{ vote: -1 | 0 | 1 }>;
|
239
240
|
}
|
240
241
|
|
241
|
-
public async replaceMockWithAPICall(prompt: ImplementAPIClients) {
|
242
|
+
public async replaceMockWithAPICall(prompt: ImplementAPIClients): Promise<HTMLPage[]> {
|
242
243
|
const u = `${this._baseUrl}/v2/ui/implement-api-clients-all`;
|
243
244
|
const response = await fetch(u, {
|
244
245
|
method: 'POST',
|
245
246
|
body: JSON.stringify(prompt.pages),
|
246
247
|
});
|
247
|
-
|
248
|
-
return data;
|
248
|
+
return await response.json() as HTMLPage[];
|
249
249
|
}
|
250
250
|
|
251
251
|
public async generatePrompt(pages: string[]): Promise<string> {
|
@@ -259,6 +259,20 @@ class StormClient {
|
|
259
259
|
return await response.text();
|
260
260
|
}
|
261
261
|
|
262
|
+
public async createSimpleBackend(handle: string, systemId: string, input: CreateSimpleBackendRequest) {
|
263
|
+
const u = `${this._baseUrl}/v2/create-simple-backend/${handle}/${systemId}`;
|
264
|
+
const response = await fetch(u, {
|
265
|
+
method: 'POST',
|
266
|
+
body: JSON.stringify({
|
267
|
+
pages: input.pages,
|
268
|
+
}),
|
269
|
+
});
|
270
|
+
if (!response.ok) {
|
271
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
272
|
+
}
|
273
|
+
return await response.text();
|
274
|
+
}
|
275
|
+
|
262
276
|
public classifyUIReferences(prompt: string, conversationId?: string) {
|
263
277
|
return this.send('/v2/ui/references', {
|
264
278
|
prompt: prompt,
|
package/src/storm/stream.ts
CHANGED
@@ -143,11 +143,21 @@ export interface StormUIListPrompt {
|
|
143
143
|
prompt: string;
|
144
144
|
}
|
145
145
|
|
146
|
+
export enum HTMLPageEncoding {
|
147
|
+
TEXT = 'TEXT',
|
148
|
+
BINARY = 'BINARY',
|
149
|
+
}
|
150
|
+
|
146
151
|
export interface ImplementAPIClients {
|
147
|
-
pages:
|
152
|
+
pages: HTMLPage[];
|
148
153
|
}
|
149
154
|
|
150
|
-
export interface
|
155
|
+
export interface HTMLPage {
|
151
156
|
fileName: string;
|
152
|
-
content: string
|
157
|
+
content: string;
|
158
|
+
encoding: HTMLPageEncoding;
|
159
|
+
}
|
160
|
+
|
161
|
+
export interface CreateSimpleBackendRequest {
|
162
|
+
pages: HTMLPage[];
|
153
163
|
}
|
package/src/storm/utils.ts
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
*/
|
5
5
|
import FS from 'fs-extra';
|
6
6
|
import Path from 'path';
|
7
|
-
import {
|
7
|
+
import { HTMLPage, HTMLPageEncoding } from './stream';
|
8
8
|
|
9
9
|
export async function copyDirectory(
|
10
10
|
src: string,
|
@@ -32,19 +32,27 @@ export async function copyDirectory(
|
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
35
|
-
export function readFilesAndContent(directoryPath: string):
|
36
|
-
const htmlFiles:
|
35
|
+
export function readFilesAndContent(directoryPath: string, htmlExclusive: boolean = true): HTMLPage[] {
|
36
|
+
const htmlFiles:HTMLPage[] = [];
|
37
37
|
|
38
38
|
function traverseDirectory(currentPath: string) {
|
39
39
|
const files = FS.readdirSync(currentPath);
|
40
40
|
for (const file of files) {
|
41
41
|
const fileName = Path.join(currentPath, file);
|
42
|
+
const relativeFilename = Path.relative(directoryPath, fileName);
|
42
43
|
const stats = FS.statSync(fileName);
|
43
44
|
if (stats.isDirectory()) {
|
44
45
|
traverseDirectory(fileName);
|
45
|
-
} else if (stats.isFile()
|
46
|
-
|
47
|
-
|
46
|
+
} else if (stats.isFile()) {
|
47
|
+
if (Path.extname(fileName) === '.html') {
|
48
|
+
const content = FS.readFileSync(fileName, 'utf8');
|
49
|
+
htmlFiles.push({fileName: relativeFilename, content: content, encoding: HTMLPageEncoding.TEXT });
|
50
|
+
} else {
|
51
|
+
if (!htmlExclusive) {
|
52
|
+
const content = FS.readFileSync(fileName);
|
53
|
+
htmlFiles.push({fileName: relativeFilename, content: content.toString('base64'), encoding: HTMLPageEncoding.BINARY })
|
54
|
+
}
|
55
|
+
}
|
48
56
|
}
|
49
57
|
}
|
50
58
|
}
|