neoagent 3.2.1-beta.10 → 3.2.1-beta.12
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_controller.dart +46 -4
- package/flutter_app/lib/main_models.dart +4 -2
- package/flutter_app/lib/main_operations.dart +0 -49
- package/flutter_app/lib/main_settings.dart +338 -0
- package/flutter_app/lib/src/backend_client.dart +19 -0
- package/package.json +1 -1
- package/server/http/routes.js +1 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +65635 -65088
- package/server/routes/behavior.js +80 -0
- package/server/routes/settings.js +4 -0
- package/server/services/ai/history.js +1 -1
- package/server/services/ai/loop/agent_engine_core.js +97 -16
- package/server/services/ai/loop/completion_judge.js +211 -44
- package/server/services/ai/loop/conversation_loop.js +6 -11
- package/server/services/ai/loop/messaging_delivery.js +47 -0
- package/server/services/ai/messagingFallback.js +2 -2
- package/server/services/ai/model_failure_cache.js +7 -0
- package/server/services/ai/systemPrompt.js +30 -128
- package/server/services/ai/taskAnalysis.js +47 -2
- package/server/services/ai/toolEvidence.js +65 -159
- package/server/services/ai/tools.js +60 -8
- package/server/services/behavior/config.js +251 -0
- package/server/services/behavior/defaults.js +68 -0
- package/server/services/behavior/delivery.js +176 -0
- package/server/services/behavior/index.js +43 -0
- package/server/services/behavior/model_client.js +35 -0
- package/server/services/behavior/modules/agent_identity.js +37 -0
- package/server/services/behavior/modules/channel_style.js +28 -0
- package/server/services/behavior/modules/index.js +29 -0
- package/server/services/behavior/modules/norms.js +101 -0
- package/server/services/behavior/modules/persona.js +172 -0
- package/server/services/behavior/modules/persona_prompt.js +238 -0
- package/server/services/behavior/modules/social_memory.js +86 -0
- package/server/services/behavior/modules/social_observability.js +94 -0
- package/server/services/behavior/modules/social_signals.js +41 -0
- package/server/services/behavior/modules/theory_of_mind.js +118 -0
- package/server/services/behavior/modules/turn_taking.js +237 -0
- package/server/services/behavior/pipeline.js +324 -0
- package/server/services/behavior/registry.js +78 -0
- package/server/services/behavior/signals.js +107 -0
- package/server/services/behavior/state.js +99 -0
- package/server/services/behavior/system_prompt.js +75 -0
- package/server/services/memory/manager.js +14 -33
- package/server/services/messaging/access_policy.js +10 -6
- package/server/services/messaging/automation.js +158 -27
- package/server/services/messaging/discord.js +11 -1
- package/server/services/messaging/formatting_guides.js +2 -4
- package/server/services/messaging/http_platforms.js +4 -3
- package/server/services/messaging/inbound_queue.js +74 -13
- package/server/services/messaging/inbound_store.js +33 -0
- package/server/services/messaging/manager.js +18 -0
- package/server/services/messaging/telegram.js +10 -1
- package/server/services/messaging/whatsapp.js +11 -0
- package/server/services/social_reach/channels/social_video.js +1 -1
- package/server/services/social_video/captions.js +2 -2
- package/server/services/social_video/service.js +194 -29
- package/server/services/voice/message.js +1 -1
- package/server/services/voice/runtime.js +2 -2
- package/server/utils/logger.js +19 -0
- package/server/services/ai/terminal_reply.js +0 -18
|
@@ -132,6 +132,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
132
132
|
const <LinkedAuthProviderItem>[];
|
|
133
133
|
QrLoginChallenge? qrLoginChallenge;
|
|
134
134
|
Map<String, dynamic> settings = const <String, dynamic>{};
|
|
135
|
+
Map<String, dynamic> behaviorConfig = const <String, dynamic>{};
|
|
135
136
|
Map<String, dynamic>? versionInfo;
|
|
136
137
|
Map<String, dynamic>? backendHealthStatus;
|
|
137
138
|
HealthBridgeStatus? deviceHealthStatus;
|
|
@@ -1420,6 +1421,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1420
1421
|
usageAndLimits = null;
|
|
1421
1422
|
linkedAuthProviders = const <LinkedAuthProviderItem>[];
|
|
1422
1423
|
settings = const <String, dynamic>{};
|
|
1424
|
+
behaviorConfig = const <String, dynamic>{};
|
|
1423
1425
|
chatMessages = const <ChatEntry>[];
|
|
1424
1426
|
_resetChatHistoryPagination();
|
|
1425
1427
|
agentProfiles = const <AgentProfile>[];
|
|
@@ -1958,6 +1960,11 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1958
1960
|
_backendClient.fetchSettings(backendUrl, agentId: agentId),
|
|
1959
1961
|
const <String, dynamic>{},
|
|
1960
1962
|
);
|
|
1963
|
+
final behaviorFuture = _softRefreshLoad<Map<String, dynamic>>(
|
|
1964
|
+
'behavior_config',
|
|
1965
|
+
_backendClient.fetchBehaviorConfig(backendUrl, agentId: agentId),
|
|
1966
|
+
const <String, dynamic>{},
|
|
1967
|
+
);
|
|
1961
1968
|
final runsFuture = _softRefreshLoad<Map<String, dynamic>>(
|
|
1962
1969
|
'runs',
|
|
1963
1970
|
_backendClient.fetchRuns(backendUrl, agentId: agentId),
|
|
@@ -2094,6 +2101,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2094
2101
|
final modelsResponse = await modelsFuture;
|
|
2095
2102
|
final providersResponse = await providersFuture;
|
|
2096
2103
|
final settingsResponse = await settingsFuture;
|
|
2104
|
+
final behaviorResponse = await behaviorFuture;
|
|
2097
2105
|
final runsResponse = await runsFuture;
|
|
2098
2106
|
final timelineResponse = await timelineFuture;
|
|
2099
2107
|
final versionResponse = await versionFuture;
|
|
@@ -2137,6 +2145,9 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2137
2145
|
);
|
|
2138
2146
|
|
|
2139
2147
|
settings = Map<String, dynamic>.from(settingsResponse);
|
|
2148
|
+
behaviorConfig = behaviorResponse['config'] is Map
|
|
2149
|
+
? Map<String, dynamic>.from(behaviorResponse['config'] as Map)
|
|
2150
|
+
: const <String, dynamic>{};
|
|
2140
2151
|
recentRuns = _decodeModelList(
|
|
2141
2152
|
'runs',
|
|
2142
2153
|
runsResponse['runs'],
|
|
@@ -4221,6 +4232,27 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4221
4232
|
}
|
|
4222
4233
|
}
|
|
4223
4234
|
|
|
4235
|
+
Future<void> saveBehaviorConfig(Map<String, dynamic> config) async {
|
|
4236
|
+
isSavingSettings = true;
|
|
4237
|
+
errorMessage = null;
|
|
4238
|
+
notifyListeners();
|
|
4239
|
+
try {
|
|
4240
|
+
final response = await _backendClient.saveBehaviorConfig(
|
|
4241
|
+
backendUrl,
|
|
4242
|
+
config,
|
|
4243
|
+
agentId: _scopedAgentId,
|
|
4244
|
+
);
|
|
4245
|
+
behaviorConfig = response['config'] is Map
|
|
4246
|
+
? Map<String, dynamic>.from(response['config'] as Map)
|
|
4247
|
+
: Map<String, dynamic>.from(config);
|
|
4248
|
+
} catch (error) {
|
|
4249
|
+
errorMessage = _friendlyErrorMessage(error);
|
|
4250
|
+
} finally {
|
|
4251
|
+
isSavingSettings = false;
|
|
4252
|
+
notifyListeners();
|
|
4253
|
+
}
|
|
4254
|
+
}
|
|
4255
|
+
|
|
4224
4256
|
void _applyAccountResponse(Map<String, dynamic> response) {
|
|
4225
4257
|
if (response['user'] is Map) {
|
|
4226
4258
|
user = Map<String, dynamic>.from(response['user'] as Map);
|
|
@@ -5338,10 +5370,20 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5338
5370
|
}
|
|
5339
5371
|
|
|
5340
5372
|
Future<void> updateAssistantBehaviorNotes(String content) async {
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5373
|
+
isSavingSettings = true;
|
|
5374
|
+
errorMessage = null;
|
|
5375
|
+
notifyListeners();
|
|
5376
|
+
try {
|
|
5377
|
+
await _backendClient.saveSettings(backendUrl, <String, dynamic>{
|
|
5378
|
+
'assistant_behavior_notes': content,
|
|
5379
|
+
}, agentId: _scopedAgentId);
|
|
5380
|
+
await refreshMemory();
|
|
5381
|
+
} catch (error) {
|
|
5382
|
+
errorMessage = _friendlyErrorMessage(error);
|
|
5383
|
+
} finally {
|
|
5384
|
+
isSavingSettings = false;
|
|
5385
|
+
notifyListeners();
|
|
5386
|
+
}
|
|
5345
5387
|
}
|
|
5346
5388
|
|
|
5347
5389
|
Future<void> updateCoreMemory(String key, String value) async {
|
|
@@ -2548,7 +2548,8 @@ class OfficialIntegrationAppItem {
|
|
|
2548
2548
|
String get effectiveStatus =>
|
|
2549
2549
|
!isConnected && hasExpiredAccounts ? 'expired' : connection.status;
|
|
2550
2550
|
|
|
2551
|
-
String get statusLabel =>
|
|
2551
|
+
String get statusLabel =>
|
|
2552
|
+
effectiveStatus == 'expired' ? 'Expired' : connection.statusLabel;
|
|
2552
2553
|
}
|
|
2553
2554
|
|
|
2554
2555
|
class OfficialIntegrationEnvStatus {
|
|
@@ -2780,7 +2781,8 @@ class OfficialIntegrationItem {
|
|
|
2780
2781
|
String get effectiveStatus =>
|
|
2781
2782
|
!isConnected && hasExpiredAccounts ? 'expired' : connection.status;
|
|
2782
2783
|
|
|
2783
|
-
String get statusLabel =>
|
|
2784
|
+
String get statusLabel =>
|
|
2785
|
+
effectiveStatus == 'expired' ? 'Expired' : connection.statusLabel;
|
|
2784
2786
|
}
|
|
2785
2787
|
|
|
2786
2788
|
class SkillDocument {
|
|
@@ -1663,11 +1663,6 @@ class _MemoryPanelState extends State<MemoryPanel>
|
|
|
1663
1663
|
icon: Icon(Icons.bug_report_outlined),
|
|
1664
1664
|
label: Text('Inspect'),
|
|
1665
1665
|
),
|
|
1666
|
-
OutlinedButton.icon(
|
|
1667
|
-
onPressed: () => _openBehaviorNotesEditor(context, controller),
|
|
1668
|
-
icon: Icon(Icons.edit_outlined),
|
|
1669
|
-
label: Text('Behavior Notes'),
|
|
1670
|
-
),
|
|
1671
1666
|
FilledButton.icon(
|
|
1672
1667
|
onPressed: () => _openMemoryCreator(context, controller),
|
|
1673
1668
|
icon: Icon(Icons.add),
|
|
@@ -2291,50 +2286,6 @@ class _MemoryPanelState extends State<MemoryPanel>
|
|
|
2291
2286
|
);
|
|
2292
2287
|
}
|
|
2293
2288
|
|
|
2294
|
-
Future<void> _openBehaviorNotesEditor(
|
|
2295
|
-
BuildContext context,
|
|
2296
|
-
NeoAgentController controller,
|
|
2297
|
-
) async {
|
|
2298
|
-
final contentController = TextEditingController(
|
|
2299
|
-
text: controller.memoryOverview.assistantBehaviorNotes,
|
|
2300
|
-
);
|
|
2301
|
-
await showDialog<void>(
|
|
2302
|
-
context: context,
|
|
2303
|
-
builder: (context) {
|
|
2304
|
-
return AlertDialog(
|
|
2305
|
-
backgroundColor: _bgCard,
|
|
2306
|
-
title: Text('Edit Assistant Behavior Notes'),
|
|
2307
|
-
content: SizedBox(
|
|
2308
|
-
width: 720,
|
|
2309
|
-
child: TextField(
|
|
2310
|
-
controller: contentController,
|
|
2311
|
-
minLines: 16,
|
|
2312
|
-
maxLines: 24,
|
|
2313
|
-
decoration: const InputDecoration(
|
|
2314
|
-
labelText: 'assistant_behavior_notes',
|
|
2315
|
-
),
|
|
2316
|
-
),
|
|
2317
|
-
),
|
|
2318
|
-
actions: <Widget>[
|
|
2319
|
-
TextButton(
|
|
2320
|
-
onPressed: () => Navigator.of(context).pop(),
|
|
2321
|
-
child: Text('Cancel'),
|
|
2322
|
-
),
|
|
2323
|
-
FilledButton(
|
|
2324
|
-
onPressed: () async {
|
|
2325
|
-
await controller.updateAssistantBehaviorNotes(
|
|
2326
|
-
contentController.text,
|
|
2327
|
-
);
|
|
2328
|
-
if (context.mounted) Navigator.of(context).pop();
|
|
2329
|
-
},
|
|
2330
|
-
child: Text('Save'),
|
|
2331
|
-
),
|
|
2332
|
-
],
|
|
2333
|
-
);
|
|
2334
|
-
},
|
|
2335
|
-
);
|
|
2336
|
-
}
|
|
2337
|
-
|
|
2338
2289
|
Future<void> _openCoreMemoryEditor(
|
|
2339
2290
|
BuildContext context,
|
|
2340
2291
|
NeoAgentController controller, {
|
|
@@ -106,6 +106,18 @@ const _workspaceSettingsSection = _SettingsSection('workspace', <String>[
|
|
|
106
106
|
'routing',
|
|
107
107
|
]);
|
|
108
108
|
|
|
109
|
+
const _behaviorSettingsSection = _SettingsSection('behavior', <String>[
|
|
110
|
+
'behavior',
|
|
111
|
+
'persona',
|
|
112
|
+
'social intelligence',
|
|
113
|
+
'turn taking',
|
|
114
|
+
'groups',
|
|
115
|
+
'memory',
|
|
116
|
+
'norms',
|
|
117
|
+
'theory of mind',
|
|
118
|
+
'delivery',
|
|
119
|
+
]);
|
|
120
|
+
|
|
109
121
|
const _modelsSettingsSection = _SettingsSection('models', <String>[
|
|
110
122
|
'models',
|
|
111
123
|
'providers',
|
|
@@ -173,6 +185,7 @@ const _securitySettingsSection = _SettingsSection('security', <String>[
|
|
|
173
185
|
|
|
174
186
|
const List<_SettingsSection> _settingsSearchSections = <_SettingsSection>[
|
|
175
187
|
_overviewSettingsSection,
|
|
188
|
+
_behaviorSettingsSection,
|
|
176
189
|
_workspaceSettingsSection,
|
|
177
190
|
_socialReachSettingsSection,
|
|
178
191
|
_modelsSettingsSection,
|
|
@@ -200,6 +213,17 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
200
213
|
final Map<String, bool> _providerEnabled = <String, bool>{};
|
|
201
214
|
final Map<String, TextEditingController> _providerBaseUrlControllers =
|
|
202
215
|
<String, TextEditingController>{};
|
|
216
|
+
late final TextEditingController _behaviorNotesController;
|
|
217
|
+
late bool _behaviorEnabled;
|
|
218
|
+
late String _behaviorParticipationMode;
|
|
219
|
+
late double _behaviorMinimumNeedScore;
|
|
220
|
+
late double _behaviorBatchWindowMs;
|
|
221
|
+
late String _behaviorDecisionModelId;
|
|
222
|
+
late String _behaviorDeliveryStyle;
|
|
223
|
+
late bool _behaviorTheoryOfMindEnabled;
|
|
224
|
+
late bool _behaviorSocialMemoryEnabled;
|
|
225
|
+
late bool _behaviorNormsEnabled;
|
|
226
|
+
late bool _behaviorObservabilityEnabled;
|
|
203
227
|
|
|
204
228
|
bool _hasUnsavedChanges = false;
|
|
205
229
|
|
|
@@ -218,12 +242,14 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
218
242
|
void initState() {
|
|
219
243
|
super.initState();
|
|
220
244
|
_searchController = TextEditingController();
|
|
245
|
+
_behaviorNotesController = TextEditingController();
|
|
221
246
|
_hydrate();
|
|
222
247
|
}
|
|
223
248
|
|
|
224
249
|
@override
|
|
225
250
|
void dispose() {
|
|
226
251
|
_searchController.dispose();
|
|
252
|
+
_behaviorNotesController.dispose();
|
|
227
253
|
for (final controller in _providerBaseUrlControllers.values) {
|
|
228
254
|
controller.dispose();
|
|
229
255
|
}
|
|
@@ -234,6 +260,10 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
234
260
|
void didUpdateWidget(covariant SettingsPanel oldWidget) {
|
|
235
261
|
super.didUpdateWidget(oldWidget);
|
|
236
262
|
if (oldWidget.controller.settings != widget.controller.settings ||
|
|
263
|
+
oldWidget.controller.behaviorConfig !=
|
|
264
|
+
widget.controller.behaviorConfig ||
|
|
265
|
+
oldWidget.controller.memoryOverview !=
|
|
266
|
+
widget.controller.memoryOverview ||
|
|
237
267
|
oldWidget.controller.aiProviders != widget.controller.aiProviders ||
|
|
238
268
|
oldWidget.controller.supportedModels !=
|
|
239
269
|
widget.controller.supportedModels) {
|
|
@@ -270,6 +300,45 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
270
300
|
_voiceLiveProvider = controller.voiceLiveProvider;
|
|
271
301
|
_voiceLiveModel = controller.voiceLiveModel;
|
|
272
302
|
_voiceLiveVoice = controller.voiceLiveVoice;
|
|
303
|
+
final behavior = controller.behaviorConfig;
|
|
304
|
+
final modules = behavior['modules'] is Map
|
|
305
|
+
? Map<String, dynamic>.from(behavior['modules'] as Map)
|
|
306
|
+
: const <String, dynamic>{};
|
|
307
|
+
bool moduleEnabled(String id) {
|
|
308
|
+
final module = modules[id];
|
|
309
|
+
return module is! Map || module['enabled'] != false;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
_behaviorEnabled = behavior['enabled'] != false;
|
|
313
|
+
_behaviorParticipationMode =
|
|
314
|
+
<String>{
|
|
315
|
+
'automatic',
|
|
316
|
+
'mention_only',
|
|
317
|
+
'always',
|
|
318
|
+
}.contains(behavior['participationMode']?.toString())
|
|
319
|
+
? behavior['participationMode'].toString()
|
|
320
|
+
: 'automatic';
|
|
321
|
+
_behaviorMinimumNeedScore =
|
|
322
|
+
((behavior['minimumNeedScore'] as num?)?.toDouble() ?? 0.72)
|
|
323
|
+
.clamp(0.0, 1.0)
|
|
324
|
+
.toDouble();
|
|
325
|
+
_behaviorBatchWindowMs =
|
|
326
|
+
((behavior['batchWindowMs'] as num?)?.toDouble() ?? 900)
|
|
327
|
+
.clamp(0.0, 5000.0)
|
|
328
|
+
.toDouble();
|
|
329
|
+
_behaviorDecisionModelId =
|
|
330
|
+
behavior['decisionModelId']?.toString().trim() ?? '';
|
|
331
|
+
_behaviorDeliveryStyle = behavior['deliveryStyle'] == 'single'
|
|
332
|
+
? 'single'
|
|
333
|
+
: 'natural_bubbles';
|
|
334
|
+
_behaviorTheoryOfMindEnabled = moduleEnabled('theory_of_mind');
|
|
335
|
+
_behaviorSocialMemoryEnabled = moduleEnabled('social_memory');
|
|
336
|
+
_behaviorNormsEnabled = moduleEnabled('norms');
|
|
337
|
+
_behaviorObservabilityEnabled = moduleEnabled('social_observability');
|
|
338
|
+
final behaviorNotes = controller.memoryOverview.assistantBehaviorNotes;
|
|
339
|
+
if (_behaviorNotesController.text != behaviorNotes) {
|
|
340
|
+
_behaviorNotesController.text = behaviorNotes;
|
|
341
|
+
}
|
|
273
342
|
if (!_voiceLiveModelsByProvider.containsKey(_voiceLiveProvider)) {
|
|
274
343
|
_voiceLiveProvider = 'openai';
|
|
275
344
|
}
|
|
@@ -401,6 +470,13 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
401
470
|
_buildSettingsOverview(controller, availableModels.length),
|
|
402
471
|
const SizedBox(height: 16),
|
|
403
472
|
],
|
|
473
|
+
if (_matchesSettingsSection(
|
|
474
|
+
searchQuery,
|
|
475
|
+
_behaviorSettingsSection,
|
|
476
|
+
)) ...<Widget>[
|
|
477
|
+
_buildBehaviorSection(controller, routingModels),
|
|
478
|
+
const SizedBox(height: 16),
|
|
479
|
+
],
|
|
404
480
|
if (_matchesSettingsSection(
|
|
405
481
|
searchQuery,
|
|
406
482
|
_workspaceSettingsSection,
|
|
@@ -522,6 +598,42 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
522
598
|
voiceLiveVoice: _voiceLiveVoice,
|
|
523
599
|
aiProviderConfigs: _buildProviderPayload(),
|
|
524
600
|
);
|
|
601
|
+
if (controller.errorMessage != null) return;
|
|
602
|
+
final existingModules = controller.behaviorConfig['modules'] is Map
|
|
603
|
+
? Map<String, dynamic>.from(controller.behaviorConfig['modules'] as Map)
|
|
604
|
+
: <String, dynamic>{};
|
|
605
|
+
existingModules.addAll(<String, dynamic>{
|
|
606
|
+
'theory_of_mind': <String, dynamic>{
|
|
607
|
+
'enabled': _behaviorTheoryOfMindEnabled,
|
|
608
|
+
},
|
|
609
|
+
'social_memory': <String, dynamic>{
|
|
610
|
+
'enabled': _behaviorSocialMemoryEnabled,
|
|
611
|
+
},
|
|
612
|
+
'norms': <String, dynamic>{'enabled': _behaviorNormsEnabled},
|
|
613
|
+
'social_observability': <String, dynamic>{
|
|
614
|
+
'enabled': _behaviorObservabilityEnabled,
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
await controller.saveBehaviorConfig(<String, dynamic>{
|
|
618
|
+
...controller.behaviorConfig,
|
|
619
|
+
'enabled': _behaviorEnabled,
|
|
620
|
+
'participationMode': _behaviorParticipationMode,
|
|
621
|
+
'minimumNeedScore': _behaviorMinimumNeedScore,
|
|
622
|
+
'batchWindowMs': _behaviorBatchWindowMs.round(),
|
|
623
|
+
'decisionModelId': _behaviorDecisionModelId.isEmpty
|
|
624
|
+
? null
|
|
625
|
+
: _behaviorDecisionModelId,
|
|
626
|
+
'deliveryStyle': _behaviorDeliveryStyle,
|
|
627
|
+
'modules': existingModules,
|
|
628
|
+
});
|
|
629
|
+
if (controller.errorMessage != null) return;
|
|
630
|
+
if (_behaviorNotesController.text !=
|
|
631
|
+
controller.memoryOverview.assistantBehaviorNotes) {
|
|
632
|
+
await controller.updateAssistantBehaviorNotes(
|
|
633
|
+
_behaviorNotesController.text,
|
|
634
|
+
);
|
|
635
|
+
if (controller.errorMessage != null) return;
|
|
636
|
+
}
|
|
525
637
|
if (mounted) setState(() => _hasUnsavedChanges = false);
|
|
526
638
|
}
|
|
527
639
|
|
|
@@ -627,6 +739,232 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
627
739
|
);
|
|
628
740
|
}
|
|
629
741
|
|
|
742
|
+
Widget _buildBehaviorSection(
|
|
743
|
+
NeoAgentController controller,
|
|
744
|
+
List<ModelMeta> routingModels,
|
|
745
|
+
) {
|
|
746
|
+
final modelIds = <String>{
|
|
747
|
+
if (_behaviorDecisionModelId.isNotEmpty) _behaviorDecisionModelId,
|
|
748
|
+
...routingModels.map((model) => model.id),
|
|
749
|
+
}.toList();
|
|
750
|
+
return Card(
|
|
751
|
+
child: Padding(
|
|
752
|
+
padding: const EdgeInsets.all(20),
|
|
753
|
+
child: Column(
|
|
754
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
755
|
+
children: <Widget>[
|
|
756
|
+
const _SectionTitle('Behavior Modules'),
|
|
757
|
+
const SizedBox(height: 10),
|
|
758
|
+
Text(
|
|
759
|
+
'One runtime controls persona, group turn-taking, room memory, norms, Theory of Mind, and delivery.',
|
|
760
|
+
style: TextStyle(color: _textSecondary, height: 1.45),
|
|
761
|
+
),
|
|
762
|
+
const SizedBox(height: 12),
|
|
763
|
+
SwitchListTile.adaptive(
|
|
764
|
+
contentPadding: EdgeInsets.zero,
|
|
765
|
+
title: const Text('Enable behavior modules'),
|
|
766
|
+
subtitle: const Text(
|
|
767
|
+
'Direct messages remain responsive. Allowlisted groups use the participation mode below.',
|
|
768
|
+
),
|
|
769
|
+
value: _behaviorEnabled,
|
|
770
|
+
onChanged: (value) => setState(() {
|
|
771
|
+
_behaviorEnabled = value;
|
|
772
|
+
_hasUnsavedChanges = true;
|
|
773
|
+
}),
|
|
774
|
+
),
|
|
775
|
+
const SizedBox(height: 8),
|
|
776
|
+
DropdownButtonFormField<String>(
|
|
777
|
+
initialValue: _behaviorParticipationMode,
|
|
778
|
+
decoration: const InputDecoration(
|
|
779
|
+
labelText: 'Default group participation',
|
|
780
|
+
helperText:
|
|
781
|
+
'Automatic reads the room and normally holds back. Mention-only makes no decision call until directly addressed.',
|
|
782
|
+
),
|
|
783
|
+
items: const <DropdownMenuItem<String>>[
|
|
784
|
+
DropdownMenuItem(
|
|
785
|
+
value: 'automatic',
|
|
786
|
+
child: Text('Automatic, reserved'),
|
|
787
|
+
),
|
|
788
|
+
DropdownMenuItem(
|
|
789
|
+
value: 'mention_only',
|
|
790
|
+
child: Text('Mention or reply only'),
|
|
791
|
+
),
|
|
792
|
+
DropdownMenuItem(value: 'always', child: Text('Always engage')),
|
|
793
|
+
],
|
|
794
|
+
onChanged: !_behaviorEnabled
|
|
795
|
+
? null
|
|
796
|
+
: (value) {
|
|
797
|
+
if (value == null) return;
|
|
798
|
+
setState(() {
|
|
799
|
+
_behaviorParticipationMode = value;
|
|
800
|
+
_hasUnsavedChanges = true;
|
|
801
|
+
});
|
|
802
|
+
},
|
|
803
|
+
),
|
|
804
|
+
const SizedBox(height: 18),
|
|
805
|
+
Text(
|
|
806
|
+
'Minimum contribution value: ${_behaviorMinimumNeedScore.toStringAsFixed(2)}',
|
|
807
|
+
style: TextStyle(
|
|
808
|
+
color: _textPrimary,
|
|
809
|
+
fontWeight: FontWeight.w600,
|
|
810
|
+
),
|
|
811
|
+
),
|
|
812
|
+
Slider(
|
|
813
|
+
value: _behaviorMinimumNeedScore,
|
|
814
|
+
min: 0,
|
|
815
|
+
max: 1,
|
|
816
|
+
divisions: 20,
|
|
817
|
+
label: _behaviorMinimumNeedScore.toStringAsFixed(2),
|
|
818
|
+
onChanged: !_behaviorEnabled
|
|
819
|
+
? null
|
|
820
|
+
: (value) => setState(() {
|
|
821
|
+
_behaviorMinimumNeedScore = value;
|
|
822
|
+
_hasUnsavedChanges = true;
|
|
823
|
+
}),
|
|
824
|
+
),
|
|
825
|
+
Text(
|
|
826
|
+
'Higher values make NeoAgent more selective in groups.',
|
|
827
|
+
style: TextStyle(color: _textSecondary, fontSize: 12),
|
|
828
|
+
),
|
|
829
|
+
const SizedBox(height: 14),
|
|
830
|
+
Text(
|
|
831
|
+
'Room batch window: ${_behaviorBatchWindowMs.round()} ms',
|
|
832
|
+
style: TextStyle(
|
|
833
|
+
color: _textPrimary,
|
|
834
|
+
fontWeight: FontWeight.w600,
|
|
835
|
+
),
|
|
836
|
+
),
|
|
837
|
+
Slider(
|
|
838
|
+
value: _behaviorBatchWindowMs,
|
|
839
|
+
min: 0,
|
|
840
|
+
max: 5000,
|
|
841
|
+
divisions: 20,
|
|
842
|
+
label: '${_behaviorBatchWindowMs.round()} ms',
|
|
843
|
+
onChanged: !_behaviorEnabled
|
|
844
|
+
? null
|
|
845
|
+
: (value) => setState(() {
|
|
846
|
+
_behaviorBatchWindowMs = value;
|
|
847
|
+
_hasUnsavedChanges = true;
|
|
848
|
+
}),
|
|
849
|
+
),
|
|
850
|
+
const SizedBox(height: 12),
|
|
851
|
+
DropdownButtonFormField<String>(
|
|
852
|
+
initialValue: _behaviorDecisionModelId,
|
|
853
|
+
decoration: const InputDecoration(
|
|
854
|
+
labelText: 'Turn-taking model',
|
|
855
|
+
helperText:
|
|
856
|
+
'Automatic selects a fast model through the normal model catalog.',
|
|
857
|
+
),
|
|
858
|
+
items: <DropdownMenuItem<String>>[
|
|
859
|
+
const DropdownMenuItem(
|
|
860
|
+
value: '',
|
|
861
|
+
child: Text('Automatic (fast)'),
|
|
862
|
+
),
|
|
863
|
+
...modelIds.map(
|
|
864
|
+
(id) => DropdownMenuItem(value: id, child: Text(id)),
|
|
865
|
+
),
|
|
866
|
+
],
|
|
867
|
+
onChanged: !_behaviorEnabled
|
|
868
|
+
? null
|
|
869
|
+
: (value) {
|
|
870
|
+
if (value == null) return;
|
|
871
|
+
setState(() {
|
|
872
|
+
_behaviorDecisionModelId = value;
|
|
873
|
+
_hasUnsavedChanges = true;
|
|
874
|
+
});
|
|
875
|
+
},
|
|
876
|
+
),
|
|
877
|
+
const SizedBox(height: 12),
|
|
878
|
+
DropdownButtonFormField<String>(
|
|
879
|
+
initialValue: _behaviorDeliveryStyle,
|
|
880
|
+
decoration: const InputDecoration(
|
|
881
|
+
labelText: 'Messaging delivery',
|
|
882
|
+
),
|
|
883
|
+
items: const <DropdownMenuItem<String>>[
|
|
884
|
+
DropdownMenuItem(
|
|
885
|
+
value: 'natural_bubbles',
|
|
886
|
+
child: Text('Natural bubbles'),
|
|
887
|
+
),
|
|
888
|
+
DropdownMenuItem(
|
|
889
|
+
value: 'single',
|
|
890
|
+
child: Text('Single message'),
|
|
891
|
+
),
|
|
892
|
+
],
|
|
893
|
+
onChanged: !_behaviorEnabled
|
|
894
|
+
? null
|
|
895
|
+
: (value) {
|
|
896
|
+
if (value == null) return;
|
|
897
|
+
setState(() {
|
|
898
|
+
_behaviorDeliveryStyle = value;
|
|
899
|
+
_hasUnsavedChanges = true;
|
|
900
|
+
});
|
|
901
|
+
},
|
|
902
|
+
),
|
|
903
|
+
const SizedBox(height: 10),
|
|
904
|
+
SwitchListTile.adaptive(
|
|
905
|
+
contentPadding: EdgeInsets.zero,
|
|
906
|
+
title: const Text('Theory of Mind refinement'),
|
|
907
|
+
value: _behaviorTheoryOfMindEnabled,
|
|
908
|
+
onChanged: !_behaviorEnabled
|
|
909
|
+
? null
|
|
910
|
+
: (value) => setState(() {
|
|
911
|
+
_behaviorTheoryOfMindEnabled = value;
|
|
912
|
+
_hasUnsavedChanges = true;
|
|
913
|
+
}),
|
|
914
|
+
),
|
|
915
|
+
SwitchListTile.adaptive(
|
|
916
|
+
contentPadding: EdgeInsets.zero,
|
|
917
|
+
title: const Text('Channel-scoped social memory'),
|
|
918
|
+
value: _behaviorSocialMemoryEnabled,
|
|
919
|
+
onChanged: !_behaviorEnabled
|
|
920
|
+
? null
|
|
921
|
+
: (value) => setState(() {
|
|
922
|
+
_behaviorSocialMemoryEnabled = value;
|
|
923
|
+
_hasUnsavedChanges = true;
|
|
924
|
+
}),
|
|
925
|
+
),
|
|
926
|
+
SwitchListTile.adaptive(
|
|
927
|
+
contentPadding: EdgeInsets.zero,
|
|
928
|
+
title: const Text('Learn room norms'),
|
|
929
|
+
value: _behaviorNormsEnabled,
|
|
930
|
+
onChanged: !_behaviorEnabled
|
|
931
|
+
? null
|
|
932
|
+
: (value) => setState(() {
|
|
933
|
+
_behaviorNormsEnabled = value;
|
|
934
|
+
_hasUnsavedChanges = true;
|
|
935
|
+
}),
|
|
936
|
+
),
|
|
937
|
+
SwitchListTile.adaptive(
|
|
938
|
+
contentPadding: EdgeInsets.zero,
|
|
939
|
+
title: const Text('Social observability'),
|
|
940
|
+
value: _behaviorObservabilityEnabled,
|
|
941
|
+
onChanged: !_behaviorEnabled
|
|
942
|
+
? null
|
|
943
|
+
: (value) => setState(() {
|
|
944
|
+
_behaviorObservabilityEnabled = value;
|
|
945
|
+
_hasUnsavedChanges = true;
|
|
946
|
+
}),
|
|
947
|
+
),
|
|
948
|
+
const SizedBox(height: 12),
|
|
949
|
+
TextField(
|
|
950
|
+
controller: _behaviorNotesController,
|
|
951
|
+
minLines: 4,
|
|
952
|
+
maxLines: 10,
|
|
953
|
+
onChanged: (_) => setState(() {
|
|
954
|
+
_hasUnsavedChanges = true;
|
|
955
|
+
}),
|
|
956
|
+
decoration: const InputDecoration(
|
|
957
|
+
labelText: 'Persona behavior notes',
|
|
958
|
+
helperText:
|
|
959
|
+
'Durable instructions for voice and interaction style. Safety and execution rules still take priority.',
|
|
960
|
+
),
|
|
961
|
+
),
|
|
962
|
+
],
|
|
963
|
+
),
|
|
964
|
+
),
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
|
|
630
968
|
Widget _buildWorkspaceSection(NeoAgentController controller) {
|
|
631
969
|
return Card(
|
|
632
970
|
child: Padding(
|
|
@@ -514,6 +514,25 @@ class BackendClient {
|
|
|
514
514
|
return putMap(baseUrl, '/api/settings', _withAgentId(payload, agentId));
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
+
Future<Map<String, dynamic>> fetchBehaviorConfig(
|
|
518
|
+
String baseUrl, {
|
|
519
|
+
String? agentId,
|
|
520
|
+
}) async {
|
|
521
|
+
return getMap(baseUrl, _withAgentQuery('/api/behavior', agentId));
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
Future<Map<String, dynamic>> saveBehaviorConfig(
|
|
525
|
+
String baseUrl,
|
|
526
|
+
Map<String, dynamic> config, {
|
|
527
|
+
String? agentId,
|
|
528
|
+
}) async {
|
|
529
|
+
return putMap(
|
|
530
|
+
baseUrl,
|
|
531
|
+
'/api/behavior',
|
|
532
|
+
_withAgentId(<String, dynamic>{'config': config}, agentId),
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
517
536
|
Future<Map<String, dynamic>> fetchTokenUsageSummary(
|
|
518
537
|
String baseUrl, {
|
|
519
538
|
String? agentId,
|
package/package.json
CHANGED
package/server/http/routes.js
CHANGED
|
@@ -11,6 +11,7 @@ const routeRegistry = [
|
|
|
11
11
|
{ basePath: null, modulePath: '../routes/auth' },
|
|
12
12
|
{ basePath: '/api/account', modulePath: '../routes/account' },
|
|
13
13
|
{ basePath: '/api/settings', modulePath: '../routes/settings' },
|
|
14
|
+
{ basePath: '/api/behavior', modulePath: '../routes/behavior' },
|
|
14
15
|
{ basePath: '/api/agent-profiles', modulePath: '../routes/agent_profiles' },
|
|
15
16
|
{ basePath: '/api/agents', modulePath: '../routes/agents' },
|
|
16
17
|
{ basePath: '/api/messaging', modulePath: '../routes/messaging' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
c8c38f82bd70c22831fff4fb2d557bfb
|
|
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"0cd610717bde95fd88343c64f81c11ba4e5c00
|
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "614467213" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|