openkbs 0.0.28 → 0.0.31

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 ADDED
@@ -0,0 +1,83 @@
1
+ #### HUMAN-DEFINED REQUIREMENTS
2
+
3
+ Define any additional features, integrations, or behavior modifications
4
+
5
+ #### HUMAN-DEFINED REQUIREMENTS END
6
+
7
+
8
+ # OpenKBS Framework Technical Guide (For AI Coding Agents)
9
+
10
+ This guide provides a brief overview of developing backend and frontend logic for your OpenKBS app/agent.
11
+
12
+ ## Project Structure Overview
13
+
14
+ A typical OpenKBS project has the following key directories:
15
+
16
+ * **`src/`**: Contains your custom source code.
17
+ * **`Events/`**: Houses backend event handlers.
18
+ * `actions.js`: Often used for shared logic/tool definitions (does not have own NPM dependencies).
19
+ * `onRequest.js`: Handles incoming user messages before LLM processing.
20
+ * `onRequest.json`: NPM dependencies for `onRequest.js`.
21
+ * `onResponse.js`: Handles LLM responses before sending to the user.
22
+ * `onResponse.json`: NPM dependencies for `onResponse.js`.
23
+ * `onPublicAPIRequest.js`: Handles unauthenticated public API calls.
24
+ * `onPublicAPIRequest.json`: Dependencies for `onPublicAPIRequest.js`.
25
+ * `onAddMessages.js`: Handles messages added via the `chatAddMessages` API.
26
+ * `onAddMessages.json`: Dependencies for `onAddMessages.js`.
27
+ * **`Frontend/`**: Contains frontend customization logic.
28
+ * `contentRender.js`: Custom UI rendering for chat messages, headers, etc.
29
+ * `contentRender.json`: NPM dependencies for `contentRender.js`.
30
+ * **`app/`**: Application-level configuration.
31
+ * `settings.json`: Core application settings (model, vendor, etc.).
32
+ * `instructions.txt`: Instructions for the LLM.
33
+ * `icon.png`: Application icon.
34
+
35
+ #### onRequest and onResponse Handlers
36
+
37
+ The core of the OpenKBS backend framework revolves around the `onRequest` and `onResponse` event handlers.
38
+ These handlers act as middleware, intercepting messages before and after they are processed by the LLM.
39
+
40
+ * **`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.
41
+
42
+ * **`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.
43
+
44
+
45
+ ## Backend Dependencies
46
+
47
+ To use external NPM packages in your backend event handlers, you must declare them in the corresponding `.json` file.
48
+ OpenKBS also provides a secure way to handle sensitive information using the `{{secrets.your_secret_name}}` syntax.
49
+
50
+ **Example: Using axios with an API key**
51
+
52
+ 1. **Declare dependencies** in both `src/Events/onRequest.json` and `src/Events/onResponse.json` (as each handler have separate build):
53
+ ```json
54
+ {
55
+ "dependencies": {
56
+ "axios": "^1.6.2"
57
+ }
58
+ }
59
+ ```
60
+
61
+ 2. **Implement and use in `src/Events/actions.js`**:
62
+ ```javascript
63
+ import axios from 'axios';
64
+
65
+ export const getActions = (meta) => {
66
+ return [
67
+ [/\/?getNews\("(.*)"\)/, async (match) => {
68
+ const topic = match[1];
69
+ const response = await axios.get('https://newsapi.org/v2/everything', {
70
+ params: {
71
+ q: topic,
72
+ apiKey: '{{secrets.news_api_key}}' // Securely injected at runtime
73
+ }
74
+ });
75
+ return { result: response.data.articles, ...meta };
76
+ }],
77
+ // ... other actions
78
+ ];
79
+ };
80
+ ```
81
+ ## Secrets Management
82
+ Define `news_api_key` in your application's secrets manager on the OpenKBS platform.
83
+ The platform will inject the actual value at runtime, keeping your credentials secure while enabling you to make API calls with authenticated services.
package/README.md CHANGED
@@ -23,6 +23,7 @@ deploy and integrate AI agents and applications.
23
23
  - [onAddMessages Event Handler](#onaddmessages-event-handler)
24
24
  - [Meta Actions](#meta-actions)
25
25
  - [SDK](#sdk)
26
+ - [Managing Secrets](#managing-secrets)
26
27
  - [Application Settings](#application-settings)
27
28
  - [LLM Instructions](#llm-instructions)
28
29
  - [Execution Environment](#execution-environment)
@@ -631,6 +632,17 @@ const encryptedValue = await openkbs.encrypt(userData);
631
632
 
632
633
  ```
633
634
 
635
+ #### Managing Secrets
636
+ To securely manage sensitive information like API keys or database passwords within your backend event handlers (`onRequest`, `onResponse`, etc.), use the `{{secrets.your_secret_name}}` syntax.
637
+
638
+ Define the placeholder in your code:
639
+
640
+ ```javascript
641
+ const apiKey = '{{secrets.external_api_key}}';
642
+ const dbPassword = '{{secrets.db_password}}';
643
+ ```
644
+ The actual values for `external_api_key` and `db_password` are set securely within the OpenKBS platform's file manager for your application. These values are injected at runtime and are never committed to your code repository, ensuring your secrets remain confidential.
645
+
634
646
  #### Application Settings
635
647
  `app/settings.json`
636
648
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkbs",
3
- "version": "0.0.28",
3
+ "version": "0.0.31",
4
4
  "description": "OpenKBS - Command Line Interface",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/actions.js CHANGED
@@ -3,6 +3,7 @@ const os = require('os');
3
3
  const path = require('path');
4
4
  const express = require('express');
5
5
  const { exec, execSync } = require('child_process');
6
+ const https = require('https');
6
7
 
7
8
  const {
8
9
  fetchLocalKBData, fetchKBJWT, createAccountIdFromPublicKey, signPayload, getUserProfile, getKB,
@@ -359,6 +360,20 @@ async function deleteKBAction(kbId) {
359
360
  }
360
361
 
361
362
  async function modifyAction(prompt, files, options) {
363
+ // Check if MODIFY.md file exists in current directory
364
+ const modifyFilePath = path.join(process.cwd(), 'MODIFY.md');
365
+ const modifyFileExists = await fs.pathExists(modifyFilePath);
366
+
367
+ // If MODIFY.md doesn't exist, download it first
368
+ if (!modifyFileExists) {
369
+ console.yellow('MODIFY.md file not found. Downloading it first...');
370
+ try {
371
+ await downloadModifyAction();
372
+ } catch (error) {
373
+ console.yellow('Could not download MODIFY.md, continuing without it...');
374
+ }
375
+ }
376
+
362
377
  const { kbId } = await fetchLocalKBData();
363
378
  const {kbToken} = await fetchKBJWT(kbId);
364
379
  const kbData = await getKB(kbToken);
@@ -455,6 +470,43 @@ function installFrontendPackageAction(packageName) {
455
470
  }
456
471
  }
457
472
 
473
+ async function downloadModifyAction() {
474
+ const url = 'https://raw.githubusercontent.com/open-kbs/openkbs/refs/heads/main/MODIFY.md';
475
+ const filePath = path.join(process.cwd(), 'MODIFY.md');
476
+
477
+ console.log(`Downloading MODIFY.md template from GitHub...`);
478
+
479
+ return new Promise((resolve, reject) => {
480
+ https.get(url, (response) => {
481
+ if (response.statusCode === 200) {
482
+ const file = fs.createWriteStream(filePath);
483
+ response.pipe(file);
484
+
485
+ file.on('finish', () => {
486
+ file.close();
487
+ console.green(`Successfully downloaded MODIFY.md to ${filePath}`);
488
+ resolve();
489
+ });
490
+
491
+ file.on('error', (err) => {
492
+ fs.unlink(filePath, () => {}); // Delete the file if there was an error
493
+ console.red(`Error writing to file: ${err.message}`);
494
+ reject(err);
495
+ });
496
+ } else if (response.statusCode === 404) {
497
+ console.red(`File not found at ${url}`);
498
+ reject(new Error('File not found'));
499
+ } else {
500
+ console.red(`Failed to download file. Status code: ${response.statusCode}`);
501
+ reject(new Error(`HTTP Status Code: ${response.statusCode}`));
502
+ }
503
+ }).on('error', (err) => {
504
+ console.red(`Error downloading file: ${err.message}`);
505
+ reject(err);
506
+ });
507
+ });
508
+ }
509
+
458
510
  module.exports = {
459
511
  signAction,
460
512
  loginAction,
@@ -470,5 +522,6 @@ module.exports = {
470
522
  initByTemplateAction,
471
523
  logoutAction,
472
524
  installFrontendPackageAction,
473
- modifyAction
525
+ modifyAction,
526
+ downloadModifyAction
474
527
  };
package/src/index.js CHANGED
@@ -12,7 +12,7 @@ const {
12
12
  deleteKBAction,
13
13
  deleteFileAction,
14
14
  describeAction, deployAction, createByTemplateAction, initByTemplateAction,
15
- logoutAction, installFrontendPackageAction, modifyAction
15
+ logoutAction, installFrontendPackageAction, modifyAction, downloadModifyAction
16
16
  } = require('./actions');
17
17
 
18
18
 
@@ -141,4 +141,16 @@ program
141
141
  .description('Log out from OpenKBS by deleting the locally stored session token.')
142
142
  .action(logoutAction);
143
143
 
144
+ program
145
+ .command('init-modify')
146
+ .description('Download the latest MODIFY.md template from GitHub to help with KB modifications')
147
+ .action(downloadModifyAction)
148
+ .addHelpText('after', `
149
+ Examples:
150
+ $ openkbs init-modify
151
+
152
+ This will download the MODIFY.md template file from the OpenKBS GitHub repository to your current directory.
153
+ This file will be automatically included when you run the 'openkbs modify' command.
154
+ `);
155
+
144
156
  program.parse(process.argv);
package/src/utils.js CHANGED
@@ -311,6 +311,18 @@ async function modifyKB(kbToken, kbData, prompt, files, options) {
311
311
  const { kbId, key } = kbData;
312
312
  const url = options?.chatURL || CHAT_API_URL;
313
313
 
314
+ // Try to find and add MODIFY.md file
315
+ const modifyFilePath = path.join(process.cwd(), 'MODIFY.md');
316
+ let hasModifyFile = false;
317
+
318
+ try {
319
+ if (await fs.pathExists(modifyFilePath)) {
320
+ hasModifyFile = true;
321
+ }
322
+ } catch (error) {
323
+ console.error('Error checking for MODIFY.md:', error);
324
+ }
325
+
314
326
  if (!files || files.length === 0) {
315
327
  try {
316
328
  const srcFiles = await getAllFiles('./src');
@@ -321,6 +333,11 @@ async function modifyKB(kbToken, kbData, prompt, files, options) {
321
333
  }
322
334
  }
323
335
 
336
+ // Add MODIFY.md to files list if it exists
337
+ if (hasModifyFile && !files.includes(modifyFilePath)) {
338
+ files.unshift(modifyFilePath);
339
+ }
340
+
324
341
  const fileContents = await Promise.all(files.map(async (filePath) => {
325
342
  try {
326
343
  const content = await fs.readFile(filePath, 'utf8');