openkbs 0.0.65 → 0.0.67
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/README.md +0 -2
- package/package.json +1 -1
- package/src/actions.js +93 -85
- package/src/index.js +16 -15
- package/templates/.claude/skills/openkbs/SKILL.md +184 -0
- package/templates/.claude/skills/openkbs/metadata.json +1 -0
- package/templates/.claude/skills/openkbs/reference/backend-sdk.md +428 -0
- package/templates/.claude/skills/openkbs/reference/commands.md +370 -0
- package/templates/.claude/skills/openkbs/reference/elastic-services.md +327 -0
- package/templates/.claude/skills/openkbs/reference/frontend-sdk.md +299 -0
- package/templates/platform/README.md +70 -0
- package/templates/platform/agents/assistant/app/instructions.txt +25 -0
- package/templates/platform/agents/assistant/app/settings.json +17 -0
- package/templates/platform/agents/assistant/src/Events/actions.js +81 -0
- package/templates/platform/agents/assistant/src/Events/onResponse.js +41 -0
- package/templates/platform/agents/assistant/src/Events/onResponse.json +3 -0
- package/templates/platform/agents/assistant/src/Frontend/contentRender.js +26 -0
- package/templates/platform/agents/assistant/src/Frontend/contentRender.json +10 -0
- package/templates/platform/functions/api/index.mjs +69 -0
- package/templates/platform/openkbs.json +14 -0
- package/templates/platform/site/index.html +76 -0
- package/version.json +3 -3
- package/templates/.openkbs/knowledge/metadata.json +0 -3
- package/templates/CLAUDE.md +0 -655
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/app/icon.png +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/app/instructions.txt +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/app/settings.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/scripts/run_job.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/scripts/utils/agent_client.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/actions.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/handler.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onRequest.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onRequest.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onResponse.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onResponse.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Frontend/contentRender.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Frontend/contentRender.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/README.md +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/app/instructions.txt +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/app/settings.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/actions.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onRequest.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onRequest.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onResponse.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onResponse.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Frontend/contentRender.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Frontend/contentRender.json +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# Frontend SDK Reference
|
|
2
|
+
|
|
3
|
+
OpenKBS frontend is a React 18 application. Customize through `src/Frontend/contentRender.js`.
|
|
4
|
+
|
|
5
|
+
## Built-in Libraries (No Install Needed)
|
|
6
|
+
|
|
7
|
+
These libraries are provided by OpenKBS and marked with `(fixed)` in `contentRender.json`:
|
|
8
|
+
|
|
9
|
+
- React 18 (`react`, `react-dom`)
|
|
10
|
+
- Material-UI (`@mui/material`, `@mui/icons-material`)
|
|
11
|
+
- Emotion (`@emotion/react`, `@emotion/styled`)
|
|
12
|
+
|
|
13
|
+
## contentRender.js Exports
|
|
14
|
+
|
|
15
|
+
| Export | Purpose |
|
|
16
|
+
|--------|---------|
|
|
17
|
+
| `onRenderChatMessage` | Custom message rendering |
|
|
18
|
+
| `Header` | Custom header component |
|
|
19
|
+
|
|
20
|
+
## onRenderChatMessage
|
|
21
|
+
|
|
22
|
+
Receives each message and returns custom rendering:
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
const onRenderChatMessage = async (params) => {
|
|
26
|
+
const { content, role } = params.messages[params.msgIndex];
|
|
27
|
+
const { msgIndex, messages, markdownHandler } = params;
|
|
28
|
+
|
|
29
|
+
// Return null for default markdown rendering
|
|
30
|
+
// Return React component for custom rendering
|
|
31
|
+
// Return JSON.stringify({ type: 'HIDDEN_MESSAGE' }) to hide
|
|
32
|
+
|
|
33
|
+
return null;
|
|
34
|
+
};
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Parameters
|
|
38
|
+
|
|
39
|
+
- `params.messages` - All messages in conversation
|
|
40
|
+
- `params.msgIndex` - Current message index
|
|
41
|
+
- `params.markdownHandler` - Function to render markdown
|
|
42
|
+
- `params.setSystemAlert({ severity, message })` - Show alerts (success, error, warning, info)
|
|
43
|
+
- `params.setBlockingLoading(bool)` - Show loading overlay
|
|
44
|
+
- `params.RequestChatAPI(messages)` - Send messages to LLM
|
|
45
|
+
- `params.kbUserData()` - Get user info
|
|
46
|
+
- `params.generateMsgId()` - Generate unique message ID
|
|
47
|
+
- `params.theme` - Current MUI theme
|
|
48
|
+
|
|
49
|
+
### Return Values
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// Default rendering
|
|
53
|
+
return null;
|
|
54
|
+
|
|
55
|
+
// Custom component
|
|
56
|
+
return <div>Custom content</div>;
|
|
57
|
+
|
|
58
|
+
// Hide message
|
|
59
|
+
return JSON.stringify({ type: 'HIDDEN_MESSAGE' });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Header Component
|
|
63
|
+
|
|
64
|
+
Customize the chat header:
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const Header = ({ setRenderSettings }) => {
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
setRenderSettings({
|
|
70
|
+
disableShareButton: true,
|
|
71
|
+
disableBalanceView: true
|
|
72
|
+
});
|
|
73
|
+
}, [setRenderSettings]);
|
|
74
|
+
|
|
75
|
+
return <div>Custom Header</div>;
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Command Rendering Pattern
|
|
80
|
+
|
|
81
|
+
Define commands with icons:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
// commands.js
|
|
85
|
+
import SearchIcon from '@mui/icons-material/Search';
|
|
86
|
+
import ImageIcon from '@mui/icons-material/Image';
|
|
87
|
+
|
|
88
|
+
export const COMMANDS = {
|
|
89
|
+
googleSearch: { icon: SearchIcon },
|
|
90
|
+
createAIImage: { icon: ImageIcon },
|
|
91
|
+
cleanupMemory: { icon: ClearIcon, selfClosing: true }
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Generate regex patterns
|
|
95
|
+
export const COMMAND_PATTERNS = Object.entries(COMMANDS).map(([name, config]) => {
|
|
96
|
+
if (config.selfClosing) {
|
|
97
|
+
return new RegExp(`<${name}\\s*\\/>`);
|
|
98
|
+
}
|
|
99
|
+
return new RegExp(`<${name}>[\\s\\S]*?<\\/${name}>`);
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Command Circle Component
|
|
104
|
+
|
|
105
|
+
Render commands as interactive icons:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
const CommandCircle = ({ command, response }) => {
|
|
109
|
+
const IconComponent = COMMANDS[command.name]?.icon || BoltIcon;
|
|
110
|
+
const isSuccess = response && !response.error;
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<Tooltip title={getTooltipContent()}>
|
|
114
|
+
<Box sx={{
|
|
115
|
+
width: 36, height: 36,
|
|
116
|
+
borderRadius: '50%',
|
|
117
|
+
backgroundColor: isSuccess ? 'rgba(76, 175, 80, 0.08)' : 'rgba(0, 0, 0, 0.04)',
|
|
118
|
+
border: '2px solid',
|
|
119
|
+
borderColor: isSuccess ? 'rgba(76, 175, 80, 0.3)' : 'rgba(0, 0, 0, 0.12)',
|
|
120
|
+
display: 'flex',
|
|
121
|
+
alignItems: 'center',
|
|
122
|
+
justifyContent: 'center'
|
|
123
|
+
}}>
|
|
124
|
+
<IconComponent sx={{ fontSize: 18 }} />
|
|
125
|
+
</Box>
|
|
126
|
+
</Tooltip>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Image Display with Download
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
const ImageWithDownload = ({ imageUrl }) => {
|
|
135
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
136
|
+
|
|
137
|
+
const handleDownload = async () => {
|
|
138
|
+
const link = document.createElement('a');
|
|
139
|
+
link.download = 'image.png';
|
|
140
|
+
|
|
141
|
+
const response = await fetch(imageUrl);
|
|
142
|
+
const blob = await response.blob();
|
|
143
|
+
link.href = URL.createObjectURL(blob);
|
|
144
|
+
link.click();
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<div>
|
|
149
|
+
<img
|
|
150
|
+
src={imageUrl}
|
|
151
|
+
onLoad={() => setIsLoading(false)}
|
|
152
|
+
style={{ maxWidth: '100%', borderRadius: 8 }}
|
|
153
|
+
/>
|
|
154
|
+
{!isLoading && (
|
|
155
|
+
<button onClick={handleDownload}>
|
|
156
|
+
<DownloadIcon /> Download
|
|
157
|
+
</button>
|
|
158
|
+
)}
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Parsing JSON Results
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
const onRenderChatMessage = async (params) => {
|
|
168
|
+
const { content } = params.messages[params.msgIndex];
|
|
169
|
+
|
|
170
|
+
let JSONData;
|
|
171
|
+
try { JSONData = JSON.parse(content); } catch (e) {}
|
|
172
|
+
|
|
173
|
+
// Handle CHAT_IMAGE result
|
|
174
|
+
if (JSONData?.type === 'CHAT_IMAGE' && JSONData?.data?.imageUrl) {
|
|
175
|
+
return <ImageWithDownload imageUrl={JSONData.data.imageUrl} />;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Hide CONTINUE messages
|
|
179
|
+
if (JSONData?.type === 'CONTINUE') {
|
|
180
|
+
return JSON.stringify({ type: 'HIDDEN_MESSAGE' });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return null;
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## contentRender.json
|
|
188
|
+
|
|
189
|
+
Declare dependencies:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"dependencies": {
|
|
194
|
+
"react": "^18.2.0 (fixed)",
|
|
195
|
+
"react-dom": "^18.2.0 (fixed)",
|
|
196
|
+
"@mui/material": "^5.16.1 (fixed)",
|
|
197
|
+
"@mui/icons-material": "^5.16.1 (fixed)",
|
|
198
|
+
"@emotion/react": "^11.10.6 (fixed)",
|
|
199
|
+
"@emotion/styled": "^11.10.6 (fixed)"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The `(fixed)` suffix indicates built-in libraries that don't need bundling.
|
|
205
|
+
|
|
206
|
+
## Frontend openkbs Object
|
|
207
|
+
|
|
208
|
+
The `openkbs` object is available globally in frontend code.
|
|
209
|
+
|
|
210
|
+
### Item CRUD
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
// Create item
|
|
214
|
+
await openkbs.createItem({
|
|
215
|
+
itemType: 'memory',
|
|
216
|
+
itemId: 'memory_key',
|
|
217
|
+
body: { value: 'data' }
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Update item
|
|
221
|
+
await openkbs.updateItem({
|
|
222
|
+
itemType: 'memory',
|
|
223
|
+
itemId: 'memory_key',
|
|
224
|
+
body: { value: 'updated' }
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Get single item
|
|
228
|
+
const item = await openkbs.getItem('memory_key');
|
|
229
|
+
console.log(item.item.body.value);
|
|
230
|
+
|
|
231
|
+
// Fetch multiple items
|
|
232
|
+
const items = await openkbs.fetchItems({
|
|
233
|
+
itemType: 'memory',
|
|
234
|
+
beginsWith: 'memory_',
|
|
235
|
+
limit: 100
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Delete item
|
|
239
|
+
await openkbs.deleteItem('memory_key');
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Files API
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// List files
|
|
246
|
+
const files = await openkbs.Files.listFiles('files');
|
|
247
|
+
// Returns: [{ Key, Size, LastModified }, ...]
|
|
248
|
+
|
|
249
|
+
// Upload with progress
|
|
250
|
+
const onProgress = (percent) => console.log(`${percent}%`);
|
|
251
|
+
await openkbs.Files.uploadFileAPI(fileObject, 'files', onProgress);
|
|
252
|
+
|
|
253
|
+
// Delete file
|
|
254
|
+
await openkbs.Files.deleteRawKBFile('filename.jpg', 'files');
|
|
255
|
+
|
|
256
|
+
// Rename file
|
|
257
|
+
await openkbs.Files.renameFile('old.jpg', 'new.jpg', 'files');
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Sharing API
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
// Share KB
|
|
264
|
+
await openkbs.KBAPI.shareKBWith('user@example.com');
|
|
265
|
+
|
|
266
|
+
// Get shares
|
|
267
|
+
const shares = await openkbs.KBAPI.getKBShares();
|
|
268
|
+
// Returns: { sharedWith: ['email1', 'email2'] }
|
|
269
|
+
|
|
270
|
+
// Remove share
|
|
271
|
+
await openkbs.KBAPI.unshareKBWith('user@example.com');
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Properties
|
|
275
|
+
|
|
276
|
+
```javascript
|
|
277
|
+
openkbs.kbId // Current KB ID
|
|
278
|
+
openkbs.isMobile // Boolean - is mobile device
|
|
279
|
+
openkbs.KBData // KB metadata
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Debug Mode
|
|
283
|
+
|
|
284
|
+
Add `?debug=1` to URL to see raw messages:
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
https://YOUR_KB_ID.apps.openkbs.com?debug=1
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Mobile Detection
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
const isMobile = window.innerWidth < 960;
|
|
294
|
+
// Or use: openkbs.isMobile
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Complete Example
|
|
298
|
+
|
|
299
|
+
See [examples/ai-marketing-agent/src/Frontend/](../examples/ai-marketing-agent/src/Frontend/) for a full implementation.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# {{APP_NAME}} Platform
|
|
2
|
+
|
|
3
|
+
OpenKBS full-stack platform with AI agents, serverless functions, and static site.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
{{APP_NAME}}/
|
|
9
|
+
├── agents/ # AI agents
|
|
10
|
+
│ └── assistant/ # Sample assistant agent
|
|
11
|
+
│ ├── app/
|
|
12
|
+
│ │ ├── settings.json
|
|
13
|
+
│ │ └── instructions.txt
|
|
14
|
+
│ └── src/
|
|
15
|
+
│ ├── Events/
|
|
16
|
+
│ └── Frontend/
|
|
17
|
+
├── functions/ # Serverless Lambda functions
|
|
18
|
+
│ └── api/
|
|
19
|
+
│ └── index.mjs # Sample API endpoint
|
|
20
|
+
├── site/ # Static site for whitelabel
|
|
21
|
+
│ └── index.html
|
|
22
|
+
├── openkbs.json # Elastic services configuration
|
|
23
|
+
└── README.md
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Deploy
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Deploy elastic services (postgres, storage, pulse)
|
|
30
|
+
openkbs deploy
|
|
31
|
+
|
|
32
|
+
# Deploy the API function
|
|
33
|
+
openkbs fn push api
|
|
34
|
+
|
|
35
|
+
# Deploy static site
|
|
36
|
+
openkbs site push
|
|
37
|
+
|
|
38
|
+
# Deploy an agent
|
|
39
|
+
cd agents/assistant
|
|
40
|
+
openkbs push
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Elastic Services
|
|
44
|
+
|
|
45
|
+
Enabled in `openkbs.json`:
|
|
46
|
+
|
|
47
|
+
- **Postgres**: `openkbs postgres shell` to connect
|
|
48
|
+
- **Storage**: `openkbs storage ls` to list files
|
|
49
|
+
- **Pulse**: `openkbs pulse status` for WebSocket info
|
|
50
|
+
- **Functions**: `openkbs fn list` to see deployed functions
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Check stack status
|
|
56
|
+
openkbs stack status
|
|
57
|
+
|
|
58
|
+
# View function logs
|
|
59
|
+
openkbs fn logs api
|
|
60
|
+
|
|
61
|
+
# Invoke function locally
|
|
62
|
+
openkbs fn invoke api '{"action": "hello"}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## URLs
|
|
66
|
+
|
|
67
|
+
After deployment:
|
|
68
|
+
- Site: `https://YOUR_DOMAIN/`
|
|
69
|
+
- API: `https://fn.openkbs.com/YOUR_KB_ID/api`
|
|
70
|
+
- Agent: `https://YOUR_KB_ID.apps.openkbs.com`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
You are an AI assistant for {{APP_NAME}}.
|
|
2
|
+
|
|
3
|
+
## Available Commands
|
|
4
|
+
|
|
5
|
+
<googleSearch>
|
|
6
|
+
{"query": "search terms"}
|
|
7
|
+
</googleSearch>
|
|
8
|
+
Search the web for information.
|
|
9
|
+
|
|
10
|
+
<setMemory>
|
|
11
|
+
{"itemId": "memory_key", "value": "data to remember"}
|
|
12
|
+
</setMemory>
|
|
13
|
+
Save data to memory. The itemId must start with "memory_".
|
|
14
|
+
|
|
15
|
+
<deleteItem>
|
|
16
|
+
{"itemId": "memory_key"}
|
|
17
|
+
</deleteItem>
|
|
18
|
+
Delete a memory item.
|
|
19
|
+
|
|
20
|
+
## Guidelines
|
|
21
|
+
|
|
22
|
+
1. Be helpful and concise
|
|
23
|
+
2. Use commands when needed to assist the user
|
|
24
|
+
3. Remember important information using setMemory
|
|
25
|
+
4. Search the web when you need current information
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kbTitle": "{{APP_NAME}} Assistant",
|
|
3
|
+
"kbDescription": "AI assistant for {{APP_NAME}} platform",
|
|
4
|
+
"model": "anthropic/claude-sonnet-4-20250514",
|
|
5
|
+
"maxTokens": 16000,
|
|
6
|
+
"itemTypes": {
|
|
7
|
+
"memory": {
|
|
8
|
+
"attributes": [
|
|
9
|
+
{ "attrName": "itemId", "attrType": "itemId", "encrypted": false },
|
|
10
|
+
{ "attrName": "body", "attrType": "body", "encrypted": true }
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"options": {
|
|
15
|
+
"priorityItems": [{ "prefix": "memory_", "limit": 50 }]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command actions for {{APP_NAME}} Assistant
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const getActions = (meta, event) => [
|
|
6
|
+
// Google Search
|
|
7
|
+
[/<googleSearch>([\s\S]*?)<\/googleSearch>/s, async (match) => {
|
|
8
|
+
try {
|
|
9
|
+
const data = JSON.parse(match[1].trim());
|
|
10
|
+
const results = await openkbs.googleSearch(data.query);
|
|
11
|
+
|
|
12
|
+
const formatted = results?.slice(0, 5).map(({ title, link, snippet }) => ({
|
|
13
|
+
title, link, snippet
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
type: 'SEARCH_RESULTS',
|
|
18
|
+
data: formatted,
|
|
19
|
+
...meta,
|
|
20
|
+
_meta_actions: ["REQUEST_CHAT_MODEL"]
|
|
21
|
+
};
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return { error: e.message, ...meta, _meta_actions: ["REQUEST_CHAT_MODEL"] };
|
|
24
|
+
}
|
|
25
|
+
}],
|
|
26
|
+
|
|
27
|
+
// Set Memory
|
|
28
|
+
[/<setMemory>([\s\S]*?)<\/setMemory>/s, async (match) => {
|
|
29
|
+
try {
|
|
30
|
+
const data = JSON.parse(match[1].trim());
|
|
31
|
+
|
|
32
|
+
if (!data.itemId?.startsWith('memory_')) {
|
|
33
|
+
return {
|
|
34
|
+
type: "MEMORY_ERROR",
|
|
35
|
+
error: "itemId must start with 'memory_'",
|
|
36
|
+
_meta_actions: ["REQUEST_CHAT_MODEL"]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
await openkbs.updateItem({
|
|
42
|
+
itemType: 'memory',
|
|
43
|
+
itemId: data.itemId,
|
|
44
|
+
body: { value: data.value, updatedAt: new Date().toISOString() }
|
|
45
|
+
});
|
|
46
|
+
} catch (e) {
|
|
47
|
+
await openkbs.createItem({
|
|
48
|
+
itemType: 'memory',
|
|
49
|
+
itemId: data.itemId,
|
|
50
|
+
body: { value: data.value, updatedAt: new Date().toISOString() }
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
type: "MEMORY_SAVED",
|
|
56
|
+
itemId: data.itemId,
|
|
57
|
+
...meta,
|
|
58
|
+
_meta_actions: ["REQUEST_CHAT_MODEL"]
|
|
59
|
+
};
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return { error: e.message, ...meta, _meta_actions: ["REQUEST_CHAT_MODEL"] };
|
|
62
|
+
}
|
|
63
|
+
}],
|
|
64
|
+
|
|
65
|
+
// Delete Item
|
|
66
|
+
[/<deleteItem>([\s\S]*?)<\/deleteItem>/s, async (match) => {
|
|
67
|
+
try {
|
|
68
|
+
const data = JSON.parse(match[1].trim());
|
|
69
|
+
await openkbs.deleteItem(data.itemId);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
type: "ITEM_DELETED",
|
|
73
|
+
itemId: data.itemId,
|
|
74
|
+
...meta,
|
|
75
|
+
_meta_actions: ["REQUEST_CHAT_MODEL"]
|
|
76
|
+
};
|
|
77
|
+
} catch (e) {
|
|
78
|
+
return { error: e.message, ...meta, _meta_actions: ["REQUEST_CHAT_MODEL"] };
|
|
79
|
+
}
|
|
80
|
+
}]
|
|
81
|
+
];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getActions } from './actions.js';
|
|
2
|
+
|
|
3
|
+
export const handler = async (event) => {
|
|
4
|
+
const response = event?.payload?.response?.content ?? event?.payload?.response;
|
|
5
|
+
if (!response) return { type: 'EMPTY_RESPONSE' };
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
role: 'tool',
|
|
9
|
+
name: 'command_executor',
|
|
10
|
+
msgId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const actions = getActions(meta, event);
|
|
14
|
+
const results = [];
|
|
15
|
+
|
|
16
|
+
for (const [pattern, handler] of actions) {
|
|
17
|
+
const matches = response.matchAll(new RegExp(pattern.source, pattern.flags + 'g'));
|
|
18
|
+
for (const match of matches) {
|
|
19
|
+
results.push(handler(match));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (results.length === 0) {
|
|
24
|
+
return { type: 'NO_COMMANDS', _meta_actions: [] };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const resolved = await Promise.all(results);
|
|
28
|
+
|
|
29
|
+
if (resolved.length === 1) {
|
|
30
|
+
return resolved[0];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
type: 'MULTI_COMMAND_RESULT',
|
|
35
|
+
results: resolved,
|
|
36
|
+
...meta,
|
|
37
|
+
_meta_actions: resolved.some(r => r._meta_actions?.includes("REQUEST_CHAT_MODEL"))
|
|
38
|
+
? ["REQUEST_CHAT_MODEL"]
|
|
39
|
+
: []
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
const onRenderChatMessage = async (params) => {
|
|
4
|
+
const { content, role } = params.messages[params.msgIndex];
|
|
5
|
+
|
|
6
|
+
// Hide tool messages
|
|
7
|
+
if (role === 'tool') {
|
|
8
|
+
return JSON.stringify({ type: 'HIDDEN_MESSAGE' });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return null; // Default rendering
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const Header = ({ setRenderSettings }) => {
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
setRenderSettings({
|
|
17
|
+
disableBalanceView: true
|
|
18
|
+
});
|
|
19
|
+
}, [setRenderSettings]);
|
|
20
|
+
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const exports = { onRenderChatMessage, Header };
|
|
25
|
+
window.contentRender = exports;
|
|
26
|
+
export default exports;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example API function for {{APP_NAME}} platform
|
|
3
|
+
*
|
|
4
|
+
* Endpoint: https://fn.openkbs.com/YOUR_KB_ID/api
|
|
5
|
+
*
|
|
6
|
+
* This function has access to:
|
|
7
|
+
* - process.env.POSTGRES_URL (if postgres enabled)
|
|
8
|
+
* - process.env.KB_ID (your whitelabel kbId)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const handler = async (event) => {
|
|
12
|
+
const body = JSON.parse(event.body || '{}');
|
|
13
|
+
const { action, data } = body;
|
|
14
|
+
|
|
15
|
+
// CORS headers
|
|
16
|
+
const headers = {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
'Access-Control-Allow-Origin': '*',
|
|
19
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
20
|
+
'Access-Control-Allow-Headers': 'Content-Type'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Handle preflight
|
|
24
|
+
if (event.httpMethod === 'OPTIONS') {
|
|
25
|
+
return { statusCode: 200, headers, body: '' };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
switch (action) {
|
|
30
|
+
case 'hello':
|
|
31
|
+
return {
|
|
32
|
+
statusCode: 200,
|
|
33
|
+
headers,
|
|
34
|
+
body: JSON.stringify({
|
|
35
|
+
message: 'Hello from {{APP_NAME}} API!',
|
|
36
|
+
timestamp: new Date().toISOString(),
|
|
37
|
+
input: data
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
case 'health':
|
|
42
|
+
return {
|
|
43
|
+
statusCode: 200,
|
|
44
|
+
headers,
|
|
45
|
+
body: JSON.stringify({
|
|
46
|
+
status: 'healthy',
|
|
47
|
+
kbId: process.env.KB_ID,
|
|
48
|
+
hasPostgres: !!process.env.POSTGRES_URL
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
default:
|
|
53
|
+
return {
|
|
54
|
+
statusCode: 400,
|
|
55
|
+
headers,
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
error: 'Unknown action',
|
|
58
|
+
availableActions: ['hello', 'health']
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
statusCode: 500,
|
|
65
|
+
headers,
|
|
66
|
+
body: JSON.stringify({ error: error.message })
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|