@kapeta/local-cluster-service 0.71.0 → 0.71.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 +8 -0
- package/dist/cjs/src/storm/routes.js +20 -7
- package/dist/cjs/src/storm/stormClient.d.ts +2 -1
- package/dist/cjs/src/storm/stormClient.js +8 -23
- package/dist/esm/src/storm/routes.js +20 -7
- package/dist/esm/src/storm/stormClient.d.ts +2 -1
- package/dist/esm/src/storm/stormClient.js +8 -23
- package/package.json +2 -2
- package/src/storm/PageGenerator.ts +1 -1
- package/src/storm/routes.ts +21 -7
- package/src/storm/stormClient.ts +3 -19
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## [0.71.1](https://github.com/kapetacom/local-cluster-service/compare/v0.71.0...v0.71.1) (2024-09-17)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* emit all events except chunks from screen endpoints ([8e67b58](https://github.com/kapetacom/local-cluster-service/commit/8e67b58b6cc70c359556edfc61dd904254f9d3bc))
|
7
|
+
* replace fetch retry handler library to avoid fetch failed ([59a4342](https://github.com/kapetacom/local-cluster-service/commit/59a4342203cd8efb706beba254284ce321fe313a))
|
8
|
+
|
1
9
|
# [0.71.0](https://github.com/kapetacom/local-cluster-service/compare/v0.70.12...v0.71.0) (2024-09-16)
|
2
10
|
|
3
11
|
|
@@ -129,6 +129,12 @@ router.post('/ui/screen', async (req, res) => {
|
|
129
129
|
console.error('Failed to process page', err);
|
130
130
|
sendError(err, res);
|
131
131
|
});
|
132
|
+
queue.on('event', (event) => {
|
133
|
+
if (event.type === 'FILE_CHUNK') {
|
134
|
+
return;
|
135
|
+
}
|
136
|
+
sendEvent(res, event);
|
137
|
+
});
|
132
138
|
await queue.addPrompt(aiRequest, conversationId, true);
|
133
139
|
await queue.wait();
|
134
140
|
await Promise.allSettled(promises);
|
@@ -207,8 +213,11 @@ router.post('/:handle/ui/iterative', async (req, res) => {
|
|
207
213
|
pageQueue.cancel();
|
208
214
|
});
|
209
215
|
pageQueue.on('page', (screenData) => sendPageEvent(landingPagesStream.getConversationId(), screenData, res));
|
210
|
-
pageQueue.on('event', (
|
211
|
-
|
216
|
+
pageQueue.on('event', (event) => {
|
217
|
+
if (event.type === 'FILE_CHUNK') {
|
218
|
+
return;
|
219
|
+
}
|
220
|
+
sendEvent(res, event);
|
212
221
|
});
|
213
222
|
pageQueue.on('error', (err) => {
|
214
223
|
console.error('Failed to process page', err);
|
@@ -360,8 +369,11 @@ router.post('/:handle/ui', async (req, res) => {
|
|
360
369
|
queue.cancel();
|
361
370
|
});
|
362
371
|
queue.on('page', (screenData) => sendPageEvent(outerConversationId, screenData, res));
|
363
|
-
queue.on('event', (
|
364
|
-
|
372
|
+
queue.on('event', (event) => {
|
373
|
+
if (event.type === 'FILE_CHUNK') {
|
374
|
+
return;
|
375
|
+
}
|
376
|
+
sendEvent(res, event);
|
365
377
|
});
|
366
378
|
queue.on('error', (err) => {
|
367
379
|
console.error('Failed to process page', err);
|
@@ -417,10 +429,11 @@ router.post('/ui/edit', async (req, res) => {
|
|
417
429
|
return promise;
|
418
430
|
}
|
419
431
|
});
|
420
|
-
queue.on('event', (
|
421
|
-
if (
|
422
|
-
|
432
|
+
queue.on('event', (event) => {
|
433
|
+
if (event.type === 'FILE_CHUNK') {
|
434
|
+
return;
|
423
435
|
}
|
436
|
+
sendEvent(res, event);
|
424
437
|
});
|
425
438
|
queue.on('error', (err) => {
|
426
439
|
console.error('Failed to process page', err);
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/// <reference types="node" />
|
1
2
|
import { ConversationItem, ImplementAPIClientsRequest, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
2
3
|
import { Page, StormEventPageUrl } from './events';
|
3
4
|
export declare const STORM_ID = "storm";
|
@@ -65,7 +66,7 @@ declare class StormClient {
|
|
65
66
|
createUIShells(prompt: UIShellsPrompt, conversationId?: string): Promise<StormStream>;
|
66
67
|
createUILandingPages(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
|
67
68
|
createUIPage(prompt: UIPagePrompt, conversationId?: string, history?: ConversationItem[]): Promise<StormStream>;
|
68
|
-
voteUIPage(topic: string, conversationId: string, vote: -1 | 0 | 1, mainConversationId?: string): Promise<
|
69
|
+
voteUIPage(topic: string, conversationId: string, vote: -1 | 0 | 1, mainConversationId?: string): Promise<Response>;
|
69
70
|
getVoteUIPage(topic: string, conversationId: string, mainConversationId?: string): Promise<{
|
70
71
|
vote: -1 | 0 | 1;
|
71
72
|
}>;
|
@@ -13,22 +13,8 @@ const utils_1 = require("../utils/utils");
|
|
13
13
|
const promises_1 = __importDefault(require("node:readline/promises"));
|
14
14
|
const node_stream_1 = require("node:stream");
|
15
15
|
const stream_1 = require("./stream");
|
16
|
-
const
|
17
|
-
|
18
|
-
// See https://github.com/nodejs/undici/blob/990df2c7e37cbe5bb44fe2f576dddeaeb5916590/docs/docs/api/RetryAgent.md
|
19
|
-
const retryAgent = new undici_1.RetryAgent(new undici_1.Agent(), {
|
20
|
-
methods: [
|
21
|
-
// Added methods ↓ (not idempotent), but we want to retry on POST:
|
22
|
-
'POST',
|
23
|
-
// defaults below
|
24
|
-
'GET',
|
25
|
-
'HEAD',
|
26
|
-
'OPTIONS',
|
27
|
-
'PUT',
|
28
|
-
'DELETE',
|
29
|
-
'TRACE',
|
30
|
-
],
|
31
|
-
});
|
16
|
+
const fetch_retry_1 = __importDefault(require("fetch-retry"));
|
17
|
+
const fetchWithRetries = (0, fetch_retry_1.default)(global.fetch, { retries: 5, retryDelay: 10 });
|
32
18
|
exports.STORM_ID = 'storm';
|
33
19
|
exports.ConversationIdHeader = 'Conversation-Id';
|
34
20
|
class StormClient {
|
@@ -54,7 +40,6 @@ class StormClient {
|
|
54
40
|
method: method,
|
55
41
|
body: JSON.stringify(body),
|
56
42
|
headers,
|
57
|
-
dispatcher: retryAgent,
|
58
43
|
};
|
59
44
|
}
|
60
45
|
async send(path, body, method = 'POST') {
|
@@ -65,7 +50,7 @@ class StormClient {
|
|
65
50
|
});
|
66
51
|
const abort = new AbortController();
|
67
52
|
options.signal = abort.signal;
|
68
|
-
const response = await (
|
53
|
+
const response = await fetchWithRetries(options.url, options);
|
69
54
|
if (response.status !== 200) {
|
70
55
|
throw new Error(`Got error response from ${options.url}: ${response.status}\nContent: ${await response.text()}`);
|
71
56
|
}
|
@@ -138,19 +123,19 @@ class StormClient {
|
|
138
123
|
prompt: JSON.stringify({ topic, vote, mainConversationId }),
|
139
124
|
conversationId,
|
140
125
|
});
|
141
|
-
return
|
126
|
+
return fetch(options.url, options);
|
142
127
|
}
|
143
128
|
async getVoteUIPage(topic, conversationId, mainConversationId) {
|
144
129
|
const options = await this.createOptions('/v2/ui/get-vote', 'POST', {
|
145
130
|
prompt: JSON.stringify({ topic, mainConversationId }),
|
146
131
|
conversationId,
|
147
132
|
});
|
148
|
-
const response = await
|
133
|
+
const response = await fetch(options.url, options);
|
149
134
|
return response.json();
|
150
135
|
}
|
151
136
|
async implementAPIClients(prompt) {
|
152
137
|
const u = `${this._baseUrl}/v2/ui/implement-api-clients`;
|
153
|
-
const response = await
|
138
|
+
const response = await fetch(u, {
|
154
139
|
method: 'POST',
|
155
140
|
body: JSON.stringify({
|
156
141
|
fileName: prompt.fileName,
|
@@ -162,7 +147,7 @@ class StormClient {
|
|
162
147
|
}
|
163
148
|
async generatePrompt(pages) {
|
164
149
|
const u = `${this._baseUrl}/v2/ui/prompt`;
|
165
|
-
const response = await
|
150
|
+
const response = await fetch(u, {
|
166
151
|
method: 'POST',
|
167
152
|
body: JSON.stringify({
|
168
153
|
pages: pages,
|
@@ -235,7 +220,7 @@ class StormClient {
|
|
235
220
|
prompt: '',
|
236
221
|
conversationId: conversationId,
|
237
222
|
});
|
238
|
-
const response = await
|
223
|
+
const response = await fetch(options.url, options);
|
239
224
|
return response.text();
|
240
225
|
}
|
241
226
|
}
|
@@ -129,6 +129,12 @@ router.post('/ui/screen', async (req, res) => {
|
|
129
129
|
console.error('Failed to process page', err);
|
130
130
|
sendError(err, res);
|
131
131
|
});
|
132
|
+
queue.on('event', (event) => {
|
133
|
+
if (event.type === 'FILE_CHUNK') {
|
134
|
+
return;
|
135
|
+
}
|
136
|
+
sendEvent(res, event);
|
137
|
+
});
|
132
138
|
await queue.addPrompt(aiRequest, conversationId, true);
|
133
139
|
await queue.wait();
|
134
140
|
await Promise.allSettled(promises);
|
@@ -207,8 +213,11 @@ router.post('/:handle/ui/iterative', async (req, res) => {
|
|
207
213
|
pageQueue.cancel();
|
208
214
|
});
|
209
215
|
pageQueue.on('page', (screenData) => sendPageEvent(landingPagesStream.getConversationId(), screenData, res));
|
210
|
-
pageQueue.on('event', (
|
211
|
-
|
216
|
+
pageQueue.on('event', (event) => {
|
217
|
+
if (event.type === 'FILE_CHUNK') {
|
218
|
+
return;
|
219
|
+
}
|
220
|
+
sendEvent(res, event);
|
212
221
|
});
|
213
222
|
pageQueue.on('error', (err) => {
|
214
223
|
console.error('Failed to process page', err);
|
@@ -360,8 +369,11 @@ router.post('/:handle/ui', async (req, res) => {
|
|
360
369
|
queue.cancel();
|
361
370
|
});
|
362
371
|
queue.on('page', (screenData) => sendPageEvent(outerConversationId, screenData, res));
|
363
|
-
queue.on('event', (
|
364
|
-
|
372
|
+
queue.on('event', (event) => {
|
373
|
+
if (event.type === 'FILE_CHUNK') {
|
374
|
+
return;
|
375
|
+
}
|
376
|
+
sendEvent(res, event);
|
365
377
|
});
|
366
378
|
queue.on('error', (err) => {
|
367
379
|
console.error('Failed to process page', err);
|
@@ -417,10 +429,11 @@ router.post('/ui/edit', async (req, res) => {
|
|
417
429
|
return promise;
|
418
430
|
}
|
419
431
|
});
|
420
|
-
queue.on('event', (
|
421
|
-
if (
|
422
|
-
|
432
|
+
queue.on('event', (event) => {
|
433
|
+
if (event.type === 'FILE_CHUNK') {
|
434
|
+
return;
|
423
435
|
}
|
436
|
+
sendEvent(res, event);
|
424
437
|
});
|
425
438
|
queue.on('error', (err) => {
|
426
439
|
console.error('Failed to process page', err);
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/// <reference types="node" />
|
1
2
|
import { ConversationItem, ImplementAPIClientsRequest, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt, StormUIListPrompt } from './stream';
|
2
3
|
import { Page, StormEventPageUrl } from './events';
|
3
4
|
export declare const STORM_ID = "storm";
|
@@ -65,7 +66,7 @@ declare class StormClient {
|
|
65
66
|
createUIShells(prompt: UIShellsPrompt, conversationId?: string): Promise<StormStream>;
|
66
67
|
createUILandingPages(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
|
67
68
|
createUIPage(prompt: UIPagePrompt, conversationId?: string, history?: ConversationItem[]): Promise<StormStream>;
|
68
|
-
voteUIPage(topic: string, conversationId: string, vote: -1 | 0 | 1, mainConversationId?: string): Promise<
|
69
|
+
voteUIPage(topic: string, conversationId: string, vote: -1 | 0 | 1, mainConversationId?: string): Promise<Response>;
|
69
70
|
getVoteUIPage(topic: string, conversationId: string, mainConversationId?: string): Promise<{
|
70
71
|
vote: -1 | 0 | 1;
|
71
72
|
}>;
|
@@ -13,22 +13,8 @@ const utils_1 = require("../utils/utils");
|
|
13
13
|
const promises_1 = __importDefault(require("node:readline/promises"));
|
14
14
|
const node_stream_1 = require("node:stream");
|
15
15
|
const stream_1 = require("./stream");
|
16
|
-
const
|
17
|
-
|
18
|
-
// See https://github.com/nodejs/undici/blob/990df2c7e37cbe5bb44fe2f576dddeaeb5916590/docs/docs/api/RetryAgent.md
|
19
|
-
const retryAgent = new undici_1.RetryAgent(new undici_1.Agent(), {
|
20
|
-
methods: [
|
21
|
-
// Added methods ↓ (not idempotent), but we want to retry on POST:
|
22
|
-
'POST',
|
23
|
-
// defaults below
|
24
|
-
'GET',
|
25
|
-
'HEAD',
|
26
|
-
'OPTIONS',
|
27
|
-
'PUT',
|
28
|
-
'DELETE',
|
29
|
-
'TRACE',
|
30
|
-
],
|
31
|
-
});
|
16
|
+
const fetch_retry_1 = __importDefault(require("fetch-retry"));
|
17
|
+
const fetchWithRetries = (0, fetch_retry_1.default)(global.fetch, { retries: 5, retryDelay: 10 });
|
32
18
|
exports.STORM_ID = 'storm';
|
33
19
|
exports.ConversationIdHeader = 'Conversation-Id';
|
34
20
|
class StormClient {
|
@@ -54,7 +40,6 @@ class StormClient {
|
|
54
40
|
method: method,
|
55
41
|
body: JSON.stringify(body),
|
56
42
|
headers,
|
57
|
-
dispatcher: retryAgent,
|
58
43
|
};
|
59
44
|
}
|
60
45
|
async send(path, body, method = 'POST') {
|
@@ -65,7 +50,7 @@ class StormClient {
|
|
65
50
|
});
|
66
51
|
const abort = new AbortController();
|
67
52
|
options.signal = abort.signal;
|
68
|
-
const response = await (
|
53
|
+
const response = await fetchWithRetries(options.url, options);
|
69
54
|
if (response.status !== 200) {
|
70
55
|
throw new Error(`Got error response from ${options.url}: ${response.status}\nContent: ${await response.text()}`);
|
71
56
|
}
|
@@ -138,19 +123,19 @@ class StormClient {
|
|
138
123
|
prompt: JSON.stringify({ topic, vote, mainConversationId }),
|
139
124
|
conversationId,
|
140
125
|
});
|
141
|
-
return
|
126
|
+
return fetch(options.url, options);
|
142
127
|
}
|
143
128
|
async getVoteUIPage(topic, conversationId, mainConversationId) {
|
144
129
|
const options = await this.createOptions('/v2/ui/get-vote', 'POST', {
|
145
130
|
prompt: JSON.stringify({ topic, mainConversationId }),
|
146
131
|
conversationId,
|
147
132
|
});
|
148
|
-
const response = await
|
133
|
+
const response = await fetch(options.url, options);
|
149
134
|
return response.json();
|
150
135
|
}
|
151
136
|
async implementAPIClients(prompt) {
|
152
137
|
const u = `${this._baseUrl}/v2/ui/implement-api-clients`;
|
153
|
-
const response = await
|
138
|
+
const response = await fetch(u, {
|
154
139
|
method: 'POST',
|
155
140
|
body: JSON.stringify({
|
156
141
|
fileName: prompt.fileName,
|
@@ -162,7 +147,7 @@ class StormClient {
|
|
162
147
|
}
|
163
148
|
async generatePrompt(pages) {
|
164
149
|
const u = `${this._baseUrl}/v2/ui/prompt`;
|
165
|
-
const response = await
|
150
|
+
const response = await fetch(u, {
|
166
151
|
method: 'POST',
|
167
152
|
body: JSON.stringify({
|
168
153
|
pages: pages,
|
@@ -235,7 +220,7 @@ class StormClient {
|
|
235
220
|
prompt: '',
|
236
221
|
conversationId: conversationId,
|
237
222
|
});
|
238
|
-
const response = await
|
223
|
+
const response = await fetch(options.url, options);
|
239
224
|
return response.text();
|
240
225
|
}
|
241
226
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.71.
|
3
|
+
"version": "0.71.1",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -70,6 +70,7 @@
|
|
70
70
|
"download-git-repo": "^3.0.2",
|
71
71
|
"express": "4.17.1",
|
72
72
|
"express-promise-router": "^4.1.1",
|
73
|
+
"fetch-retry": "^6.0.0",
|
73
74
|
"fs-extra": "^11.1.0",
|
74
75
|
"glob": "^7.1.6",
|
75
76
|
"gunzip-maybe": "^1.4.2",
|
@@ -88,7 +89,6 @@
|
|
88
89
|
"stream-json": "^1.8.0",
|
89
90
|
"tar-stream": "^3.1.6",
|
90
91
|
"typescript": "^5.1.6",
|
91
|
-
"undici": "^6.19.8",
|
92
92
|
"uuid": "^9.0.1",
|
93
93
|
"yaml": "^1.6.0"
|
94
94
|
},
|
@@ -259,7 +259,7 @@ export class PageQueue extends EventEmitter {
|
|
259
259
|
// Add safeguard to avoid generating images for nonsense URLs
|
260
260
|
// Sometimes we get entries for Base URLs that will then cause issues on the filesystem
|
261
261
|
// Example: https://www.kapeta.com/images/
|
262
|
-
const mimeType = mimetypes.lookup(prompt.url)
|
262
|
+
const mimeType = mimetypes.lookup(prompt.url);
|
263
263
|
if (!mimeType || !mimeType.startsWith('image/')) {
|
264
264
|
console.warn('Skipping image reference of type %s for url %s', mimeType, prompt.url);
|
265
265
|
return;
|
package/src/storm/routes.ts
CHANGED
@@ -181,6 +181,13 @@ router.post('/ui/screen', async (req: KapetaBodyRequest, res: Response) => {
|
|
181
181
|
sendError(err as any, res);
|
182
182
|
});
|
183
183
|
|
184
|
+
queue.on('event', (event: StormEvent) => {
|
185
|
+
if (event.type === 'FILE_CHUNK') {
|
186
|
+
return;
|
187
|
+
}
|
188
|
+
sendEvent(res, event);
|
189
|
+
});
|
190
|
+
|
184
191
|
await queue.addPrompt(aiRequest, conversationId, true);
|
185
192
|
|
186
193
|
await queue.wait();
|
@@ -274,8 +281,11 @@ router.post('/:handle/ui/iterative', async (req: KapetaBodyRequest, res: Respons
|
|
274
281
|
sendPageEvent(landingPagesStream.getConversationId(), screenData, res)
|
275
282
|
);
|
276
283
|
|
277
|
-
pageQueue.on('event', (
|
278
|
-
|
284
|
+
pageQueue.on('event', (event: StormEvent) => {
|
285
|
+
if (event.type === 'FILE_CHUNK') {
|
286
|
+
return;
|
287
|
+
}
|
288
|
+
sendEvent(res, event);
|
279
289
|
});
|
280
290
|
|
281
291
|
pageQueue.on('error', (err) => {
|
@@ -460,8 +470,11 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
|
|
460
470
|
|
461
471
|
queue.on('page', (screenData: StormEventPage) => sendPageEvent(outerConversationId, screenData, res));
|
462
472
|
|
463
|
-
queue.on('event', (
|
464
|
-
|
473
|
+
queue.on('event', (event: StormEvent) => {
|
474
|
+
if (event.type === 'FILE_CHUNK') {
|
475
|
+
return;
|
476
|
+
}
|
477
|
+
sendEvent(res, event);
|
465
478
|
});
|
466
479
|
|
467
480
|
queue.on('error', (err) => {
|
@@ -527,10 +540,11 @@ router.post('/ui/edit', async (req: KapetaBodyRequest, res: Response) => {
|
|
527
540
|
}
|
528
541
|
});
|
529
542
|
|
530
|
-
queue.on('event', (
|
531
|
-
if (
|
532
|
-
|
543
|
+
queue.on('event', (event) => {
|
544
|
+
if (event.type === 'FILE_CHUNK') {
|
545
|
+
return;
|
533
546
|
}
|
547
|
+
sendEvent(res, event);
|
534
548
|
});
|
535
549
|
|
536
550
|
queue.on('error', (err) => {
|
package/src/storm/stormClient.ts
CHANGED
@@ -16,23 +16,8 @@ import {
|
|
16
16
|
StormUIListPrompt,
|
17
17
|
} from './stream';
|
18
18
|
import { Page, StormEventPageUrl } from './events';
|
19
|
-
import
|
20
|
-
|
21
|
-
// Will only retry on error codes and GET requests by default
|
22
|
-
// See https://github.com/nodejs/undici/blob/990df2c7e37cbe5bb44fe2f576dddeaeb5916590/docs/docs/api/RetryAgent.md
|
23
|
-
const retryAgent = new RetryAgent(new Agent(), {
|
24
|
-
methods: [
|
25
|
-
// Added methods ↓ (not idempotent), but we want to retry on POST:
|
26
|
-
'POST',
|
27
|
-
// defaults below
|
28
|
-
'GET',
|
29
|
-
'HEAD',
|
30
|
-
'OPTIONS',
|
31
|
-
'PUT',
|
32
|
-
'DELETE',
|
33
|
-
'TRACE',
|
34
|
-
],
|
35
|
-
});
|
19
|
+
import createFetch from 'fetch-retry';
|
20
|
+
const fetchWithRetries = createFetch(global.fetch, { retries: 5, retryDelay: 10 });
|
36
21
|
|
37
22
|
export const STORM_ID = 'storm';
|
38
23
|
|
@@ -129,7 +114,6 @@ class StormClient {
|
|
129
114
|
method: method,
|
130
115
|
body: JSON.stringify(body),
|
131
116
|
headers,
|
132
|
-
dispatcher: retryAgent,
|
133
117
|
};
|
134
118
|
}
|
135
119
|
|
@@ -148,7 +132,7 @@ class StormClient {
|
|
148
132
|
const abort = new AbortController();
|
149
133
|
options.signal = abort.signal;
|
150
134
|
|
151
|
-
const response = await
|
135
|
+
const response = await fetchWithRetries(options.url, options);
|
152
136
|
|
153
137
|
if (response.status !== 200) {
|
154
138
|
throw new Error(
|