neoagent 2.3.1-beta.72 → 2.3.1-beta.73
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_account_settings.dart +62 -0
- package/flutter_app/lib/main_controller.dart +30 -6
- package/flutter_app/lib/main_settings.dart +2 -9
- package/flutter_app/lib/src/backend_client.dart +10 -1
- package/package.json +1 -1
- package/server/db/database.js +13 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +33084 -32987
- package/server/routes/account.js +26 -1
- package/server/routes/auth.js +6 -4
- package/server/routes/settings.js +8 -17
- package/server/services/bootstrap_helpers.js +0 -34
- package/server/services/browser/controller.js +2 -5
- package/server/services/runtime/backends/local-vm.js +2 -2
- package/server/guest-agent.README.md +0 -8
|
@@ -167,6 +167,7 @@ class AccountSettingsPanel extends StatefulWidget {
|
|
|
167
167
|
|
|
168
168
|
class _AccountSettingsPanelState extends State<AccountSettingsPanel> {
|
|
169
169
|
late AccountSettingsTab _selectedTab;
|
|
170
|
+
late final TextEditingController _displayNameController;
|
|
170
171
|
late final TextEditingController _emailController;
|
|
171
172
|
late final TextEditingController _emailPasswordController;
|
|
172
173
|
late final TextEditingController _setupPasswordController;
|
|
@@ -178,6 +179,8 @@ class _AccountSettingsPanelState extends State<AccountSettingsPanel> {
|
|
|
178
179
|
late final TextEditingController _confirmNewPasswordController;
|
|
179
180
|
Map<String, dynamic>? _pendingSetup;
|
|
180
181
|
List<String> _recoveryCodes = const <String>[];
|
|
182
|
+
String? _displayNameSuccessMessage;
|
|
183
|
+
String? _displayNameInlineError;
|
|
181
184
|
String? _emailSuccessMessage;
|
|
182
185
|
String? _emailInlineError;
|
|
183
186
|
String? _passwordSuccessMessage;
|
|
@@ -187,6 +190,9 @@ class _AccountSettingsPanelState extends State<AccountSettingsPanel> {
|
|
|
187
190
|
void initState() {
|
|
188
191
|
super.initState();
|
|
189
192
|
_selectedTab = widget.initialTab ?? AccountSettingsTab.account;
|
|
193
|
+
_displayNameController = TextEditingController(
|
|
194
|
+
text: widget.controller.user?['display_name']?.toString() ?? '',
|
|
195
|
+
);
|
|
190
196
|
_emailController = TextEditingController(
|
|
191
197
|
text: widget.controller.user?['email']?.toString() ?? '',
|
|
192
198
|
);
|
|
@@ -208,6 +214,11 @@ class _AccountSettingsPanelState extends State<AccountSettingsPanel> {
|
|
|
208
214
|
oldWidget.initialTab != widget.initialTab) {
|
|
209
215
|
_selectedTab = widget.initialTab!;
|
|
210
216
|
}
|
|
217
|
+
final displayName =
|
|
218
|
+
widget.controller.user?['display_name']?.toString() ?? '';
|
|
219
|
+
if (_displayNameController.text.isEmpty && displayName.isNotEmpty) {
|
|
220
|
+
_displayNameController.text = displayName;
|
|
221
|
+
}
|
|
211
222
|
final email = widget.controller.user?['email']?.toString() ?? '';
|
|
212
223
|
if (_emailController.text.isEmpty && email.isNotEmpty) {
|
|
213
224
|
_emailController.text = email;
|
|
@@ -216,6 +227,7 @@ class _AccountSettingsPanelState extends State<AccountSettingsPanel> {
|
|
|
216
227
|
|
|
217
228
|
@override
|
|
218
229
|
void dispose() {
|
|
230
|
+
_displayNameController.dispose();
|
|
219
231
|
_emailController.dispose();
|
|
220
232
|
_emailPasswordController.dispose();
|
|
221
233
|
_setupPasswordController.dispose();
|
|
@@ -409,6 +421,56 @@ class _AccountSettingsPanelState extends State<AccountSettingsPanel> {
|
|
|
409
421
|
const SizedBox(height: 12),
|
|
410
422
|
_MetaPill(label: username, icon: Icons.person_outline),
|
|
411
423
|
const SizedBox(height: 18),
|
|
424
|
+
TextField(
|
|
425
|
+
controller: _displayNameController,
|
|
426
|
+
decoration: const InputDecoration(
|
|
427
|
+
labelText: 'Display name',
|
|
428
|
+
helperText: 'Shown in the sidebar. Leave blank to use your username.',
|
|
429
|
+
),
|
|
430
|
+
),
|
|
431
|
+
if (_displayNameInlineError != null) ...<Widget>[
|
|
432
|
+
const SizedBox(height: 10),
|
|
433
|
+
_InlineError(message: _displayNameInlineError!),
|
|
434
|
+
],
|
|
435
|
+
if (_displayNameSuccessMessage != null) ...<Widget>[
|
|
436
|
+
const SizedBox(height: 10),
|
|
437
|
+
_InlineSuccess(message: _displayNameSuccessMessage!),
|
|
438
|
+
],
|
|
439
|
+
const SizedBox(height: 14),
|
|
440
|
+
FilledButton.icon(
|
|
441
|
+
onPressed: controller.isSavingAccountSettings
|
|
442
|
+
? null
|
|
443
|
+
: () async {
|
|
444
|
+
setState(() {
|
|
445
|
+
_displayNameInlineError = null;
|
|
446
|
+
_displayNameSuccessMessage = null;
|
|
447
|
+
});
|
|
448
|
+
final trimmed = _displayNameController.text.trim();
|
|
449
|
+
if (trimmed.length > 64) {
|
|
450
|
+
setState(() {
|
|
451
|
+
_displayNameInlineError =
|
|
452
|
+
'Display name must be 64 characters or fewer.';
|
|
453
|
+
});
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
final saved = await controller.updateAccountDisplayName(
|
|
457
|
+
displayName: trimmed,
|
|
458
|
+
);
|
|
459
|
+
if (saved && mounted) {
|
|
460
|
+
setState(() {
|
|
461
|
+
_displayNameSuccessMessage = 'Display name saved.';
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
icon: controller.isSavingAccountSettings
|
|
466
|
+
? const SizedBox.square(
|
|
467
|
+
dimension: 16,
|
|
468
|
+
child: CircularProgressIndicator(strokeWidth: 2),
|
|
469
|
+
)
|
|
470
|
+
: Icon(Icons.save_outlined),
|
|
471
|
+
label: Text('Save name'),
|
|
472
|
+
),
|
|
473
|
+
const SizedBox(height: 22),
|
|
412
474
|
Text('Current email: $currentEmail'),
|
|
413
475
|
const SizedBox(height: 16),
|
|
414
476
|
TextField(
|
|
@@ -4510,7 +4510,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4510
4510
|
notifyListeners();
|
|
4511
4511
|
|
|
4512
4512
|
final payload = <String, dynamic>{
|
|
4513
|
-
'headless_browser':
|
|
4513
|
+
'headless_browser': true,
|
|
4514
4514
|
'browser_backend': browserBackend,
|
|
4515
4515
|
'smarter_model_selector': smarterSelector,
|
|
4516
4516
|
'enabled_models': enabledModels,
|
|
@@ -4645,6 +4645,29 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4645
4645
|
}
|
|
4646
4646
|
}
|
|
4647
4647
|
|
|
4648
|
+
Future<bool> updateAccountDisplayName({
|
|
4649
|
+
required String displayName,
|
|
4650
|
+
}) async {
|
|
4651
|
+
isSavingAccountSettings = true;
|
|
4652
|
+
errorMessage = null;
|
|
4653
|
+
notifyListeners();
|
|
4654
|
+
try {
|
|
4655
|
+
_applyAccountResponse(
|
|
4656
|
+
await _backendClient.updateAccountDisplayName(
|
|
4657
|
+
baseUrl: backendUrl,
|
|
4658
|
+
displayName: displayName,
|
|
4659
|
+
),
|
|
4660
|
+
);
|
|
4661
|
+
return true;
|
|
4662
|
+
} catch (error) {
|
|
4663
|
+
errorMessage = _friendlyErrorMessage(error);
|
|
4664
|
+
return false;
|
|
4665
|
+
} finally {
|
|
4666
|
+
isSavingAccountSettings = false;
|
|
4667
|
+
notifyListeners();
|
|
4668
|
+
}
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4648
4671
|
Future<void> linkAccountProvider(String provider) async {
|
|
4649
4672
|
isSavingAccountSettings = true;
|
|
4650
4673
|
errorMessage = null;
|
|
@@ -5957,9 +5980,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5957
5980
|
details.length <= 800;
|
|
5958
5981
|
}
|
|
5959
5982
|
|
|
5960
|
-
bool get headlessBrowser =>
|
|
5961
|
-
settings['headless_browser'] != false &&
|
|
5962
|
-
settings['headless_browser'] != 'false';
|
|
5983
|
+
bool get headlessBrowser => true;
|
|
5963
5984
|
|
|
5964
5985
|
String get browserBackend =>
|
|
5965
5986
|
settings['browser_backend']?.toString().trim().toLowerCase() ?? 'vm';
|
|
@@ -6099,8 +6120,11 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
6099
6120
|
|
|
6100
6121
|
DateTime? get liveVoiceCaptureStartedAt => _liveVoiceCaptureStartedAt;
|
|
6101
6122
|
|
|
6102
|
-
String get accountLabel
|
|
6103
|
-
|
|
6123
|
+
String get accountLabel {
|
|
6124
|
+
final displayName = user?['display_name']?.toString().trim() ?? '';
|
|
6125
|
+
if (displayName.isNotEmpty) return displayName;
|
|
6126
|
+
return user?['username']?.toString() ?? username.ifEmpty('NeoAgent User');
|
|
6127
|
+
}
|
|
6104
6128
|
|
|
6105
6129
|
String get modelIndicator {
|
|
6106
6130
|
if (defaultChatModel != 'auto') {
|
|
@@ -456,7 +456,7 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
456
456
|
onPressed: controller.isSavingSettings
|
|
457
457
|
? null
|
|
458
458
|
: () => controller.saveSettings(
|
|
459
|
-
headlessBrowser:
|
|
459
|
+
headlessBrowser: true,
|
|
460
460
|
browserBackend: _browserBackend == 'extension'
|
|
461
461
|
? 'extension'
|
|
462
462
|
: 'vm',
|
|
@@ -593,14 +593,7 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
593
593
|
),
|
|
594
594
|
),
|
|
595
595
|
const SizedBox(height: 12),
|
|
596
|
-
|
|
597
|
-
title: 'Run browser headless',
|
|
598
|
-
subtitle:
|
|
599
|
-
'Keep browser automation off-screen when visible windows are not needed.',
|
|
600
|
-
value: _headlessBrowser,
|
|
601
|
-
onChanged: (value) => setState(() => _headlessBrowser = value),
|
|
602
|
-
),
|
|
603
|
-
const SizedBox(height: 12),
|
|
596
|
+
|
|
604
597
|
DropdownButtonFormField<String>(
|
|
605
598
|
initialValue: _browserBackend,
|
|
606
599
|
decoration: const InputDecoration(
|
|
@@ -10,7 +10,7 @@ class BackendClient {
|
|
|
10
10
|
BackendClient({AppHttpClient? httpClient})
|
|
11
11
|
: _httpClient = httpClient ?? createAppHttpClient();
|
|
12
12
|
|
|
13
|
-
static const Duration _requestTimeout = Duration(seconds:
|
|
13
|
+
static const Duration _requestTimeout = Duration(seconds: 60);
|
|
14
14
|
|
|
15
15
|
final AppHttpClient _httpClient;
|
|
16
16
|
|
|
@@ -246,6 +246,15 @@ class BackendClient {
|
|
|
246
246
|
});
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
Future<Map<String, dynamic>> updateAccountDisplayName({
|
|
250
|
+
required String baseUrl,
|
|
251
|
+
required String displayName,
|
|
252
|
+
}) async {
|
|
253
|
+
return putMap(baseUrl, '/api/account/display-name', <String, dynamic>{
|
|
254
|
+
'displayName': displayName,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
249
258
|
Future<Map<String, dynamic>> beginTwoFactorSetup({
|
|
250
259
|
required String baseUrl,
|
|
251
260
|
required String currentPassword,
|
package/package.json
CHANGED
package/server/db/database.js
CHANGED
|
@@ -1589,6 +1589,19 @@ function migrateUsersOnboarding() {
|
|
|
1589
1589
|
}
|
|
1590
1590
|
migrateUsersOnboarding();
|
|
1591
1591
|
|
|
1592
|
+
function migrateUsersDisplayName() {
|
|
1593
|
+
try {
|
|
1594
|
+
const columns = db.pragma('table_info(users)');
|
|
1595
|
+
const hasDisplayNameCol = columns.some((c) => c.name === 'display_name');
|
|
1596
|
+
if (!hasDisplayNameCol) {
|
|
1597
|
+
db.exec('ALTER TABLE users ADD COLUMN display_name TEXT');
|
|
1598
|
+
}
|
|
1599
|
+
} catch (err) {
|
|
1600
|
+
console.warn('Could not add display_name column:', err.message);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
migrateUsersDisplayName();
|
|
1604
|
+
|
|
1592
1605
|
try {
|
|
1593
1606
|
db.exec(`
|
|
1594
1607
|
INSERT OR REPLACE INTO conversation_history_fts(rowid, content, role, user_id, agent_id, agent_run_id)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
af7040916c02919dd1df9c5d1b46d6a6
|
|
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"42d3d75a56efe1a2e9902f52dc8006099c45d9
|
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "2814524395" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|