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 +83 -0
- package/README.md +12 -0
- package/package.json +1 -1
- package/src/actions.js +54 -1
- package/src/index.js +13 -1
- package/src/utils.js +17 -0
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
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');
|