openkbs 0.0.30 → 0.0.32

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/MODIFY.md CHANGED
@@ -15,7 +15,7 @@ A typical OpenKBS project has the following key directories:
15
15
 
16
16
  * **`src/`**: Contains your custom source code.
17
17
  * **`Events/`**: Houses backend event handlers.
18
- * `actions.js`: Often used for shared logic/tool definitions.
18
+ * `actions.js`: Example file commonly used for shared logic/tools definitions.
19
19
  * `onRequest.js`: Handles incoming user messages before LLM processing.
20
20
  * `onRequest.json`: NPM dependencies for `onRequest.js`.
21
21
  * `onResponse.js`: Handles LLM responses before sending to the user.
@@ -32,41 +32,76 @@ A typical OpenKBS project has the following key directories:
32
32
  * `instructions.txt`: Instructions for the LLM.
33
33
  * `icon.png`: Application icon.
34
34
 
35
- ## Backend Dependencies and Secrets Management
35
+ #### Important Coding guidelines
36
+ Organize new features across multiple files (like Events/utils.js) rather than adding everything to actions.js; export functionality from separate modules and import them in actions.js as needed.
36
37
 
37
- To use external NPM packages in your backend event handlers, you must declare them in the corresponding `.json` file.
38
- OpenKBS also provides a secure way to handle sensitive information using the `{{secrets.your_secret_name}}` syntax.
38
+ #### onRequest and onResponse Handlers
39
39
 
40
- **Example: Using axios with an API key**
40
+ The core of the OpenKBS backend framework revolves around the `onRequest` and `onResponse` event handlers.
41
+ These handlers act as middleware, intercepting messages before and after they are processed by the LLM.
41
42
 
42
- 1. **Declare dependency in `src/Events/onRequest.json` and `src/Events/onResponse.json` **:
43
+ * **`onRequest` Handler:** This handler is invoked every time a user sends a message to the chat. It provides an opportunity to pre-process the user's input, extract commands and perform actions based on the user's message. The `onRequest.js` file must export a function that receives `request` and `metadata` parameters and returns a modified request object.
44
+
45
+ * **`onResponse` Handler:** This handler is invoked after the LLM generates a response. It allows post-processing of the LLM's output, execution of commands based on the LLM's intentions. The `onResponse.js` file must export a function that receives `response` and `metadata` parameters and returns a modified response object.
46
+
47
+ #### NPM Dependencies for Handlers
48
+
49
+ **Important**: Files with names starting with "on" (like onRequest.js) are entry points for Node.js builds:
50
+
51
+ 1. Each handler has its own build process
52
+ 2. If a file imports node-fetch, then node-fetch must be in that handler's JSON file
53
+ 3. Example: If utils.js uses node-fetch and is imported by onRequest.js, then node-fetch must be in onRequest.json
54
+
55
+
56
+ ## Backend Dependencies
57
+
58
+ To use external NPM packages in your backend event handlers, you must declare them in the corresponding `.json` file.
59
+
60
+ **Example: Using https module with an API key**
61
+
62
+ 1. **Declare dependencies** in both `src/Events/onRequest.json` and `src/Events/onResponse.json` (as each handler have separate build):
43
63
  ```json
44
64
  {
45
65
  "dependencies": {
46
- "axios": "^1.6.2"
66
+ "got": "^11.8.5"
47
67
  }
48
68
  }
49
69
  ```
50
70
 
51
- 2. **Implement and use in `src/Events/actions.js`**:
52
- ```javascript
53
- import axios from 'axios';
54
-
55
- export const getActions = (meta) => {
56
- return [
57
- [/\/?getNews\("(.*)"\)/, async (match) => {
58
- const topic = match[1];
59
- const response = await axios.get('https://newsapi.org/v2/everything', {
60
- params: {
61
- q: topic,
62
- apiKey: '{{secrets.news_api_key}}' // Securely injected at runtime
63
- }
64
- });
65
- return { result: response.data.articles, ...meta };
66
- }],
67
- // ... other actions
68
- ];
69
- };
70
- ```
71
+ 2. **Implement in any JavaScript file** (actions.js is just an example name):
72
+
73
+ ```javascript
74
+ export const getActions = (meta) => {
75
+ return [
76
+ [/\/?getNews\("(.*)"\)/, async (match) => {
77
+ const { body } = await got(`https://newsapi.org/v2/everything?q=${match[1]}&apiKey={{secrets.news_api_key}}`,
78
+ { responseType: 'json' });
79
+
80
+ return { result: body.articles, ...meta };
81
+ }],
82
+ // ... other actions
83
+ ];
84
+ };
85
+ ```
86
+
87
+ ## Secrets Management
88
+ OpenKBS provides a secure way to handle sensitive information using the `{{secrets.your_secret_name}}` syntax.
89
+ Never hardcode secrets in the code, if any secrets are provided by the user replace them with placeholders syntax above.
90
+ The user will later insert the secrets using the secrets manager
91
+
92
+ #### LLM Instructions
93
+ `app/instructions.txt`
94
+ This file contains the instructions for the agent
95
+
96
+ **Example Instructions:**
97
+
98
+ ```
99
+ You are an AI assistant.
100
+
101
+ You can execute the following commands:
71
102
 
72
- Define `news_api_key` in your application's secrets manager on the OpenKBS platform. The platform will inject the actual value at runtime, keeping your credentials secure while enabling you to make API calls with authenticated services.
103
+ /getNews("query")
104
+ Description: """
105
+ Get the latest news
106
+ """
107
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkbs",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "OpenKBS - Command Line Interface",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/actions.js CHANGED
@@ -247,12 +247,31 @@ async function pushAction(location = 'origin', targetFile, options) {
247
247
  }
248
248
 
249
249
  async function cloneAction(kbId) {
250
+ // Store the original directory so we can restore it if needed
251
+ const originalDir = process.cwd();
252
+
250
253
  try {
254
+ // Create a subdirectory with the name of the kbId
255
+ const targetDir = path.join(originalDir, kbId);
256
+
257
+ // Check if directory already exists
258
+ if (fs.existsSync(targetDir)) {
259
+ console.red(`Directory ${kbId} already exists.`);
260
+ return;
261
+ }
262
+
263
+ // Create the subdirectory
264
+ fs.mkdirSync(targetDir);
265
+
266
+ // Change to the new directory
267
+ process.chdir(targetDir);
268
+
251
269
  const localKBData = await fetchLocalKBData({forceInit: true});
252
270
 
253
271
  if (localKBData?.kbId) {
254
272
  console.red(`KB ${localKBData?.kbId} already saved in settings.json.`);
255
273
  console.yellow(`To pull the changes from OpenKBS remote use "openkbs pull"`);
274
+ process.chdir(originalDir); // Change back to original directory
256
275
  return;
257
276
  }
258
277
 
@@ -262,9 +281,18 @@ async function cloneAction(kbId) {
262
281
  await fetchAndSaveSettings({ kbId }, kbId, kbToken);
263
282
  await downloadIcon(kbId);
264
283
  await downloadFiles(['functions', 'frontend'], kbId, kbToken);
265
- console.green('Cloning complete!');
284
+ console.green(`Cloning complete! Files created in directory: ${kbId}`);
266
285
  } catch (error) {
267
286
  console.error('Error during clone operation:', error.message);
287
+ // Make sure we return to the original directory in case of error
288
+ if (process.cwd() !== originalDir) {
289
+ process.chdir(originalDir);
290
+ }
291
+ } finally {
292
+ // Always ensure we return to the original directory
293
+ if (process.cwd() !== originalDir) {
294
+ process.chdir(originalDir);
295
+ }
268
296
  }
269
297
  }
270
298
 
package/src/utils.js CHANGED
@@ -332,10 +332,10 @@ async function modifyKB(kbToken, kbData, prompt, files, options) {
332
332
  console.error('Error getting files from directories:', error);
333
333
  }
334
334
  }
335
-
335
+
336
336
  // Add MODIFY.md to files list if it exists
337
337
  if (hasModifyFile && !files.includes(modifyFilePath)) {
338
- files.push(modifyFilePath);
338
+ files.unshift(modifyFilePath);
339
339
  }
340
340
 
341
341
  const fileContents = await Promise.all(files.map(async (filePath) => {