openkbs 0.0.66 → 0.0.70

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.
Files changed (63) hide show
  1. package/README.md +1 -0
  2. package/elastic/README.md +1 -1
  3. package/elastic/functions.md +5 -5
  4. package/elastic/pulse.md +2 -2
  5. package/package.json +2 -2
  6. package/scripts/deploy.js +68 -0
  7. package/src/actions.js +59 -0
  8. package/src/index.js +8 -6
  9. package/templates/.claude/skills/openkbs/SKILL.md +37 -8
  10. package/templates/.claude/skills/openkbs/examples/monitoring-bot/README.md +55 -0
  11. package/templates/.claude/skills/openkbs/examples/monitoring-bot/app/instructions.txt +40 -0
  12. package/templates/.claude/skills/openkbs/examples/monitoring-bot/app/settings.json +41 -0
  13. package/templates/.claude/skills/openkbs/examples/monitoring-bot/openkbs.json +3 -0
  14. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/actions.js +141 -0
  15. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/handler.js +32 -0
  16. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/memoryHelpers.js +91 -0
  17. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onCronjob.js +105 -0
  18. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onPublicAPIRequest.js +165 -0
  19. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onRequest.js +2 -0
  20. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onResponse.js +2 -0
  21. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Frontend/contentRender.js +74 -0
  22. package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Frontend/contentRender.json +3 -0
  23. package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/auth/index.mjs +228 -0
  24. package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/auth/package.json +7 -0
  25. package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/posts/index.mjs +287 -0
  26. package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/posts/package.json +10 -0
  27. package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/settings.json +4 -0
  28. package/templates/.claude/skills/openkbs/examples/nodejs-demo/openkbs.json +16 -0
  29. package/templates/.claude/skills/openkbs/examples/nodejs-demo/site/index.html +658 -0
  30. package/templates/.claude/skills/openkbs/examples/nodejs-demo/site/settings.json +4 -0
  31. package/templates/.claude/skills/openkbs/patterns/cronjob-batch-processing.md +278 -0
  32. package/templates/.claude/skills/openkbs/patterns/cronjob-monitoring.md +341 -0
  33. package/templates/.claude/skills/openkbs/patterns/file-upload.md +205 -0
  34. package/templates/.claude/skills/openkbs/patterns/image-generation.md +139 -0
  35. package/templates/.claude/skills/openkbs/patterns/memory-system.md +264 -0
  36. package/templates/.claude/skills/openkbs/patterns/public-api-item-proxy.md +254 -0
  37. package/templates/.claude/skills/openkbs/patterns/scheduled-tasks.md +157 -0
  38. package/templates/.claude/skills/openkbs/patterns/telegram-webhook.md +424 -0
  39. package/templates/.claude/skills/openkbs/patterns/telegram.md +222 -0
  40. package/templates/.claude/skills/openkbs/patterns/vectordb-archive.md +231 -0
  41. package/templates/.claude/skills/openkbs/patterns/video-generation.md +145 -0
  42. package/templates/.claude/skills/openkbs/patterns/web-publishing.md +257 -0
  43. package/templates/.claude/skills/openkbs/reference/backend-sdk.md +13 -2
  44. package/templates/.claude/skills/openkbs/reference/elastic-services.md +61 -29
  45. package/templates/platform/README.md +35 -0
  46. package/templates/platform/agents/assistant/app/icon.png +0 -0
  47. package/templates/platform/agents/assistant/app/instructions.txt +13 -0
  48. package/templates/platform/agents/assistant/app/settings.json +13 -0
  49. package/templates/platform/agents/assistant/src/Events/actions.js +50 -0
  50. package/templates/platform/agents/assistant/src/Events/handler.js +54 -0
  51. package/templates/platform/agents/assistant/src/Events/onRequest.js +3 -0
  52. package/templates/platform/agents/assistant/src/Events/onRequest.json +5 -0
  53. package/templates/platform/agents/assistant/src/Events/onResponse.js +3 -0
  54. package/templates/platform/agents/assistant/src/Events/onResponse.json +5 -0
  55. package/templates/platform/agents/assistant/src/Frontend/contentRender.js +27 -0
  56. package/templates/platform/agents/assistant/src/Frontend/contentRender.json +10 -0
  57. package/templates/platform/functions/api/index.mjs +63 -0
  58. package/templates/platform/functions/api/package.json +4 -0
  59. package/templates/platform/openkbs.json +19 -0
  60. package/templates/platform/site/index.html +75 -0
  61. package/version.json +3 -3
  62. package/templates/.claude/skills/openkbs/examples/ai-copywriter-agent/scripts/run_job.js +0 -26
  63. package/templates/.claude/skills/openkbs/examples/ai-copywriter-agent/scripts/utils/agent_client.js +0 -265
@@ -0,0 +1,254 @@
1
+ # Public API Item Proxy Pattern
2
+
3
+ Complete working code for creating items via public API with geolocation capture.
4
+
5
+ ## Concept
6
+
7
+ Accept external requests to create items with:
8
+ - Client geolocation from CloudFront headers
9
+ - IP address capture
10
+ - Automatic encryption of sensitive fields
11
+ - Item type validation
12
+
13
+ ## onPublicAPIRequest.js
14
+
15
+ ```javascript
16
+ export const handler = async ({ payload, headers }) => {
17
+ const { item, attributes, itemType, action } = payload;
18
+
19
+ if (action === 'createItem') {
20
+ const enrichedItem = {};
21
+
22
+ // Capture geolocation from CloudFront headers
23
+ enrichedItem.country = openkbs.clientHeaders['cloudfront-viewer-country-name'];
24
+ enrichedItem.countryCode = openkbs.clientHeaders['cloudfront-viewer-country'];
25
+ enrichedItem.city = openkbs.clientHeaders['cloudfront-viewer-city'];
26
+ enrichedItem.ip = openkbs.clientHeaders['x-forwarded-for'];
27
+
28
+ // Add timestamp
29
+ enrichedItem.createdAt = new Date().toISOString();
30
+
31
+ // Process attributes with encryption
32
+ for (const attribute of attributes) {
33
+ const { attrName, encrypted } = attribute;
34
+
35
+ if (item[attrName] !== undefined) {
36
+ if (encrypted) {
37
+ enrichedItem[attrName] = await openkbs.encrypt(item[attrName]);
38
+ } else {
39
+ enrichedItem[attrName] = item[attrName];
40
+ }
41
+ }
42
+ }
43
+
44
+ // Create the item
45
+ return await openkbs.items({
46
+ action,
47
+ itemType,
48
+ attributes,
49
+ item: enrichedItem
50
+ });
51
+ }
52
+
53
+ // Handle other actions
54
+ if (action === 'getItem' || action === 'fetchItems') {
55
+ return await openkbs.items(payload);
56
+ }
57
+
58
+ return { error: 'Action not allowed', action };
59
+ };
60
+
61
+ module.exports = { handler };
62
+ ```
63
+
64
+ ## Extended Version with Validation
65
+
66
+ ```javascript
67
+ export const handler = async ({ payload, headers, queryStringParameters }) => {
68
+ const { item, attributes, itemType, action } = payload;
69
+
70
+ // Whitelist allowed item types
71
+ const ALLOWED_TYPES = ['lead', 'contact', 'feedback'];
72
+
73
+ if (!ALLOWED_TYPES.includes(itemType)) {
74
+ return {
75
+ statusCode: 403,
76
+ body: { error: 'Item type not allowed' }
77
+ };
78
+ }
79
+
80
+ // Rate limiting check (simple example)
81
+ const ip = openkbs.clientHeaders['x-forwarded-for'];
82
+ const rateLimitKey = `ratelimit_${ip}_${itemType}`;
83
+
84
+ try {
85
+ const rateLimit = await openkbs.getItem(rateLimitKey);
86
+ const count = rateLimit?.item?.body?.count || 0;
87
+ const lastReset = rateLimit?.item?.body?.lastReset;
88
+
89
+ // Reset counter every hour
90
+ const hourAgo = Date.now() - 3600000;
91
+ if (lastReset && new Date(lastReset).getTime() > hourAgo && count >= 100) {
92
+ return {
93
+ statusCode: 429,
94
+ body: { error: 'Rate limit exceeded', retryAfter: 3600 }
95
+ };
96
+ }
97
+ } catch (e) {
98
+ // No rate limit record yet
99
+ }
100
+
101
+ if (action === 'createItem') {
102
+ const enrichedItem = {
103
+ // Geolocation
104
+ country: openkbs.clientHeaders['cloudfront-viewer-country-name'],
105
+ countryCode: openkbs.clientHeaders['cloudfront-viewer-country'],
106
+ region: openkbs.clientHeaders['cloudfront-viewer-country-region-name'],
107
+ city: openkbs.clientHeaders['cloudfront-viewer-city'],
108
+ ip: ip,
109
+
110
+ // User agent
111
+ userAgent: headers['user-agent'],
112
+
113
+ // Timestamps
114
+ createdAt: new Date().toISOString(),
115
+
116
+ // Source tracking
117
+ source: queryStringParameters?.source || 'api',
118
+ referer: headers['referer']
119
+ };
120
+
121
+ // Process and encrypt fields
122
+ for (const attribute of attributes) {
123
+ const { attrName, encrypted } = attribute;
124
+
125
+ if (item[attrName] !== undefined) {
126
+ // Validate required fields
127
+ if (attribute.required && !item[attrName]) {
128
+ return {
129
+ statusCode: 400,
130
+ body: { error: `Missing required field: ${attrName}` }
131
+ };
132
+ }
133
+
134
+ if (encrypted) {
135
+ enrichedItem[attrName] = await openkbs.encrypt(item[attrName]);
136
+ } else {
137
+ enrichedItem[attrName] = item[attrName];
138
+ }
139
+ }
140
+ }
141
+
142
+ // Create the item
143
+ const result = await openkbs.items({
144
+ action,
145
+ itemType,
146
+ attributes,
147
+ item: enrichedItem
148
+ });
149
+
150
+ // Update rate limit counter
151
+ try {
152
+ await openkbs.createItem({
153
+ itemType: 'ratelimit',
154
+ itemId: rateLimitKey,
155
+ body: {
156
+ count: 1,
157
+ lastReset: new Date().toISOString()
158
+ }
159
+ });
160
+ } catch (e) {
161
+ // Update existing
162
+ const existing = await openkbs.getItem(rateLimitKey);
163
+ await openkbs.updateItem({
164
+ itemType: 'ratelimit',
165
+ itemId: rateLimitKey,
166
+ body: {
167
+ count: (existing?.item?.body?.count || 0) + 1,
168
+ lastReset: existing?.item?.body?.lastReset || new Date().toISOString()
169
+ }
170
+ });
171
+ }
172
+
173
+ return result;
174
+ }
175
+
176
+ return { error: 'Action not supported' };
177
+ };
178
+ ```
179
+
180
+ ## Frontend Usage
181
+
182
+ ```javascript
183
+ // From website form
184
+ async function submitLead(formData) {
185
+ const response = await fetch(
186
+ `https://chat.openkbs.com/publicAPIRequest?kbId=YOUR_KB_ID`,
187
+ {
188
+ method: 'POST',
189
+ headers: { 'Content-Type': 'application/json' },
190
+ body: JSON.stringify({
191
+ action: 'createItem',
192
+ itemType: 'lead',
193
+ attributes: [
194
+ { attrName: 'itemId', attrType: 'itemId', encrypted: false },
195
+ { attrName: 'body', attrType: 'body', encrypted: true }
196
+ ],
197
+ item: {
198
+ itemId: `lead_${Date.now()}`,
199
+ body: JSON.stringify({
200
+ name: formData.name,
201
+ email: formData.email,
202
+ message: formData.message
203
+ })
204
+ }
205
+ })
206
+ }
207
+ );
208
+
209
+ return response.json();
210
+ }
211
+ ```
212
+
213
+ ## settings.json - Item Type Configuration
214
+
215
+ ```json
216
+ {
217
+ "itemTypes": {
218
+ "lead": {
219
+ "attributes": [
220
+ { "attrName": "itemId", "attrType": "itemId", "encrypted": false },
221
+ { "attrName": "body", "attrType": "body", "encrypted": true }
222
+ ]
223
+ }
224
+ },
225
+ "options": {
226
+ "priorityItems": [
227
+ { "limit": 100, "prefix": "lead" }
228
+ ]
229
+ }
230
+ }
231
+ ```
232
+
233
+ ## Available CloudFront Headers
234
+
235
+ ```javascript
236
+ openkbs.clientHeaders['cloudfront-viewer-country'] // "US"
237
+ openkbs.clientHeaders['cloudfront-viewer-country-name'] // "United States"
238
+ openkbs.clientHeaders['cloudfront-viewer-country-region'] // "CA"
239
+ openkbs.clientHeaders['cloudfront-viewer-country-region-name'] // "California"
240
+ openkbs.clientHeaders['cloudfront-viewer-city'] // "Los Angeles"
241
+ openkbs.clientHeaders['cloudfront-viewer-latitude'] // "34.05"
242
+ openkbs.clientHeaders['cloudfront-viewer-longitude'] // "-118.24"
243
+ openkbs.clientHeaders['cloudfront-viewer-time-zone'] // "America/Los_Angeles"
244
+ openkbs.clientHeaders['x-forwarded-for'] // "1.2.3.4"
245
+ ```
246
+
247
+ ## Key Points
248
+
249
+ 1. **Geolocation from CloudFront** - Free, no external API needed
250
+ 2. **Encryption for sensitive data** - Use `openkbs.encrypt()`
251
+ 3. **Item type whitelisting** - Don't allow arbitrary types
252
+ 4. **Rate limiting** - Prevent abuse
253
+ 5. **Source tracking** - Query params for attribution
254
+ 6. **Timestamp enrichment** - Add createdAt automatically
@@ -0,0 +1,157 @@
1
+ # Scheduled Tasks Pattern
2
+
3
+ Complete working code for creating, listing, and deleting scheduled tasks.
4
+
5
+ ## actions.js
6
+
7
+ ```javascript
8
+ // Create scheduled task
9
+ [/<scheduleTask>([\s\S]*?)<\/scheduleTask>/s, async (match) => {
10
+ try {
11
+ const data = JSON.parse(match[1].trim());
12
+
13
+ let scheduledTime;
14
+
15
+ if (data.time) {
16
+ // Parse specific ISO time
17
+ let isoTimeStr = data.time.replace(' ', 'T');
18
+ if (!isoTimeStr.includes('Z') && !isoTimeStr.includes('+')) {
19
+ isoTimeStr += 'Z';
20
+ }
21
+ scheduledTime = new Date(isoTimeStr).getTime();
22
+ } else if (data.delay) {
23
+ // Parse relative delay: "30" (minutes), "2h" (hours), "1d" (days)
24
+ let delayMs = 0;
25
+ const delayStr = String(data.delay);
26
+ if (delayStr.endsWith('h')) {
27
+ delayMs = parseFloat(delayStr) * 60 * 60 * 1000;
28
+ } else if (delayStr.endsWith('d')) {
29
+ delayMs = parseFloat(delayStr) * 24 * 60 * 60 * 1000;
30
+ } else {
31
+ delayMs = parseFloat(delayStr) * 60 * 1000; // default minutes
32
+ }
33
+ scheduledTime = Date.now() + delayMs;
34
+ } else {
35
+ // Default: 1 hour from now
36
+ scheduledTime = Date.now() + (60 * 60 * 1000);
37
+ }
38
+
39
+ // Round to nearest minute (required by scheduler)
40
+ scheduledTime = Math.floor(scheduledTime / 60000) * 60000;
41
+
42
+ const response = await openkbs.kb({
43
+ action: 'createScheduledTask',
44
+ scheduledTime: scheduledTime,
45
+ taskPayload: {
46
+ message: `[SCHEDULED_TASK] ${data.message}`,
47
+ source: 'agent_scheduled',
48
+ createdAt: Date.now()
49
+ },
50
+ description: data.message.substring(0, 100)
51
+ });
52
+
53
+ return {
54
+ type: 'TASK_SCHEDULED',
55
+ data: {
56
+ scheduledTime: new Date(scheduledTime).toISOString(),
57
+ taskId: response.taskId,
58
+ message: data.message
59
+ },
60
+ ...meta
61
+ };
62
+ } catch (e) {
63
+ return { error: e.message || 'Failed to schedule task', ...meta };
64
+ }
65
+ }],
66
+
67
+ // List scheduled tasks
68
+ [/<getScheduledTasks\/>/s, async () => {
69
+ try {
70
+ const response = await openkbs.kb({ action: 'getScheduledTasks' });
71
+
72
+ return {
73
+ type: 'SCHEDULED_TASKS_LIST',
74
+ data: response,
75
+ ...meta
76
+ };
77
+ } catch (e) {
78
+ return { error: e.message || 'Failed to get scheduled tasks', ...meta };
79
+ }
80
+ }],
81
+
82
+ // Delete scheduled task
83
+ [/<deleteScheduledTask>([\s\S]*?)<\/deleteScheduledTask>/s, async (match) => {
84
+ try {
85
+ const data = JSON.parse(match[1].trim());
86
+
87
+ await openkbs.kb({
88
+ action: 'deleteScheduledTask',
89
+ timestamp: data.timestamp
90
+ });
91
+
92
+ return {
93
+ type: 'TASK_DELETED',
94
+ data: {
95
+ deletedTimestamp: data.timestamp,
96
+ message: 'Task deleted successfully'
97
+ },
98
+ ...meta
99
+ };
100
+ } catch (e) {
101
+ return { error: e.message || 'Failed to delete task', ...meta };
102
+ }
103
+ }]
104
+ ```
105
+
106
+ ## onCronjob.js - Handle Scheduled Task Execution
107
+
108
+ ```javascript
109
+ export const handler = async (event) => {
110
+ // Scheduled task payload is in event.payload
111
+ const taskPayload = event.payload;
112
+
113
+ if (taskPayload?.message?.includes('[SCHEDULED_TASK]')) {
114
+ // Create a new chat with the scheduled message
115
+ await openkbs.chats({
116
+ chatTitle: 'Scheduled Task',
117
+ message: JSON.stringify([{
118
+ type: "text",
119
+ text: taskPayload.message.replace('[SCHEDULED_TASK] ', '')
120
+ }])
121
+ });
122
+ }
123
+
124
+ return { success: true };
125
+ };
126
+
127
+ // Define cron schedule - runs every minute to check for due tasks
128
+ handler.CRON_SCHEDULE = "* * * * *";
129
+ ```
130
+
131
+ ## instructions.txt (LLM prompt)
132
+
133
+ ```
134
+ Scheduled Tasks:
135
+
136
+ Schedule task with delay:
137
+ <scheduleTask>{"message": "Send weekly report", "delay": "1h"}</scheduleTask>
138
+
139
+ Schedule at specific time:
140
+ <scheduleTask>{"message": "Meeting reminder", "time": "2025-01-15T10:00:00Z"}</scheduleTask>
141
+
142
+ Delay formats: "30" (minutes), "2h" (hours), "1d" (days)
143
+
144
+ List all scheduled tasks:
145
+ <getScheduledTasks/>
146
+
147
+ Delete a scheduled task:
148
+ <deleteScheduledTask>{"timestamp": 1704067200000}</deleteScheduledTask>
149
+ ```
150
+
151
+ ## Key Points
152
+
153
+ 1. **Time precision** - Scheduler works at minute-level, times are rounded
154
+ 2. **Task payload** - Use `[SCHEDULED_TASK]` prefix to identify in onCronjob
155
+ 3. **Creates new chat** - Task execution creates new chat conversation
156
+ 4. **Delete by timestamp** - Tasks are identified by their scheduled timestamp
157
+ 5. **CRON_SCHEDULE** - Define at end of onCronjob.js file