neoagent 1.4.5 → 1.4.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/package.json
CHANGED
|
@@ -11,7 +11,8 @@ const PACKS = {
|
|
|
11
11
|
images: ['generate_image', 'analyze_image'],
|
|
12
12
|
tables: ['generate_table', 'generate_graph'],
|
|
13
13
|
subagents: ['spawn_subagent'],
|
|
14
|
-
mcpAdmin: ['mcp_add_server', 'mcp_list_servers', 'mcp_remove_server']
|
|
14
|
+
mcpAdmin: ['mcp_add_server', 'mcp_list_servers', 'mcp_remove_server'],
|
|
15
|
+
health: ['read_health_data']
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
function containsAny(text, patterns) {
|
|
@@ -100,6 +101,10 @@ function detectRequestedPacks(task = '', options = {}) {
|
|
|
100
101
|
packs.add('images');
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
if (containsAny(text, [/\bhealth\b/, /\bfitness\b/, /\bsteps\b/, /\bsleep\b/, /\bheart rate\b/, /\bworkout\b/, /\bblood\b/, /\bsamsung health\b/, /\bhealth connect\b/])) {
|
|
105
|
+
packs.add('health');
|
|
106
|
+
}
|
|
107
|
+
|
|
103
108
|
return packs;
|
|
104
109
|
}
|
|
105
110
|
|
|
@@ -581,6 +581,17 @@ function getAvailableTools(app, options = {}) {
|
|
|
581
581
|
},
|
|
582
582
|
required: ['image_path']
|
|
583
583
|
}
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
name: 'read_health_data',
|
|
587
|
+
description: 'Read the user\'s synced mobile health data (like steps, heart rate, sleep). If you omit metric_type, it returns a summary of all available metrics. If you provide a metric_type, it returns the most recent historical records for that metric.',
|
|
588
|
+
parameters: {
|
|
589
|
+
type: 'object',
|
|
590
|
+
properties: {
|
|
591
|
+
metric_type: { type: 'string', description: 'The specific metric to query, e.g. "Steps", "HeartRate", "SleepSession". Optional.' },
|
|
592
|
+
limit: { type: 'number', description: 'Maximum number of recent records to return if metric_type is specified (default 50, max 200).' }
|
|
593
|
+
}
|
|
594
|
+
}
|
|
584
595
|
}
|
|
585
596
|
];
|
|
586
597
|
|
|
@@ -801,6 +812,12 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
801
812
|
return { success: true, key: args.key, message: 'Core memory updated' };
|
|
802
813
|
}
|
|
803
814
|
|
|
815
|
+
case 'read_health_data': {
|
|
816
|
+
const { readHealthData } = require('../health/ingestion');
|
|
817
|
+
const result = readHealthData(userId, args.metric_type, args.limit);
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
820
|
+
|
|
804
821
|
case 'memory_write': {
|
|
805
822
|
const { MemoryManager } = require('../memory/manager');
|
|
806
823
|
const mm = new MemoryManager();
|
|
@@ -169,7 +169,42 @@ function getHealthSyncStatus(userId) {
|
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
function readHealthData(userId, metricType, limit = 50) {
|
|
173
|
+
if (!metricType) {
|
|
174
|
+
const metrics = db.prepare(`
|
|
175
|
+
SELECT metric_type, COUNT(*) AS sample_count, MAX(COALESCE(end_time, recorded_at, start_time)) AS last_seen_at
|
|
176
|
+
FROM health_metric_samples
|
|
177
|
+
WHERE user_id = ?
|
|
178
|
+
GROUP BY metric_type
|
|
179
|
+
ORDER BY metric_type ASC
|
|
180
|
+
`).all(userId);
|
|
181
|
+
return { metrics };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const samples = db.prepare(`
|
|
185
|
+
SELECT
|
|
186
|
+
start_time, end_time, recorded_at,
|
|
187
|
+
numeric_value, text_value, unit,
|
|
188
|
+
source_app_id, source_device,
|
|
189
|
+
payload_json
|
|
190
|
+
FROM health_metric_samples
|
|
191
|
+
WHERE user_id = ? AND metric_type = ?
|
|
192
|
+
ORDER BY COALESCE(end_time, recorded_at, start_time) DESC
|
|
193
|
+
LIMIT ?
|
|
194
|
+
`).all(userId, metricType, limit);
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
metricType,
|
|
198
|
+
samples: samples.map(s => ({
|
|
199
|
+
...s,
|
|
200
|
+
payload: s.payload_json ? JSON.parse(s.payload_json) : null,
|
|
201
|
+
payload_json: undefined
|
|
202
|
+
}))
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
172
206
|
module.exports = {
|
|
173
207
|
getHealthSyncStatus,
|
|
174
208
|
ingestHealthSync,
|
|
209
|
+
readHealthData,
|
|
175
210
|
};
|
|
@@ -107,8 +107,8 @@ async function startServices(app, io) {
|
|
|
107
107
|
: '';
|
|
108
108
|
|
|
109
109
|
const prompt = isVoiceCall
|
|
110
|
-
? `You are on a live phone call. The caller (${msg.senderName || msg.sender}) said:\n<caller_speech>\n${msg.content}\n</caller_speech>\n\nRespond via send_message with platform="telnyx" and to="${msg.chatId}".`
|
|
111
|
-
: `You received a ${msg.platform} message from ${msg.senderName || msg.sender} (chat: ${msg.chatId}):\n<external_message>\n${msg.content}\n</external_message>${mediaNote}${discordContext}${sttNote}\n\nReply via send_message with platform="${msg.platform}" and to="${msg.chatId}".`;
|
|
110
|
+
? `You are on a live phone call. The caller (${msg.senderName || msg.sender}) said:\n<caller_speech>\n${msg.content}\n</caller_speech>\n\nRespond via send_message with platform="telnyx" and to="${msg.chatId}". Note: once you successfully send your voice response, end the tool loop and output exactly [NO RESPONSE] as your final text.`
|
|
111
|
+
: `You received a ${msg.platform} message from ${msg.senderName || msg.sender} (chat: ${msg.chatId}):\n<external_message>\n${msg.content}\n</external_message>${mediaNote}${discordContext}${sttNote}\n\nReply via send_message with platform="${msg.platform}" and to="${msg.chatId}". Note: once you successfully send your reply, end the tool loop and output exactly [NO RESPONSE] as your final text to prevent double-notifications.`;
|
|
112
112
|
|
|
113
113
|
let convRow = db.prepare(
|
|
114
114
|
'SELECT id FROM conversations WHERE user_id = ? AND platform = ? AND platform_chat_id = ?'
|