@kapeta/local-cluster-service 0.69.0 → 0.70.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 +15 -0
- package/dist/cjs/src/storm/PageGenerator.js +9 -2
- package/dist/cjs/src/storm/UIServer.d.ts +3 -1
- package/dist/cjs/src/storm/UIServer.js +7 -1
- package/dist/cjs/src/storm/routes.js +25 -16
- package/dist/esm/src/storm/PageGenerator.js +9 -2
- package/dist/esm/src/storm/UIServer.d.ts +3 -1
- package/dist/esm/src/storm/UIServer.js +7 -1
- package/dist/esm/src/storm/routes.js +25 -16
- package/package.json +1 -1
- package/src/storm/PageGenerator.ts +9 -2
- package/src/storm/UIServer.ts +9 -1
- package/src/storm/routes.ts +36 -19
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## [0.70.1](https://github.com/kapetacom/local-cluster-service/compare/v0.70.0...v0.70.1) (2024-09-09)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* filenames and lazier generation for refs ([#235](https://github.com/kapetacom/local-cluster-service/issues/235)) ([02c5589](https://github.com/kapetacom/local-cluster-service/commit/02c55895c4ae3ed5632f4b53f33509ec18c87dcb))
|
7
|
+
|
8
|
+
# [0.70.0](https://github.com/kapetacom/local-cluster-service/compare/v0.69.0...v0.70.0) (2024-09-04)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* add "serve" endpoint to resume a UI conversation server ([a2eadb2](https://github.com/kapetacom/local-cluster-service/commit/a2eadb25298d0d59aaf47202eba0fc911ba5e2f8))
|
14
|
+
* change endpoint to end conversation to same format as resume ([6161e5c](https://github.com/kapetacom/local-cluster-service/commit/6161e5ce2fda1261bb26abd6a608ea9e41d46099))
|
15
|
+
|
1
16
|
# [0.69.0](https://github.com/kapetacom/local-cluster-service/compare/v0.68.0...v0.69.0) (2024-09-03)
|
2
17
|
|
3
18
|
|
@@ -103,6 +103,9 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
103
103
|
generator.on('event', (event) => this.emit('event', event));
|
104
104
|
generator.on('page_refs', async ({ event, references }) => {
|
105
105
|
try {
|
106
|
+
const matchesExistingPages = (url) => {
|
107
|
+
return [...this.pages.keys()].some((path) => new RegExp(path.replaceAll('/*', '/[^/]+')).test(url));
|
108
|
+
};
|
106
109
|
const initialPrompts = [];
|
107
110
|
const resourcePromises = references.map(async (reference) => {
|
108
111
|
if (reference.url.startsWith('#') ||
|
@@ -124,6 +127,9 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
124
127
|
break;
|
125
128
|
case 'html':
|
126
129
|
//console.log('Adding page generator for', reference);
|
130
|
+
if (matchesExistingPages(reference.url)) {
|
131
|
+
break;
|
132
|
+
}
|
127
133
|
this.pages.set(reference.url, reference.description);
|
128
134
|
initialPrompts.push({
|
129
135
|
name: reference.name,
|
@@ -134,7 +140,8 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
134
140
|
prompt: `Implement a page for ${reference.name} at ${reference.url} with the following description: ${reference.description}.\n` +
|
135
141
|
`The page was referenced from this page: \n### PATH: ${event.payload.path}\n\`\`\`html\n${event.payload.content}\n\`\`\`\n`,
|
136
142
|
description: reference.description,
|
137
|
-
|
143
|
+
// Only used for matching
|
144
|
+
filename: reference.name + '.ref.html',
|
138
145
|
theme: this.theme,
|
139
146
|
});
|
140
147
|
break;
|
@@ -153,7 +160,7 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
153
160
|
payload: {
|
154
161
|
name: prompt.name,
|
155
162
|
title: prompt.title,
|
156
|
-
filename:
|
163
|
+
filename: prompt.filename,
|
157
164
|
method: 'GET',
|
158
165
|
path: prompt.path,
|
159
166
|
prompt: prompt.description,
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import { StormEventPage } from './events';
|
2
2
|
export declare class UIServer {
|
3
3
|
private readonly systemId;
|
4
|
-
private port;
|
5
4
|
private server;
|
5
|
+
private port;
|
6
6
|
constructor(systemId: string);
|
7
|
+
isRunning(): boolean;
|
8
|
+
getUrl(): string;
|
7
9
|
start(): Promise<void>;
|
8
10
|
close(): void;
|
9
11
|
resolveUrl(screenData: StormEventPage): string;
|
@@ -15,11 +15,17 @@ const http_1 = require("http");
|
|
15
15
|
const path_1 = require("path");
|
16
16
|
class UIServer {
|
17
17
|
systemId;
|
18
|
-
port = 50000;
|
19
18
|
server;
|
19
|
+
port = 50000;
|
20
20
|
constructor(systemId) {
|
21
21
|
this.systemId = systemId;
|
22
22
|
}
|
23
|
+
isRunning() {
|
24
|
+
return !!this.server;
|
25
|
+
}
|
26
|
+
getUrl() {
|
27
|
+
return `http://localhost:${this.port}`;
|
28
|
+
}
|
23
29
|
async start() {
|
24
30
|
const app = (0, express_1.default)();
|
25
31
|
app.get('/_reset', (req, res) => {
|
@@ -50,7 +50,7 @@ function convertPageEvent(screenData, innerConversationId, mainConversationId) {
|
|
50
50
|
description: screenData.payload.description,
|
51
51
|
prompt: screenData.payload.prompt,
|
52
52
|
path: screenData.payload.path,
|
53
|
-
url:
|
53
|
+
url: screenData.payload.content ? screenData.payload.path : '',
|
54
54
|
method: screenData.payload.method,
|
55
55
|
conversationId: innerConversationId,
|
56
56
|
},
|
@@ -58,8 +58,17 @@ function convertPageEvent(screenData, innerConversationId, mainConversationId) {
|
|
58
58
|
}
|
59
59
|
return screenData;
|
60
60
|
}
|
61
|
-
router.
|
62
|
-
|
61
|
+
router.post('/ui/serve/:systemId', async (req, res) => {
|
62
|
+
const systemId = req.params.systemId;
|
63
|
+
if (!systemId) {
|
64
|
+
res.status(404).send({ error: 'Missing "systemId" in URL' });
|
65
|
+
return;
|
66
|
+
}
|
67
|
+
const svr = (UI_SERVERS[systemId] = UI_SERVERS[systemId] || new UIServer_1.UIServer(systemId));
|
68
|
+
if (!svr.isRunning()) {
|
69
|
+
await UI_SERVERS[systemId].start();
|
70
|
+
}
|
71
|
+
res.status(200).send({ status: 'running', url: svr.getUrl() });
|
63
72
|
});
|
64
73
|
router.post('/ui/create-system/:systemId', async (req, res) => {
|
65
74
|
const systemId = req.params.systemId;
|
@@ -75,6 +84,19 @@ router.post('/ui/create-system/:systemId', async (req, res) => {
|
|
75
84
|
res.end();
|
76
85
|
return;
|
77
86
|
});
|
87
|
+
router.delete('/ui/serve/:systemId', async (req, res) => {
|
88
|
+
const systemId = req.params.systemId;
|
89
|
+
if (!systemId) {
|
90
|
+
res.status(404).send({ error: 'Missing "systemId" in URL' });
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
const server = UI_SERVERS[systemId];
|
94
|
+
if (server) {
|
95
|
+
server.close();
|
96
|
+
delete UI_SERVERS[systemId];
|
97
|
+
}
|
98
|
+
res.status(200).json({ status: 'ok' });
|
99
|
+
});
|
78
100
|
router.post('/ui/screen', async (req, res) => {
|
79
101
|
try {
|
80
102
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
@@ -117,19 +139,6 @@ router.post('/ui/screen', async (req, res) => {
|
|
117
139
|
}
|
118
140
|
}
|
119
141
|
});
|
120
|
-
router.delete('/:handle/ui', async (req, res) => {
|
121
|
-
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
122
|
-
if (!conversationId) {
|
123
|
-
res.status(400).send('Missing conversation id');
|
124
|
-
return;
|
125
|
-
}
|
126
|
-
const server = UI_SERVERS[conversationId];
|
127
|
-
if (server) {
|
128
|
-
server.close();
|
129
|
-
delete UI_SERVERS[conversationId];
|
130
|
-
}
|
131
|
-
res.status(200).json({ status: 'ok' });
|
132
|
-
});
|
133
142
|
router.post('/:handle/ui/iterative', async (req, res) => {
|
134
143
|
const handle = req.params.handle;
|
135
144
|
try {
|
@@ -103,6 +103,9 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
103
103
|
generator.on('event', (event) => this.emit('event', event));
|
104
104
|
generator.on('page_refs', async ({ event, references }) => {
|
105
105
|
try {
|
106
|
+
const matchesExistingPages = (url) => {
|
107
|
+
return [...this.pages.keys()].some((path) => new RegExp(path.replaceAll('/*', '/[^/]+')).test(url));
|
108
|
+
};
|
106
109
|
const initialPrompts = [];
|
107
110
|
const resourcePromises = references.map(async (reference) => {
|
108
111
|
if (reference.url.startsWith('#') ||
|
@@ -124,6 +127,9 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
124
127
|
break;
|
125
128
|
case 'html':
|
126
129
|
//console.log('Adding page generator for', reference);
|
130
|
+
if (matchesExistingPages(reference.url)) {
|
131
|
+
break;
|
132
|
+
}
|
127
133
|
this.pages.set(reference.url, reference.description);
|
128
134
|
initialPrompts.push({
|
129
135
|
name: reference.name,
|
@@ -134,7 +140,8 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
134
140
|
prompt: `Implement a page for ${reference.name} at ${reference.url} with the following description: ${reference.description}.\n` +
|
135
141
|
`The page was referenced from this page: \n### PATH: ${event.payload.path}\n\`\`\`html\n${event.payload.content}\n\`\`\`\n`,
|
136
142
|
description: reference.description,
|
137
|
-
|
143
|
+
// Only used for matching
|
144
|
+
filename: reference.name + '.ref.html',
|
138
145
|
theme: this.theme,
|
139
146
|
});
|
140
147
|
break;
|
@@ -153,7 +160,7 @@ class PageQueue extends node_events_1.EventEmitter {
|
|
153
160
|
payload: {
|
154
161
|
name: prompt.name,
|
155
162
|
title: prompt.title,
|
156
|
-
filename:
|
163
|
+
filename: prompt.filename,
|
157
164
|
method: 'GET',
|
158
165
|
path: prompt.path,
|
159
166
|
prompt: prompt.description,
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import { StormEventPage } from './events';
|
2
2
|
export declare class UIServer {
|
3
3
|
private readonly systemId;
|
4
|
-
private port;
|
5
4
|
private server;
|
5
|
+
private port;
|
6
6
|
constructor(systemId: string);
|
7
|
+
isRunning(): boolean;
|
8
|
+
getUrl(): string;
|
7
9
|
start(): Promise<void>;
|
8
10
|
close(): void;
|
9
11
|
resolveUrl(screenData: StormEventPage): string;
|
@@ -15,11 +15,17 @@ const http_1 = require("http");
|
|
15
15
|
const path_1 = require("path");
|
16
16
|
class UIServer {
|
17
17
|
systemId;
|
18
|
-
port = 50000;
|
19
18
|
server;
|
19
|
+
port = 50000;
|
20
20
|
constructor(systemId) {
|
21
21
|
this.systemId = systemId;
|
22
22
|
}
|
23
|
+
isRunning() {
|
24
|
+
return !!this.server;
|
25
|
+
}
|
26
|
+
getUrl() {
|
27
|
+
return `http://localhost:${this.port}`;
|
28
|
+
}
|
23
29
|
async start() {
|
24
30
|
const app = (0, express_1.default)();
|
25
31
|
app.get('/_reset', (req, res) => {
|
@@ -50,7 +50,7 @@ function convertPageEvent(screenData, innerConversationId, mainConversationId) {
|
|
50
50
|
description: screenData.payload.description,
|
51
51
|
prompt: screenData.payload.prompt,
|
52
52
|
path: screenData.payload.path,
|
53
|
-
url:
|
53
|
+
url: screenData.payload.content ? screenData.payload.path : '',
|
54
54
|
method: screenData.payload.method,
|
55
55
|
conversationId: innerConversationId,
|
56
56
|
},
|
@@ -58,8 +58,17 @@ function convertPageEvent(screenData, innerConversationId, mainConversationId) {
|
|
58
58
|
}
|
59
59
|
return screenData;
|
60
60
|
}
|
61
|
-
router.
|
62
|
-
|
61
|
+
router.post('/ui/serve/:systemId', async (req, res) => {
|
62
|
+
const systemId = req.params.systemId;
|
63
|
+
if (!systemId) {
|
64
|
+
res.status(404).send({ error: 'Missing "systemId" in URL' });
|
65
|
+
return;
|
66
|
+
}
|
67
|
+
const svr = (UI_SERVERS[systemId] = UI_SERVERS[systemId] || new UIServer_1.UIServer(systemId));
|
68
|
+
if (!svr.isRunning()) {
|
69
|
+
await UI_SERVERS[systemId].start();
|
70
|
+
}
|
71
|
+
res.status(200).send({ status: 'running', url: svr.getUrl() });
|
63
72
|
});
|
64
73
|
router.post('/ui/create-system/:systemId', async (req, res) => {
|
65
74
|
const systemId = req.params.systemId;
|
@@ -75,6 +84,19 @@ router.post('/ui/create-system/:systemId', async (req, res) => {
|
|
75
84
|
res.end();
|
76
85
|
return;
|
77
86
|
});
|
87
|
+
router.delete('/ui/serve/:systemId', async (req, res) => {
|
88
|
+
const systemId = req.params.systemId;
|
89
|
+
if (!systemId) {
|
90
|
+
res.status(404).send({ error: 'Missing "systemId" in URL' });
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
const server = UI_SERVERS[systemId];
|
94
|
+
if (server) {
|
95
|
+
server.close();
|
96
|
+
delete UI_SERVERS[systemId];
|
97
|
+
}
|
98
|
+
res.status(200).json({ status: 'ok' });
|
99
|
+
});
|
78
100
|
router.post('/ui/screen', async (req, res) => {
|
79
101
|
try {
|
80
102
|
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
@@ -117,19 +139,6 @@ router.post('/ui/screen', async (req, res) => {
|
|
117
139
|
}
|
118
140
|
}
|
119
141
|
});
|
120
|
-
router.delete('/:handle/ui', async (req, res) => {
|
121
|
-
const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
|
122
|
-
if (!conversationId) {
|
123
|
-
res.status(400).send('Missing conversation id');
|
124
|
-
return;
|
125
|
-
}
|
126
|
-
const server = UI_SERVERS[conversationId];
|
127
|
-
if (server) {
|
128
|
-
server.close();
|
129
|
-
delete UI_SERVERS[conversationId];
|
130
|
-
}
|
131
|
-
res.status(200).json({ status: 'ok' });
|
132
|
-
});
|
133
142
|
router.post('/:handle/ui/iterative', async (req, res) => {
|
134
143
|
const handle = req.params.handle;
|
135
144
|
try {
|
package/package.json
CHANGED
@@ -136,6 +136,9 @@ export class PageQueue extends EventEmitter {
|
|
136
136
|
generator.on('event', (event: StormEvent) => this.emit('event', event));
|
137
137
|
generator.on('page_refs', async ({ event, references }) => {
|
138
138
|
try {
|
139
|
+
const matchesExistingPages = (url: string) => {
|
140
|
+
return [...this.pages.keys()].some((path) => new RegExp(path.replaceAll('/*', '/[^/]+')).test(url));
|
141
|
+
};
|
139
142
|
const initialPrompts: InitialPrompt[] = [];
|
140
143
|
const resourcePromises = references.map(async (reference) => {
|
141
144
|
if (
|
@@ -160,6 +163,9 @@ export class PageQueue extends EventEmitter {
|
|
160
163
|
break;
|
161
164
|
case 'html':
|
162
165
|
//console.log('Adding page generator for', reference);
|
166
|
+
if (matchesExistingPages(reference.url)) {
|
167
|
+
break;
|
168
|
+
}
|
163
169
|
this.pages.set(reference.url, reference.description);
|
164
170
|
|
165
171
|
initialPrompts.push({
|
@@ -172,7 +178,8 @@ export class PageQueue extends EventEmitter {
|
|
172
178
|
`Implement a page for ${reference.name} at ${reference.url} with the following description: ${reference.description}.\n` +
|
173
179
|
`The page was referenced from this page: \n### PATH: ${event.payload.path}\n\`\`\`html\n${event.payload.content}\n\`\`\`\n`,
|
174
180
|
description: reference.description,
|
175
|
-
|
181
|
+
// Only used for matching
|
182
|
+
filename: reference.name + '.ref.html',
|
176
183
|
theme: this.theme,
|
177
184
|
});
|
178
185
|
break;
|
@@ -193,7 +200,7 @@ export class PageQueue extends EventEmitter {
|
|
193
200
|
payload: {
|
194
201
|
name: prompt.name,
|
195
202
|
title: prompt.title,
|
196
|
-
filename:
|
203
|
+
filename: prompt.filename,
|
197
204
|
method: 'GET',
|
198
205
|
path: prompt.path,
|
199
206
|
prompt: prompt.description,
|
package/src/storm/UIServer.ts
CHANGED
@@ -12,13 +12,21 @@ import { join } from 'path';
|
|
12
12
|
export class UIServer {
|
13
13
|
private readonly systemId: string;
|
14
14
|
|
15
|
-
private port: number = 50000;
|
16
15
|
private server: Server | undefined;
|
16
|
+
private port: number = 50000;
|
17
17
|
|
18
18
|
constructor(systemId: string) {
|
19
19
|
this.systemId = systemId;
|
20
20
|
}
|
21
21
|
|
22
|
+
public isRunning() {
|
23
|
+
return !!this.server;
|
24
|
+
}
|
25
|
+
|
26
|
+
public getUrl() {
|
27
|
+
return `http://localhost:${this.port}`;
|
28
|
+
}
|
29
|
+
|
22
30
|
public async start() {
|
23
31
|
const app = express();
|
24
32
|
app.get('/_reset', (req: Request, res: Response) => {
|
package/src/storm/routes.ts
CHANGED
@@ -35,7 +35,15 @@ import {
|
|
35
35
|
import { StormCodegen } from './codegen';
|
36
36
|
import { assetManager } from '../assetManager';
|
37
37
|
import uuid from 'node-uuid';
|
38
|
-
import {
|
38
|
+
import {
|
39
|
+
getSystemBaseDir,
|
40
|
+
readPageFromDisk,
|
41
|
+
resolveReadPath,
|
42
|
+
SystemIdHeader,
|
43
|
+
writeAssetToDisk,
|
44
|
+
writeImageToDisk,
|
45
|
+
writePageToDisk,
|
46
|
+
} from './page-utils';
|
39
47
|
import { UIServer } from './UIServer';
|
40
48
|
import { randomUUID } from 'crypto';
|
41
49
|
import { ImagePrompt, PageQueue } from './PageGenerator';
|
@@ -69,7 +77,7 @@ function convertPageEvent(screenData: StormEvent, innerConversationId: string, m
|
|
69
77
|
description: screenData.payload.description,
|
70
78
|
prompt: screenData.payload.prompt,
|
71
79
|
path: screenData.payload.path,
|
72
|
-
url:
|
80
|
+
url: screenData.payload.content ? screenData.payload.path : '',
|
73
81
|
method: screenData.payload.method,
|
74
82
|
conversationId: innerConversationId,
|
75
83
|
},
|
@@ -79,8 +87,19 @@ function convertPageEvent(screenData: StormEvent, innerConversationId: string, m
|
|
79
87
|
return screenData;
|
80
88
|
}
|
81
89
|
|
82
|
-
router.
|
83
|
-
|
90
|
+
router.post('/ui/serve/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
91
|
+
const systemId = req.params.systemId as string | undefined;
|
92
|
+
if (!systemId) {
|
93
|
+
res.status(404).send({ error: 'Missing "systemId" in URL' });
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
|
97
|
+
const svr = (UI_SERVERS[systemId] = UI_SERVERS[systemId] || new UIServer(systemId));
|
98
|
+
if (!svr.isRunning()) {
|
99
|
+
await UI_SERVERS[systemId].start();
|
100
|
+
}
|
101
|
+
|
102
|
+
res.status(200).send({ status: 'running', url: svr.getUrl() });
|
84
103
|
});
|
85
104
|
|
86
105
|
router.post('/ui/create-system/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
@@ -100,7 +119,20 @@ router.post('/ui/create-system/:systemId', async (req: KapetaBodyRequest, res: R
|
|
100
119
|
return;
|
101
120
|
});
|
102
121
|
|
122
|
+
router.delete('/ui/serve/:systemId', async (req: KapetaBodyRequest, res: Response) => {
|
123
|
+
const systemId = req.params.systemId as string | undefined;
|
124
|
+
if (!systemId) {
|
125
|
+
res.status(404).send({ error: 'Missing "systemId" in URL' });
|
126
|
+
return;
|
127
|
+
}
|
103
128
|
|
129
|
+
const server = UI_SERVERS[systemId];
|
130
|
+
if (server) {
|
131
|
+
server.close();
|
132
|
+
delete UI_SERVERS[systemId];
|
133
|
+
}
|
134
|
+
res.status(200).json({ status: 'ok' });
|
135
|
+
});
|
104
136
|
|
105
137
|
router.post('/ui/screen', async (req: KapetaBodyRequest, res: Response) => {
|
106
138
|
try {
|
@@ -152,21 +184,6 @@ router.post('/ui/screen', async (req: KapetaBodyRequest, res: Response) => {
|
|
152
184
|
}
|
153
185
|
});
|
154
186
|
|
155
|
-
router.delete('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
156
|
-
const conversationId = req.headers[ConversationIdHeader.toLowerCase()] as string | undefined;
|
157
|
-
if (!conversationId) {
|
158
|
-
res.status(400).send('Missing conversation id');
|
159
|
-
return;
|
160
|
-
}
|
161
|
-
|
162
|
-
const server = UI_SERVERS[conversationId];
|
163
|
-
if (server) {
|
164
|
-
server.close();
|
165
|
-
delete UI_SERVERS[conversationId];
|
166
|
-
}
|
167
|
-
res.status(200).json({ status: 'ok' });
|
168
|
-
});
|
169
|
-
|
170
187
|
router.post('/:handle/ui/iterative', async (req: KapetaBodyRequest, res: Response) => {
|
171
188
|
const handle = req.params.handle as string;
|
172
189
|
try {
|