neoagent 2.3.1-beta.63 → 2.3.1-beta.64

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.
@@ -0,0 +1,388 @@
1
+ part of 'main.dart';
2
+
3
+ enum _ToolsPageTab { integrations, mcp, skills }
4
+
5
+ enum _RunsPageTab { runs, logs }
6
+
7
+ enum _SettingsWorkspaceSection { app, account, security }
8
+
9
+ class ToolsPanel extends StatefulWidget {
10
+ const ToolsPanel({super.key, required this.controller});
11
+
12
+ final NeoAgentController controller;
13
+
14
+ @override
15
+ State<ToolsPanel> createState() => _ToolsPanelState();
16
+ }
17
+
18
+ class _ToolsPanelState extends State<ToolsPanel>
19
+ with SingleTickerProviderStateMixin {
20
+ late final TabController _tabController;
21
+
22
+ @override
23
+ void initState() {
24
+ super.initState();
25
+ _tabController = TabController(
26
+ length: _ToolsPageTab.values.length,
27
+ vsync: this,
28
+ initialIndex: _tabForSection(widget.controller.selectedSection).index,
29
+ );
30
+ }
31
+
32
+ @override
33
+ void didUpdateWidget(covariant ToolsPanel oldWidget) {
34
+ super.didUpdateWidget(oldWidget);
35
+ final selectedSection = widget.controller.selectedSection;
36
+ if (selectedSection != oldWidget.controller.selectedSection &&
37
+ (selectedSection == AppSection.integrations ||
38
+ selectedSection == AppSection.mcp ||
39
+ selectedSection == AppSection.skills)) {
40
+ final targetIndex = _tabForSection(selectedSection).index;
41
+ if (_tabController.index != targetIndex) {
42
+ _tabController.index = targetIndex;
43
+ }
44
+ }
45
+ }
46
+
47
+ @override
48
+ void dispose() {
49
+ _tabController.dispose();
50
+ super.dispose();
51
+ }
52
+
53
+ _ToolsPageTab _tabForSection(AppSection section) {
54
+ switch (section) {
55
+ case AppSection.mcp:
56
+ return _ToolsPageTab.mcp;
57
+ case AppSection.skills:
58
+ return _ToolsPageTab.skills;
59
+ default:
60
+ return _ToolsPageTab.integrations;
61
+ }
62
+ }
63
+
64
+ @override
65
+ Widget build(BuildContext context) {
66
+ final controller = widget.controller;
67
+ final visibleIntegrations = controller.officialIntegrations
68
+ .where(
69
+ (item) =>
70
+ item.env.configured ||
71
+ item.env.setupMode == 'user' ||
72
+ item.isConnected,
73
+ )
74
+ .length;
75
+ return Padding(
76
+ padding: _pagePadding(context),
77
+ child: Column(
78
+ children: <Widget>[
79
+ const _PageTitle(
80
+ title: 'Tools',
81
+ subtitle:
82
+ 'Manage official integrations, MCP servers, and reusable skills in one place.',
83
+ ),
84
+ const SizedBox(height: 12),
85
+ Container(
86
+ decoration: BoxDecoration(
87
+ color: _bgSecondary,
88
+ borderRadius: BorderRadius.circular(14),
89
+ border: Border.all(color: _border),
90
+ ),
91
+ child: TabBar(
92
+ controller: _tabController,
93
+ dividerColor: Colors.transparent,
94
+ indicatorSize: TabBarIndicatorSize.tab,
95
+ labelStyle: const TextStyle(fontWeight: FontWeight.w700),
96
+ tabs: <Widget>[
97
+ Tab(text: 'Integrations ($visibleIntegrations)'),
98
+ Tab(text: 'MCP (${controller.mcpServers.length})'),
99
+ Tab(text: 'Skills (${controller.skills.length})'),
100
+ ],
101
+ ),
102
+ ),
103
+ const SizedBox(height: 12),
104
+ Expanded(
105
+ child: TabBarView(
106
+ controller: _tabController,
107
+ children: <Widget>[
108
+ IntegrationsPanel(controller: controller, embedded: true),
109
+ McpPanel(controller: controller, embedded: true),
110
+ SkillsPanel(controller: controller, embedded: true),
111
+ ],
112
+ ),
113
+ ),
114
+ ],
115
+ ),
116
+ );
117
+ }
118
+ }
119
+
120
+ class RunsAndLogsPanel extends StatefulWidget {
121
+ const RunsAndLogsPanel({super.key, required this.controller});
122
+
123
+ final NeoAgentController controller;
124
+
125
+ @override
126
+ State<RunsAndLogsPanel> createState() => _RunsAndLogsPanelState();
127
+ }
128
+
129
+ class _RunsAndLogsPanelState extends State<RunsAndLogsPanel>
130
+ with SingleTickerProviderStateMixin {
131
+ late final TabController _tabController;
132
+
133
+ @override
134
+ void initState() {
135
+ super.initState();
136
+ _tabController = TabController(
137
+ length: _RunsPageTab.values.length,
138
+ vsync: this,
139
+ initialIndex: _tabForSection(widget.controller.selectedSection).index,
140
+ );
141
+ }
142
+
143
+ @override
144
+ void didUpdateWidget(covariant RunsAndLogsPanel oldWidget) {
145
+ super.didUpdateWidget(oldWidget);
146
+ final selectedSection = widget.controller.selectedSection;
147
+ if (selectedSection != oldWidget.controller.selectedSection &&
148
+ (selectedSection == AppSection.runs ||
149
+ selectedSection == AppSection.logs)) {
150
+ final targetIndex = _tabForSection(selectedSection).index;
151
+ if (_tabController.index != targetIndex) {
152
+ _tabController.index = targetIndex;
153
+ }
154
+ }
155
+ }
156
+
157
+ @override
158
+ void dispose() {
159
+ _tabController.dispose();
160
+ super.dispose();
161
+ }
162
+
163
+ _RunsPageTab _tabForSection(AppSection section) {
164
+ switch (section) {
165
+ case AppSection.logs:
166
+ return _RunsPageTab.logs;
167
+ default:
168
+ return _RunsPageTab.runs;
169
+ }
170
+ }
171
+
172
+ @override
173
+ Widget build(BuildContext context) {
174
+ final controller = widget.controller;
175
+ return Padding(
176
+ padding: _pagePadding(context),
177
+ child: Column(
178
+ children: <Widget>[
179
+ const _PageTitle(
180
+ title: 'Runs & Logs',
181
+ subtitle:
182
+ 'Inspect execution history, failures, tool traces, and diagnostics from one workspace.',
183
+ ),
184
+ const SizedBox(height: 12),
185
+ Container(
186
+ decoration: BoxDecoration(
187
+ color: _bgSecondary,
188
+ borderRadius: BorderRadius.circular(14),
189
+ border: Border.all(color: _border),
190
+ ),
191
+ child: TabBar(
192
+ controller: _tabController,
193
+ dividerColor: Colors.transparent,
194
+ indicatorSize: TabBarIndicatorSize.tab,
195
+ labelStyle: const TextStyle(fontWeight: FontWeight.w700),
196
+ tabs: <Widget>[
197
+ Tab(text: 'Runs (${controller.recentRuns.length})'),
198
+ Tab(text: 'Logs (${controller.logs.length})'),
199
+ ],
200
+ ),
201
+ ),
202
+ const SizedBox(height: 12),
203
+ Expanded(
204
+ child: TabBarView(
205
+ controller: _tabController,
206
+ children: <Widget>[
207
+ RunsPanel(controller: controller, embedded: true),
208
+ LogsPanel(controller: controller, embedded: true),
209
+ ],
210
+ ),
211
+ ),
212
+ ],
213
+ ),
214
+ );
215
+ }
216
+ }
217
+
218
+ class SettingsWorkspacePanel extends StatefulWidget {
219
+ const SettingsWorkspacePanel({super.key, required this.controller});
220
+
221
+ final NeoAgentController controller;
222
+
223
+ @override
224
+ State<SettingsWorkspacePanel> createState() => _SettingsWorkspacePanelState();
225
+ }
226
+
227
+ class _SettingsWorkspacePanelState extends State<SettingsWorkspacePanel> {
228
+ late _SettingsWorkspaceSection _selectedSection;
229
+
230
+ @override
231
+ void initState() {
232
+ super.initState();
233
+ _selectedSection =
234
+ widget.controller.selectedSection == AppSection.accountSettings
235
+ ? _SettingsWorkspaceSection.account
236
+ : _SettingsWorkspaceSection.app;
237
+ }
238
+
239
+ @override
240
+ void didUpdateWidget(covariant SettingsWorkspacePanel oldWidget) {
241
+ super.didUpdateWidget(oldWidget);
242
+ if (widget.controller.selectedSection == AppSection.settings &&
243
+ _selectedSection != _SettingsWorkspaceSection.app) {
244
+ _selectedSection = _SettingsWorkspaceSection.app;
245
+ }
246
+ if (widget.controller.selectedSection == AppSection.accountSettings &&
247
+ _selectedSection == _SettingsWorkspaceSection.app) {
248
+ _selectedSection = _SettingsWorkspaceSection.account;
249
+ }
250
+ }
251
+
252
+ @override
253
+ Widget build(BuildContext context) {
254
+ final compact = MediaQuery.sizeOf(context).width < 960;
255
+ return Padding(
256
+ padding: _pagePadding(context),
257
+ child: Column(
258
+ children: <Widget>[
259
+ const _PageTitle(
260
+ title: 'Settings',
261
+ subtitle:
262
+ 'Workspace configuration and account security in one place.',
263
+ ),
264
+ const SizedBox(height: 12),
265
+ Expanded(
266
+ child: Card(
267
+ child: Padding(
268
+ padding: const EdgeInsets.all(20),
269
+ child: compact
270
+ ? Column(
271
+ crossAxisAlignment: CrossAxisAlignment.start,
272
+ children: <Widget>[
273
+ _SettingsWorkspaceNav(
274
+ selected: _selectedSection,
275
+ compact: true,
276
+ onSelected: _selectSection,
277
+ ),
278
+ const SizedBox(height: 16),
279
+ Expanded(child: _buildContent()),
280
+ ],
281
+ )
282
+ : Row(
283
+ crossAxisAlignment: CrossAxisAlignment.start,
284
+ children: <Widget>[
285
+ SizedBox(
286
+ width: 220,
287
+ child: _SettingsWorkspaceNav(
288
+ selected: _selectedSection,
289
+ compact: false,
290
+ onSelected: _selectSection,
291
+ ),
292
+ ),
293
+ const SizedBox(width: 24),
294
+ Expanded(child: _buildContent()),
295
+ ],
296
+ ),
297
+ ),
298
+ ),
299
+ ),
300
+ ],
301
+ ),
302
+ );
303
+ }
304
+
305
+ void _selectSection(_SettingsWorkspaceSection section) {
306
+ setState(() => _selectedSection = section);
307
+ if (section == _SettingsWorkspaceSection.app) {
308
+ widget.controller.setSelectedSection(AppSection.settings);
309
+ return;
310
+ }
311
+ widget.controller.setSelectedSection(AppSection.accountSettings);
312
+ }
313
+
314
+ Widget _buildContent() {
315
+ switch (_selectedSection) {
316
+ case _SettingsWorkspaceSection.app:
317
+ return SettingsPanel(controller: widget.controller, embedded: true);
318
+ case _SettingsWorkspaceSection.account:
319
+ return AccountSettingsPanel(
320
+ controller: widget.controller,
321
+ embedded: true,
322
+ initialTab: AccountSettingsTab.account,
323
+ );
324
+ case _SettingsWorkspaceSection.security:
325
+ return AccountSettingsPanel(
326
+ controller: widget.controller,
327
+ embedded: true,
328
+ initialTab: AccountSettingsTab.security,
329
+ );
330
+ }
331
+ }
332
+ }
333
+
334
+ class _SettingsWorkspaceNav extends StatelessWidget {
335
+ const _SettingsWorkspaceNav({
336
+ required this.selected,
337
+ required this.compact,
338
+ required this.onSelected,
339
+ });
340
+
341
+ final _SettingsWorkspaceSection selected;
342
+ final bool compact;
343
+ final ValueChanged<_SettingsWorkspaceSection> onSelected;
344
+
345
+ @override
346
+ Widget build(BuildContext context) {
347
+ final items = <Widget>[
348
+ _navButton(
349
+ section: _SettingsWorkspaceSection.app,
350
+ icon: Icons.tune,
351
+ label: 'App Settings',
352
+ ),
353
+ _navButton(
354
+ section: _SettingsWorkspaceSection.account,
355
+ icon: Icons.person_outline,
356
+ label: 'Account',
357
+ ),
358
+ _navButton(
359
+ section: _SettingsWorkspaceSection.security,
360
+ icon: Icons.security_outlined,
361
+ label: 'Security',
362
+ ),
363
+ ];
364
+ return compact
365
+ ? Wrap(spacing: 8, runSpacing: 8, children: items)
366
+ : Column(
367
+ crossAxisAlignment: CrossAxisAlignment.stretch,
368
+ children: items,
369
+ );
370
+ }
371
+
372
+ Widget _navButton({
373
+ required _SettingsWorkspaceSection section,
374
+ required IconData icon,
375
+ required String label,
376
+ }) {
377
+ final button = _SidebarButton(
378
+ label: label,
379
+ icon: icon,
380
+ active: selected == section,
381
+ onTap: () => onSelected(section),
382
+ );
383
+ if (compact) {
384
+ return button;
385
+ }
386
+ return Padding(padding: const EdgeInsets.only(bottom: 8), child: button);
387
+ }
388
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.3.1-beta.63",
3
+ "version": "2.3.1-beta.64",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
@@ -442,6 +442,9 @@ db.exec(`
442
442
  user_id INTEGER NOT NULL,
443
443
  agent_id TEXT,
444
444
  name TEXT NOT NULL,
445
+ widget_kind TEXT DEFAULT 'custom',
446
+ system_key TEXT,
447
+ is_system INTEGER DEFAULT 0,
445
448
  template TEXT NOT NULL,
446
449
  layout_variant TEXT NOT NULL,
447
450
  definition_json TEXT DEFAULT '{}',
@@ -493,6 +496,13 @@ db.exec(`
493
496
  user_id INTEGER NOT NULL,
494
497
  agent_id TEXT,
495
498
  category TEXT DEFAULT 'episodic',
499
+ scope_type TEXT DEFAULT 'agent',
500
+ scope_id TEXT,
501
+ source_type TEXT,
502
+ source_id TEXT,
503
+ source_label TEXT,
504
+ stale_after_days INTEGER,
505
+ metadata_json TEXT DEFAULT '{}',
496
506
  content TEXT NOT NULL,
497
507
  importance INTEGER DEFAULT 5,
498
508
  embedding TEXT,
@@ -517,6 +527,36 @@ db.exec(`
517
527
  CREATE INDEX IF NOT EXISTS idx_memories_user ON memories(user_id, archived, updated_at DESC);
518
528
  CREATE INDEX IF NOT EXISTS idx_memories_category ON memories(user_id, category, archived);
519
529
 
530
+ CREATE TABLE IF NOT EXISTS assistant_self_state (
531
+ user_id INTEGER NOT NULL,
532
+ agent_id TEXT NOT NULL,
533
+ identity_json TEXT DEFAULT '{}',
534
+ focus_json TEXT DEFAULT '{}',
535
+ updated_at TEXT DEFAULT (datetime('now')),
536
+ PRIMARY KEY (user_id, agent_id),
537
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
538
+ FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE CASCADE
539
+ );
540
+
541
+ CREATE TABLE IF NOT EXISTS agent_run_events (
542
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
543
+ run_id TEXT NOT NULL,
544
+ user_id INTEGER NOT NULL,
545
+ agent_id TEXT,
546
+ event_type TEXT NOT NULL,
547
+ request_id TEXT,
548
+ step_id TEXT,
549
+ sequence_index INTEGER DEFAULT 0,
550
+ payload_json TEXT DEFAULT '{}',
551
+ created_at TEXT DEFAULT (datetime('now')),
552
+ FOREIGN KEY (run_id) REFERENCES agent_runs(id) ON DELETE CASCADE,
553
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
554
+ FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL
555
+ );
556
+
557
+ CREATE INDEX IF NOT EXISTS idx_agent_run_events_run ON agent_run_events(run_id, sequence_index, id);
558
+ CREATE INDEX IF NOT EXISTS idx_agent_run_events_user ON agent_run_events(user_id, created_at DESC);
559
+
520
560
  CREATE TABLE IF NOT EXISTS agent_settings (
521
561
  id INTEGER PRIMARY KEY AUTOINCREMENT,
522
562
  user_id INTEGER NOT NULL,
@@ -837,6 +877,16 @@ for (const col of [
837
877
  "ALTER TABLE conversation_history ADD COLUMN agent_id TEXT",
838
878
  "ALTER TABLE memories ADD COLUMN agent_id TEXT",
839
879
  "ALTER TABLE core_memory ADD COLUMN agent_id TEXT",
880
+ "ALTER TABLE ai_widgets ADD COLUMN widget_kind TEXT DEFAULT 'custom'",
881
+ "ALTER TABLE ai_widgets ADD COLUMN system_key TEXT",
882
+ "ALTER TABLE ai_widgets ADD COLUMN is_system INTEGER DEFAULT 0",
883
+ "ALTER TABLE memories ADD COLUMN scope_type TEXT DEFAULT 'agent'",
884
+ "ALTER TABLE memories ADD COLUMN scope_id TEXT",
885
+ "ALTER TABLE memories ADD COLUMN source_type TEXT",
886
+ "ALTER TABLE memories ADD COLUMN source_id TEXT",
887
+ "ALTER TABLE memories ADD COLUMN source_label TEXT",
888
+ "ALTER TABLE memories ADD COLUMN stale_after_days INTEGER",
889
+ "ALTER TABLE memories ADD COLUMN metadata_json TEXT DEFAULT '{}'",
840
890
  "ALTER TABLE scheduled_tasks ADD COLUMN run_at TEXT",
841
891
  "ALTER TABLE scheduled_tasks ADD COLUMN one_time INTEGER DEFAULT 0",
842
892
  "ALTER TABLE scheduled_tasks ADD COLUMN execution_mode TEXT DEFAULT 'prompt'",
@@ -895,7 +945,9 @@ function createAgentScopedIndexes() {
895
945
  ['scheduled_tasks', 'CREATE INDEX IF NOT EXISTS idx_scheduled_tasks_agent ON scheduled_tasks(user_id, agent_id)'],
896
946
  ['conversation_history', 'CREATE INDEX IF NOT EXISTS idx_conv_history_agent ON conversation_history(user_id, agent_id, created_at DESC)'],
897
947
  ['memories', 'CREATE INDEX IF NOT EXISTS idx_memories_agent ON memories(user_id, agent_id, archived, updated_at DESC)'],
948
+ ['memories', 'CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(user_id, agent_id, scope_type, scope_id, archived, updated_at DESC)'],
898
949
  ['core_memory', 'CREATE INDEX IF NOT EXISTS idx_core_memory_agent ON core_memory(user_id, agent_id, key)'],
950
+ ['ai_widgets', 'CREATE UNIQUE INDEX IF NOT EXISTS idx_ai_widgets_system_key ON ai_widgets(user_id, agent_id, system_key) WHERE system_key IS NOT NULL'],
899
951
  ];
900
952
  for (const [table, statement] of statements) {
901
953
  if (!tableHasColumn(table, 'agent_id')) continue;
@@ -1 +1 @@
1
- 70a278b8aca183460b7852b89e27d1c7
1
+ 041b637a102d15b05aa2cd1af9c6e61e
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"42d3d75a56efe1a2e9902f52dc8006099c45d9
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "3646065568" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "4064509463" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });