@kapeta/local-cluster-service 0.74.0 → 0.74.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/src/storm/PageGenerator.js +6 -3
- package/dist/cjs/src/storm/codegen.js +11 -7
- package/dist/cjs/src/storm/routes.js +20 -11
- package/dist/cjs/src/storm/stormClient.d.ts +4 -4
- package/dist/cjs/src/storm/stormClient.js +13 -3
- package/dist/cjs/src/storm/stream.d.ts +2 -0
- package/dist/cjs/src/stormService.d.ts +2 -2
- package/dist/cjs/src/stormService.js +8 -6
- package/dist/esm/src/storm/PageGenerator.js +6 -3
- package/dist/esm/src/storm/codegen.js +11 -7
- package/dist/esm/src/storm/routes.js +20 -11
- package/dist/esm/src/storm/stormClient.d.ts +4 -4
- package/dist/esm/src/storm/stormClient.js +13 -3
- package/dist/esm/src/storm/stream.d.ts +2 -0
- package/dist/esm/src/stormService.d.ts +2 -2
- package/dist/esm/src/stormService.js +8 -6
- package/package.json +1 -1
- package/src/storm/PageGenerator.ts +7 -4
- package/src/storm/codegen.ts +5 -2
- package/src/storm/routes.ts +15 -9
- package/src/storm/stormClient.ts +12 -7
- package/src/storm/stream.ts +2 -0
- package/src/stormService.ts +9 -7
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## [0.74.1](https://github.com/kapetacom/local-cluster-service/compare/v0.74.0...v0.74.1) (2024-09-27)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* adding system id to all calls ([b3e978f](https://github.com/kapetacom/local-cluster-service/commit/b3e978ffb74fe0ab1a46006412e52c63fe49eff8))
|
7
|
+
|
1
8
|
# [0.74.0](https://github.com/kapetacom/local-cluster-service/compare/v0.73.0...v0.74.0) (2024-09-26)
|
2
9
|
|
3
10
|
|
@@ -240,8 +240,9 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
240
240
|
console.warn('Skipping image reference of type %s for url %s', mimeType, prompt.url);
|
241
241
|
return;
|
242
242
|
}
|
243
|
+
const client = new stormClient_1.StormClient(this.systemId);
|
243
244
|
this.images.set(prompt.url, prompt.description);
|
244
|
-
const result = await
|
245
|
+
const result = await client.createImage(`Create an image for the url "${prompt.url}" with this description: ${prompt.description}`.trim());
|
245
246
|
let imageEvent = null;
|
246
247
|
result.on('data', (event) => {
|
247
248
|
if (event.type === 'IMAGE') {
|
@@ -256,7 +257,8 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
256
257
|
this.emit('image', imageEvent, prompt);
|
257
258
|
}
|
258
259
|
async generate(prompt, conversationId) {
|
259
|
-
const
|
260
|
+
const client = new stormClient_1.StormClient(this.systemId);
|
261
|
+
const screenStream = await client.createUIPage(prompt, conversationId);
|
260
262
|
let pageEvent = null;
|
261
263
|
screenStream.on('data', (event) => {
|
262
264
|
if (event.type === 'PAGE') {
|
@@ -273,7 +275,8 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
273
275
|
await this.processPageEventWithReferences(pageEvent);
|
274
276
|
}
|
275
277
|
async resolveReferences(content) {
|
276
|
-
const
|
278
|
+
const client = new stormClient_1.StormClient(this.systemId);
|
279
|
+
const referenceStream = await client.classifyUIReferences(content);
|
277
280
|
const references = [];
|
278
281
|
referenceStream.on('data', (referenceData) => {
|
279
282
|
if (referenceData.type !== 'REF_CLASSIFICATION') {
|
@@ -311,9 +311,10 @@ class StormCodegen {
|
|
311
311
|
permissions: '0644',
|
312
312
|
});
|
313
313
|
const uiEvents = [];
|
314
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
314
315
|
// generate screens
|
315
316
|
if (uiTemplates.length) {
|
316
|
-
const screenStream = await
|
317
|
+
const screenStream = await stormClient.listScreens({
|
317
318
|
events: filteredEvents,
|
318
319
|
templates: uiTemplates,
|
319
320
|
context: relevantFiles,
|
@@ -346,7 +347,7 @@ class StormCodegen {
|
|
346
347
|
context: relevantFiles.concat([getScreenEventsFile()]),
|
347
348
|
prompt: this.userPrompt,
|
348
349
|
};
|
349
|
-
const uiStream = await
|
350
|
+
const uiStream = await stormClient.createUIImplementation(payload);
|
350
351
|
uiStream.on('data', (evt) => {
|
351
352
|
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
352
353
|
if (uiFile != undefined) {
|
@@ -374,13 +375,13 @@ class StormCodegen {
|
|
374
375
|
});
|
375
376
|
allFiles.push(...screenFilesConverted);
|
376
377
|
let webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
|
377
|
-
webRouters = await this.processTemplates(blockUri, block.aiName,
|
378
|
+
webRouters = await this.processTemplates(blockUri, block.aiName, stormClient.generateCode.bind(stormClient), webRouters, screenFilesConverted.concat([getScreenEventsFile()]));
|
378
379
|
// Gather the context files for implementation. These will be all be passed to the AI
|
379
380
|
const contextFiles = relevantFiles.filter((file) => ![codegen_1.AIFileTypes.SERVICE, codegen_1.AIFileTypes.WEB_SCREEN, codegen_1.AIFileTypes.WEB_ROUTER].includes(file.type));
|
380
381
|
// Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
|
381
382
|
let serviceFiles = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.SERVICE);
|
382
383
|
if (serviceFiles.length > 0) {
|
383
|
-
serviceFiles = await this.processTemplates(blockUri, block.aiName,
|
384
|
+
serviceFiles = await this.processTemplates(blockUri, block.aiName, stormClient.createServiceImplementation.bind(stormClient), serviceFiles, contextFiles);
|
384
385
|
}
|
385
386
|
if (this.isAborted()) {
|
386
387
|
return;
|
@@ -510,7 +511,8 @@ class StormCodegen {
|
|
510
511
|
}
|
511
512
|
}
|
512
513
|
async classifyErrors(errors, basePath) {
|
513
|
-
const
|
514
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
515
|
+
const errorStream = await stormClient.createErrorClassification(errors, []);
|
514
516
|
const fixes = new Map();
|
515
517
|
this.out.on('aborted', () => {
|
516
518
|
errorStream.abort();
|
@@ -547,7 +549,8 @@ class StormCodegen {
|
|
547
549
|
error: error,
|
548
550
|
projectFiles: allFiles.map((f) => f.filename),
|
549
551
|
};
|
550
|
-
const
|
552
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
553
|
+
const detailsStream = await stormClient.createErrorDetails(JSON.stringify(request), []);
|
551
554
|
detailsStream.on('data', (evt) => {
|
552
555
|
if (evt.type === 'ERROR_DETAILS') {
|
553
556
|
resolve(evt.payload.files);
|
@@ -611,7 +614,8 @@ class StormCodegen {
|
|
611
614
|
async codeFix(blockUri, blockName, fix, history) {
|
612
615
|
return new Promise(async (resolve, reject) => {
|
613
616
|
try {
|
614
|
-
const
|
617
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
618
|
+
const fixStream = await stormClient.createCodeFix(fix, history, this.conversationId);
|
615
619
|
let resolved = false;
|
616
620
|
fixStream.on('data', (evt) => {
|
617
621
|
if (this.handleFileEvents(blockUri, blockName, evt)) {
|
@@ -117,8 +117,10 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
117
117
|
res.set(stormClient_1.ConversationIdHeader, systemId);
|
118
118
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
119
119
|
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
120
|
-
const
|
120
|
+
const client = new stormClient_1.StormClient(systemId);
|
121
|
+
const pagesWithImplementation = await client.replaceMockWithAPICall({
|
121
122
|
pages: pagesFromDisk,
|
123
|
+
systemId: systemId,
|
122
124
|
});
|
123
125
|
await (0, utils_1.copyDirectory)(srcDir, destDir, (fileName, content) => {
|
124
126
|
// find the page from result1 and write the content to the file
|
@@ -131,7 +133,7 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
131
133
|
const pageContents = pagesWithImplementation.map((page) => {
|
132
134
|
return page.content;
|
133
135
|
});
|
134
|
-
const prompt = await
|
136
|
+
const prompt = await client.generatePrompt(pageContents);
|
135
137
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
136
138
|
req.query.systemId = systemId;
|
137
139
|
const promptRequest = {
|
@@ -149,10 +151,12 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
|
149
151
|
//res.set('Access-Control-Expose-Headers', ConversationIdHeader);
|
150
152
|
//res.set(ConversationIdHeader, systemId);
|
151
153
|
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
154
|
+
const client = new stormClient_1.StormClient(systemId);
|
152
155
|
try {
|
153
156
|
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
154
|
-
const pagesWithImplementation = await
|
157
|
+
const pagesWithImplementation = await client.replaceMockWithAPICall({
|
155
158
|
pages: pagesFromDisk,
|
159
|
+
systemId: systemId,
|
156
160
|
});
|
157
161
|
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
158
162
|
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
@@ -165,7 +169,7 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
|
165
169
|
}
|
166
170
|
return page;
|
167
171
|
});
|
168
|
-
const systemUrl = await
|
172
|
+
const systemUrl = await client.createSimpleBackend(handle, systemId, { pages: allFiles });
|
169
173
|
//sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
170
174
|
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
171
175
|
//sendDone(res);
|
@@ -250,7 +254,8 @@ router.post('/:handle/ui/iterative', async (req, res) => {
|
|
250
254
|
try {
|
251
255
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
252
256
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
253
|
-
const
|
257
|
+
const client = new stormClient_1.StormClient(conversationId); //todo is this correct we are using the landing page getConversationId down below as well
|
258
|
+
const landingPagesStream = await client.createUILandingPages(aiRequest, conversationId);
|
254
259
|
onRequestAborted(req, res, () => {
|
255
260
|
landingPagesStream.abort();
|
256
261
|
});
|
@@ -339,8 +344,9 @@ router.post('/:handle/ui', async (req, res) => {
|
|
339
344
|
try {
|
340
345
|
const outerConversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()] || (0, crypto_1.randomUUID)();
|
341
346
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
347
|
+
const stormClient = new stormClient_1.StormClient(outerConversationId);
|
342
348
|
// Get user journeys
|
343
|
-
const userJourneysStream = await
|
349
|
+
const userJourneysStream = await stormClient.createUIUserJourneys(aiRequest, outerConversationId);
|
344
350
|
onRequestAborted(req, res, () => {
|
345
351
|
userJourneysStream.abort();
|
346
352
|
});
|
@@ -378,7 +384,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
378
384
|
});
|
379
385
|
let theme = '';
|
380
386
|
try {
|
381
|
-
const themeStream = await
|
387
|
+
const themeStream = await stormClient.createTheme(aiRequest, outerConversationId);
|
382
388
|
onRequestAborted(req, res, () => {
|
383
389
|
themeStream.abort();
|
384
390
|
});
|
@@ -417,7 +423,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
417
423
|
}
|
418
424
|
await waitForStormStream(userJourneysStream);
|
419
425
|
// Get the UI shells
|
420
|
-
const shellsStream = await
|
426
|
+
const shellsStream = await stormClient.createUIShells({
|
421
427
|
theme: theme || undefined,
|
422
428
|
pages: Object.values(uniqueUserJourneyScreens).map((screen) => ({
|
423
429
|
name: screen.name,
|
@@ -574,7 +580,8 @@ router.post('/ui/vote', async (req, res) => {
|
|
574
580
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
575
581
|
const { topic, vote, mainConversationId } = aiRequest;
|
576
582
|
try {
|
577
|
-
|
583
|
+
const stormClient = new stormClient_1.StormClient(mainConversationId);
|
584
|
+
await stormClient.voteUIPage(topic, conversationId, vote, mainConversationId);
|
578
585
|
}
|
579
586
|
catch (e) {
|
580
587
|
res.status(500).send({ error: e.message });
|
@@ -585,7 +592,8 @@ router.post('/ui/get-vote', async (req, res) => {
|
|
585
592
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
586
593
|
const { topic, mainConversationId } = aiRequest;
|
587
594
|
try {
|
588
|
-
const
|
595
|
+
const stormClient = new stormClient_1.StormClient(mainConversationId);
|
596
|
+
const vote = await stormClient.getVoteUIPage(topic, conversationId, mainConversationId);
|
589
597
|
res.send({ vote });
|
590
598
|
}
|
591
599
|
catch (e) {
|
@@ -609,7 +617,8 @@ async function handleAll(req, res) {
|
|
609
617
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
610
618
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
611
619
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
612
|
-
const
|
620
|
+
const stormClient = new stormClient_1.StormClient(systemId);
|
621
|
+
const metaStream = await stormClient.createMetadata(aiRequest, conversationId);
|
613
622
|
onRequestAborted(req, res, () => {
|
614
623
|
metaStream.abort();
|
615
624
|
});
|
@@ -4,6 +4,7 @@ import { ConversationItem, CreateSimpleBackendRequest, HTMLPage, ImplementAPICli
|
|
4
4
|
import { Page, StormEventPageUrl } from './events';
|
5
5
|
export declare const STORM_ID = "storm";
|
6
6
|
export declare const ConversationIdHeader = "Conversation-Id";
|
7
|
+
export declare const SystemIdHeader = "System-Id";
|
7
8
|
export interface UIShellsPrompt {
|
8
9
|
theme?: string;
|
9
10
|
pages: {
|
@@ -55,9 +56,10 @@ export interface BasePromptRequest {
|
|
55
56
|
prompt: string;
|
56
57
|
skipImprovement?: boolean;
|
57
58
|
}
|
58
|
-
declare class StormClient {
|
59
|
+
export declare class StormClient {
|
59
60
|
private readonly _baseUrl;
|
60
|
-
|
61
|
+
private readonly _systemId;
|
62
|
+
constructor(systemId?: string);
|
61
63
|
private createOptions;
|
62
64
|
private send;
|
63
65
|
createMetadata(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
|
@@ -88,5 +90,3 @@ declare class StormClient {
|
|
88
90
|
downloadSystem(handle: string, conversationId: string): Promise<Buffer>;
|
89
91
|
uploadSystem(handle: string, conversationId: string, buffer: Buffer): Promise<Response>;
|
90
92
|
}
|
91
|
-
export declare const stormClient: StormClient;
|
92
|
-
export {};
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.
|
6
|
+
exports.StormClient = exports.SystemIdHeader = exports.ConversationIdHeader = exports.STORM_ID = void 0;
|
7
7
|
/**
|
8
8
|
* Copyright 2023 Kapeta Inc.
|
9
9
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -17,10 +17,13 @@ const fetch_retry_1 = __importDefault(require("fetch-retry"));
|
|
17
17
|
const fetchWithRetries = (0, fetch_retry_1.default)(global.fetch, { retries: 5, retryDelay: 10 });
|
18
18
|
exports.STORM_ID = 'storm';
|
19
19
|
exports.ConversationIdHeader = 'Conversation-Id';
|
20
|
+
exports.SystemIdHeader = 'System-Id';
|
20
21
|
class StormClient {
|
21
22
|
_baseUrl;
|
22
|
-
|
23
|
+
_systemId;
|
24
|
+
constructor(systemId) {
|
23
25
|
this._baseUrl = (0, utils_1.getRemoteUrl)('ai-service', 'https://ai.kapeta.com');
|
26
|
+
this._systemId = systemId || "";
|
24
27
|
}
|
25
28
|
async createOptions(path, method, body) {
|
26
29
|
const url = `${this._baseUrl}${path}`;
|
@@ -35,6 +38,9 @@ class StormClient {
|
|
35
38
|
if (body.conversationId) {
|
36
39
|
headers[exports.ConversationIdHeader] = body.conversationId;
|
37
40
|
}
|
41
|
+
if (this._systemId) {
|
42
|
+
headers[exports.SystemIdHeader] = this._systemId;
|
43
|
+
}
|
38
44
|
return {
|
39
45
|
url,
|
40
46
|
method: method,
|
@@ -103,6 +109,7 @@ class StormClient {
|
|
103
109
|
createUIShells(prompt, conversationId) {
|
104
110
|
return this.send('/v2/ui/shells', {
|
105
111
|
prompt: JSON.stringify(prompt),
|
112
|
+
conversationId: conversationId,
|
106
113
|
});
|
107
114
|
}
|
108
115
|
createUILandingPages(prompt, conversationId) {
|
@@ -138,6 +145,9 @@ class StormClient {
|
|
138
145
|
const response = await fetch(u, {
|
139
146
|
method: 'POST',
|
140
147
|
body: JSON.stringify(prompt.pages),
|
148
|
+
headers: {
|
149
|
+
'systemId': prompt.systemId,
|
150
|
+
},
|
141
151
|
});
|
142
152
|
return (await response.json());
|
143
153
|
}
|
@@ -252,4 +262,4 @@ class StormClient {
|
|
252
262
|
return response;
|
253
263
|
}
|
254
264
|
}
|
255
|
-
exports.
|
265
|
+
exports.StormClient = StormClient;
|
@@ -35,6 +35,7 @@ export interface ConversationItem {
|
|
35
35
|
}
|
36
36
|
export interface StormContextRequest<T = string> {
|
37
37
|
conversationId?: string;
|
38
|
+
systemId?: string;
|
38
39
|
history?: ConversationItem[];
|
39
40
|
prompt: T;
|
40
41
|
}
|
@@ -78,6 +79,7 @@ export declare enum HTMLPageEncoding {
|
|
78
79
|
}
|
79
80
|
export interface ImplementAPIClients {
|
80
81
|
pages: HTMLPage[];
|
82
|
+
systemId: string;
|
81
83
|
}
|
82
84
|
export interface HTMLPage {
|
83
85
|
fileName: string;
|
@@ -13,8 +13,8 @@ export declare class StormService {
|
|
13
13
|
saveConversation(conversationId: string, events: StormEvent[]): Promise<void>;
|
14
14
|
appendConversation(conversationId: string, events: StormEvent[]): Promise<void>;
|
15
15
|
deleteConversation(conversationId: string): Promise<void>;
|
16
|
-
uploadConversation(handle: string,
|
17
|
-
installProjectById(handle: string,
|
16
|
+
uploadConversation(handle: string, systemId: string): Promise<void>;
|
17
|
+
installProjectById(handle: string, systemId: string): Promise<void>;
|
18
18
|
}
|
19
19
|
declare const _default: StormService;
|
20
20
|
export default _default;
|
@@ -119,8 +119,8 @@ class StormService {
|
|
119
119
|
await promises_1.default.rm(conversationDir, { recursive: true, force: true });
|
120
120
|
}
|
121
121
|
}
|
122
|
-
async uploadConversation(handle,
|
123
|
-
const tarballFile = this.getConversationTarball(
|
122
|
+
async uploadConversation(handle, systemId) {
|
123
|
+
const tarballFile = this.getConversationTarball(systemId);
|
124
124
|
const destDir = path_1.default.dirname(tarballFile);
|
125
125
|
const tarballName = path_1.default.basename(tarballFile);
|
126
126
|
await tar.create({
|
@@ -129,12 +129,14 @@ class StormService {
|
|
129
129
|
gzip: true,
|
130
130
|
filter: (entry) => !entry.includes(tarballName),
|
131
131
|
}, ['.']);
|
132
|
-
|
132
|
+
const stormClient = new stormClient_1.StormClient(systemId);
|
133
|
+
await stormClient.uploadSystem(handle, systemId, await promises_1.default.readFile(tarballFile));
|
133
134
|
}
|
134
|
-
async installProjectById(handle,
|
135
|
-
const tarballFile = this.getConversationTarball(
|
135
|
+
async installProjectById(handle, systemId) {
|
136
|
+
const tarballFile = this.getConversationTarball(systemId);
|
136
137
|
const destDir = path_1.default.dirname(tarballFile);
|
137
|
-
const
|
138
|
+
const stormClient = new stormClient_1.StormClient(systemId);
|
139
|
+
const buffer = await stormClient.downloadSystem(handle, systemId);
|
138
140
|
await promises_1.default.mkdir(destDir, { recursive: true });
|
139
141
|
await promises_1.default.writeFile(tarballFile, buffer);
|
140
142
|
await tar.extract({
|
@@ -240,8 +240,9 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
240
240
|
console.warn('Skipping image reference of type %s for url %s', mimeType, prompt.url);
|
241
241
|
return;
|
242
242
|
}
|
243
|
+
const client = new stormClient_1.StormClient(this.systemId);
|
243
244
|
this.images.set(prompt.url, prompt.description);
|
244
|
-
const result = await
|
245
|
+
const result = await client.createImage(`Create an image for the url "${prompt.url}" with this description: ${prompt.description}`.trim());
|
245
246
|
let imageEvent = null;
|
246
247
|
result.on('data', (event) => {
|
247
248
|
if (event.type === 'IMAGE') {
|
@@ -256,7 +257,8 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
256
257
|
this.emit('image', imageEvent, prompt);
|
257
258
|
}
|
258
259
|
async generate(prompt, conversationId) {
|
259
|
-
const
|
260
|
+
const client = new stormClient_1.StormClient(this.systemId);
|
261
|
+
const screenStream = await client.createUIPage(prompt, conversationId);
|
260
262
|
let pageEvent = null;
|
261
263
|
screenStream.on('data', (event) => {
|
262
264
|
if (event.type === 'PAGE') {
|
@@ -273,7 +275,8 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
273
275
|
await this.processPageEventWithReferences(pageEvent);
|
274
276
|
}
|
275
277
|
async resolveReferences(content) {
|
276
|
-
const
|
278
|
+
const client = new stormClient_1.StormClient(this.systemId);
|
279
|
+
const referenceStream = await client.classifyUIReferences(content);
|
277
280
|
const references = [];
|
278
281
|
referenceStream.on('data', (referenceData) => {
|
279
282
|
if (referenceData.type !== 'REF_CLASSIFICATION') {
|
@@ -311,9 +311,10 @@ class StormCodegen {
|
|
311
311
|
permissions: '0644',
|
312
312
|
});
|
313
313
|
const uiEvents = [];
|
314
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
314
315
|
// generate screens
|
315
316
|
if (uiTemplates.length) {
|
316
|
-
const screenStream = await
|
317
|
+
const screenStream = await stormClient.listScreens({
|
317
318
|
events: filteredEvents,
|
318
319
|
templates: uiTemplates,
|
319
320
|
context: relevantFiles,
|
@@ -346,7 +347,7 @@ class StormCodegen {
|
|
346
347
|
context: relevantFiles.concat([getScreenEventsFile()]),
|
347
348
|
prompt: this.userPrompt,
|
348
349
|
};
|
349
|
-
const uiStream = await
|
350
|
+
const uiStream = await stormClient.createUIImplementation(payload);
|
350
351
|
uiStream.on('data', (evt) => {
|
351
352
|
const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
|
352
353
|
if (uiFile != undefined) {
|
@@ -374,13 +375,13 @@ class StormCodegen {
|
|
374
375
|
});
|
375
376
|
allFiles.push(...screenFilesConverted);
|
376
377
|
let webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
|
377
|
-
webRouters = await this.processTemplates(blockUri, block.aiName,
|
378
|
+
webRouters = await this.processTemplates(blockUri, block.aiName, stormClient.generateCode.bind(stormClient), webRouters, screenFilesConverted.concat([getScreenEventsFile()]));
|
378
379
|
// Gather the context files for implementation. These will be all be passed to the AI
|
379
380
|
const contextFiles = relevantFiles.filter((file) => ![codegen_1.AIFileTypes.SERVICE, codegen_1.AIFileTypes.WEB_SCREEN, codegen_1.AIFileTypes.WEB_ROUTER].includes(file.type));
|
380
381
|
// Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
|
381
382
|
let serviceFiles = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.SERVICE);
|
382
383
|
if (serviceFiles.length > 0) {
|
383
|
-
serviceFiles = await this.processTemplates(blockUri, block.aiName,
|
384
|
+
serviceFiles = await this.processTemplates(blockUri, block.aiName, stormClient.createServiceImplementation.bind(stormClient), serviceFiles, contextFiles);
|
384
385
|
}
|
385
386
|
if (this.isAborted()) {
|
386
387
|
return;
|
@@ -510,7 +511,8 @@ class StormCodegen {
|
|
510
511
|
}
|
511
512
|
}
|
512
513
|
async classifyErrors(errors, basePath) {
|
513
|
-
const
|
514
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
515
|
+
const errorStream = await stormClient.createErrorClassification(errors, []);
|
514
516
|
const fixes = new Map();
|
515
517
|
this.out.on('aborted', () => {
|
516
518
|
errorStream.abort();
|
@@ -547,7 +549,8 @@ class StormCodegen {
|
|
547
549
|
error: error,
|
548
550
|
projectFiles: allFiles.map((f) => f.filename),
|
549
551
|
};
|
550
|
-
const
|
552
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
553
|
+
const detailsStream = await stormClient.createErrorDetails(JSON.stringify(request), []);
|
551
554
|
detailsStream.on('data', (evt) => {
|
552
555
|
if (evt.type === 'ERROR_DETAILS') {
|
553
556
|
resolve(evt.payload.files);
|
@@ -611,7 +614,8 @@ class StormCodegen {
|
|
611
614
|
async codeFix(blockUri, blockName, fix, history) {
|
612
615
|
return new Promise(async (resolve, reject) => {
|
613
616
|
try {
|
614
|
-
const
|
617
|
+
const stormClient = new stormClient_1.StormClient(this.uiSystemId);
|
618
|
+
const fixStream = await stormClient.createCodeFix(fix, history, this.conversationId);
|
615
619
|
let resolved = false;
|
616
620
|
fixStream.on('data', (evt) => {
|
617
621
|
if (this.handleFileEvents(blockUri, blockName, evt)) {
|
@@ -117,8 +117,10 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
117
117
|
res.set(stormClient_1.ConversationIdHeader, systemId);
|
118
118
|
sendEvent(res, (0, event_parser_1.createPhaseStartEvent)(events_1.StormEventPhaseType.IMPLEMENT_APIS));
|
119
119
|
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
120
|
-
const
|
120
|
+
const client = new stormClient_1.StormClient(systemId);
|
121
|
+
const pagesWithImplementation = await client.replaceMockWithAPICall({
|
121
122
|
pages: pagesFromDisk,
|
123
|
+
systemId: systemId,
|
122
124
|
});
|
123
125
|
await (0, utils_1.copyDirectory)(srcDir, destDir, (fileName, content) => {
|
124
126
|
// find the page from result1 and write the content to the file
|
@@ -131,7 +133,7 @@ router.post('/ui/create-system/:handle/:systemId', async (req, res) => {
|
|
131
133
|
const pageContents = pagesWithImplementation.map((page) => {
|
132
134
|
return page.content;
|
133
135
|
});
|
134
|
-
const prompt = await
|
136
|
+
const prompt = await client.generatePrompt(pageContents);
|
135
137
|
sendEvent(res, (0, event_parser_1.createPhaseEndEvent)(events_1.StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
136
138
|
req.query.systemId = systemId;
|
137
139
|
const promptRequest = {
|
@@ -149,10 +151,12 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
|
149
151
|
//res.set('Access-Control-Expose-Headers', ConversationIdHeader);
|
150
152
|
//res.set(ConversationIdHeader, systemId);
|
151
153
|
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
154
|
+
const client = new stormClient_1.StormClient(systemId);
|
152
155
|
try {
|
153
156
|
const pagesFromDisk = (0, utils_1.readFilesAndContent)(srcDir);
|
154
|
-
const pagesWithImplementation = await
|
157
|
+
const pagesWithImplementation = await client.replaceMockWithAPICall({
|
155
158
|
pages: pagesFromDisk,
|
159
|
+
systemId: systemId,
|
156
160
|
});
|
157
161
|
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
158
162
|
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
@@ -165,7 +169,7 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req, res) => {
|
|
165
169
|
}
|
166
170
|
return page;
|
167
171
|
});
|
168
|
-
const systemUrl = await
|
172
|
+
const systemUrl = await client.createSimpleBackend(handle, systemId, { pages: allFiles });
|
169
173
|
//sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
170
174
|
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
171
175
|
//sendDone(res);
|
@@ -250,7 +254,8 @@ router.post('/:handle/ui/iterative', async (req, res) => {
|
|
250
254
|
try {
|
251
255
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
252
256
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
253
|
-
const
|
257
|
+
const client = new stormClient_1.StormClient(conversationId); //todo is this correct we are using the landing page getConversationId down below as well
|
258
|
+
const landingPagesStream = await client.createUILandingPages(aiRequest, conversationId);
|
254
259
|
onRequestAborted(req, res, () => {
|
255
260
|
landingPagesStream.abort();
|
256
261
|
});
|
@@ -339,8 +344,9 @@ router.post('/:handle/ui', async (req, res) => {
|
|
339
344
|
try {
|
340
345
|
const outerConversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()] || (0, crypto_1.randomUUID)();
|
341
346
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
347
|
+
const stormClient = new stormClient_1.StormClient(outerConversationId);
|
342
348
|
// Get user journeys
|
343
|
-
const userJourneysStream = await
|
349
|
+
const userJourneysStream = await stormClient.createUIUserJourneys(aiRequest, outerConversationId);
|
344
350
|
onRequestAborted(req, res, () => {
|
345
351
|
userJourneysStream.abort();
|
346
352
|
});
|
@@ -378,7 +384,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
378
384
|
});
|
379
385
|
let theme = '';
|
380
386
|
try {
|
381
|
-
const themeStream = await
|
387
|
+
const themeStream = await stormClient.createTheme(aiRequest, outerConversationId);
|
382
388
|
onRequestAborted(req, res, () => {
|
383
389
|
themeStream.abort();
|
384
390
|
});
|
@@ -417,7 +423,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
417
423
|
}
|
418
424
|
await waitForStormStream(userJourneysStream);
|
419
425
|
// Get the UI shells
|
420
|
-
const shellsStream = await
|
426
|
+
const shellsStream = await stormClient.createUIShells({
|
421
427
|
theme: theme || undefined,
|
422
428
|
pages: Object.values(uniqueUserJourneyScreens).map((screen) => ({
|
423
429
|
name: screen.name,
|
@@ -574,7 +580,8 @@ router.post('/ui/vote', async (req, res) => {
|
|
574
580
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
575
581
|
const { topic, vote, mainConversationId } = aiRequest;
|
576
582
|
try {
|
577
|
-
|
583
|
+
const stormClient = new stormClient_1.StormClient(mainConversationId);
|
584
|
+
await stormClient.voteUIPage(topic, conversationId, vote, mainConversationId);
|
578
585
|
}
|
579
586
|
catch (e) {
|
580
587
|
res.status(500).send({ error: e.message });
|
@@ -585,7 +592,8 @@ router.post('/ui/get-vote', async (req, res) => {
|
|
585
592
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
586
593
|
const { topic, mainConversationId } = aiRequest;
|
587
594
|
try {
|
588
|
-
const
|
595
|
+
const stormClient = new stormClient_1.StormClient(mainConversationId);
|
596
|
+
const vote = await stormClient.getVoteUIPage(topic, conversationId, mainConversationId);
|
589
597
|
res.send({ vote });
|
590
598
|
}
|
591
599
|
catch (e) {
|
@@ -609,7 +617,8 @@ async function handleAll(req, res) {
|
|
609
617
|
const eventParser = new event_parser_1.StormEventParser(stormOptions);
|
610
618
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
611
619
|
const aiRequest = JSON.parse(req.stringBody ?? '{}');
|
612
|
-
const
|
620
|
+
const stormClient = new stormClient_1.StormClient(systemId);
|
621
|
+
const metaStream = await stormClient.createMetadata(aiRequest, conversationId);
|
613
622
|
onRequestAborted(req, res, () => {
|
614
623
|
metaStream.abort();
|
615
624
|
});
|
@@ -4,6 +4,7 @@ import { ConversationItem, CreateSimpleBackendRequest, HTMLPage, ImplementAPICli
|
|
4
4
|
import { Page, StormEventPageUrl } from './events';
|
5
5
|
export declare const STORM_ID = "storm";
|
6
6
|
export declare const ConversationIdHeader = "Conversation-Id";
|
7
|
+
export declare const SystemIdHeader = "System-Id";
|
7
8
|
export interface UIShellsPrompt {
|
8
9
|
theme?: string;
|
9
10
|
pages: {
|
@@ -55,9 +56,10 @@ export interface BasePromptRequest {
|
|
55
56
|
prompt: string;
|
56
57
|
skipImprovement?: boolean;
|
57
58
|
}
|
58
|
-
declare class StormClient {
|
59
|
+
export declare class StormClient {
|
59
60
|
private readonly _baseUrl;
|
60
|
-
|
61
|
+
private readonly _systemId;
|
62
|
+
constructor(systemId?: string);
|
61
63
|
private createOptions;
|
62
64
|
private send;
|
63
65
|
createMetadata(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
|
@@ -88,5 +90,3 @@ declare class StormClient {
|
|
88
90
|
downloadSystem(handle: string, conversationId: string): Promise<Buffer>;
|
89
91
|
uploadSystem(handle: string, conversationId: string, buffer: Buffer): Promise<Response>;
|
90
92
|
}
|
91
|
-
export declare const stormClient: StormClient;
|
92
|
-
export {};
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.
|
6
|
+
exports.StormClient = exports.SystemIdHeader = exports.ConversationIdHeader = exports.STORM_ID = void 0;
|
7
7
|
/**
|
8
8
|
* Copyright 2023 Kapeta Inc.
|
9
9
|
* SPDX-License-Identifier: BUSL-1.1
|
@@ -17,10 +17,13 @@ const fetch_retry_1 = __importDefault(require("fetch-retry"));
|
|
17
17
|
const fetchWithRetries = (0, fetch_retry_1.default)(global.fetch, { retries: 5, retryDelay: 10 });
|
18
18
|
exports.STORM_ID = 'storm';
|
19
19
|
exports.ConversationIdHeader = 'Conversation-Id';
|
20
|
+
exports.SystemIdHeader = 'System-Id';
|
20
21
|
class StormClient {
|
21
22
|
_baseUrl;
|
22
|
-
|
23
|
+
_systemId;
|
24
|
+
constructor(systemId) {
|
23
25
|
this._baseUrl = (0, utils_1.getRemoteUrl)('ai-service', 'https://ai.kapeta.com');
|
26
|
+
this._systemId = systemId || "";
|
24
27
|
}
|
25
28
|
async createOptions(path, method, body) {
|
26
29
|
const url = `${this._baseUrl}${path}`;
|
@@ -35,6 +38,9 @@ class StormClient {
|
|
35
38
|
if (body.conversationId) {
|
36
39
|
headers[exports.ConversationIdHeader] = body.conversationId;
|
37
40
|
}
|
41
|
+
if (this._systemId) {
|
42
|
+
headers[exports.SystemIdHeader] = this._systemId;
|
43
|
+
}
|
38
44
|
return {
|
39
45
|
url,
|
40
46
|
method: method,
|
@@ -103,6 +109,7 @@ class StormClient {
|
|
103
109
|
createUIShells(prompt, conversationId) {
|
104
110
|
return this.send('/v2/ui/shells', {
|
105
111
|
prompt: JSON.stringify(prompt),
|
112
|
+
conversationId: conversationId,
|
106
113
|
});
|
107
114
|
}
|
108
115
|
createUILandingPages(prompt, conversationId) {
|
@@ -138,6 +145,9 @@ class StormClient {
|
|
138
145
|
const response = await fetch(u, {
|
139
146
|
method: 'POST',
|
140
147
|
body: JSON.stringify(prompt.pages),
|
148
|
+
headers: {
|
149
|
+
'systemId': prompt.systemId,
|
150
|
+
},
|
141
151
|
});
|
142
152
|
return (await response.json());
|
143
153
|
}
|
@@ -252,4 +262,4 @@ class StormClient {
|
|
252
262
|
return response;
|
253
263
|
}
|
254
264
|
}
|
255
|
-
exports.
|
265
|
+
exports.StormClient = StormClient;
|
@@ -35,6 +35,7 @@ export interface ConversationItem {
|
|
35
35
|
}
|
36
36
|
export interface StormContextRequest<T = string> {
|
37
37
|
conversationId?: string;
|
38
|
+
systemId?: string;
|
38
39
|
history?: ConversationItem[];
|
39
40
|
prompt: T;
|
40
41
|
}
|
@@ -78,6 +79,7 @@ export declare enum HTMLPageEncoding {
|
|
78
79
|
}
|
79
80
|
export interface ImplementAPIClients {
|
80
81
|
pages: HTMLPage[];
|
82
|
+
systemId: string;
|
81
83
|
}
|
82
84
|
export interface HTMLPage {
|
83
85
|
fileName: string;
|
@@ -13,8 +13,8 @@ export declare class StormService {
|
|
13
13
|
saveConversation(conversationId: string, events: StormEvent[]): Promise<void>;
|
14
14
|
appendConversation(conversationId: string, events: StormEvent[]): Promise<void>;
|
15
15
|
deleteConversation(conversationId: string): Promise<void>;
|
16
|
-
uploadConversation(handle: string,
|
17
|
-
installProjectById(handle: string,
|
16
|
+
uploadConversation(handle: string, systemId: string): Promise<void>;
|
17
|
+
installProjectById(handle: string, systemId: string): Promise<void>;
|
18
18
|
}
|
19
19
|
declare const _default: StormService;
|
20
20
|
export default _default;
|
@@ -119,8 +119,8 @@ class StormService {
|
|
119
119
|
await promises_1.default.rm(conversationDir, { recursive: true, force: true });
|
120
120
|
}
|
121
121
|
}
|
122
|
-
async uploadConversation(handle,
|
123
|
-
const tarballFile = this.getConversationTarball(
|
122
|
+
async uploadConversation(handle, systemId) {
|
123
|
+
const tarballFile = this.getConversationTarball(systemId);
|
124
124
|
const destDir = path_1.default.dirname(tarballFile);
|
125
125
|
const tarballName = path_1.default.basename(tarballFile);
|
126
126
|
await tar.create({
|
@@ -129,12 +129,14 @@ class StormService {
|
|
129
129
|
gzip: true,
|
130
130
|
filter: (entry) => !entry.includes(tarballName),
|
131
131
|
}, ['.']);
|
132
|
-
|
132
|
+
const stormClient = new stormClient_1.StormClient(systemId);
|
133
|
+
await stormClient.uploadSystem(handle, systemId, await promises_1.default.readFile(tarballFile));
|
133
134
|
}
|
134
|
-
async installProjectById(handle,
|
135
|
-
const tarballFile = this.getConversationTarball(
|
135
|
+
async installProjectById(handle, systemId) {
|
136
|
+
const tarballFile = this.getConversationTarball(systemId);
|
136
137
|
const destDir = path_1.default.dirname(tarballFile);
|
137
|
-
const
|
138
|
+
const stormClient = new stormClient_1.StormClient(systemId);
|
139
|
+
const buffer = await stormClient.downloadSystem(handle, systemId);
|
138
140
|
await promises_1.default.mkdir(destDir, { recursive: true });
|
139
141
|
await promises_1.default.writeFile(tarballFile, buffer);
|
140
142
|
await tar.extract({
|
package/package.json
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
*/
|
5
5
|
|
6
6
|
import uuid from 'node-uuid';
|
7
|
-
import {
|
7
|
+
import { StormClient, UIPagePrompt } from './stormClient';
|
8
8
|
import { ReferenceClassification, StormEvent, StormEventPage, StormImage, UIShell } from './events';
|
9
9
|
import { EventEmitter } from 'node:events';
|
10
10
|
import PQueue from 'p-queue';
|
@@ -265,8 +265,9 @@ export class PageQueue extends EventEmitter {
|
|
265
265
|
return;
|
266
266
|
}
|
267
267
|
|
268
|
+
const client = new StormClient(this.systemId);
|
268
269
|
this.images.set(prompt.url, prompt.description);
|
269
|
-
const result = await
|
270
|
+
const result = await client.createImage(
|
270
271
|
`Create an image for the url "${prompt.url}" with this description: ${prompt.description}`.trim()
|
271
272
|
);
|
272
273
|
|
@@ -287,7 +288,8 @@ export class PageQueue extends EventEmitter {
|
|
287
288
|
}
|
288
289
|
|
289
290
|
public async generate(prompt: UIPagePrompt, conversationId: string) {
|
290
|
-
const
|
291
|
+
const client = new StormClient(this.systemId);
|
292
|
+
const screenStream = await client.createUIPage(prompt, conversationId);
|
291
293
|
let pageEvent: StormEventPage | null = null;
|
292
294
|
screenStream.on('data', (event: StormEvent) => {
|
293
295
|
if (event.type === 'PAGE') {
|
@@ -306,7 +308,8 @@ export class PageQueue extends EventEmitter {
|
|
306
308
|
}
|
307
309
|
|
308
310
|
private async resolveReferences(content: string): Promise<ReferenceClassification[]> {
|
309
|
-
const
|
311
|
+
const client = new StormClient(this.systemId);
|
312
|
+
const referenceStream = await client.classifyUIReferences(content);
|
310
313
|
|
311
314
|
const references: ReferenceClassification[] = [];
|
312
315
|
|
package/src/storm/codegen.ts
CHANGED
@@ -17,7 +17,7 @@ import {
|
|
17
17
|
|
18
18
|
import { BlockDefinition } from '@kapeta/schemas';
|
19
19
|
import { codeGeneratorManager } from '../codeGeneratorManager';
|
20
|
-
import { STORM_ID,
|
20
|
+
import { STORM_ID, StormClient } from './stormClient';
|
21
21
|
import {
|
22
22
|
StormEvent,
|
23
23
|
StormEventBlockStatusType,
|
@@ -371,6 +371,7 @@ export class StormCodegen {
|
|
371
371
|
});
|
372
372
|
const uiEvents = [];
|
373
373
|
|
374
|
+
const stormClient = new StormClient(this.uiSystemId);
|
374
375
|
// generate screens
|
375
376
|
if (uiTemplates.length) {
|
376
377
|
const screenStream = await stormClient.listScreens({
|
@@ -663,6 +664,7 @@ export class StormCodegen {
|
|
663
664
|
}
|
664
665
|
|
665
666
|
private async classifyErrors(errors: string, basePath: string): Promise<Map<string, ErrorClassification[]>> {
|
667
|
+
const stormClient = new StormClient(this.uiSystemId);
|
666
668
|
const errorStream = await stormClient.createErrorClassification(errors, []);
|
667
669
|
const fixes = new Map<string, ErrorClassification[]>();
|
668
670
|
|
@@ -711,7 +713,7 @@ export class StormCodegen {
|
|
711
713
|
error: error,
|
712
714
|
projectFiles: allFiles.map((f) => f.filename),
|
713
715
|
};
|
714
|
-
|
716
|
+
const stormClient = new StormClient(this.uiSystemId);
|
715
717
|
const detailsStream = await stormClient.createErrorDetails(JSON.stringify(request), []);
|
716
718
|
detailsStream.on('data', (evt) => {
|
717
719
|
if (evt.type === 'ERROR_DETAILS') {
|
@@ -799,6 +801,7 @@ export class StormCodegen {
|
|
799
801
|
): Promise<StormEventErrorDetailsFile> {
|
800
802
|
return new Promise<StormEventErrorDetailsFile>(async (resolve, reject) => {
|
801
803
|
try {
|
804
|
+
const stormClient = new StormClient(this.uiSystemId);
|
802
805
|
const fixStream = await stormClient.createCodeFix(fix, history, this.conversationId);
|
803
806
|
let resolved = false;
|
804
807
|
fixStream.on('data', (evt) => {
|
package/src/storm/routes.ts
CHANGED
@@ -21,12 +21,12 @@ import {
|
|
21
21
|
|
22
22
|
import {
|
23
23
|
ConversationIdHeader,
|
24
|
-
stormClient,
|
25
24
|
UIPagePrompt,
|
26
25
|
UIPageEditRequest,
|
27
26
|
BasePromptRequest,
|
28
27
|
UIPageVoteRequest,
|
29
28
|
UIPageGetVoteRequest,
|
29
|
+
StormClient,
|
30
30
|
} from './stormClient';
|
31
31
|
import { StormEvent, StormEventPage, StormEventPhaseType, UserJourneyScreen } from './events';
|
32
32
|
|
@@ -162,8 +162,10 @@ router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest
|
|
162
162
|
sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
163
163
|
|
164
164
|
const pagesFromDisk = readFilesAndContent(srcDir);
|
165
|
-
const
|
165
|
+
const client = new StormClient(systemId)
|
166
|
+
const pagesWithImplementation = await client.replaceMockWithAPICall({
|
166
167
|
pages: pagesFromDisk,
|
168
|
+
systemId: systemId,
|
167
169
|
});
|
168
170
|
|
169
171
|
await copyDirectory(srcDir, destDir, (fileName, content) => {
|
@@ -181,7 +183,7 @@ router.post('/ui/create-system/:handle/:systemId', async (req: KapetaBodyRequest
|
|
181
183
|
return page.content;
|
182
184
|
});
|
183
185
|
|
184
|
-
const prompt = await
|
186
|
+
const prompt = await client.generatePrompt(pageContents);
|
185
187
|
|
186
188
|
sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM_PROMPT));
|
187
189
|
|
@@ -204,11 +206,12 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req: KapetaBody
|
|
204
206
|
//res.set(ConversationIdHeader, systemId);
|
205
207
|
|
206
208
|
//sendEvent(res, createPhaseStartEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
207
|
-
|
209
|
+
const client = new StormClient(systemId);
|
208
210
|
try {
|
209
211
|
const pagesFromDisk = readFilesAndContent(srcDir);
|
210
|
-
const pagesWithImplementation = await
|
212
|
+
const pagesWithImplementation = await client.replaceMockWithAPICall({
|
211
213
|
pages: pagesFromDisk,
|
214
|
+
systemId: systemId,
|
212
215
|
});
|
213
216
|
|
214
217
|
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.IMPLEMENT_APIS));
|
@@ -227,7 +230,7 @@ router.post('/ui/create-system-simple/:handle/:systemId', async (req: KapetaBody
|
|
227
230
|
return page;
|
228
231
|
});
|
229
232
|
|
230
|
-
const systemUrl = await
|
233
|
+
const systemUrl = await client.createSimpleBackend(handle, systemId, { pages: allFiles });
|
231
234
|
//sendEvent(res, {type: 'SYSTEM_READY', created: Math.floor(Date.now() / 1000), reason: 'System Ready', payload: { systemUrl: systemUrl }});
|
232
235
|
|
233
236
|
//sendEvent(res, createPhaseEndEvent(StormEventPhaseType.COMPOSE_SYSTEM));
|
@@ -328,8 +331,8 @@ router.post('/:handle/ui/iterative', async (req: KapetaBodyRequest, res: Respons
|
|
328
331
|
const conversationId = req.headers[ConversationIdHeader.toLowerCase()] as string | undefined;
|
329
332
|
|
330
333
|
const aiRequest: BasePromptRequest = JSON.parse(req.stringBody ?? '{}');
|
331
|
-
|
332
|
-
const landingPagesStream = await
|
334
|
+
const client = new StormClient(conversationId); //todo is this correct we are using the landing page getConversationId down below as well
|
335
|
+
const landingPagesStream = await client.createUILandingPages(aiRequest, conversationId);
|
333
336
|
|
334
337
|
onRequestAborted(req, res, () => {
|
335
338
|
landingPagesStream.abort();
|
@@ -437,7 +440,7 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
437
440
|
(req.headers[ConversationIdHeader.toLowerCase()] as string | undefined) || randomUUID();
|
438
441
|
|
439
442
|
const aiRequest: BasePromptRequest = JSON.parse(req.stringBody ?? '{}');
|
440
|
-
|
443
|
+
const stormClient = new StormClient(outerConversationId);
|
441
444
|
// Get user journeys
|
442
445
|
const userJourneysStream = await stormClient.createUIUserJourneys(aiRequest, outerConversationId);
|
443
446
|
|
@@ -719,6 +722,7 @@ router.post('/ui/vote', async (req: KapetaBodyRequest, res: Response) => {
|
|
719
722
|
const aiRequest: UIPageVoteRequest = JSON.parse(req.stringBody ?? '{}');
|
720
723
|
const { topic, vote, mainConversationId } = aiRequest;
|
721
724
|
try {
|
725
|
+
const stormClient = new StormClient(mainConversationId);
|
722
726
|
await stormClient.voteUIPage(topic, conversationId, vote, mainConversationId);
|
723
727
|
} catch (e: any) {
|
724
728
|
res.status(500).send({ error: e.message });
|
@@ -730,6 +734,7 @@ router.post('/ui/get-vote', async (req: KapetaBodyRequest, res: Response) => {
|
|
730
734
|
const aiRequest: UIPageGetVoteRequest = JSON.parse(req.stringBody ?? '{}');
|
731
735
|
const { topic, mainConversationId } = aiRequest;
|
732
736
|
try {
|
737
|
+
const stormClient = new StormClient(mainConversationId);
|
733
738
|
const vote = await stormClient.getVoteUIPage(topic, conversationId, mainConversationId);
|
734
739
|
res.send({ vote });
|
735
740
|
} catch (e: any) {
|
@@ -761,6 +766,7 @@ async function handleAll(req: KapetaBodyRequest, res: Response) {
|
|
761
766
|
const conversationId = req.headers[ConversationIdHeader.toLowerCase()] as string | undefined;
|
762
767
|
|
763
768
|
const aiRequest: BasePromptRequest = JSON.parse(req.stringBody ?? '{}');
|
769
|
+
const stormClient = new StormClient(systemId);
|
764
770
|
const metaStream = await stormClient.createMetadata(aiRequest, conversationId);
|
765
771
|
|
766
772
|
onRequestAborted(req, res, () => {
|
package/src/storm/stormClient.ts
CHANGED
@@ -24,6 +24,7 @@ const fetchWithRetries = createFetch(global.fetch, { retries: 5, retryDelay: 10
|
|
24
24
|
export const STORM_ID = 'storm';
|
25
25
|
|
26
26
|
export const ConversationIdHeader = 'Conversation-Id';
|
27
|
+
export const SystemIdHeader = 'System-Id';
|
27
28
|
|
28
29
|
export interface UIShellsPrompt {
|
29
30
|
theme?: string;
|
@@ -85,11 +86,12 @@ export interface BasePromptRequest {
|
|
85
86
|
skipImprovement?: boolean;
|
86
87
|
}
|
87
88
|
|
88
|
-
class StormClient {
|
89
|
+
export class StormClient {
|
89
90
|
private readonly _baseUrl: string;
|
90
|
-
|
91
|
-
constructor() {
|
91
|
+
private readonly _systemId: string;
|
92
|
+
constructor(systemId?: string) {
|
92
93
|
this._baseUrl = getRemoteUrl('ai-service', 'https://ai.kapeta.com');
|
94
|
+
this._systemId = systemId || "";
|
93
95
|
}
|
94
96
|
|
95
97
|
private async createOptions(
|
@@ -110,7 +112,9 @@ class StormClient {
|
|
110
112
|
if (body.conversationId) {
|
111
113
|
headers[ConversationIdHeader] = body.conversationId;
|
112
114
|
}
|
113
|
-
|
115
|
+
if (this._systemId) {
|
116
|
+
headers[SystemIdHeader] = this._systemId
|
117
|
+
}
|
114
118
|
return {
|
115
119
|
url,
|
116
120
|
method: method,
|
@@ -130,7 +134,6 @@ class StormClient {
|
|
130
134
|
prompt: stringPrompt,
|
131
135
|
conversationId: body.conversationId,
|
132
136
|
});
|
133
|
-
|
134
137
|
const abort = new AbortController();
|
135
138
|
options.signal = abort.signal;
|
136
139
|
|
@@ -202,6 +205,7 @@ class StormClient {
|
|
202
205
|
public createUIShells(prompt: UIShellsPrompt, conversationId?: string) {
|
203
206
|
return this.send('/v2/ui/shells', {
|
204
207
|
prompt: JSON.stringify(prompt),
|
208
|
+
conversationId: conversationId,
|
205
209
|
});
|
206
210
|
}
|
207
211
|
|
@@ -245,6 +249,9 @@ class StormClient {
|
|
245
249
|
const response = await fetch(u, {
|
246
250
|
method: 'POST',
|
247
251
|
body: JSON.stringify(prompt.pages),
|
252
|
+
headers: {
|
253
|
+
'systemId': prompt.systemId,
|
254
|
+
},
|
248
255
|
});
|
249
256
|
return (await response.json()) as HTMLPage[];
|
250
257
|
}
|
@@ -377,5 +384,3 @@ class StormClient {
|
|
377
384
|
return response;
|
378
385
|
}
|
379
386
|
}
|
380
|
-
|
381
|
-
export const stormClient = new StormClient();
|
package/src/storm/stream.ts
CHANGED
@@ -99,6 +99,7 @@ export interface ConversationItem {
|
|
99
99
|
|
100
100
|
export interface StormContextRequest<T = string> {
|
101
101
|
conversationId?: string;
|
102
|
+
systemId?: string;
|
102
103
|
history?: ConversationItem[];
|
103
104
|
prompt: T;
|
104
105
|
}
|
@@ -150,6 +151,7 @@ export enum HTMLPageEncoding {
|
|
150
151
|
|
151
152
|
export interface ImplementAPIClients {
|
152
153
|
pages: HTMLPage[];
|
154
|
+
systemId: string;
|
153
155
|
}
|
154
156
|
|
155
157
|
export interface HTMLPage {
|
package/src/stormService.ts
CHANGED
@@ -5,7 +5,7 @@ import path from 'path';
|
|
5
5
|
import { existsSync } from 'fs';
|
6
6
|
import { StormEvent, StormEventModelResponse, StormEventPromptImprove, StormEventUIShell } from './storm/events';
|
7
7
|
import * as tar from 'tar';
|
8
|
-
import {
|
8
|
+
import { StormClient } from './storm/stormClient';
|
9
9
|
|
10
10
|
export class StormService {
|
11
11
|
private getConversationFile(conversationId: string) {
|
@@ -118,8 +118,8 @@ export class StormService {
|
|
118
118
|
}
|
119
119
|
}
|
120
120
|
|
121
|
-
async uploadConversation(handle: string,
|
122
|
-
const tarballFile = this.getConversationTarball(
|
121
|
+
async uploadConversation(handle: string, systemId: string) {
|
122
|
+
const tarballFile = this.getConversationTarball(systemId);
|
123
123
|
const destDir = path.dirname(tarballFile);
|
124
124
|
const tarballName = path.basename(tarballFile);
|
125
125
|
await tar.create(
|
@@ -131,13 +131,15 @@ export class StormService {
|
|
131
131
|
},
|
132
132
|
['.']
|
133
133
|
);
|
134
|
-
|
134
|
+
const stormClient = new StormClient(systemId);
|
135
|
+
await stormClient.uploadSystem(handle, systemId, await fs.readFile(tarballFile));
|
135
136
|
}
|
136
137
|
|
137
|
-
async installProjectById(handle: string,
|
138
|
-
const tarballFile = this.getConversationTarball(
|
138
|
+
async installProjectById(handle: string, systemId: string) {
|
139
|
+
const tarballFile = this.getConversationTarball(systemId);
|
139
140
|
const destDir = path.dirname(tarballFile);
|
140
|
-
const
|
141
|
+
const stormClient = new StormClient(systemId);
|
142
|
+
const buffer = await stormClient.downloadSystem(handle, systemId);
|
141
143
|
await fs.mkdir(destDir, { recursive: true });
|
142
144
|
await fs.writeFile(tarballFile, buffer);
|
143
145
|
await tar.extract({
|