openkbs 0.0.67 → 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.
- package/README.md +1 -0
- package/elastic/README.md +1 -1
- package/elastic/functions.md +5 -5
- package/elastic/pulse.md +2 -2
- package/package.json +2 -2
- package/scripts/deploy.js +68 -0
- package/src/actions.js +7 -0
- package/templates/.claude/skills/openkbs/SKILL.md +37 -8
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/README.md +55 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/app/instructions.txt +40 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/app/settings.json +41 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/openkbs.json +3 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/actions.js +141 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/handler.js +32 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/memoryHelpers.js +91 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onCronjob.js +105 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onPublicAPIRequest.js +165 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onRequest.js +2 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onResponse.js +2 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Frontend/contentRender.js +74 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Frontend/contentRender.json +3 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/auth/index.mjs +228 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/auth/package.json +7 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/posts/index.mjs +287 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/posts/package.json +10 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/settings.json +4 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/openkbs.json +16 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/site/index.html +658 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/site/settings.json +4 -0
- package/templates/.claude/skills/openkbs/patterns/cronjob-batch-processing.md +278 -0
- package/templates/.claude/skills/openkbs/patterns/cronjob-monitoring.md +341 -0
- package/templates/.claude/skills/openkbs/patterns/file-upload.md +205 -0
- package/templates/.claude/skills/openkbs/patterns/image-generation.md +139 -0
- package/templates/.claude/skills/openkbs/patterns/memory-system.md +264 -0
- package/templates/.claude/skills/openkbs/patterns/public-api-item-proxy.md +254 -0
- package/templates/.claude/skills/openkbs/patterns/scheduled-tasks.md +157 -0
- package/templates/.claude/skills/openkbs/patterns/telegram-webhook.md +424 -0
- package/templates/.claude/skills/openkbs/patterns/telegram.md +222 -0
- package/templates/.claude/skills/openkbs/patterns/vectordb-archive.md +231 -0
- package/templates/.claude/skills/openkbs/patterns/video-generation.md +145 -0
- package/templates/.claude/skills/openkbs/patterns/web-publishing.md +257 -0
- package/templates/.claude/skills/openkbs/reference/backend-sdk.md +13 -2
- package/templates/.claude/skills/openkbs/reference/elastic-services.md +61 -29
- package/templates/platform/README.md +15 -50
- package/templates/platform/agents/assistant/app/icon.png +0 -0
- package/templates/platform/agents/assistant/app/instructions.txt +9 -21
- package/templates/platform/agents/assistant/app/settings.json +11 -15
- package/templates/platform/agents/assistant/src/Events/actions.js +31 -62
- package/templates/platform/agents/assistant/src/Events/handler.js +54 -0
- package/templates/platform/agents/assistant/src/Events/onRequest.js +3 -0
- package/templates/platform/agents/assistant/src/Events/onRequest.json +5 -0
- package/templates/platform/agents/assistant/src/Events/onResponse.js +2 -40
- package/templates/platform/agents/assistant/src/Events/onResponse.json +4 -2
- package/templates/platform/agents/assistant/src/Frontend/contentRender.js +17 -16
- package/templates/platform/agents/assistant/src/Frontend/contentRender.json +1 -1
- package/templates/platform/functions/api/index.mjs +17 -23
- package/templates/platform/functions/api/package.json +4 -0
- package/templates/platform/openkbs.json +7 -2
- package/templates/platform/site/index.html +18 -19
- package/version.json +3 -3
- package/templates/.claude/skills/openkbs/examples/ai-copywriter-agent/scripts/run_job.js +0 -26
- 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
|