neoagent 2.3.1-beta.63 → 2.3.1-beta.65
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/capabilities.md +1 -1
- package/docs/configuration.md +2 -2
- package/flutter_app/lib/main.dart +1 -0
- package/flutter_app/lib/main_account_settings.dart +50 -22
- package/flutter_app/lib/main_admin.dart +24 -10
- package/flutter_app/lib/main_app_shell.dart +10 -9
- package/flutter_app/lib/main_chat.dart +631 -318
- package/flutter_app/lib/main_controller.dart +29 -8
- package/flutter_app/lib/main_devices.dart +4 -6
- package/flutter_app/lib/main_integrations.dart +15 -7
- package/flutter_app/lib/main_models.dart +207 -8
- package/flutter_app/lib/main_navigation.dart +36 -18
- package/flutter_app/lib/main_operations.dart +162 -91
- package/flutter_app/lib/main_settings.dart +273 -78
- package/flutter_app/lib/main_shared.dart +8 -6
- package/flutter_app/lib/main_unified.dart +388 -0
- package/package.json +1 -1
- package/server/db/database.js +52 -0
- package/server/public/.last_build_id +1 -1
- 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 +79074 -78010
- package/server/routes/agents.js +2 -1
- package/server/routes/browser.js +1 -14
- package/server/routes/memory.js +75 -3
- package/server/routes/settings.js +1 -5
- package/server/routes/widgets.js +4 -4
- package/server/services/ai/capabilityHealth.js +1 -10
- package/server/services/ai/deliverables/artifact_helpers.js +190 -0
- package/server/services/ai/deliverables/contracts.js +113 -0
- package/server/services/ai/deliverables/deliverables.test.js +76 -0
- package/server/services/ai/deliverables/index.js +20 -0
- package/server/services/ai/deliverables/selector.js +94 -0
- package/server/services/ai/deliverables/validator.js +63 -0
- package/server/services/ai/deliverables/workflows.js +195 -0
- package/server/services/ai/engine.js +259 -1
- package/server/services/ai/runEvents.js +100 -0
- package/server/services/ai/systemPrompt.js +6 -0
- package/server/services/ai/tools.js +1 -5
- package/server/services/manager.js +5 -56
- package/server/services/memory/manager.js +242 -26
- package/server/services/runtime/manager.js +2 -6
- package/server/services/runtime/settings.js +6 -12
- package/server/services/websocket.js +3 -1
- package/server/services/widgets/focus_widget.js +134 -0
- package/server/services/widgets/service.js +130 -2
- package/server/utils/deployment.js +4 -3
|
@@ -2,8 +2,13 @@ const crypto = require('crypto');
|
|
|
2
2
|
const db = require('../../db/database');
|
|
3
3
|
const { resolveAgentId } = require('../agents/manager');
|
|
4
4
|
const { findNextRun, getMinimumIntervalMinutes } = require('../tasks/schedule_utils');
|
|
5
|
+
const {
|
|
6
|
+
buildAssistantFocusSnapshot,
|
|
7
|
+
buildAssistantFocusWidgetPayload,
|
|
8
|
+
} = require('./focus_widget');
|
|
5
9
|
|
|
6
10
|
const MIN_WIDGET_REFRESH_MINUTES = 60;
|
|
11
|
+
const SYSTEM_WIDGET_KEY_ASSISTANT_FOCUS = 'assistant_focus';
|
|
7
12
|
|
|
8
13
|
const TEMPLATE_VARIANTS = {
|
|
9
14
|
stat: ['hero', 'split', 'compact'],
|
|
@@ -102,6 +107,9 @@ function normalizeWidgetInput(input = {}, userId) {
|
|
|
102
107
|
layoutVariant,
|
|
103
108
|
refreshCron,
|
|
104
109
|
enabled: input.enabled !== false,
|
|
110
|
+
widgetKind: normalizeText(input.widgetKind || input.widget_kind || 'custom', 40).toLowerCase() || 'custom',
|
|
111
|
+
systemKey: normalizeOptionalText(input.systemKey || input.system_key, 80),
|
|
112
|
+
isSystem: input.isSystem === true || input.is_system === true,
|
|
105
113
|
definition: normalizeDefinition(input.definition || input.definition_json || {
|
|
106
114
|
prompt: input.prompt || input.refreshPrompt || input.refresh_prompt || '',
|
|
107
115
|
description: input.description || '',
|
|
@@ -226,6 +234,8 @@ function validateSnapshotPayload(widget, snapshot = {}) {
|
|
|
226
234
|
class WidgetService {
|
|
227
235
|
constructor({ app }) {
|
|
228
236
|
this.app = app;
|
|
237
|
+
this._pendingSystemWidgetTaskSetup = new Set();
|
|
238
|
+
this._pendingSystemWidgetRefresh = new Set();
|
|
229
239
|
}
|
|
230
240
|
|
|
231
241
|
get taskRuntime() {
|
|
@@ -237,6 +247,7 @@ class WidgetService {
|
|
|
237
247
|
}
|
|
238
248
|
|
|
239
249
|
getWidget(userId, widgetId) {
|
|
250
|
+
this.ensureSystemFocusWidget(userId);
|
|
240
251
|
const row = db.prepare(
|
|
241
252
|
`SELECT *
|
|
242
253
|
FROM ai_widgets
|
|
@@ -251,7 +262,11 @@ class WidgetService {
|
|
|
251
262
|
}
|
|
252
263
|
|
|
253
264
|
listWidgets(userId, { agentId = null } = {}) {
|
|
265
|
+
this.ensureSystemFocusWidget(userId);
|
|
254
266
|
const scopedAgentId = agentId ? resolveAgentId(userId, agentId) : null;
|
|
267
|
+
if (scopedAgentId) {
|
|
268
|
+
this.ensureSystemFocusWidget(userId, { agentId: scopedAgentId });
|
|
269
|
+
}
|
|
255
270
|
const rows = scopedAgentId
|
|
256
271
|
? db.prepare(
|
|
257
272
|
`SELECT *
|
|
@@ -287,14 +302,17 @@ class WidgetService {
|
|
|
287
302
|
const tx = db.transaction(() => {
|
|
288
303
|
db.prepare(
|
|
289
304
|
`INSERT INTO ai_widgets (
|
|
290
|
-
id, user_id, agent_id, name, template, layout_variant, definition_json,
|
|
305
|
+
id, user_id, agent_id, name, widget_kind, system_key, is_system, template, layout_variant, definition_json,
|
|
291
306
|
refresh_cron, enabled, created_at, updated_at
|
|
292
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'))`
|
|
307
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'))`
|
|
293
308
|
).run(
|
|
294
309
|
widgetId,
|
|
295
310
|
userId,
|
|
296
311
|
normalized.agentId,
|
|
297
312
|
normalized.name,
|
|
313
|
+
normalized.widgetKind,
|
|
314
|
+
normalized.systemKey,
|
|
315
|
+
normalized.isSystem ? 1 : 0,
|
|
298
316
|
normalized.template,
|
|
299
317
|
normalized.layoutVariant,
|
|
300
318
|
JSON.stringify(normalized.definition),
|
|
@@ -347,6 +365,9 @@ class WidgetService {
|
|
|
347
365
|
if (!existingRow) {
|
|
348
366
|
throw new Error('Widget not found.');
|
|
349
367
|
}
|
|
368
|
+
if (existingRow.is_system) {
|
|
369
|
+
throw new Error('System widgets cannot be edited directly.');
|
|
370
|
+
}
|
|
350
371
|
|
|
351
372
|
const current = this._serializeWidget(existingRow, null, []);
|
|
352
373
|
const normalized = normalizeWidgetInput({
|
|
@@ -441,6 +462,9 @@ class WidgetService {
|
|
|
441
462
|
if (!existingRow) {
|
|
442
463
|
throw new Error('Widget not found.');
|
|
443
464
|
}
|
|
465
|
+
if (existingRow.is_system) {
|
|
466
|
+
throw new Error('System widgets cannot be deleted.');
|
|
467
|
+
}
|
|
444
468
|
|
|
445
469
|
const taskRuntime = this.taskRuntime;
|
|
446
470
|
const tx = db.transaction(() => {
|
|
@@ -494,6 +518,31 @@ class WidgetService {
|
|
|
494
518
|
return { skipped: true, reason: 'disabled' };
|
|
495
519
|
}
|
|
496
520
|
const engine = this.agentEngine;
|
|
521
|
+
if (widget.isSystem && widget.systemKey === SYSTEM_WIDGET_KEY_ASSISTANT_FOCUS) {
|
|
522
|
+
const memoryManager = this.app?.locals?.memoryManager || null;
|
|
523
|
+
const snapshot = buildAssistantFocusSnapshot(memoryManager, userId, widget.agentId);
|
|
524
|
+
if (memoryManager?.updateAssistantSelfState) {
|
|
525
|
+
memoryManager.updateAssistantSelfState(userId, {
|
|
526
|
+
focus: {
|
|
527
|
+
currentFocus: snapshot.currentFocus,
|
|
528
|
+
activeThreads: snapshot.activeThreads,
|
|
529
|
+
nearTermPriorities: snapshot.nearTermPriorities,
|
|
530
|
+
recentSignals: snapshot.recentSignals,
|
|
531
|
+
rememberedContext: snapshot.rememberedContext,
|
|
532
|
+
generatedAt: snapshot.generatedAt,
|
|
533
|
+
},
|
|
534
|
+
}, { agentId: widget.agentId });
|
|
535
|
+
}
|
|
536
|
+
return {
|
|
537
|
+
widgetId,
|
|
538
|
+
snapshot: this.saveSnapshot(
|
|
539
|
+
userId,
|
|
540
|
+
widgetId,
|
|
541
|
+
buildAssistantFocusWidgetPayload(snapshot),
|
|
542
|
+
{ sourceRunId: null, status: 'ready' },
|
|
543
|
+
),
|
|
544
|
+
};
|
|
545
|
+
}
|
|
497
546
|
if (!engine) {
|
|
498
547
|
throw new Error('Agent engine not available.');
|
|
499
548
|
}
|
|
@@ -635,6 +684,9 @@ class WidgetService {
|
|
|
635
684
|
userId: row.user_id,
|
|
636
685
|
agentId: row.agent_id || null,
|
|
637
686
|
name: row.name,
|
|
687
|
+
widgetKind: row.widget_kind || 'custom',
|
|
688
|
+
systemKey: row.system_key || null,
|
|
689
|
+
isSystem: row.is_system !== 0 && row.is_system !== false,
|
|
638
690
|
template: row.template,
|
|
639
691
|
layoutVariant: row.layout_variant,
|
|
640
692
|
definition,
|
|
@@ -650,10 +702,86 @@ class WidgetService {
|
|
|
650
702
|
tasks,
|
|
651
703
|
};
|
|
652
704
|
}
|
|
705
|
+
|
|
706
|
+
ensureSystemFocusWidget(userId, { agentId = null } = {}) {
|
|
707
|
+
const scopedAgentId = resolveAgentId(userId, agentId || null);
|
|
708
|
+
const ensureKey = `${userId}:${scopedAgentId || 'default'}:${SYSTEM_WIDGET_KEY_ASSISTANT_FOCUS}`;
|
|
709
|
+
const ensured = db.transaction(() => {
|
|
710
|
+
db.prepare(
|
|
711
|
+
`INSERT OR IGNORE INTO ai_widgets (
|
|
712
|
+
id, user_id, agent_id, name, widget_kind, system_key, is_system, template, layout_variant,
|
|
713
|
+
definition_json, refresh_cron, enabled, created_at, updated_at
|
|
714
|
+
) VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, 1, datetime('now'), datetime('now'))`
|
|
715
|
+
).run(
|
|
716
|
+
crypto.randomUUID(),
|
|
717
|
+
userId,
|
|
718
|
+
scopedAgentId,
|
|
719
|
+
'Today / Focus',
|
|
720
|
+
'system',
|
|
721
|
+
SYSTEM_WIDGET_KEY_ASSISTANT_FOCUS,
|
|
722
|
+
'summary',
|
|
723
|
+
'focus',
|
|
724
|
+
JSON.stringify({
|
|
725
|
+
prompt: 'System-managed assistant focus widget.',
|
|
726
|
+
description: 'Always-visible assistant continuity widget.',
|
|
727
|
+
}),
|
|
728
|
+
'0 * * * *',
|
|
729
|
+
);
|
|
730
|
+
const row = db.prepare(
|
|
731
|
+
`SELECT * FROM ai_widgets
|
|
732
|
+
WHERE user_id = ? AND agent_id = ? AND system_key = ?`
|
|
733
|
+
).get(userId, scopedAgentId, SYSTEM_WIDGET_KEY_ASSISTANT_FOCUS);
|
|
734
|
+
return {
|
|
735
|
+
widgetId: row?.id || null,
|
|
736
|
+
scheduledTaskId: row?.scheduled_task_id || null,
|
|
737
|
+
lastSnapshotAt: row?.last_snapshot_at || null,
|
|
738
|
+
};
|
|
739
|
+
})();
|
|
740
|
+
|
|
741
|
+
if (!ensured.widgetId) return null;
|
|
742
|
+
const taskRuntime = this.taskRuntime;
|
|
743
|
+
if (taskRuntime && !ensured.scheduledTaskId && !this._pendingSystemWidgetTaskSetup.has(ensureKey)) {
|
|
744
|
+
this._pendingSystemWidgetTaskSetup.add(ensureKey);
|
|
745
|
+
Promise.resolve(taskRuntime.createTask(userId, {
|
|
746
|
+
name: buildWidgetRefreshTaskName('Today / Focus'),
|
|
747
|
+
triggerType: 'schedule',
|
|
748
|
+
triggerConfig: {
|
|
749
|
+
mode: 'recurring',
|
|
750
|
+
cronExpression: '0 * * * *',
|
|
751
|
+
},
|
|
752
|
+
enabled: true,
|
|
753
|
+
agentId: scopedAgentId,
|
|
754
|
+
taskType: 'widget_refresh',
|
|
755
|
+
taskConfig: { widgetId: ensured.widgetId },
|
|
756
|
+
})).then((task) => {
|
|
757
|
+
db.prepare(
|
|
758
|
+
`UPDATE ai_widgets
|
|
759
|
+
SET scheduled_task_id = COALESCE(scheduled_task_id, ?), updated_at = datetime('now')
|
|
760
|
+
WHERE id = ?`
|
|
761
|
+
).run(task.id, ensured.widgetId);
|
|
762
|
+
}).catch((error) => {
|
|
763
|
+
console.error('[widgets] Failed to create Today / Focus refresh task:', error);
|
|
764
|
+
}).finally(() => {
|
|
765
|
+
this._pendingSystemWidgetTaskSetup.delete(ensureKey);
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (!ensured.lastSnapshotAt && !this._pendingSystemWidgetRefresh.has(ensureKey)) {
|
|
770
|
+
this._pendingSystemWidgetRefresh.add(ensureKey);
|
|
771
|
+
Promise.resolve(this.refreshWidget(userId, ensured.widgetId)).catch((error) => {
|
|
772
|
+
console.error('[widgets] Failed to refresh Today / Focus widget:', error);
|
|
773
|
+
}).finally(() => {
|
|
774
|
+
this._pendingSystemWidgetRefresh.delete(ensureKey);
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
return ensured.widgetId;
|
|
779
|
+
}
|
|
653
780
|
}
|
|
654
781
|
|
|
655
782
|
module.exports = {
|
|
656
783
|
MIN_WIDGET_REFRESH_MINUTES,
|
|
784
|
+
SYSTEM_WIDGET_KEY_ASSISTANT_FOCUS,
|
|
657
785
|
TEMPLATE_VARIANTS,
|
|
658
786
|
WidgetService,
|
|
659
787
|
buildWidgetRefreshTaskName,
|
|
@@ -42,10 +42,11 @@ function parseDeploymentProfile(value) {
|
|
|
42
42
|
case 'single':
|
|
43
43
|
case 'single-user':
|
|
44
44
|
case 'single_user':
|
|
45
|
-
case '':
|
|
46
45
|
return DEPLOYMENT_PROFILE_PRIVATE;
|
|
46
|
+
case '':
|
|
47
|
+
return DEPLOYMENT_PROFILE_PROD;
|
|
47
48
|
default:
|
|
48
|
-
return
|
|
49
|
+
return DEPLOYMENT_PROFILE_PROD;
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -66,7 +67,7 @@ function getDeploymentPolicy(env = process.env) {
|
|
|
66
67
|
runtimeDefaults: {
|
|
67
68
|
runtime_profile: isProdProfile ? 'secure-vm' : 'trusted-host',
|
|
68
69
|
runtime_backend: isProdProfile ? 'vm' : 'host',
|
|
69
|
-
browser_backend:
|
|
70
|
+
browser_backend: 'vm',
|
|
70
71
|
android_backend: isProdProfile ? 'vm' : 'host',
|
|
71
72
|
mcp_backend: 'host-remote',
|
|
72
73
|
},
|