@kapeta/local-cluster-service 0.62.1 → 0.62.2
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.d.ts +4 -2
- package/dist/cjs/src/storm/PageGenerator.js +17 -5
- package/dist/cjs/src/storm/page-utils.d.ts +1 -0
- package/dist/cjs/src/storm/page-utils.js +8 -1
- package/dist/cjs/src/storm/routes.js +13 -21
- package/dist/esm/src/storm/PageGenerator.d.ts +4 -2
- package/dist/esm/src/storm/PageGenerator.js +17 -5
- package/dist/esm/src/storm/page-utils.d.ts +1 -0
- package/dist/esm/src/storm/page-utils.js +8 -1
- package/dist/esm/src/storm/routes.js +13 -21
- package/package.json +1 -1
- package/src/storm/PageGenerator.ts +33 -6
- package/src/storm/page-utils.ts +7 -0
- package/src/storm/routes.ts +16 -25
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## [0.62.2](https://github.com/kapetacom/local-cluster-service/compare/v0.62.1...v0.62.2) (2024-08-14)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Single page adjustments ([#217](https://github.com/kapetacom/local-cluster-service/issues/217)) ([8d0f7e6](https://github.com/kapetacom/local-cluster-service/commit/8d0f7e6b9a3fdd971559a4c9b06b78db38145b4d))
|
7
|
+
|
1
8
|
## [0.62.1](https://github.com/kapetacom/local-cluster-service/compare/v0.62.0...v0.62.1) (2024-08-14)
|
2
9
|
|
3
10
|
|
@@ -4,18 +4,20 @@
|
|
4
4
|
*/
|
5
5
|
/// <reference types="node" />
|
6
6
|
import { UIPagePrompt } from './stormClient';
|
7
|
-
import { ReferenceClassification, StormEvent, StormEventPage } from './events';
|
7
|
+
import { ReferenceClassification, StormEvent, StormEventPage, UIShell } from './events';
|
8
8
|
import { EventEmitter } from 'node:events';
|
9
9
|
export declare class PageQueue extends EventEmitter {
|
10
10
|
private readonly queue;
|
11
11
|
private readonly systemId;
|
12
12
|
private readonly references;
|
13
|
+
private uiShells;
|
13
14
|
constructor(systemId: string, concurrency?: number);
|
14
15
|
on(event: 'event', listener: (data: StormEvent) => void): this;
|
15
16
|
on(event: 'page', listener: (data: StormEventPage) => void): this;
|
16
17
|
emit(type: 'event', event: StormEvent): boolean;
|
17
18
|
emit(type: 'page', event: StormEventPage): boolean;
|
18
|
-
|
19
|
+
addUiShell(uiShell: UIShell): void;
|
20
|
+
addPrompt(initialPrompt: Omit<UIPagePrompt, 'shell_page'>, conversationId?: string, overwrite?: boolean): Promise<void>;
|
19
21
|
private addPageGenerator;
|
20
22
|
cancel(): void;
|
21
23
|
wait(): Promise<void>;
|
@@ -12,10 +12,12 @@ const node_uuid_1 = __importDefault(require("node-uuid"));
|
|
12
12
|
const stormClient_1 = require("./stormClient");
|
13
13
|
const node_events_1 = require("node:events");
|
14
14
|
const PromiseQueue_1 = require("./PromiseQueue");
|
15
|
+
const page_utils_1 = require("./page-utils");
|
15
16
|
class PageQueue extends node_events_1.EventEmitter {
|
16
17
|
queue;
|
17
18
|
systemId;
|
18
19
|
references = new Map();
|
20
|
+
uiShells = [];
|
19
21
|
constructor(systemId, concurrency = 5) {
|
20
22
|
super();
|
21
23
|
this.systemId = systemId;
|
@@ -27,14 +29,24 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
27
29
|
emit(eventName, ...args) {
|
28
30
|
return super.emit(eventName, ...args);
|
29
31
|
}
|
30
|
-
|
31
|
-
|
32
|
+
addUiShell(uiShell) {
|
33
|
+
this.uiShells.push(uiShell);
|
34
|
+
}
|
35
|
+
addPrompt(initialPrompt, conversationId = node_uuid_1.default.v4(), overwrite = false) {
|
36
|
+
if (!overwrite && this.references.has(initialPrompt.path)) {
|
32
37
|
console.log('Ignoring duplicate prompt', initialPrompt.path);
|
33
38
|
return Promise.resolve();
|
34
39
|
}
|
35
|
-
|
36
|
-
|
37
|
-
|
40
|
+
if (!overwrite && (0, page_utils_1.hasPageOnDisk)(this.systemId, initialPrompt.method, initialPrompt.path)) {
|
41
|
+
console.log('Ignoring prompt with existing page', initialPrompt.path);
|
42
|
+
return Promise.resolve();
|
43
|
+
}
|
44
|
+
const prompt = {
|
45
|
+
...initialPrompt,
|
46
|
+
shell_page: this.uiShells.find((shell) => shell.screens.includes(initialPrompt.name))?.content,
|
47
|
+
};
|
48
|
+
const generator = new PageGenerator(prompt, conversationId);
|
49
|
+
this.references.set(prompt.path, generator);
|
38
50
|
return this.addPageGenerator(generator);
|
39
51
|
}
|
40
52
|
async addPageGenerator(generator) {
|
@@ -9,6 +9,7 @@ export declare const SystemIdHeader = "System-Id";
|
|
9
9
|
export declare function writePageToDisk(systemId: string, event: StormEventPage): Promise<{
|
10
10
|
path: string;
|
11
11
|
}>;
|
12
|
+
export declare function hasPageOnDisk(systemId: string, method: string, path: string): boolean;
|
12
13
|
export declare function resolveReadPath(systemId: string, path: string, method: string): string | null;
|
13
14
|
export declare function readPageFromDiskAsString(systemId: string, path: string, method: string): string | null;
|
14
15
|
export declare function readPageFromDisk(systemId: string, path: string, method: string, res: Response): void;
|
@@ -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.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.writePageToDisk = exports.SystemIdHeader = void 0;
|
6
|
+
exports.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.hasPageOnDisk = exports.writePageToDisk = exports.SystemIdHeader = void 0;
|
7
7
|
const node_os_1 = __importDefault(require("node:os"));
|
8
8
|
const path_1 = __importDefault(require("path"));
|
9
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
@@ -26,6 +26,13 @@ async function writePageToDisk(systemId, event) {
|
|
26
26
|
};
|
27
27
|
}
|
28
28
|
exports.writePageToDisk = writePageToDisk;
|
29
|
+
function hasPageOnDisk(systemId, method, path) {
|
30
|
+
const baseDir = getBaseDir(systemId);
|
31
|
+
const filePath = getFilePath(method);
|
32
|
+
const fullPath = path_1.default.join(baseDir, normalizePath(path), filePath);
|
33
|
+
return fs_extra_1.default.existsSync(fullPath);
|
34
|
+
}
|
35
|
+
exports.hasPageOnDisk = hasPageOnDisk;
|
29
36
|
function getBaseDir(systemId) {
|
30
37
|
return path_1.default.join(node_os_1.default.tmpdir(), 'ai-systems', systemId);
|
31
38
|
}
|
@@ -71,19 +71,13 @@ router.post('/ui/screen', async (req, res) => {
|
|
71
71
|
onRequestAborted(req, res, () => {
|
72
72
|
queue.cancel();
|
73
73
|
});
|
74
|
-
await queue.addPrompt(aiRequest);
|
75
74
|
const promises = [];
|
76
75
|
queue.on('page', (data) => {
|
77
|
-
|
78
|
-
|
79
|
-
console.log('Processing page event', data);
|
80
|
-
if (systemId) {
|
81
|
-
promises.push(sendPageEvent(systemId, data, res));
|
82
|
-
}
|
83
|
-
break;
|
76
|
+
if (systemId) {
|
77
|
+
promises.push(sendPageEvent(systemId, data, res));
|
84
78
|
}
|
85
|
-
sendEvent(res, data);
|
86
79
|
});
|
80
|
+
await queue.addPrompt(aiRequest, conversationId, true);
|
87
81
|
await queue.wait();
|
88
82
|
await Promise.allSettled(promises);
|
89
83
|
sendDone(res);
|
@@ -233,7 +227,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
233
227
|
onRequestAborted(req, res, () => {
|
234
228
|
shellsStream.abort();
|
235
229
|
});
|
236
|
-
const
|
230
|
+
const queue = new PageGenerator_1.PageQueue(outerConversationId, 5);
|
237
231
|
shellsStream.on('data', (data) => {
|
238
232
|
console.log('Processing shell event', data);
|
239
233
|
sendEvent(res, data);
|
@@ -243,7 +237,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
243
237
|
if (shellsStream.isAborted()) {
|
244
238
|
return;
|
245
239
|
}
|
246
|
-
|
240
|
+
queue.addUiShell(data.payload);
|
247
241
|
});
|
248
242
|
shellsStream.on('error', (error) => {
|
249
243
|
console.error('Error on shellsStream', error);
|
@@ -254,7 +248,6 @@ router.post('/:handle/ui', async (req, res) => {
|
|
254
248
|
UI_SERVERS[outerConversationId] = new UIServer_1.UIServer(outerConversationId);
|
255
249
|
await UI_SERVERS[outerConversationId].start();
|
256
250
|
// Get the pages (5 at a time)
|
257
|
-
const queue = new PageGenerator_1.PageQueue(outerConversationId, 5);
|
258
251
|
const pagePromises = [];
|
259
252
|
onRequestAborted(req, res, () => {
|
260
253
|
queue.cancel();
|
@@ -276,7 +269,6 @@ router.post('/:handle/ui', async (req, res) => {
|
|
276
269
|
title: screen.title,
|
277
270
|
filename: screen.filename,
|
278
271
|
storage_prefix: outerConversationId + '_',
|
279
|
-
shell_page: uiShells.find((shell) => shell.screens.includes(screen.name))?.content,
|
280
272
|
}));
|
281
273
|
}
|
282
274
|
await queue.wait();
|
@@ -536,7 +528,7 @@ function streamStormPartialResponse(result, res) {
|
|
536
528
|
switch (data.type) {
|
537
529
|
// todo: temporarily (for demo purposes) disable error messages when codegen fails
|
538
530
|
case 'ERROR_INTERNAL':
|
539
|
-
console.log(
|
531
|
+
console.log('Error internal', data);
|
540
532
|
return;
|
541
533
|
}
|
542
534
|
sendEvent(res, data);
|
@@ -555,13 +547,13 @@ function onRequestAborted(req, res, onAborted) {
|
|
555
547
|
onAborted();
|
556
548
|
});
|
557
549
|
}
|
558
|
-
function sendPageEvent(mainConversationId, data, res) {
|
559
|
-
|
560
|
-
.
|
550
|
+
async function sendPageEvent(mainConversationId, data, res) {
|
551
|
+
try {
|
552
|
+
await (0, page_utils_1.writePageToDisk)(mainConversationId, data);
|
553
|
+
}
|
554
|
+
catch (err) {
|
561
555
|
console.error('Failed to write page to disk', err);
|
562
|
-
}
|
563
|
-
|
564
|
-
sendEvent(res, convertPageEvent(data, data.payload.conversationId, mainConversationId));
|
565
|
-
});
|
556
|
+
}
|
557
|
+
sendEvent(res, convertPageEvent(data, data.payload.conversationId, mainConversationId));
|
566
558
|
}
|
567
559
|
exports.default = router;
|
@@ -4,18 +4,20 @@
|
|
4
4
|
*/
|
5
5
|
/// <reference types="node" />
|
6
6
|
import { UIPagePrompt } from './stormClient';
|
7
|
-
import { ReferenceClassification, StormEvent, StormEventPage } from './events';
|
7
|
+
import { ReferenceClassification, StormEvent, StormEventPage, UIShell } from './events';
|
8
8
|
import { EventEmitter } from 'node:events';
|
9
9
|
export declare class PageQueue extends EventEmitter {
|
10
10
|
private readonly queue;
|
11
11
|
private readonly systemId;
|
12
12
|
private readonly references;
|
13
|
+
private uiShells;
|
13
14
|
constructor(systemId: string, concurrency?: number);
|
14
15
|
on(event: 'event', listener: (data: StormEvent) => void): this;
|
15
16
|
on(event: 'page', listener: (data: StormEventPage) => void): this;
|
16
17
|
emit(type: 'event', event: StormEvent): boolean;
|
17
18
|
emit(type: 'page', event: StormEventPage): boolean;
|
18
|
-
|
19
|
+
addUiShell(uiShell: UIShell): void;
|
20
|
+
addPrompt(initialPrompt: Omit<UIPagePrompt, 'shell_page'>, conversationId?: string, overwrite?: boolean): Promise<void>;
|
19
21
|
private addPageGenerator;
|
20
22
|
cancel(): void;
|
21
23
|
wait(): Promise<void>;
|
@@ -12,10 +12,12 @@ const node_uuid_1 = __importDefault(require("node-uuid"));
|
|
12
12
|
const stormClient_1 = require("./stormClient");
|
13
13
|
const node_events_1 = require("node:events");
|
14
14
|
const PromiseQueue_1 = require("./PromiseQueue");
|
15
|
+
const page_utils_1 = require("./page-utils");
|
15
16
|
class PageQueue extends node_events_1.EventEmitter {
|
16
17
|
queue;
|
17
18
|
systemId;
|
18
19
|
references = new Map();
|
20
|
+
uiShells = [];
|
19
21
|
constructor(systemId, concurrency = 5) {
|
20
22
|
super();
|
21
23
|
this.systemId = systemId;
|
@@ -27,14 +29,24 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
27
29
|
emit(eventName, ...args) {
|
28
30
|
return super.emit(eventName, ...args);
|
29
31
|
}
|
30
|
-
|
31
|
-
|
32
|
+
addUiShell(uiShell) {
|
33
|
+
this.uiShells.push(uiShell);
|
34
|
+
}
|
35
|
+
addPrompt(initialPrompt, conversationId = node_uuid_1.default.v4(), overwrite = false) {
|
36
|
+
if (!overwrite && this.references.has(initialPrompt.path)) {
|
32
37
|
console.log('Ignoring duplicate prompt', initialPrompt.path);
|
33
38
|
return Promise.resolve();
|
34
39
|
}
|
35
|
-
|
36
|
-
|
37
|
-
|
40
|
+
if (!overwrite && (0, page_utils_1.hasPageOnDisk)(this.systemId, initialPrompt.method, initialPrompt.path)) {
|
41
|
+
console.log('Ignoring prompt with existing page', initialPrompt.path);
|
42
|
+
return Promise.resolve();
|
43
|
+
}
|
44
|
+
const prompt = {
|
45
|
+
...initialPrompt,
|
46
|
+
shell_page: this.uiShells.find((shell) => shell.screens.includes(initialPrompt.name))?.content,
|
47
|
+
};
|
48
|
+
const generator = new PageGenerator(prompt, conversationId);
|
49
|
+
this.references.set(prompt.path, generator);
|
38
50
|
return this.addPageGenerator(generator);
|
39
51
|
}
|
40
52
|
async addPageGenerator(generator) {
|
@@ -9,6 +9,7 @@ export declare const SystemIdHeader = "System-Id";
|
|
9
9
|
export declare function writePageToDisk(systemId: string, event: StormEventPage): Promise<{
|
10
10
|
path: string;
|
11
11
|
}>;
|
12
|
+
export declare function hasPageOnDisk(systemId: string, method: string, path: string): boolean;
|
12
13
|
export declare function resolveReadPath(systemId: string, path: string, method: string): string | null;
|
13
14
|
export declare function readPageFromDiskAsString(systemId: string, path: string, method: string): string | null;
|
14
15
|
export declare function readPageFromDisk(systemId: string, path: string, method: string, res: Response): void;
|
@@ -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.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.writePageToDisk = exports.SystemIdHeader = void 0;
|
6
|
+
exports.writeConversationToFile = exports.readConversationFromFile = exports.readPageFromDisk = exports.readPageFromDiskAsString = exports.resolveReadPath = exports.hasPageOnDisk = exports.writePageToDisk = exports.SystemIdHeader = void 0;
|
7
7
|
const node_os_1 = __importDefault(require("node:os"));
|
8
8
|
const path_1 = __importDefault(require("path"));
|
9
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
@@ -26,6 +26,13 @@ async function writePageToDisk(systemId, event) {
|
|
26
26
|
};
|
27
27
|
}
|
28
28
|
exports.writePageToDisk = writePageToDisk;
|
29
|
+
function hasPageOnDisk(systemId, method, path) {
|
30
|
+
const baseDir = getBaseDir(systemId);
|
31
|
+
const filePath = getFilePath(method);
|
32
|
+
const fullPath = path_1.default.join(baseDir, normalizePath(path), filePath);
|
33
|
+
return fs_extra_1.default.existsSync(fullPath);
|
34
|
+
}
|
35
|
+
exports.hasPageOnDisk = hasPageOnDisk;
|
29
36
|
function getBaseDir(systemId) {
|
30
37
|
return path_1.default.join(node_os_1.default.tmpdir(), 'ai-systems', systemId);
|
31
38
|
}
|
@@ -71,19 +71,13 @@ router.post('/ui/screen', async (req, res) => {
|
|
71
71
|
onRequestAborted(req, res, () => {
|
72
72
|
queue.cancel();
|
73
73
|
});
|
74
|
-
await queue.addPrompt(aiRequest);
|
75
74
|
const promises = [];
|
76
75
|
queue.on('page', (data) => {
|
77
|
-
|
78
|
-
|
79
|
-
console.log('Processing page event', data);
|
80
|
-
if (systemId) {
|
81
|
-
promises.push(sendPageEvent(systemId, data, res));
|
82
|
-
}
|
83
|
-
break;
|
76
|
+
if (systemId) {
|
77
|
+
promises.push(sendPageEvent(systemId, data, res));
|
84
78
|
}
|
85
|
-
sendEvent(res, data);
|
86
79
|
});
|
80
|
+
await queue.addPrompt(aiRequest, conversationId, true);
|
87
81
|
await queue.wait();
|
88
82
|
await Promise.allSettled(promises);
|
89
83
|
sendDone(res);
|
@@ -233,7 +227,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
233
227
|
onRequestAborted(req, res, () => {
|
234
228
|
shellsStream.abort();
|
235
229
|
});
|
236
|
-
const
|
230
|
+
const queue = new PageGenerator_1.PageQueue(outerConversationId, 5);
|
237
231
|
shellsStream.on('data', (data) => {
|
238
232
|
console.log('Processing shell event', data);
|
239
233
|
sendEvent(res, data);
|
@@ -243,7 +237,7 @@ router.post('/:handle/ui', async (req, res) => {
|
|
243
237
|
if (shellsStream.isAborted()) {
|
244
238
|
return;
|
245
239
|
}
|
246
|
-
|
240
|
+
queue.addUiShell(data.payload);
|
247
241
|
});
|
248
242
|
shellsStream.on('error', (error) => {
|
249
243
|
console.error('Error on shellsStream', error);
|
@@ -254,7 +248,6 @@ router.post('/:handle/ui', async (req, res) => {
|
|
254
248
|
UI_SERVERS[outerConversationId] = new UIServer_1.UIServer(outerConversationId);
|
255
249
|
await UI_SERVERS[outerConversationId].start();
|
256
250
|
// Get the pages (5 at a time)
|
257
|
-
const queue = new PageGenerator_1.PageQueue(outerConversationId, 5);
|
258
251
|
const pagePromises = [];
|
259
252
|
onRequestAborted(req, res, () => {
|
260
253
|
queue.cancel();
|
@@ -276,7 +269,6 @@ router.post('/:handle/ui', async (req, res) => {
|
|
276
269
|
title: screen.title,
|
277
270
|
filename: screen.filename,
|
278
271
|
storage_prefix: outerConversationId + '_',
|
279
|
-
shell_page: uiShells.find((shell) => shell.screens.includes(screen.name))?.content,
|
280
272
|
}));
|
281
273
|
}
|
282
274
|
await queue.wait();
|
@@ -536,7 +528,7 @@ function streamStormPartialResponse(result, res) {
|
|
536
528
|
switch (data.type) {
|
537
529
|
// todo: temporarily (for demo purposes) disable error messages when codegen fails
|
538
530
|
case 'ERROR_INTERNAL':
|
539
|
-
console.log(
|
531
|
+
console.log('Error internal', data);
|
540
532
|
return;
|
541
533
|
}
|
542
534
|
sendEvent(res, data);
|
@@ -555,13 +547,13 @@ function onRequestAborted(req, res, onAborted) {
|
|
555
547
|
onAborted();
|
556
548
|
});
|
557
549
|
}
|
558
|
-
function sendPageEvent(mainConversationId, data, res) {
|
559
|
-
|
560
|
-
.
|
550
|
+
async function sendPageEvent(mainConversationId, data, res) {
|
551
|
+
try {
|
552
|
+
await (0, page_utils_1.writePageToDisk)(mainConversationId, data);
|
553
|
+
}
|
554
|
+
catch (err) {
|
561
555
|
console.error('Failed to write page to disk', err);
|
562
|
-
}
|
563
|
-
|
564
|
-
sendEvent(res, convertPageEvent(data, data.payload.conversationId, mainConversationId));
|
565
|
-
});
|
556
|
+
}
|
557
|
+
sendEvent(res, convertPageEvent(data, data.payload.conversationId, mainConversationId));
|
566
558
|
}
|
567
559
|
exports.default = router;
|
package/package.json
CHANGED
@@ -5,14 +5,22 @@
|
|
5
5
|
|
6
6
|
import uuid from 'node-uuid';
|
7
7
|
import { stormClient, UIPagePrompt } from './stormClient';
|
8
|
-
import {
|
8
|
+
import {
|
9
|
+
ReferenceClassification,
|
10
|
+
StormEvent,
|
11
|
+
StormEventPage,
|
12
|
+
StormEventReferenceClassification,
|
13
|
+
UIShell,
|
14
|
+
} from './events';
|
9
15
|
import { EventEmitter } from 'node:events';
|
10
16
|
import { PromiseQueue } from './PromiseQueue';
|
17
|
+
import { hasPageOnDisk } from './page-utils';
|
11
18
|
|
12
19
|
export class PageQueue extends EventEmitter {
|
13
20
|
private readonly queue: PromiseQueue;
|
14
21
|
private readonly systemId: string;
|
15
22
|
private readonly references: Map<string, PageGenerator> = new Map();
|
23
|
+
private uiShells: UIShell[] = [];
|
16
24
|
|
17
25
|
constructor(systemId: string, concurrency: number = 5) {
|
18
26
|
super();
|
@@ -33,14 +41,33 @@ export class PageQueue extends EventEmitter {
|
|
33
41
|
return super.emit(eventName, ...args);
|
34
42
|
}
|
35
43
|
|
36
|
-
public
|
37
|
-
|
44
|
+
public addUiShell(uiShell: UIShell) {
|
45
|
+
this.uiShells.push(uiShell);
|
46
|
+
}
|
47
|
+
|
48
|
+
public addPrompt(
|
49
|
+
initialPrompt: Omit<UIPagePrompt, 'shell_page'>,
|
50
|
+
conversationId: string = uuid.v4(),
|
51
|
+
overwrite: boolean = false
|
52
|
+
) {
|
53
|
+
if (!overwrite && this.references.has(initialPrompt.path)) {
|
38
54
|
console.log('Ignoring duplicate prompt', initialPrompt.path);
|
39
55
|
return Promise.resolve();
|
40
56
|
}
|
41
|
-
|
42
|
-
|
43
|
-
|
57
|
+
|
58
|
+
if (!overwrite && hasPageOnDisk(this.systemId, initialPrompt.method, initialPrompt.path)) {
|
59
|
+
console.log('Ignoring prompt with existing page', initialPrompt.path);
|
60
|
+
return Promise.resolve();
|
61
|
+
}
|
62
|
+
|
63
|
+
const prompt: UIPagePrompt = {
|
64
|
+
...initialPrompt,
|
65
|
+
shell_page: this.uiShells.find((shell) => shell.screens.includes(initialPrompt.name))?.content,
|
66
|
+
};
|
67
|
+
|
68
|
+
const generator = new PageGenerator(prompt, conversationId);
|
69
|
+
this.references.set(prompt.path, generator);
|
70
|
+
|
44
71
|
return this.addPageGenerator(generator);
|
45
72
|
}
|
46
73
|
|
package/src/storm/page-utils.ts
CHANGED
@@ -34,6 +34,13 @@ export async function writePageToDisk(systemId: string, event: StormEventPage) {
|
|
34
34
|
};
|
35
35
|
}
|
36
36
|
|
37
|
+
export function hasPageOnDisk(systemId: string, method: string, path: string) {
|
38
|
+
const baseDir = getBaseDir(systemId);
|
39
|
+
const filePath = getFilePath(method);
|
40
|
+
const fullPath = Path.join(baseDir, normalizePath(path), filePath);
|
41
|
+
return FS.existsSync(fullPath);
|
42
|
+
}
|
43
|
+
|
37
44
|
function getBaseDir(systemId: string) {
|
38
45
|
return Path.join(os.tmpdir(), 'ai-systems', systemId);
|
39
46
|
}
|
package/src/storm/routes.ts
CHANGED
@@ -106,22 +106,16 @@ router.post('/ui/screen', async (req: KapetaBodyRequest, res: Response) => {
|
|
106
106
|
queue.cancel();
|
107
107
|
});
|
108
108
|
|
109
|
-
await queue.addPrompt(aiRequest);
|
110
|
-
|
111
109
|
const promises: Promise<void>[] = [];
|
112
|
-
queue.on('page', (data) => {
|
113
|
-
switch (data.type) {
|
114
|
-
case 'PAGE':
|
115
|
-
console.log('Processing page event', data);
|
116
110
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
break;
|
111
|
+
queue.on('page', (data) => {
|
112
|
+
if (systemId) {
|
113
|
+
promises.push(sendPageEvent(systemId, data, res));
|
121
114
|
}
|
122
|
-
sendEvent(res, data);
|
123
115
|
});
|
124
116
|
|
117
|
+
await queue.addPrompt(aiRequest, conversationId, true);
|
118
|
+
|
125
119
|
await queue.wait();
|
126
120
|
await Promise.allSettled(promises);
|
127
121
|
|
@@ -304,8 +298,7 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
304
298
|
shellsStream.abort();
|
305
299
|
});
|
306
300
|
|
307
|
-
const
|
308
|
-
|
301
|
+
const queue = new PageQueue(outerConversationId, 5);
|
309
302
|
shellsStream.on('data', (data: StormEvent) => {
|
310
303
|
console.log('Processing shell event', data);
|
311
304
|
sendEvent(res, data);
|
@@ -318,7 +311,7 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
318
311
|
return;
|
319
312
|
}
|
320
313
|
|
321
|
-
|
314
|
+
queue.addUiShell(data.payload);
|
322
315
|
});
|
323
316
|
|
324
317
|
shellsStream.on('error', (error) => {
|
@@ -333,7 +326,7 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
333
326
|
await UI_SERVERS[outerConversationId].start();
|
334
327
|
|
335
328
|
// Get the pages (5 at a time)
|
336
|
-
|
329
|
+
|
337
330
|
const pagePromises: Promise<void>[] = [];
|
338
331
|
onRequestAborted(req, res, () => {
|
339
332
|
queue.cancel();
|
@@ -359,7 +352,6 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
359
352
|
title: screen.title,
|
360
353
|
filename: screen.filename,
|
361
354
|
storage_prefix: outerConversationId + '_',
|
362
|
-
shell_page: uiShells.find((shell) => shell.screens.includes(screen.name))?.content,
|
363
355
|
})
|
364
356
|
);
|
365
357
|
}
|
@@ -668,7 +660,7 @@ function streamStormPartialResponse(result: StormStream, res: Response) {
|
|
668
660
|
switch (data.type) {
|
669
661
|
// todo: temporarily (for demo purposes) disable error messages when codegen fails
|
670
662
|
case 'ERROR_INTERNAL':
|
671
|
-
console.log(
|
663
|
+
console.log('Error internal', data);
|
672
664
|
return;
|
673
665
|
}
|
674
666
|
sendEvent(res, data);
|
@@ -691,14 +683,13 @@ function onRequestAborted(req: KapetaBodyRequest, res: Response, onAborted: () =
|
|
691
683
|
});
|
692
684
|
}
|
693
685
|
|
694
|
-
function sendPageEvent(mainConversationId: string, data: StormEventPage, res: Response) {
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
});
|
686
|
+
async function sendPageEvent(mainConversationId: string, data: StormEventPage, res: Response) {
|
687
|
+
try {
|
688
|
+
await writePageToDisk(mainConversationId, data);
|
689
|
+
} catch (err) {
|
690
|
+
console.error('Failed to write page to disk', err);
|
691
|
+
}
|
692
|
+
sendEvent(res, convertPageEvent(data, data.payload.conversationId, mainConversationId));
|
702
693
|
}
|
703
694
|
|
704
695
|
export default router;
|