neoagent 2.2.1-beta.5 → 2.2.1-beta.7
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/docs/automation.md +2 -2
- package/docs/capabilities.md +7 -10
- package/docs/hardware.md +4 -7
- package/docs/index.md +6 -7
- package/docs/integrations.md +1 -1
- package/docs/operations.md +1 -1
- package/docs/why-neoagent.md +2 -2
- package/package.json +1 -1
- package/server/db/database.js +76 -61
- package/server/http/routes.js +1 -2
- package/server/public/assets/AssetManifest.json +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +65118 -64805
- package/server/routes/{scheduler.js → tasks.js} +31 -29
- package/server/routes/widgets.js +7 -7
- package/server/services/ai/capabilityHealth.js +4 -4
- package/server/services/ai/engine.js +31 -12
- package/server/services/ai/systemPrompt.js +7 -7
- package/server/services/ai/taskAnalysis.js +3 -3
- package/server/services/ai/toolResult.js +6 -8
- package/server/services/ai/tools.js +62 -95
- package/server/services/commands/router.js +14 -6
- package/server/services/integrations/whatsapp/provider.js +23 -1
- package/server/services/manager.js +14 -14
- package/server/services/memory/manager.js +7 -7
- package/server/services/memory/policy.js +1 -1
- package/server/services/messaging/formatting_guides.js +0 -4
- package/server/services/messaging/manager.js +0 -2
- package/server/services/tasks/adapters/gmail_message_received.js +36 -0
- package/server/services/tasks/adapters/index.js +10 -0
- package/server/services/tasks/adapters/outlook_email_received.js +38 -0
- package/server/services/tasks/adapters/schedule.js +57 -0
- package/server/services/tasks/adapters/slack_message_received.js +39 -0
- package/server/services/tasks/adapters/teams_message_received.js +39 -0
- package/server/services/tasks/adapters/whatsapp_personal_message_received.js +42 -0
- package/server/services/tasks/integration_runtime.js +260 -0
- package/server/services/tasks/runtime.js +539 -0
- package/server/services/{scheduler/cron_utils.js → tasks/schedule_utils.js} +2 -0
- package/server/services/tasks/security.js +60 -0
- package/server/services/tasks/task_repository.js +162 -0
- package/server/services/tasks/trigger_registry.js +29 -0
- package/server/services/tasks/utils.js +45 -0
- package/server/services/websocket.js +1 -1
- package/server/services/widgets/service.js +38 -25
- package/server/routes/wearable_device.js +0 -147
- package/server/services/messaging/waveshare_wearable.js +0 -40
- package/server/services/scheduler/cron.js +0 -580
- package/server/services/wearables/device_auth.js +0 -228
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
const crypto = require('crypto');
|
|
2
|
-
const db = require('../../db/database');
|
|
3
|
-
|
|
4
|
-
const DEFAULT_PAIRING_TTL_MINUTES = 10;
|
|
5
|
-
|
|
6
|
-
function sha256(value) {
|
|
7
|
-
return crypto.createHash('sha256').update(String(value || '')).digest('hex');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function randomToken(prefix = 'nwd_', bytes = 36) {
|
|
11
|
-
return `${prefix}${crypto.randomBytes(bytes).toString('base64url')}`;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function randomDigits(length = 6) {
|
|
15
|
-
const min = 10 ** (length - 1);
|
|
16
|
-
const max = (10 ** length) - 1;
|
|
17
|
-
return String(Math.floor(Math.random() * (max - min + 1)) + min);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function isoDate(offsetMs = 0) {
|
|
21
|
-
return new Date(Date.now() + offsetMs).toISOString();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function safeJson(value) {
|
|
25
|
-
try {
|
|
26
|
-
return JSON.stringify(value || {});
|
|
27
|
-
} catch {
|
|
28
|
-
return '{}';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
class WearableDeviceAuth {
|
|
33
|
-
createPairingCode(userId, options = {}) {
|
|
34
|
-
const ttlMinutes = Math.max(1, Math.min(30, Number(options.ttlMinutes || DEFAULT_PAIRING_TTL_MINUTES)));
|
|
35
|
-
const code = randomDigits(6);
|
|
36
|
-
const pairingId = crypto.randomUUID();
|
|
37
|
-
const expiresAt = isoDate(ttlMinutes * 60 * 1000);
|
|
38
|
-
|
|
39
|
-
db.prepare(
|
|
40
|
-
`INSERT INTO wearable_pairing_codes (
|
|
41
|
-
id, user_id, agent_id, code_hash, status, metadata_json, expires_at
|
|
42
|
-
) VALUES (?, ?, ?, ?, 'active', ?, ?)`
|
|
43
|
-
).run(
|
|
44
|
-
pairingId,
|
|
45
|
-
userId,
|
|
46
|
-
options.agentId || null,
|
|
47
|
-
sha256(code),
|
|
48
|
-
safeJson({
|
|
49
|
-
source: options.source || 'app',
|
|
50
|
-
deviceHint: options.deviceHint || null,
|
|
51
|
-
}),
|
|
52
|
-
expiresAt,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
id: pairingId,
|
|
57
|
-
code,
|
|
58
|
-
expiresAt,
|
|
59
|
-
ttlMinutes,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
claimPairingCode(code, payload = {}) {
|
|
64
|
-
const row = db.prepare(
|
|
65
|
-
`SELECT * FROM wearable_pairing_codes
|
|
66
|
-
WHERE code_hash = ? AND status = 'active'
|
|
67
|
-
ORDER BY datetime(created_at) DESC
|
|
68
|
-
LIMIT 1`
|
|
69
|
-
).get(sha256(code));
|
|
70
|
-
|
|
71
|
-
if (!row) {
|
|
72
|
-
const error = new Error('Pairing code is invalid.');
|
|
73
|
-
error.status = 404;
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (Date.parse(row.expires_at) <= Date.now()) {
|
|
78
|
-
db.prepare(`UPDATE wearable_pairing_codes SET status = 'expired' WHERE id = ?`).run(row.id);
|
|
79
|
-
const error = new Error('Pairing code expired.');
|
|
80
|
-
error.status = 410;
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const token = randomToken();
|
|
85
|
-
const tokenId = crypto.randomUUID();
|
|
86
|
-
const deviceId = String(payload.deviceId || '').trim().slice(0, 120) || crypto.randomUUID();
|
|
87
|
-
const deviceName = String(payload.deviceName || 'NeoOS Wearable').trim().slice(0, 120);
|
|
88
|
-
const macAddress = String(payload.macAddress || '').trim().slice(0, 64) || null;
|
|
89
|
-
const protocol = String(payload.protocol || 'waveshare_amoled_1_8').trim().slice(0, 80);
|
|
90
|
-
const firmwareVersion = String(payload.firmwareVersion || '').trim().slice(0, 80) || null;
|
|
91
|
-
|
|
92
|
-
const tx = db.transaction(() => {
|
|
93
|
-
db.prepare(
|
|
94
|
-
`UPDATE wearable_pairing_codes
|
|
95
|
-
SET status = 'claimed', claimed_at = datetime('now')
|
|
96
|
-
WHERE id = ?`
|
|
97
|
-
).run(row.id);
|
|
98
|
-
|
|
99
|
-
db.prepare(
|
|
100
|
-
`INSERT INTO wearable_device_tokens (
|
|
101
|
-
id, user_id, agent_id, token_hash, device_id, device_name,
|
|
102
|
-
mac_address, protocol, firmware_version, status,
|
|
103
|
-
last_seen_at, last_connected_at, metadata_json
|
|
104
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', datetime('now'), datetime('now'), ?)`
|
|
105
|
-
).run(
|
|
106
|
-
tokenId,
|
|
107
|
-
row.user_id,
|
|
108
|
-
row.agent_id || null,
|
|
109
|
-
sha256(token),
|
|
110
|
-
deviceId,
|
|
111
|
-
deviceName,
|
|
112
|
-
macAddress,
|
|
113
|
-
protocol,
|
|
114
|
-
firmwareVersion,
|
|
115
|
-
safeJson({
|
|
116
|
-
pairingCodeId: row.id,
|
|
117
|
-
claimedAt: new Date().toISOString(),
|
|
118
|
-
}),
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
tx();
|
|
123
|
-
|
|
124
|
-
return {
|
|
125
|
-
token,
|
|
126
|
-
tokenId,
|
|
127
|
-
userId: row.user_id,
|
|
128
|
-
agentId: row.agent_id || null,
|
|
129
|
-
deviceId,
|
|
130
|
-
deviceName,
|
|
131
|
-
protocol,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
validateBearerToken(token) {
|
|
136
|
-
if (!token) return null;
|
|
137
|
-
const row = db.prepare(
|
|
138
|
-
`SELECT * FROM wearable_device_tokens
|
|
139
|
-
WHERE token_hash = ? AND status = 'active' AND revoked_at IS NULL
|
|
140
|
-
LIMIT 1`
|
|
141
|
-
).get(sha256(token));
|
|
142
|
-
if (!row) return null;
|
|
143
|
-
return row;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
touchToken(tokenId) {
|
|
147
|
-
db.prepare(
|
|
148
|
-
`UPDATE wearable_device_tokens
|
|
149
|
-
SET last_seen_at = datetime('now')
|
|
150
|
-
WHERE id = ?`
|
|
151
|
-
).run(tokenId);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
getLastCursor(tokenId) {
|
|
155
|
-
const row = db.prepare(
|
|
156
|
-
`SELECT last_message_id AS lastMessageId
|
|
157
|
-
FROM wearable_device_message_cursors
|
|
158
|
-
WHERE token_id = ?`
|
|
159
|
-
).get(tokenId);
|
|
160
|
-
return Number(row?.lastMessageId || 0);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
setLastCursor(tokenId, lastMessageId) {
|
|
164
|
-
db.prepare(
|
|
165
|
-
`INSERT INTO wearable_device_message_cursors (token_id, last_message_id, updated_at)
|
|
166
|
-
VALUES (?, ?, datetime('now'))
|
|
167
|
-
ON CONFLICT(token_id) DO UPDATE
|
|
168
|
-
SET last_message_id = excluded.last_message_id,
|
|
169
|
-
updated_at = datetime('now')`
|
|
170
|
-
).run(tokenId, Number(lastMessageId || 0));
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
getPendingResponses(tokenRow, limit = 5) {
|
|
174
|
-
const lastId = this.getLastCursor(tokenRow.id);
|
|
175
|
-
return db.prepare(
|
|
176
|
-
`SELECT id, content, created_at AS createdAt, metadata
|
|
177
|
-
FROM messages
|
|
178
|
-
WHERE user_id = ?
|
|
179
|
-
AND role = 'assistant'
|
|
180
|
-
AND platform = 'waveshare_wearable'
|
|
181
|
-
AND id > ?
|
|
182
|
-
ORDER BY id ASC
|
|
183
|
-
LIMIT ?`
|
|
184
|
-
).all(tokenRow.user_id, lastId, Math.max(1, Math.min(20, Number(limit || 5))));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
listDevicesForUser(userId, options = {}) {
|
|
188
|
-
const rows = db.prepare(
|
|
189
|
-
`SELECT
|
|
190
|
-
t.id,
|
|
191
|
-
t.device_id AS deviceId,
|
|
192
|
-
t.device_name AS name,
|
|
193
|
-
t.mac_address AS macAddress,
|
|
194
|
-
t.protocol,
|
|
195
|
-
t.firmware_version AS firmwareVersion,
|
|
196
|
-
t.status,
|
|
197
|
-
t.last_seen_at AS lastSeenAt,
|
|
198
|
-
t.last_connected_at AS lastConnectedAt,
|
|
199
|
-
t.created_at AS createdAt,
|
|
200
|
-
d.battery_level AS batteryLevel,
|
|
201
|
-
d.updated_at AS deviceUpdatedAt,
|
|
202
|
-
d.status AS runtimeStatus
|
|
203
|
-
FROM wearable_device_tokens t
|
|
204
|
-
LEFT JOIN wearable_devices d
|
|
205
|
-
ON d.user_id = t.user_id
|
|
206
|
-
AND d.mac_address = t.mac_address
|
|
207
|
-
WHERE t.user_id = ?
|
|
208
|
-
AND (? IS NULL OR t.agent_id = ?)
|
|
209
|
-
AND t.status = 'active'
|
|
210
|
-
AND t.revoked_at IS NULL
|
|
211
|
-
ORDER BY datetime(t.last_seen_at) DESC, datetime(t.created_at) DESC`
|
|
212
|
-
).all(userId, options.agentId || null, options.agentId || null);
|
|
213
|
-
|
|
214
|
-
const now = Date.now();
|
|
215
|
-
return rows.map((row) => {
|
|
216
|
-
const seenMs = row.lastSeenAt ? Date.parse(row.lastSeenAt) : 0;
|
|
217
|
-
const isConnected = seenMs > 0 && (now - seenMs) <= 90_000;
|
|
218
|
-
return {
|
|
219
|
-
...row,
|
|
220
|
-
connected: isConnected,
|
|
221
|
-
};
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
module.exports = {
|
|
227
|
-
wearableDeviceAuth: new WearableDeviceAuth(),
|
|
228
|
-
};
|