@kapeta/local-cluster-service 0.63.1 → 0.64.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 CHANGED
@@ -1,3 +1,17 @@
1
+ ## [0.64.1](https://github.com/kapetacom/local-cluster-service/compare/v0.64.0...v0.64.1) (2024-08-21)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * tweak port detection code ([#221](https://github.com/kapetacom/local-cluster-service/issues/221)) ([84000ea](https://github.com/kapetacom/local-cluster-service/commit/84000eae5eaec0d7ca975029b6cb7fcefcb87340))
7
+
8
+ # [0.64.0](https://github.com/kapetacom/local-cluster-service/compare/v0.63.1...v0.64.0) (2024-08-21)
9
+
10
+
11
+ ### Features
12
+
13
+ * Allow skip prompt improvement ([#220](https://github.com/kapetacom/local-cluster-service/issues/220)) ([f75847c](https://github.com/kapetacom/local-cluster-service/commit/f75847cd10549e730d2ea7efb1caa59ea0610865))
14
+
1
15
  ## [0.63.1](https://github.com/kapetacom/local-cluster-service/compare/v0.63.0...v0.63.1) (2024-08-20)
2
16
 
3
17
 
@@ -3,10 +3,13 @@
3
3
  * Copyright 2023 Kapeta Inc.
4
4
  * SPDX-License-Identifier: BUSL-1.1
5
5
  */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
6
9
  Object.defineProperty(exports, "__esModule", { value: true });
7
10
  exports.clusterService = void 0;
8
11
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
9
- const net = require('net');
12
+ const net_1 = __importDefault(require("net"));
10
13
  const DEFAULT_SERVER_PORT = 35100;
11
14
  const DEFAULT_START_PORT = 40000;
12
15
  const DEFAULT_HOST = '127.0.0.1';
@@ -38,56 +41,43 @@ class ClusterService {
38
41
  await this._findClusterServicePort();
39
42
  }
40
43
  async _findClusterServicePort() {
41
- while (true) {
44
+ for (; this._port <= 65535; this._port++) {
42
45
  const isUsed = await this._checkIfPortIsUsed(this._port);
43
46
  if (!isUsed) {
44
- break;
47
+ return;
45
48
  }
46
- this._port++;
47
49
  }
50
+ throw new Error('No available ports');
48
51
  }
49
52
  /**
50
53
  * Gets next available port
51
54
  */
52
55
  async getNextAvailablePort(startPort = -1) {
53
- let receivedStartPort = startPort > 0;
54
- if (!receivedStartPort) {
55
- startPort = this._currentPort;
56
- }
57
- while (true) {
58
- while (this._reservedPorts.indexOf(startPort) > -1) {
59
- startPort++;
60
- if (!receivedStartPort) {
61
- this._currentPort = startPort;
62
- }
63
- }
64
- const nextPort = startPort++;
65
- if (!receivedStartPort) {
66
- this._currentPort = startPort;
56
+ for (let nextPort = startPort > 0 ? startPort : this._currentPort; nextPort <= 65535; nextPort++) {
57
+ if (this._reservedPorts.indexOf(startPort) > -1) {
58
+ continue;
67
59
  }
68
60
  const isUsed = await this._checkIfPortIsUsed(nextPort);
69
61
  if (!isUsed) {
62
+ // Save the state if we're looking for a system port for the cluster itself
63
+ if (startPort <= 0) {
64
+ this._currentPort = nextPort;
65
+ }
70
66
  return nextPort;
71
67
  }
72
68
  }
69
+ throw new Error('No available ports');
73
70
  }
74
71
  _checkIfPortIsUsed(port, host = this._host) {
75
72
  return new Promise((resolve, reject) => {
76
- const server = net.createServer();
77
- server.once('error', function (err) {
78
- if (err.code === 'EADDRINUSE') {
79
- server.close();
80
- resolve(true);
81
- return;
82
- }
83
- server.close();
84
- reject(err);
85
- });
86
- server.once('listening', function () {
87
- server.close();
88
- resolve(false);
73
+ const server = net_1.default.createServer();
74
+ server.unref();
75
+ server.on('error', () => resolve(true));
76
+ server.listen({ port, host }, () => {
77
+ server.close(() => {
78
+ resolve(false);
79
+ });
89
80
  });
90
- server.listen(port, host);
91
81
  });
92
82
  }
93
83
  /**
@@ -107,7 +107,7 @@ router.post('/:handle/ui/iterative', async (req, res) => {
107
107
  try {
108
108
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
109
109
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
110
- const landingPagesStream = await stormClient_1.stormClient.createUILandingPages(aiRequest.prompt, conversationId);
110
+ const landingPagesStream = await stormClient_1.stormClient.createUILandingPages(aiRequest, conversationId);
111
111
  onRequestAborted(req, res, () => {
112
112
  landingPagesStream.abort();
113
113
  });
@@ -180,7 +180,7 @@ router.post('/:handle/ui', async (req, res) => {
180
180
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
181
181
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
182
182
  // Get user journeys
183
- const userJourneysStream = await stormClient_1.stormClient.createUIUserJourneys(aiRequest.prompt, conversationId);
183
+ const userJourneysStream = await stormClient_1.stormClient.createUIUserJourneys(aiRequest, conversationId);
184
184
  const outerConversationId = userJourneysStream.getConversationId();
185
185
  onRequestAborted(req, res, () => {
186
186
  userJourneysStream.abort();
@@ -365,7 +365,7 @@ router.post('/:handle/all', async (req, res) => {
365
365
  const eventParser = new event_parser_1.StormEventParser(stormOptions);
366
366
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
367
367
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
368
- const metaStream = await stormClient_1.stormClient.createMetadata(aiRequest.prompt, conversationId);
368
+ const metaStream = await stormClient_1.stormClient.createMetadata(aiRequest, conversationId);
369
369
  onRequestAborted(req, res, () => {
370
370
  metaStream.abort();
371
371
  });
@@ -38,16 +38,20 @@ export interface UIPageEditRequest {
38
38
  pages: StormEventPageUrl['payload'][];
39
39
  prompt: string;
40
40
  }
41
+ export interface BasePromptRequest {
42
+ prompt: string;
43
+ skipImprovement?: boolean;
44
+ }
41
45
  declare class StormClient {
42
46
  private readonly _baseUrl;
43
47
  constructor();
44
48
  private createOptions;
45
49
  private send;
46
- createMetadata(prompt: string, conversationId?: string): Promise<StormStream>;
50
+ createMetadata(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
47
51
  createUIPages(prompt: string, conversationId?: string): Promise<StormStream>;
48
- createUIUserJourneys(prompt: string, conversationId?: string): Promise<StormStream>;
52
+ createUIUserJourneys(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
49
53
  createUIShells(prompt: UIShellsPrompt, conversationId?: string): Promise<StormStream>;
50
- createUILandingPages(prompt: string, conversationId?: string): Promise<StormStream>;
54
+ createUILandingPages(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
51
55
  createUIPage(prompt: UIPagePrompt, conversationId?: string, history?: ConversationItem[]): Promise<StormStream>;
52
56
  classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
53
57
  editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
@@ -3,10 +3,13 @@
3
3
  * Copyright 2023 Kapeta Inc.
4
4
  * SPDX-License-Identifier: BUSL-1.1
5
5
  */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
6
9
  Object.defineProperty(exports, "__esModule", { value: true });
7
10
  exports.clusterService = void 0;
8
11
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
9
- const net = require('net');
12
+ const net_1 = __importDefault(require("net"));
10
13
  const DEFAULT_SERVER_PORT = 35100;
11
14
  const DEFAULT_START_PORT = 40000;
12
15
  const DEFAULT_HOST = '127.0.0.1';
@@ -38,56 +41,43 @@ class ClusterService {
38
41
  await this._findClusterServicePort();
39
42
  }
40
43
  async _findClusterServicePort() {
41
- while (true) {
44
+ for (; this._port <= 65535; this._port++) {
42
45
  const isUsed = await this._checkIfPortIsUsed(this._port);
43
46
  if (!isUsed) {
44
- break;
47
+ return;
45
48
  }
46
- this._port++;
47
49
  }
50
+ throw new Error('No available ports');
48
51
  }
49
52
  /**
50
53
  * Gets next available port
51
54
  */
52
55
  async getNextAvailablePort(startPort = -1) {
53
- let receivedStartPort = startPort > 0;
54
- if (!receivedStartPort) {
55
- startPort = this._currentPort;
56
- }
57
- while (true) {
58
- while (this._reservedPorts.indexOf(startPort) > -1) {
59
- startPort++;
60
- if (!receivedStartPort) {
61
- this._currentPort = startPort;
62
- }
63
- }
64
- const nextPort = startPort++;
65
- if (!receivedStartPort) {
66
- this._currentPort = startPort;
56
+ for (let nextPort = startPort > 0 ? startPort : this._currentPort; nextPort <= 65535; nextPort++) {
57
+ if (this._reservedPorts.indexOf(startPort) > -1) {
58
+ continue;
67
59
  }
68
60
  const isUsed = await this._checkIfPortIsUsed(nextPort);
69
61
  if (!isUsed) {
62
+ // Save the state if we're looking for a system port for the cluster itself
63
+ if (startPort <= 0) {
64
+ this._currentPort = nextPort;
65
+ }
70
66
  return nextPort;
71
67
  }
72
68
  }
69
+ throw new Error('No available ports');
73
70
  }
74
71
  _checkIfPortIsUsed(port, host = this._host) {
75
72
  return new Promise((resolve, reject) => {
76
- const server = net.createServer();
77
- server.once('error', function (err) {
78
- if (err.code === 'EADDRINUSE') {
79
- server.close();
80
- resolve(true);
81
- return;
82
- }
83
- server.close();
84
- reject(err);
85
- });
86
- server.once('listening', function () {
87
- server.close();
88
- resolve(false);
73
+ const server = net_1.default.createServer();
74
+ server.unref();
75
+ server.on('error', () => resolve(true));
76
+ server.listen({ port, host }, () => {
77
+ server.close(() => {
78
+ resolve(false);
79
+ });
89
80
  });
90
- server.listen(port, host);
91
81
  });
92
82
  }
93
83
  /**
@@ -107,7 +107,7 @@ router.post('/:handle/ui/iterative', async (req, res) => {
107
107
  try {
108
108
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
109
109
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
110
- const landingPagesStream = await stormClient_1.stormClient.createUILandingPages(aiRequest.prompt, conversationId);
110
+ const landingPagesStream = await stormClient_1.stormClient.createUILandingPages(aiRequest, conversationId);
111
111
  onRequestAborted(req, res, () => {
112
112
  landingPagesStream.abort();
113
113
  });
@@ -180,7 +180,7 @@ router.post('/:handle/ui', async (req, res) => {
180
180
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
181
181
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
182
182
  // Get user journeys
183
- const userJourneysStream = await stormClient_1.stormClient.createUIUserJourneys(aiRequest.prompt, conversationId);
183
+ const userJourneysStream = await stormClient_1.stormClient.createUIUserJourneys(aiRequest, conversationId);
184
184
  const outerConversationId = userJourneysStream.getConversationId();
185
185
  onRequestAborted(req, res, () => {
186
186
  userJourneysStream.abort();
@@ -365,7 +365,7 @@ router.post('/:handle/all', async (req, res) => {
365
365
  const eventParser = new event_parser_1.StormEventParser(stormOptions);
366
366
  const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
367
367
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
368
- const metaStream = await stormClient_1.stormClient.createMetadata(aiRequest.prompt, conversationId);
368
+ const metaStream = await stormClient_1.stormClient.createMetadata(aiRequest, conversationId);
369
369
  onRequestAborted(req, res, () => {
370
370
  metaStream.abort();
371
371
  });
@@ -38,16 +38,20 @@ export interface UIPageEditRequest {
38
38
  pages: StormEventPageUrl['payload'][];
39
39
  prompt: string;
40
40
  }
41
+ export interface BasePromptRequest {
42
+ prompt: string;
43
+ skipImprovement?: boolean;
44
+ }
41
45
  declare class StormClient {
42
46
  private readonly _baseUrl;
43
47
  constructor();
44
48
  private createOptions;
45
49
  private send;
46
- createMetadata(prompt: string, conversationId?: string): Promise<StormStream>;
50
+ createMetadata(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
47
51
  createUIPages(prompt: string, conversationId?: string): Promise<StormStream>;
48
- createUIUserJourneys(prompt: string, conversationId?: string): Promise<StormStream>;
52
+ createUIUserJourneys(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
49
53
  createUIShells(prompt: UIShellsPrompt, conversationId?: string): Promise<StormStream>;
50
- createUILandingPages(prompt: string, conversationId?: string): Promise<StormStream>;
54
+ createUILandingPages(prompt: BasePromptRequest, conversationId?: string): Promise<StormStream>;
51
55
  createUIPage(prompt: UIPagePrompt, conversationId?: string, history?: ConversationItem[]): Promise<StormStream>;
52
56
  classifyUIReferences(prompt: string, conversationId?: string): Promise<StormStream>;
53
57
  editPages(prompt: UIPageEditPrompt, conversationId?: string): Promise<StormStream>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.63.1",
3
+ "version": "0.64.1",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { normalizeKapetaUri } from '@kapeta/nodejs-utils';
7
7
 
8
- const net = require('net');
8
+ import net from 'net';
9
9
  const DEFAULT_SERVER_PORT = 35100;
10
10
  const DEFAULT_START_PORT = 40000;
11
11
  const DEFAULT_HOST = '127.0.0.1';
@@ -44,64 +44,47 @@ class ClusterService {
44
44
  }
45
45
 
46
46
  async _findClusterServicePort() {
47
- while (true) {
47
+ for (; this._port <= 65535; this._port++) {
48
48
  const isUsed = await this._checkIfPortIsUsed(this._port);
49
49
  if (!isUsed) {
50
- break;
50
+ return;
51
51
  }
52
-
53
- this._port++;
54
52
  }
53
+ throw new Error('No available ports');
55
54
  }
56
55
 
57
56
  /**
58
57
  * Gets next available port
59
58
  */
60
59
  public async getNextAvailablePort(startPort: number = -1) {
61
- let receivedStartPort = startPort > 0;
62
- if (!receivedStartPort) {
63
- startPort = this._currentPort;
64
- }
65
- while (true) {
66
- while (this._reservedPorts.indexOf(startPort) > -1) {
67
- startPort++;
68
- if (!receivedStartPort) {
69
- this._currentPort = startPort;
70
- }
60
+ for (let nextPort = startPort > 0 ? startPort : this._currentPort; nextPort <= 65535; nextPort++) {
61
+ if (this._reservedPorts.indexOf(startPort) > -1) {
62
+ continue;
71
63
  }
72
64
 
73
- const nextPort = startPort++;
74
- if (!receivedStartPort) {
75
- this._currentPort = startPort;
76
- }
77
65
  const isUsed = await this._checkIfPortIsUsed(nextPort);
78
66
  if (!isUsed) {
67
+ // Save the state if we're looking for a system port for the cluster itself
68
+ if (startPort <= 0) {
69
+ this._currentPort = nextPort;
70
+ }
79
71
  return nextPort;
80
72
  }
81
73
  }
74
+ throw new Error('No available ports');
82
75
  }
83
76
 
84
77
  _checkIfPortIsUsed(port: number, host: string = this._host) {
85
78
  return new Promise((resolve, reject) => {
86
79
  const server = net.createServer();
80
+ server.unref();
81
+ server.on('error', () => resolve(true));
87
82
 
88
- server.once('error', function (err: any) {
89
- if (err.code === 'EADDRINUSE') {
90
- server.close();
91
- resolve(true);
92
- return;
93
- }
94
-
95
- server.close();
96
- reject(err);
83
+ server.listen({ port, host }, () => {
84
+ server.close(() => {
85
+ resolve(false);
86
+ });
97
87
  });
98
-
99
- server.once('listening', function () {
100
- server.close();
101
- resolve(false);
102
- });
103
-
104
- server.listen(port, host);
105
88
  });
106
89
  }
107
90
 
@@ -13,7 +13,14 @@ import { stringBody } from '../middleware/stringBody';
13
13
  import { KapetaBodyRequest } from '../types';
14
14
  import { StormCodegenRequest, StormContextRequest, StormCreateBlockRequest, StormStream } from './stream';
15
15
 
16
- import { ConversationIdHeader, stormClient, UIPagePrompt, UIPageEditPrompt, UIPageEditRequest } from './stormClient';
16
+ import {
17
+ ConversationIdHeader,
18
+ stormClient,
19
+ UIPagePrompt,
20
+ UIPageEditPrompt,
21
+ UIPageEditRequest,
22
+ BasePromptRequest,
23
+ } from './stormClient';
17
24
  import { Page, StormEvent, StormEventPage, StormEventPhaseType, UserJourneyScreen } from './events';
18
25
 
19
26
  import {
@@ -132,9 +139,9 @@ router.post('/:handle/ui/iterative', async (req: KapetaBodyRequest, res: Respons
132
139
  try {
133
140
  const conversationId = req.headers[ConversationIdHeader.toLowerCase()] as string | undefined;
134
141
 
135
- const aiRequest: StormContextRequest = JSON.parse(req.stringBody ?? '{}');
142
+ const aiRequest: BasePromptRequest = JSON.parse(req.stringBody ?? '{}');
136
143
 
137
- const landingPagesStream = await stormClient.createUILandingPages(aiRequest.prompt, conversationId);
144
+ const landingPagesStream = await stormClient.createUILandingPages(aiRequest, conversationId);
138
145
 
139
146
  onRequestAborted(req, res, () => {
140
147
  landingPagesStream.abort();
@@ -219,10 +226,10 @@ router.post('/:handle/ui', async (req: KapetaBodyRequest, res: Response) => {
219
226
  try {
220
227
  const conversationId = req.headers[ConversationIdHeader.toLowerCase()] as string | undefined;
221
228
 
222
- const aiRequest: StormContextRequest = JSON.parse(req.stringBody ?? '{}');
229
+ const aiRequest: BasePromptRequest = JSON.parse(req.stringBody ?? '{}');
223
230
 
224
231
  // Get user journeys
225
- const userJourneysStream = await stormClient.createUIUserJourneys(aiRequest.prompt, conversationId);
232
+ const userJourneysStream = await stormClient.createUIUserJourneys(aiRequest, conversationId);
226
233
  const outerConversationId = userJourneysStream.getConversationId();
227
234
 
228
235
  onRequestAborted(req, res, () => {
@@ -433,7 +440,7 @@ router.post('/ui/edit', async (req: KapetaBodyRequest, res: Response) => {
433
440
 
434
441
  sendDone(res);
435
442
  } catch (err: any) {
436
- sendError(err, res);
443
+ sendError(err as Error, res);
437
444
  if (!res.closed) {
438
445
  res.end();
439
446
  }
@@ -450,8 +457,8 @@ router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
450
457
 
451
458
  const conversationId = req.headers[ConversationIdHeader.toLowerCase()] as string | undefined;
452
459
 
453
- const aiRequest: StormContextRequest = JSON.parse(req.stringBody ?? '{}');
454
- const metaStream = await stormClient.createMetadata(aiRequest.prompt, conversationId);
460
+ const aiRequest: BasePromptRequest = JSON.parse(req.stringBody ?? '{}');
461
+ const metaStream = await stormClient.createMetadata(aiRequest, conversationId);
455
462
 
456
463
  onRequestAborted(req, res, () => {
457
464
  metaStream.abort();
@@ -62,6 +62,11 @@ export interface UIPageEditRequest {
62
62
  prompt: string;
63
63
  }
64
64
 
65
+ export interface BasePromptRequest {
66
+ prompt: string;
67
+ skipImprovement?: boolean;
68
+ }
69
+
65
70
  class StormClient {
66
71
  private readonly _baseUrl: string;
67
72
 
@@ -148,7 +153,7 @@ class StormClient {
148
153
  return out;
149
154
  }
150
155
 
151
- public createMetadata(prompt: string, conversationId?: string) {
156
+ public createMetadata(prompt: BasePromptRequest, conversationId?: string) {
152
157
  return this.send('/v2/all', {
153
158
  prompt: prompt,
154
159
  conversationId,
@@ -162,7 +167,7 @@ class StormClient {
162
167
  });
163
168
  }
164
169
 
165
- public createUIUserJourneys(prompt: string, conversationId?: string) {
170
+ public createUIUserJourneys(prompt: BasePromptRequest, conversationId?: string) {
166
171
  return this.send('/v2/ui/user-journeys', {
167
172
  prompt: prompt,
168
173
  conversationId,
@@ -175,7 +180,7 @@ class StormClient {
175
180
  });
176
181
  }
177
182
 
178
- public createUILandingPages(prompt: string, conversationId?: string) {
183
+ public createUILandingPages(prompt: BasePromptRequest, conversationId?: string) {
179
184
  return this.send('/v2/ui/landing-pages', {
180
185
  prompt: prompt,
181
186
  conversationId,