neoagent 2.5.2-beta.0 → 2.5.2-beta.10
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/flutter_app/lib/main_chat.dart +0 -3
- package/flutter_app/lib/main_shared.dart +40 -29
- package/package.json +1 -1
- package/server/public/.last_build_id +1 -1
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +19016 -19016
- package/server/services/ai/deliverables/artifact_helpers.js +19 -9
- package/server/services/ai/engine.js +2 -3813
- package/server/services/ai/loop/agent_engine_core.js +1590 -0
- package/server/services/ai/loop/callbacks.js +151 -0
- package/server/services/ai/loop/completion_judge.js +252 -0
- package/server/services/ai/loop/conversation_loop.js +2343 -0
- package/server/services/ai/loop/delivery_state.js +27 -0
- package/server/services/ai/loop/error_recovery.js +49 -0
- package/server/services/ai/loop/iteration_budget.js +24 -0
- package/server/services/ai/loop/messaging_delivery.js +250 -0
- package/server/services/ai/loop/model_io.js +258 -0
- package/server/services/ai/loop/progress_monitor.js +80 -0
- package/server/services/ai/loop/run_state.js +356 -0
- package/server/services/ai/loop/tool_dispatch.js +230 -0
- package/server/services/ai/tools.js +67 -17
- package/server/services/messaging/manager.js +7 -0
- package/server/services/runtime/backends/local-vm.js +7 -7
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
normalizeOutgoingMessageForPlatform,
|
|
10
10
|
} = require('../messaging/formatting_guides');
|
|
11
11
|
const { INTERIM_KINDS, normalizeInterimKind } = require('./interim');
|
|
12
|
+
const { normalizeWhatsAppId } = require('../../utils/whatsapp');
|
|
12
13
|
const {
|
|
13
14
|
executeIntegratedTool,
|
|
14
15
|
getIntegratedToolDefinitions,
|
|
@@ -255,22 +256,32 @@ function hasAlreadySentProactiveMessage({ triggerSource, runState, deliveryState
|
|
|
255
256
|
}
|
|
256
257
|
|
|
257
258
|
function markProactiveMessageSent({ runState, deliveryState, content }) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
259
|
+
const message = String(content || '');
|
|
260
|
+
const sentAt = new Date().toISOString();
|
|
261
|
+
if (runState) {
|
|
262
|
+
runState.messagingSent = true;
|
|
263
|
+
runState.finalDeliverySent = true;
|
|
264
|
+
runState.lastFinalDeliveryAt = sentAt;
|
|
265
|
+
if (runState.progressLedger && typeof runState.progressLedger === 'object') {
|
|
266
|
+
runState.progressLedger.lastUserVisibleUpdateAt = sentAt;
|
|
267
|
+
runState.progressLedger.lastFinalDeliveryAt = sentAt;
|
|
268
|
+
runState.progressLedger.progressState = 'complete';
|
|
265
269
|
}
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
270
|
+
runState.lastSentMessage = message;
|
|
271
|
+
if (Array.isArray(runState.sentMessages)) {
|
|
272
|
+
runState.sentMessages.push(message);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (deliveryState) {
|
|
277
|
+
deliveryState.messagingSent = true;
|
|
278
|
+
deliveryState.finalDeliverySent = true;
|
|
279
|
+
deliveryState.lastFinalDeliveryAt = sentAt;
|
|
280
|
+
deliveryState.lastSentMessage = message;
|
|
281
|
+
if (!Array.isArray(deliveryState.sentMessages)) {
|
|
282
|
+
deliveryState.sentMessages = [];
|
|
283
|
+
}
|
|
284
|
+
deliveryState.sentMessages.push(message);
|
|
274
285
|
}
|
|
275
286
|
}
|
|
276
287
|
|
|
@@ -310,6 +321,31 @@ function normalizeMessagingTarget(target = {}) {
|
|
|
310
321
|
return { platform, to };
|
|
311
322
|
}
|
|
312
323
|
|
|
324
|
+
function canonicalMessagingAddress(platform, value) {
|
|
325
|
+
const normalizedPlatform = String(platform || '').trim().toLowerCase();
|
|
326
|
+
const raw = String(value || '').trim();
|
|
327
|
+
if (!normalizedPlatform || !raw) return '';
|
|
328
|
+
if (normalizedPlatform !== 'whatsapp') return raw;
|
|
329
|
+
|
|
330
|
+
const lower = raw.toLowerCase();
|
|
331
|
+
const normalizedId = normalizeWhatsAppId(lower);
|
|
332
|
+
if (!normalizedId) return '';
|
|
333
|
+
if (lower.includes('@g.us')) return `group:${normalizedId}`;
|
|
334
|
+
if (lower.includes('@lid')) return `lid:${normalizedId}`;
|
|
335
|
+
return `direct:${normalizedId}`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function isOriginMessagingDelivery({ triggerSource, source, chatId, platform, to }) {
|
|
339
|
+
if (triggerSource !== 'messaging') return true;
|
|
340
|
+
const originPlatform = String(source || '').trim().toLowerCase();
|
|
341
|
+
const targetPlatform = String(platform || '').trim().toLowerCase();
|
|
342
|
+
if (!originPlatform || !targetPlatform || originPlatform !== targetPlatform) return false;
|
|
343
|
+
|
|
344
|
+
const originAddress = canonicalMessagingAddress(originPlatform, chatId);
|
|
345
|
+
const targetAddress = canonicalMessagingAddress(targetPlatform, to);
|
|
346
|
+
return Boolean(originAddress && targetAddress && originAddress === targetAddress);
|
|
347
|
+
}
|
|
348
|
+
|
|
313
349
|
function buildAndroidUiMatchProperties(extra = {}) {
|
|
314
350
|
return {
|
|
315
351
|
x: { type: 'number', description: 'Absolute X coordinate' },
|
|
@@ -1613,6 +1649,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1613
1649
|
case 'browser_extract': {
|
|
1614
1650
|
const { provider, backend } = await bc();
|
|
1615
1651
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1652
|
+
if (!args.selector) return { error: 'browser_extract requires a "selector" argument' };
|
|
1616
1653
|
return { ...await provider.extract(args.selector, args.attribute, args.all), backend };
|
|
1617
1654
|
}
|
|
1618
1655
|
|
|
@@ -1625,7 +1662,9 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1625
1662
|
case 'browser_evaluate': {
|
|
1626
1663
|
const { provider, backend } = await bc();
|
|
1627
1664
|
if (!provider) return { error: 'Browser controller not available' };
|
|
1628
|
-
|
|
1665
|
+
const script = args.script ?? args.javascript;
|
|
1666
|
+
if (!script) return { error: 'browser_evaluate requires a "script" argument' };
|
|
1667
|
+
return { ...await provider.evaluate(script), backend };
|
|
1629
1668
|
}
|
|
1630
1669
|
|
|
1631
1670
|
case 'android_start_emulator': {
|
|
@@ -2234,7 +2273,18 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2234
2273
|
persistConversation: triggerSource === 'schedule' || triggerSource === 'tasks'
|
|
2235
2274
|
});
|
|
2236
2275
|
// Track that the agent explicitly sent a message during this run
|
|
2237
|
-
if (
|
|
2276
|
+
if (
|
|
2277
|
+
!suppressReply
|
|
2278
|
+
&& sendResult?.success === true
|
|
2279
|
+
&& sendResult?.suppressed !== true
|
|
2280
|
+
&& isOriginMessagingDelivery({
|
|
2281
|
+
triggerSource,
|
|
2282
|
+
source: context.source,
|
|
2283
|
+
chatId: context.chatId,
|
|
2284
|
+
platform: args.platform,
|
|
2285
|
+
to: args.to,
|
|
2286
|
+
})
|
|
2287
|
+
) {
|
|
2238
2288
|
markProactiveMessageSent({ runState, deliveryState, content: normalizedMessage });
|
|
2239
2289
|
if (runState && triggerSource === 'messaging') {
|
|
2240
2290
|
runState.explicitMessageSent = true;
|
|
@@ -515,6 +515,13 @@ class MessagingManager extends EventEmitter {
|
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
const result = await platform.sendMessage(to, normalizedContent, sendOptions);
|
|
518
|
+
if (result?.success === false) {
|
|
519
|
+
const reason = result.error || result.reason || 'platform rejected the message';
|
|
520
|
+
const error = new Error(`Platform ${platformName} delivery failed: ${reason}`);
|
|
521
|
+
error.code = 'MESSAGING_DELIVERY_FAILED';
|
|
522
|
+
error.deliveryResult = result;
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
518
525
|
|
|
519
526
|
db.prepare('INSERT INTO messages (user_id, agent_id, run_id, role, content, platform, platform_chat_id, media_path, metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)')
|
|
520
527
|
.run(userId, agentId, runId, 'assistant', normalizedContent, platformName, to, mediaPath, metadata ? JSON.stringify(metadata) : null);
|
|
@@ -250,8 +250,8 @@ class VmBrowserProvider {
|
|
|
250
250
|
async typeText(text, options = {}) { return this.#materialize(await this.client.request('POST', '/browser/type-text', { text, ...options })); }
|
|
251
251
|
async pressKey(key, screenshot = true) { return this.#materialize(await this.client.request('POST', '/browser/press-key', { key, screenshot })); }
|
|
252
252
|
async scroll(deltaX, deltaY, screenshot = true) { return this.#materialize(await this.client.request('POST', '/browser/scroll', { deltaX, deltaY, screenshot })); }
|
|
253
|
-
extract(selector, attribute, all = false) { return this.client.request('POST', '/browser/extract', { selector, attribute, all }); }
|
|
254
|
-
evaluate(script) { return this.client.request('POST', '/browser/execute', { code: script }); }
|
|
253
|
+
async extract(selector, attribute, all = false) { return this.client.request('POST', '/browser/extract', { selector, attribute, all }); }
|
|
254
|
+
async evaluate(script) { return this.client.request('POST', '/browser/execute', { code: script }); }
|
|
255
255
|
async screenshot(options = {}) { return this.#materialize(await this.client.request('POST', '/browser/screenshot', options)); }
|
|
256
256
|
async screenshotJpeg(quality = 80, options = {}) {
|
|
257
257
|
const result = await this.client.request('POST', '/browser/screenshot-jpeg', { ...options, quality });
|
|
@@ -259,11 +259,11 @@ class VmBrowserProvider {
|
|
|
259
259
|
if (!content) throw new Error('VM browser screenshot-jpeg returned no data.');
|
|
260
260
|
return Buffer.from(content, 'base64');
|
|
261
261
|
}
|
|
262
|
-
launch(options = {}) { return this.client.request('POST', '/browser/launch', options); }
|
|
263
|
-
closeBrowser() { return this.client.request('POST', '/browser/close'); }
|
|
264
|
-
fill(selector, value) { return this.type(selector, value); }
|
|
265
|
-
extractContent(options = {}) { return this.client.request('POST', '/browser/extract', options); }
|
|
266
|
-
executeJS(code) { return this.evaluate(code); }
|
|
262
|
+
async launch(options = {}) { return this.client.request('POST', '/browser/launch', options); }
|
|
263
|
+
async closeBrowser() { return this.client.request('POST', '/browser/close'); }
|
|
264
|
+
async fill(selector, value) { return this.type(selector, value); }
|
|
265
|
+
async extractContent(options = {}) { return this.client.request('POST', '/browser/extract', options); }
|
|
266
|
+
async executeJS(code) { return this.evaluate(code); }
|
|
267
267
|
async getPageInfo() {
|
|
268
268
|
const status = await this.client.request('GET', '/browser/status');
|
|
269
269
|
this.headless = status?.headless !== false;
|