@kapeta/local-cluster-service 0.55.2 → 0.56.0

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,23 @@
1
+ # [0.56.0](https://github.com/kapetacom/local-cluster-service/compare/v0.55.3...v0.56.0) (2024-07-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * better abort handling on reqs ([412c2f9](https://github.com/kapetacom/local-cluster-service/commit/412c2f9ab7e49f5e5d35d6b1ad4d683dafb170b8))
7
+ * guard against \\n in output ([5ae55ed](https://github.com/kapetacom/local-cluster-service/commit/5ae55ed2d6cacedb6867256a4245b413b14e061c))
8
+
9
+
10
+ ### Features
11
+
12
+ * add /block/codegen endpoint to (re)run codegen on a block ([0fec94b](https://github.com/kapetacom/local-cluster-service/commit/0fec94b563fd1bbc340c478b937f2848c9a4e644))
13
+
14
+ ## [0.55.3](https://github.com/kapetacom/local-cluster-service/compare/v0.55.2...v0.55.3) (2024-07-12)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * ensure versions on predefined blocks are the latest ([0a841bc](https://github.com/kapetacom/local-cluster-service/commit/0a841bc221cfac09cac41992a06385be1da24197))
20
+
1
21
  ## [0.55.2](https://github.com/kapetacom/local-cluster-service/compare/v0.55.1...v0.55.2) (2024-07-12)
2
22
 
3
23
 
package/definitions.d.ts CHANGED
@@ -47,4 +47,4 @@ declare module 'download-git-repo' {
47
47
  ): void;
48
48
 
49
49
  export = download;
50
- }
50
+ }
@@ -10,9 +10,10 @@ export declare class StormCodegen {
10
10
  private readonly blocks;
11
11
  private readonly out;
12
12
  private readonly events;
13
- private readonly tmpDir;
13
+ private tmpDir;
14
14
  private readonly conversationId;
15
15
  constructor(conversationId: string, userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[]);
16
+ setTmpDir(tmpDir: string): void;
16
17
  process(): Promise<void>;
17
18
  isAborted(): boolean;
18
19
  getStream(): StormStream;
@@ -107,6 +107,9 @@ class StormCodegen {
107
107
  this.tmpDir = path_2.default.join(node_os_1.default.tmpdir(), conversationId);
108
108
  this.conversationId = conversationId;
109
109
  }
110
+ setTmpDir(tmpDir) {
111
+ this.tmpDir = tmpDir;
112
+ }
110
113
  async process() {
111
114
  const promises = this.blocks.map((block) => {
112
115
  if (block.archetype) {
@@ -241,7 +244,7 @@ class StormCodegen {
241
244
  payload: {
242
245
  filename: data.payload.filename,
243
246
  path: (0, path_2.join)(this.getBasePath(blockUri.fullName), data.payload.filename),
244
- content: data.payload.content,
247
+ content: data.payload.content.replace(/\\n/g, '\n'),
245
248
  blockRef: ref,
246
249
  instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
247
250
  },
@@ -39,6 +39,7 @@ export interface StormOptions {
39
39
  desktopKind: string;
40
40
  desktopLanguage: string;
41
41
  gatewayKind: string;
42
+ [key: string]: string;
42
43
  }
43
44
  export declare function createPhaseStartEvent(type: StormEventPhaseType): StormEventPhases;
44
45
  export declare function createPhaseEndEvent(type: StormEventPhaseType): StormEventPhases;
@@ -66,7 +67,7 @@ export declare class StormEventParser {
66
67
  getEvents(): StormEvent[];
67
68
  isValid(): boolean;
68
69
  getError(): string;
69
- toResult(handle: string): Promise<StormDefinitions>;
70
+ toResult(handle: string, warn?: boolean): Promise<StormDefinitions>;
70
71
  toBlockDefinitions(handle: string): Promise<{
71
72
  [key: string]: BlockDefinitionInfo;
72
73
  }>;
@@ -244,7 +244,7 @@ class StormEventParser {
244
244
  getError() {
245
245
  return this.error;
246
246
  }
247
- async toResult(handle) {
247
+ async toResult(handle, warn = false) {
248
248
  const planRef = StormEventParser.toRef(handle, this.planName || 'undefined');
249
249
  const blockDefinitions = await this.toBlockDefinitions(handle);
250
250
  const refIdMap = {};
@@ -284,7 +284,9 @@ class StormEventParser {
284
284
  }
285
285
  const apiResource = apiProviderBlock.content.spec.providers?.find((p) => p.kind === this.options.apiKind && p.metadata.name === apiConnection.fromResource);
286
286
  if (!apiResource) {
287
- console.warn('API resource not found: %s on %s', apiConnection.fromResource, apiProviderRef.toNormalizedString(), apiConnection);
287
+ if (warn) {
288
+ console.warn('API resource not found: %s on %s', apiConnection.fromResource, apiProviderRef.toNormalizedString(), apiConnection);
289
+ }
288
290
  return;
289
291
  }
290
292
  const clientResource = clientConsumerBlock.content.spec.consumers?.find((clientResource) => {
@@ -295,7 +297,9 @@ class StormEventParser {
295
297
  return clientResource.metadata.name === apiConnection.toResource;
296
298
  });
297
299
  if (!clientResource) {
298
- console.warn('Client resource not found: %s on %s', apiConnection.toResource, clientConsumerRef.toNormalizedString(), apiConnection);
300
+ if (warn) {
301
+ console.warn('Client resource not found: %s on %s', apiConnection.toResource, clientConsumerRef.toNormalizedString(), apiConnection);
302
+ }
299
303
  return;
300
304
  }
301
305
  if (apiProviderBlock.content.spec.entities?.source?.value) {
@@ -340,7 +344,7 @@ class StormEventParser {
340
344
  blockId: refIdMap[fromRef.toNormalizedString()],
341
345
  resourceName: connection.fromResource,
342
346
  },
343
- mapping: this.toConnectionMapping(handle, connection, blockDefinitions),
347
+ mapping: this.toConnectionMapping(handle, connection, blockDefinitions, warn),
344
348
  };
345
349
  });
346
350
  const plan = {
@@ -368,7 +372,7 @@ class StormEventParser {
368
372
  const blockRef = StormEventParser.toRef(handle, blockInfo.name);
369
373
  let blockDefinitionInfo;
370
374
  if (blockInfo.archetype) {
371
- blockDefinitionInfo = await this.resolveArchetypeBlockDefinition(blockRef, blockInfo);
375
+ blockDefinitionInfo = await this.resolveArchetypeBlockDefinition(blockRef, blockInfo, handle);
372
376
  }
373
377
  else {
374
378
  blockDefinitionInfo = this.createBlockDefinitionInfo(blockRef, blockInfo, handle);
@@ -533,7 +537,7 @@ class StormEventParser {
533
537
  firstEntry.spec.source.value += api + '\n\n';
534
538
  }
535
539
  else {
536
- console.warn('Unable to find resource for API', api);
540
+ // this might be ok as we might receive api and types before resources from the ai-service
537
541
  }
538
542
  }
539
543
  });
@@ -596,7 +600,7 @@ class StormEventParser {
596
600
  }
597
601
  return '';
598
602
  }
599
- toConnectionMapping(handle, connection, blockDefinitions) {
603
+ toConnectionMapping(handle, connection, blockDefinitions, warn) {
600
604
  if (connection.fromResourceType !== 'API') {
601
605
  return;
602
606
  }
@@ -608,7 +612,9 @@ class StormEventParser {
608
612
  }
609
613
  const apiResource = apiProviderBlock.content.spec.providers?.find((p) => p.kind === this.options.apiKind && p.metadata.name === connection.fromResource);
610
614
  if (!apiResource) {
611
- console.warn('API resource not found: %s on %s', connection.fromResource, fromRef.toNormalizedString(), connection);
615
+ if (warn) {
616
+ console.warn('API resource not found: %s on %s', connection.fromResource, fromRef.toNormalizedString(), connection);
617
+ }
612
618
  return;
613
619
  }
614
620
  const apiMethods = kaplang_core_1.DSLConverters.toSchemaMethods(kaplang_core_1.DSLAPIParser.parse(apiResource.spec?.source?.value ?? '', {
@@ -681,14 +687,36 @@ class StormEventParser {
681
687
  }
682
688
  return undefined;
683
689
  }
684
- async resolveArchetypeBlockDefinition(blockRef, blockInfo) {
690
+ async resolveArchetypeBlockDefinition(blockRef, blockInfo, handle) {
685
691
  const predefinedBlock = predefined_1.PREDEFINED_BLOCKS.get(blockInfo.archetype);
686
692
  if (!predefinedBlock) {
687
693
  throw new Error('Predefined block not found for archetype [' + blockInfo.archetype + ']');
688
694
  }
695
+ const target = this.toBlockTarget(handle, blockInfo.type);
689
696
  const blockDefinition = await predefinedBlock.getBlockDefinition();
690
697
  lodash_1.default.set(blockDefinition, ['metadata', 'name'], blockRef.fullName);
691
698
  lodash_1.default.set(blockDefinition, ['metadata', 'title'], blockRef.name);
699
+ lodash_1.default.set(blockDefinition, ['spec', 'target', 'options'], target?.options);
700
+ const options = this.options;
701
+ function getKind(kind) {
702
+ for (const prop in options) {
703
+ if (options.hasOwnProperty(prop)) {
704
+ const value = options[prop];
705
+ if (value.startsWith(kind)) {
706
+ return value;
707
+ }
708
+ }
709
+ }
710
+ }
711
+ blockDefinition.kind = getKind((0, nodejs_utils_1.parseKapetaUri)(blockDefinition.kind).fullName) ?? blockDefinition.kind;
712
+ for (const provider of blockDefinition.spec.providers ?? []) {
713
+ provider.kind = getKind((0, nodejs_utils_1.parseKapetaUri)(provider.kind).fullName) ?? provider.kind;
714
+ }
715
+ for (const consumer of blockDefinition.spec.consumers ?? []) {
716
+ consumer.kind = getKind((0, nodejs_utils_1.parseKapetaUri)(consumer.kind).fullName) ?? consumer.kind;
717
+ }
718
+ blockDefinition.spec.target.kind =
719
+ getKind((0, nodejs_utils_1.parseKapetaUri)(blockDefinition.spec.target.kind).fullName) ?? blockDefinition.spec.target.kind;
692
720
  return {
693
721
  uri: blockRef.toNormalizedString(),
694
722
  aiName: blockInfo.name,
@@ -9,6 +9,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  const express_promise_router_1 = __importDefault(require("express-promise-router"));
11
11
  const fs_extra_1 = __importDefault(require("fs-extra"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const lodash_1 = __importDefault(require("lodash"));
12
14
  const cors_1 = require("../middleware/cors");
13
15
  const stringBody_1 = require("../middleware/stringBody");
14
16
  const stormClient_1 = require("./stormClient");
@@ -16,8 +18,6 @@ const events_1 = require("./events");
16
18
  const event_parser_1 = require("./event-parser");
17
19
  const codegen_1 = require("./codegen");
18
20
  const assetManager_1 = require("../assetManager");
19
- const path_1 = __importDefault(require("path"));
20
- const lodash_1 = __importDefault(require("lodash"));
21
21
  const router = (0, express_promise_router_1.default)();
22
22
  router.use('/', cors_1.corsHandler);
23
23
  router.use('/', stringBody_1.stringBody);
@@ -82,10 +82,12 @@ router.post('/:handle/all', async (req, res) => {
82
82
  res.end();
83
83
  return;
84
84
  }
85
- const result = await eventParser.toResult(handle);
85
+ const result = await eventParser.toResult(handle, true);
86
86
  if (metaStream.isAborted()) {
87
87
  return;
88
88
  }
89
+ // Cancel debounce, we don't need to send the plan again
90
+ sendUpdatedPlan.cancel();
89
91
  sendDefinitions(res, result);
90
92
  if (!req.query.skipCodegen) {
91
93
  try {
@@ -134,6 +136,26 @@ router.post('/block/create', async (req, res) => {
134
136
  res.status(500).send({ error: err.message });
135
137
  }
136
138
  });
139
+ router.post('/block/codegen', async (req, res) => {
140
+ const body = JSON.parse(req.stringBody ?? '{}');
141
+ console.log('Codegen request', body);
142
+ const conversationId = req.headers[stormClient_1.ConversationIdHeader.toLowerCase()];
143
+ try {
144
+ const stormCodegen = new codegen_1.StormCodegen(conversationId ?? '', body.prompt, [body.block], body.events || []);
145
+ stormCodegen.setTmpDir(body.outDir);
146
+ onRequestAborted(req, res, () => {
147
+ stormCodegen.abort();
148
+ });
149
+ const codegenPromise = streamStormPartialResponse(stormCodegen.getStream(), res);
150
+ await stormCodegen.process();
151
+ await codegenPromise;
152
+ sendDone(res);
153
+ }
154
+ catch (err) {
155
+ console.error('Failed to generate code', err);
156
+ res.status(500).send({ error: err.message });
157
+ }
158
+ });
137
159
  function sendDefinitions(res, result) {
138
160
  sendEvent(res, {
139
161
  type: 'DEFINITION_CHANGE',
@@ -187,10 +209,7 @@ function sendEvent(res, evt) {
187
209
  res.write(JSON.stringify(evt) + '\n');
188
210
  }
189
211
  function onRequestAborted(req, res, onAborted) {
190
- req.on('close', () => {
191
- onAborted();
192
- });
193
- res.on('close', () => {
212
+ req.socket.on('close', () => {
194
213
  onAborted();
195
214
  });
196
215
  }
@@ -7,6 +7,7 @@ import { EventEmitter } from 'node:events';
7
7
  import { StormEvent } from './events';
8
8
  import { AIFileTypes, GeneratedFile } from '@kapeta/codegen';
9
9
  import { BlockDefinition } from '@kapeta/schemas';
10
+ import { BlockDefinitionInfo } from './event-parser';
10
11
  export declare class StormStream extends EventEmitter {
11
12
  private conversationId;
12
13
  private lines;
@@ -41,6 +42,12 @@ export interface StormCreateBlockRequest {
41
42
  tmpPath: string;
42
43
  newPath: string;
43
44
  }
45
+ export interface StormCodegenRequest {
46
+ block: BlockDefinitionInfo;
47
+ prompt: string;
48
+ events: StormEvent[];
49
+ outDir: string;
50
+ }
44
51
  export interface StormFileInfo extends GeneratedFile {
45
52
  type: AIFileTypes;
46
53
  }