neoagent 3.2.1-beta.1 → 3.2.1-beta.11

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.
Files changed (198) hide show
  1. package/extensions/chrome-browser/background.mjs +318 -88
  2. package/extensions/chrome-browser/http.mjs +136 -0
  3. package/extensions/chrome-browser/protocol.mjs +654 -90
  4. package/flutter_app/lib/main_chat.dart +118 -739
  5. package/flutter_app/lib/main_controller.dart +157 -24
  6. package/flutter_app/lib/main_integrations.dart +607 -8
  7. package/flutter_app/lib/main_models.dart +7 -2
  8. package/flutter_app/lib/main_operations.dart +334 -370
  9. package/flutter_app/lib/main_security.dart +266 -112
  10. package/flutter_app/lib/main_settings.dart +342 -3
  11. package/flutter_app/lib/main_shared.dart +14 -11
  12. package/flutter_app/lib/src/backend_client.dart +97 -0
  13. package/flutter_app/lib/src/desktop_companion_actions.dart +185 -31
  14. package/flutter_app/lib/src/desktop_companion_io.dart +319 -86
  15. package/flutter_app/windows/runner/flutter_window.cpp +143 -32
  16. package/landing/index.html +3 -1
  17. package/lib/manager.js +106 -89
  18. package/lib/schema_migrations.js +115 -13
  19. package/package.json +30 -15
  20. package/runtime/paths.js +49 -5
  21. package/server/db/database.js +2 -2
  22. package/server/guest-agent.cli.package.json +13 -0
  23. package/server/guest_agent.js +85 -40
  24. package/server/http/middleware.js +24 -0
  25. package/server/http/routes.js +12 -6
  26. package/server/public/.last_build_id +1 -1
  27. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  28. package/server/public/flutter_bootstrap.js +2 -2
  29. package/server/public/main.dart.js +81930 -80509
  30. package/server/routes/admin.js +1 -1
  31. package/server/routes/android.js +30 -34
  32. package/server/routes/behavior.js +80 -0
  33. package/server/routes/browser.js +23 -15
  34. package/server/routes/desktop.js +18 -1
  35. package/server/routes/integrations.js +107 -1
  36. package/server/routes/memory.js +1 -0
  37. package/server/routes/settings.js +20 -5
  38. package/server/routes/social_reach.js +12 -3
  39. package/server/routes/social_video.js +4 -0
  40. package/server/services/agents/manager.js +1 -1
  41. package/server/services/ai/capabilityHealth.js +62 -96
  42. package/server/services/ai/compaction.js +7 -2
  43. package/server/services/ai/history.js +45 -6
  44. package/server/services/ai/integrated_tools/http_request.js +8 -0
  45. package/server/services/ai/loop/agent_engine_core.js +452 -176
  46. package/server/services/ai/loop/blank_recovery.js +5 -4
  47. package/server/services/ai/loop/callbacks.js +1 -0
  48. package/server/services/ai/loop/completion_judge.js +291 -8
  49. package/server/services/ai/loop/conversation_loop.js +515 -342
  50. package/server/services/ai/loop/messaging_delivery.js +176 -57
  51. package/server/services/ai/loop/model_call_guard.js +91 -0
  52. package/server/services/ai/loop/model_io.js +20 -45
  53. package/server/services/ai/loop/progress_classification.js +2 -0
  54. package/server/services/ai/loop/tool_dispatch.js +19 -8
  55. package/server/services/ai/loopPolicy.js +48 -21
  56. package/server/services/ai/messagingFallback.js +17 -17
  57. package/server/services/ai/model_discovery.js +227 -0
  58. package/server/services/ai/model_failure_cache.js +108 -0
  59. package/server/services/ai/model_identity.js +71 -0
  60. package/server/services/ai/models.js +68 -163
  61. package/server/services/ai/providerRetry.js +17 -59
  62. package/server/services/ai/provider_selector.js +166 -0
  63. package/server/services/ai/providers/anthropic.js +2 -2
  64. package/server/services/ai/providers/claudeCode.js +21 -33
  65. package/server/services/ai/providers/githubCopilot.js +41 -20
  66. package/server/services/ai/providers/google.js +135 -97
  67. package/server/services/ai/providers/grok.js +4 -3
  68. package/server/services/ai/providers/grokOauth.js +19 -27
  69. package/server/services/ai/providers/nvidia.js +10 -5
  70. package/server/services/ai/providers/ollama.js +111 -84
  71. package/server/services/ai/providers/ollama_stream.js +142 -0
  72. package/server/services/ai/providers/openai.js +39 -5
  73. package/server/services/ai/providers/openaiCodex.js +11 -4
  74. package/server/services/ai/providers/openrouter.js +29 -7
  75. package/server/services/ai/providers/provider_error.js +36 -0
  76. package/server/services/ai/settings.js +26 -2
  77. package/server/services/ai/systemPrompt.js +32 -123
  78. package/server/services/ai/taskAnalysis.js +104 -11
  79. package/server/services/ai/toolEvidence.js +256 -29
  80. package/server/services/ai/tools.js +248 -117
  81. package/server/services/android/controller.js +770 -237
  82. package/server/services/android/process.js +140 -0
  83. package/server/services/android/sdk_download.js +143 -0
  84. package/server/services/android/uia.js +6 -5
  85. package/server/services/artifacts/store.js +24 -0
  86. package/server/services/behavior/config.js +251 -0
  87. package/server/services/behavior/defaults.js +68 -0
  88. package/server/services/behavior/delivery.js +176 -0
  89. package/server/services/behavior/index.js +43 -0
  90. package/server/services/behavior/model_client.js +35 -0
  91. package/server/services/behavior/modules/agent_identity.js +37 -0
  92. package/server/services/behavior/modules/channel_style.js +28 -0
  93. package/server/services/behavior/modules/index.js +29 -0
  94. package/server/services/behavior/modules/norms.js +101 -0
  95. package/server/services/behavior/modules/persona.js +48 -0
  96. package/server/services/behavior/modules/persona_prompt.js +33 -0
  97. package/server/services/behavior/modules/social_memory.js +86 -0
  98. package/server/services/behavior/modules/social_observability.js +94 -0
  99. package/server/services/behavior/modules/social_signals.js +41 -0
  100. package/server/services/behavior/modules/theory_of_mind.js +110 -0
  101. package/server/services/behavior/modules/turn_taking.js +237 -0
  102. package/server/services/behavior/pipeline.js +285 -0
  103. package/server/services/behavior/registry.js +78 -0
  104. package/server/services/behavior/signals.js +107 -0
  105. package/server/services/behavior/state.js +99 -0
  106. package/server/services/behavior/system_prompt.js +75 -0
  107. package/server/services/browser/controller.js +843 -385
  108. package/server/services/browser/extension/gateway.js +40 -16
  109. package/server/services/browser/extension/protocol.js +15 -1
  110. package/server/services/browser/extension/provider.js +71 -47
  111. package/server/services/browser/extension/registry.js +155 -34
  112. package/server/services/cli/executor.js +62 -9
  113. package/server/services/credentials/bitwarden_cli.js +322 -0
  114. package/server/services/credentials/broker.js +594 -0
  115. package/server/services/desktop/gateway.js +41 -4
  116. package/server/services/desktop/protocol.js +3 -0
  117. package/server/services/desktop/provider.js +39 -42
  118. package/server/services/desktop/registry.js +137 -52
  119. package/server/services/integrations/bitwarden/constants.js +14 -0
  120. package/server/services/integrations/bitwarden/provider.js +197 -0
  121. package/server/services/integrations/bitwarden/snapshot.js +65 -0
  122. package/server/services/integrations/figma/provider.js +78 -12
  123. package/server/services/integrations/github/common.js +11 -6
  124. package/server/services/integrations/github/provider.js +52 -53
  125. package/server/services/integrations/google/provider.js +55 -19
  126. package/server/services/integrations/home_assistant/network.js +17 -20
  127. package/server/services/integrations/home_assistant/provider.js +7 -5
  128. package/server/services/integrations/home_assistant/tools.js +17 -5
  129. package/server/services/integrations/http.js +51 -0
  130. package/server/services/integrations/manager.js +159 -53
  131. package/server/services/integrations/microsoft/provider.js +80 -13
  132. package/server/services/integrations/neoarchive/provider.js +55 -29
  133. package/server/services/integrations/neorecall/client.js +17 -10
  134. package/server/services/integrations/neorecall/provider.js +20 -11
  135. package/server/services/integrations/notion/provider.js +16 -13
  136. package/server/services/integrations/oauth_provider.js +115 -51
  137. package/server/services/integrations/registry.js +2 -0
  138. package/server/services/integrations/slack/provider.js +98 -9
  139. package/server/services/integrations/spotify/provider.js +67 -71
  140. package/server/services/integrations/trello/provider.js +21 -7
  141. package/server/services/integrations/weather/provider.js +18 -12
  142. package/server/services/integrations/whatsapp/provider.js +76 -16
  143. package/server/services/manager.js +110 -1
  144. package/server/services/memory/embedding_index.js +20 -8
  145. package/server/services/memory/embeddings.js +151 -90
  146. package/server/services/memory/ingestion.js +50 -9
  147. package/server/services/memory/ingestion_documents.js +13 -3
  148. package/server/services/memory/manager.js +66 -52
  149. package/server/services/messaging/access_policy.js +10 -6
  150. package/server/services/messaging/automation.js +240 -34
  151. package/server/services/messaging/discord.js +11 -1
  152. package/server/services/messaging/formatting_guides.js +5 -4
  153. package/server/services/messaging/http_platforms.js +37 -16
  154. package/server/services/messaging/inbound_queue.js +143 -28
  155. package/server/services/messaging/inbound_store.js +257 -0
  156. package/server/services/messaging/manager.js +344 -51
  157. package/server/services/messaging/telegram.js +10 -1
  158. package/server/services/messaging/typing_keepalive.js +5 -2
  159. package/server/services/messaging/whatsapp.js +33 -14
  160. package/server/services/network/http.js +210 -0
  161. package/server/services/network/safe_request.js +307 -0
  162. package/server/services/runtime/backends/local-vm.js +227 -67
  163. package/server/services/runtime/docker-vm-manager.js +9 -0
  164. package/server/services/runtime/guest_bootstrap.js +30 -4
  165. package/server/services/runtime/guest_image.js +43 -12
  166. package/server/services/runtime/manager.js +77 -23
  167. package/server/services/runtime/validation.js +7 -6
  168. package/server/services/security/tool_categories.js +6 -0
  169. package/server/services/social_reach/channels/github.js +10 -4
  170. package/server/services/social_reach/channels/reddit.js +4 -4
  171. package/server/services/social_reach/channels/rss.js +2 -2
  172. package/server/services/social_reach/channels/social_video.js +13 -8
  173. package/server/services/social_reach/channels/v2ex.js +21 -8
  174. package/server/services/social_reach/channels/x.js +2 -2
  175. package/server/services/social_reach/channels/xueqiu.js +5 -5
  176. package/server/services/social_reach/service.js +9 -6
  177. package/server/services/social_reach/utils.js +65 -14
  178. package/server/services/social_video/captions.js +2 -2
  179. package/server/services/social_video/service.js +343 -68
  180. package/server/services/tasks/integration_runtime.js +18 -8
  181. package/server/services/tasks/runtime.js +39 -4
  182. package/server/services/voice/agentBridge.js +17 -4
  183. package/server/services/voice/bufferedLiveRelayAdapter.js +5 -0
  184. package/server/services/voice/liveSession.js +31 -0
  185. package/server/services/voice/message.js +1 -1
  186. package/server/services/voice/openaiSpeech.js +33 -8
  187. package/server/services/voice/providers.js +233 -151
  188. package/server/services/voice/runtime.js +2 -2
  189. package/server/services/voice/runtimeManager.js +118 -20
  190. package/server/services/voice/turnRunner.js +6 -0
  191. package/server/services/wearable/firmware_manifest.js +51 -13
  192. package/server/services/wearable/service.js +1 -0
  193. package/server/utils/abort.js +96 -0
  194. package/server/utils/cloud-security.js +110 -3
  195. package/server/utils/files.js +31 -0
  196. package/server/utils/image_payload.js +95 -0
  197. package/server/utils/logger.js +19 -0
  198. package/server/utils/retry.js +107 -0
@@ -505,8 +505,10 @@ class _SkillsPanelState extends State<SkillsPanel>
505
505
 
506
506
  // Installed tab search & filter state
507
507
  String _installedQuery = '';
508
- String _installedStatusFilter = 'all'; // 'all' | 'active' | 'draft' | 'disabled'
509
- String _installedSourceFilter = 'all'; // 'all' | 'built-in' | 'learned' | 'user' | 'store'
508
+ String _installedStatusFilter =
509
+ 'all'; // 'all' | 'active' | 'draft' | 'disabled'
510
+ String _installedSourceFilter =
511
+ 'all'; // 'all' | 'built-in' | 'learned' | 'user' | 'store'
510
512
  late final TextEditingController _installedSearchController;
511
513
 
512
514
  @override
@@ -645,18 +647,36 @@ class _SkillsPanelState extends State<SkillsPanel>
645
647
  final q = _installedQuery;
646
648
  if (q.isNotEmpty &&
647
649
  !skill.name.toLowerCase().contains(q) &&
648
- !skill.description.toLowerCase().contains(q)) return false;
650
+ !skill.description.toLowerCase().contains(q)) {
651
+ return false;
652
+ }
649
653
  if (_installedStatusFilter != 'all') {
650
- if (_installedStatusFilter == 'active' && (!skill.enabled || skill.draft)) return false;
651
- if (_installedStatusFilter == 'draft' && !skill.draft) return false;
652
- if (_installedStatusFilter == 'disabled' && skill.enabled) return false;
654
+ if (_installedStatusFilter == 'active' &&
655
+ (!skill.enabled || skill.draft)) {
656
+ return false;
657
+ }
658
+ if (_installedStatusFilter == 'draft' && !skill.draft) {
659
+ return false;
660
+ }
661
+ if (_installedStatusFilter == 'disabled' && skill.enabled) {
662
+ return false;
663
+ }
664
+ }
665
+ if (_installedSourceFilter != 'all' &&
666
+ skill.source != _installedSourceFilter) {
667
+ return false;
653
668
  }
654
- if (_installedSourceFilter != 'all' && skill.source != _installedSourceFilter) return false;
655
669
  return true;
656
670
  }).toList();
657
671
 
658
672
  final statusFilters = <String>['all', 'active', 'draft', 'disabled'];
659
- final sourceFilters = <String>['all', 'built-in', 'learned', 'user', 'store'];
673
+ final sourceFilters = <String>[
674
+ 'all',
675
+ 'built-in',
676
+ 'learned',
677
+ 'user',
678
+ 'store',
679
+ ];
660
680
 
661
681
  return Card(
662
682
  child: Column(
@@ -757,157 +777,174 @@ class _SkillsPanelState extends State<SkillsPanel>
757
777
  separatorBuilder: (_, __) => const SizedBox(height: 10),
758
778
  itemBuilder: (context, index) {
759
779
  final skill = filteredSkills[index];
760
- return LayoutBuilder(
761
- builder: (context, constraints) {
762
- final compact = constraints.maxWidth < 760;
763
- return Container(
764
- padding: const EdgeInsets.all(14),
765
- decoration: BoxDecoration(
766
- color: _bgSecondary,
767
- borderRadius: BorderRadius.circular(14),
768
- border: Border.all(color: _border),
769
- ),
770
- child: compact
771
- ? Column(
772
- crossAxisAlignment: CrossAxisAlignment.start,
773
- children: <Widget>[
774
- Row(
775
- children: <Widget>[
776
- Expanded(
777
- child: Text(
778
- skill.name,
779
- style: TextStyle(fontWeight: FontWeight.w700),
780
- ),
781
- ),
782
- Switch(
783
- value: skill.enabled,
784
- onChanged: (value) => controller
785
- .setSkillEnabled(skill.name, value),
786
- ),
787
- ],
788
- ),
789
- Text(
790
- skill.description.ifEmpty('No description'),
791
- style: TextStyle(color: _textSecondary),
792
- ),
793
- const SizedBox(height: 10),
794
- Wrap(
795
- spacing: 8,
796
- runSpacing: 8,
797
- children: <Widget>[
798
- _MetaPill(
799
- label: skill.category,
800
- icon: Icons.folder_outlined,
801
- ),
802
- _MetaPill(
803
- label: skill.source,
804
- icon: Icons.source_outlined,
805
- ),
806
- if (skill.draft)
807
- const _MetaPill(
808
- label: 'Draft',
809
- icon: Icons.edit_note_outlined,
810
- ),
811
- ],
812
- ),
813
- const SizedBox(height: 10),
814
- Row(
815
- children: <Widget>[
816
- const Spacer(),
817
- OutlinedButton(
818
- onPressed: () =>
819
- _openSkillEditor(context, skill.name),
820
- child: Text('Open'),
821
- ),
822
- const SizedBox(width: 8),
823
- TextButton.icon(
824
- onPressed: () =>
825
- _confirmDeleteSkill(context, skill.name),
826
- icon: Icon(Icons.delete_outline),
827
- style: TextButton.styleFrom(
828
- foregroundColor: _danger,
829
- ),
830
- label: Text('Delete'),
831
- ),
832
- ],
833
- ),
834
- ],
835
- )
836
- : Row(
837
- crossAxisAlignment: CrossAxisAlignment.start,
838
- children: <Widget>[
839
- Expanded(
840
- child: Column(
841
- crossAxisAlignment: CrossAxisAlignment.start,
842
- children: <Widget>[
843
- Text(
844
- skill.name,
845
- style: TextStyle(fontWeight: FontWeight.w700),
846
- ),
847
- const SizedBox(height: 6),
848
- Text(
849
- skill.description.ifEmpty('No description'),
850
- style: TextStyle(color: _textSecondary),
851
- ),
852
- const SizedBox(height: 10),
853
- Wrap(
854
- spacing: 8,
855
- runSpacing: 8,
856
- children: <Widget>[
857
- _MetaPill(
858
- label: skill.category,
859
- icon: Icons.folder_outlined,
860
- ),
861
- _MetaPill(
862
- label: skill.source,
863
- icon: Icons.source_outlined,
780
+ return LayoutBuilder(
781
+ builder: (context, constraints) {
782
+ final compact = constraints.maxWidth < 760;
783
+ return Container(
784
+ padding: const EdgeInsets.all(14),
785
+ decoration: BoxDecoration(
786
+ color: _bgSecondary,
787
+ borderRadius: BorderRadius.circular(14),
788
+ border: Border.all(color: _border),
789
+ ),
790
+ child: compact
791
+ ? Column(
792
+ crossAxisAlignment: CrossAxisAlignment.start,
793
+ children: <Widget>[
794
+ Row(
795
+ children: <Widget>[
796
+ Expanded(
797
+ child: Text(
798
+ skill.name,
799
+ style: TextStyle(
800
+ fontWeight: FontWeight.w700,
801
+ ),
802
+ ),
803
+ ),
804
+ Switch(
805
+ value: skill.enabled,
806
+ onChanged: (value) => controller
807
+ .setSkillEnabled(skill.name, value),
808
+ ),
809
+ ],
810
+ ),
811
+ Text(
812
+ skill.description.ifEmpty('No description'),
813
+ style: TextStyle(color: _textSecondary),
814
+ ),
815
+ const SizedBox(height: 10),
816
+ Wrap(
817
+ spacing: 8,
818
+ runSpacing: 8,
819
+ children: <Widget>[
820
+ _MetaPill(
821
+ label: skill.category,
822
+ icon: Icons.folder_outlined,
823
+ ),
824
+ _MetaPill(
825
+ label: skill.source,
826
+ icon: Icons.source_outlined,
827
+ ),
828
+ if (skill.draft)
829
+ const _MetaPill(
830
+ label: 'Draft',
831
+ icon: Icons.edit_note_outlined,
832
+ ),
833
+ ],
834
+ ),
835
+ const SizedBox(height: 10),
836
+ Row(
837
+ children: <Widget>[
838
+ const Spacer(),
839
+ OutlinedButton(
840
+ onPressed: () => _openSkillEditor(
841
+ context,
842
+ skill.name,
843
+ ),
844
+ child: Text('Open'),
845
+ ),
846
+ const SizedBox(width: 8),
847
+ TextButton.icon(
848
+ onPressed: () => _confirmDeleteSkill(
849
+ context,
850
+ skill.name,
851
+ ),
852
+ icon: Icon(Icons.delete_outline),
853
+ style: TextButton.styleFrom(
854
+ foregroundColor: _danger,
855
+ ),
856
+ label: Text('Delete'),
857
+ ),
858
+ ],
859
+ ),
860
+ ],
861
+ )
862
+ : Row(
863
+ crossAxisAlignment: CrossAxisAlignment.start,
864
+ children: <Widget>[
865
+ Expanded(
866
+ child: Column(
867
+ crossAxisAlignment:
868
+ CrossAxisAlignment.start,
869
+ children: <Widget>[
870
+ Text(
871
+ skill.name,
872
+ style: TextStyle(
873
+ fontWeight: FontWeight.w700,
874
+ ),
875
+ ),
876
+ const SizedBox(height: 6),
877
+ Text(
878
+ skill.description.ifEmpty(
879
+ 'No description',
880
+ ),
881
+ style: TextStyle(
882
+ color: _textSecondary,
883
+ ),
884
+ ),
885
+ const SizedBox(height: 10),
886
+ Wrap(
887
+ spacing: 8,
888
+ runSpacing: 8,
889
+ children: <Widget>[
890
+ _MetaPill(
891
+ label: skill.category,
892
+ icon: Icons.folder_outlined,
893
+ ),
894
+ _MetaPill(
895
+ label: skill.source,
896
+ icon: Icons.source_outlined,
897
+ ),
898
+ if (skill.draft)
899
+ const _MetaPill(
900
+ label: 'Draft',
901
+ icon: Icons.edit_note_outlined,
902
+ ),
903
+ ],
904
+ ),
905
+ ],
864
906
  ),
865
- if (skill.draft)
866
- const _MetaPill(
867
- label: 'Draft',
868
- icon: Icons.edit_note_outlined,
907
+ ),
908
+ const SizedBox(width: 10),
909
+ Column(
910
+ children: <Widget>[
911
+ Switch(
912
+ value: skill.enabled,
913
+ onChanged: (value) => controller
914
+ .setSkillEnabled(skill.name, value),
869
915
  ),
870
- ],
871
- ),
872
- ],
873
- ),
874
- ),
875
- const SizedBox(width: 10),
876
- Column(
877
- children: <Widget>[
878
- Switch(
879
- value: skill.enabled,
880
- onChanged: (value) => controller
881
- .setSkillEnabled(skill.name, value),
882
- ),
883
- OutlinedButton(
884
- onPressed: () =>
885
- _openSkillEditor(context, skill.name),
886
- child: Text('Open'),
887
- ),
888
- const SizedBox(height: 6),
889
- TextButton.icon(
890
- onPressed: () =>
891
- _confirmDeleteSkill(context, skill.name),
892
- icon: Icon(Icons.delete_outline),
893
- style: TextButton.styleFrom(
894
- foregroundColor: _danger,
895
- ),
896
- label: Text('Delete'),
916
+ OutlinedButton(
917
+ onPressed: () => _openSkillEditor(
918
+ context,
919
+ skill.name,
920
+ ),
921
+ child: Text('Open'),
922
+ ),
923
+ const SizedBox(height: 6),
924
+ TextButton.icon(
925
+ onPressed: () => _confirmDeleteSkill(
926
+ context,
927
+ skill.name,
928
+ ),
929
+ icon: Icon(Icons.delete_outline),
930
+ style: TextButton.styleFrom(
931
+ foregroundColor: _danger,
932
+ ),
933
+ label: Text('Delete'),
934
+ ),
935
+ ],
936
+ ),
937
+ ],
897
938
  ),
898
- ],
899
- ),
900
- ],
901
- ),
902
- );
903
- },
904
- );
939
+ );
940
+ },
941
+ );
905
942
  },
906
943
  ),
907
944
  ),
908
- ],
909
- ),
910
- );
945
+ ],
946
+ ),
947
+ );
911
948
  }
912
949
 
913
950
  Widget _buildStoreTab(
@@ -1465,8 +1502,9 @@ class _MemoryPanelState extends State<MemoryPanel>
1465
1502
  );
1466
1503
  if (!mounted) return;
1467
1504
  _llmImportController.clear();
1468
- final warningText =
1469
- result.warnings.isEmpty ? '' : ' ${result.warnings.join(' ')}';
1505
+ final warningText = result.warnings.isEmpty
1506
+ ? ''
1507
+ : ' ${result.warnings.join(' ')}';
1470
1508
  ScaffoldMessenger.of(context).showSnackBar(
1471
1509
  SnackBar(
1472
1510
  content: Text(
@@ -1494,9 +1532,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1494
1532
  : controller.memories;
1495
1533
  if (_entityFilter == null) return base;
1496
1534
  return base
1497
- .where(
1498
- (m) => m.entities.any((e) => e.name == _entityFilter),
1499
- )
1535
+ .where((m) => m.entities.any((e) => e.name == _entityFilter))
1500
1536
  .toList();
1501
1537
  }
1502
1538
 
@@ -1588,7 +1624,10 @@ class _MemoryPanelState extends State<MemoryPanel>
1588
1624
  });
1589
1625
  }
1590
1626
 
1591
- void _openRetrievalInspector(BuildContext context, NeoAgentController controller) {
1627
+ void _openRetrievalInspector(
1628
+ BuildContext context,
1629
+ NeoAgentController controller,
1630
+ ) {
1592
1631
  Navigator.of(context).push(
1593
1632
  MaterialPageRoute(
1594
1633
  builder: (context) => RetrievalInspectorView(controller: controller),
@@ -1603,7 +1642,8 @@ class _MemoryPanelState extends State<MemoryPanel>
1603
1642
  final memoriesToShow = _visibleMemories;
1604
1643
  final selectedIds = _selectedVisibleMemoryIds.toSet();
1605
1644
  final selectedCount = selectedIds.length;
1606
- final allVisibleSelected = memoriesToShow.isNotEmpty &&
1645
+ final allVisibleSelected =
1646
+ memoriesToShow.isNotEmpty &&
1607
1647
  memoriesToShow.every((m) => selectedIds.contains(m.id));
1608
1648
  final showingSearchResults = controller.memoryRecallResults.isNotEmpty;
1609
1649
  final compact = MediaQuery.sizeOf(context).width < 760;
@@ -1623,11 +1663,6 @@ class _MemoryPanelState extends State<MemoryPanel>
1623
1663
  icon: Icon(Icons.bug_report_outlined),
1624
1664
  label: Text('Inspect'),
1625
1665
  ),
1626
- OutlinedButton.icon(
1627
- onPressed: () => _openBehaviorNotesEditor(context, controller),
1628
- icon: Icon(Icons.edit_outlined),
1629
- label: Text('Behavior Notes'),
1630
- ),
1631
1666
  FilledButton.icon(
1632
1667
  onPressed: () => _openMemoryCreator(context, controller),
1633
1668
  icon: Icon(Icons.add),
@@ -1644,9 +1679,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1644
1679
  padding: const EdgeInsets.all(18),
1645
1680
  child: Row(
1646
1681
  children: <Widget>[
1647
- _MemoryConfidenceGauge(
1648
- confidence: stats.averageConfidence,
1649
- ),
1682
+ _MemoryConfidenceGauge(confidence: stats.averageConfidence),
1650
1683
  const SizedBox(width: 18),
1651
1684
  Expanded(
1652
1685
  child: Wrap(
@@ -1705,9 +1738,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1705
1738
  children: <Widget>[
1706
1739
  Row(
1707
1740
  children: <Widget>[
1708
- Expanded(
1709
- child: const _SectionTitle('Knowledge Graph'),
1710
- ),
1741
+ Expanded(child: const _SectionTitle('Knowledge Graph')),
1711
1742
  if (_entityFilter != null)
1712
1743
  TextButton.icon(
1713
1744
  onPressed: () =>
@@ -1720,10 +1751,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1720
1751
  const SizedBox(height: 4),
1721
1752
  Text(
1722
1753
  'Tap an entity to filter memories by it.',
1723
- style: TextStyle(
1724
- color: _textSecondary,
1725
- fontSize: 12,
1726
- ),
1754
+ style: TextStyle(color: _textSecondary, fontSize: 12),
1727
1755
  ),
1728
1756
  const SizedBox(height: 14),
1729
1757
  SizedBox(
@@ -1857,15 +1885,16 @@ class _MemoryPanelState extends State<MemoryPanel>
1857
1885
  Wrap(
1858
1886
  spacing: 8,
1859
1887
  runSpacing: 8,
1860
- crossAxisAlignment:
1861
- WrapCrossAlignment.center,
1888
+ crossAxisAlignment: WrapCrossAlignment.center,
1862
1889
  children: <Widget>[
1863
1890
  OutlinedButton.icon(
1864
- onPressed: allVisibleSelected ||
1891
+ onPressed:
1892
+ allVisibleSelected ||
1865
1893
  _bulkActionInFlight
1866
1894
  ? null
1867
1895
  : () => _selectAllVisibleMemories(
1868
- memoriesToShow),
1896
+ memoriesToShow,
1897
+ ),
1869
1898
  icon: Icon(
1870
1899
  Icons.done_all_outlined,
1871
1900
  size: 16,
@@ -1903,9 +1932,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1903
1932
  Icons.archive_outlined,
1904
1933
  size: 16,
1905
1934
  ),
1906
- label: Text(
1907
- 'Archive ($selectedCount)',
1908
- ),
1935
+ label: Text('Archive ($selectedCount)'),
1909
1936
  ),
1910
1937
  OutlinedButton.icon(
1911
1938
  onPressed: _bulkActionInFlight
@@ -1923,9 +1950,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1923
1950
  Icons.delete_sweep_outlined,
1924
1951
  size: 16,
1925
1952
  ),
1926
- label: Text(
1927
- 'Delete ($selectedCount)',
1928
- ),
1953
+ label: Text('Delete ($selectedCount)'),
1929
1954
  ),
1930
1955
  ],
1931
1956
  ],
@@ -1941,8 +1966,9 @@ class _MemoryPanelState extends State<MemoryPanel>
1941
1966
  )
1942
1967
  else
1943
1968
  ...memoriesToShow.map((memory) {
1944
- final isSelected =
1945
- selectedIds.contains(memory.id);
1969
+ final isSelected = selectedIds.contains(
1970
+ memory.id,
1971
+ );
1946
1972
  return _MemoryRow(
1947
1973
  memory: memory,
1948
1974
  isSelected: isSelected,
@@ -1950,8 +1976,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1950
1976
  memory.id,
1951
1977
  !isSelected,
1952
1978
  ),
1953
- onCheck: (value) =>
1954
- _toggleMemorySelection(
1979
+ onCheck: (value) => _toggleMemorySelection(
1955
1980
  memory.id,
1956
1981
  value ?? false,
1957
1982
  ),
@@ -1964,9 +1989,9 @@ class _MemoryPanelState extends State<MemoryPanel>
1964
1989
  'This memory will be removed permanently.',
1965
1990
  onConfirm: () =>
1966
1991
  _deleteSingleMemory(
1967
- controller,
1968
- memory.id,
1969
- ),
1992
+ controller,
1993
+ memory.id,
1994
+ ),
1970
1995
  ),
1971
1996
  );
1972
1997
  }),
@@ -1985,9 +2010,7 @@ class _MemoryPanelState extends State<MemoryPanel>
1985
2010
  Expanded(
1986
2011
  child: Text(
1987
2012
  'Key-value pairs that persist across conversations.',
1988
- style: TextStyle(
1989
- color: _textSecondary,
1990
- ),
2013
+ style: TextStyle(color: _textSecondary),
1991
2014
  ),
1992
2015
  ),
1993
2016
  TextButton.icon(
@@ -2001,75 +2024,75 @@ class _MemoryPanelState extends State<MemoryPanel>
2001
2024
  ],
2002
2025
  ),
2003
2026
  const SizedBox(height: 10),
2004
- if (controller
2005
- .memoryOverview.coreEntries.isEmpty)
2027
+ if (controller.memoryOverview.coreEntries.isEmpty)
2006
2028
  Text(
2007
2029
  'No core memory entries yet.',
2008
2030
  style: TextStyle(color: _textSecondary),
2009
2031
  )
2010
2032
  else
2011
- ...controller.memoryOverview.coreEntries
2012
- .entries
2033
+ ...controller.memoryOverview.coreEntries.entries
2013
2034
  .map((entry) {
2014
- return Container(
2015
- width: double.infinity,
2016
- margin: const EdgeInsets.only(bottom: 10),
2017
- padding: const EdgeInsets.all(12),
2018
- decoration: BoxDecoration(
2019
- color: _bgSecondary,
2020
- borderRadius:
2021
- BorderRadius.circular(12),
2022
- border: Border.all(color: _border),
2023
- ),
2024
- child: Row(
2025
- crossAxisAlignment:
2026
- CrossAxisAlignment.start,
2027
- children: <Widget>[
2028
- Expanded(
2029
- child: Column(
2030
- crossAxisAlignment:
2031
- CrossAxisAlignment.start,
2032
- children: <Widget>[
2033
- Text(
2034
- entry.key,
2035
- style: TextStyle(
2036
- fontWeight: FontWeight.w700,
2037
- ),
2038
- ),
2039
- const SizedBox(height: 6),
2040
- Text(
2041
- entry.value.toString(),
2042
- ),
2043
- ],
2044
- ),
2035
+ return Container(
2036
+ width: double.infinity,
2037
+ margin: const EdgeInsets.only(
2038
+ bottom: 10,
2045
2039
  ),
2046
- IconButton(
2047
- onPressed: () =>
2048
- _openCoreMemoryEditor(
2049
- context,
2050
- controller,
2051
- keyValue: entry,
2040
+ padding: const EdgeInsets.all(12),
2041
+ decoration: BoxDecoration(
2042
+ color: _bgSecondary,
2043
+ borderRadius: BorderRadius.circular(
2044
+ 12,
2052
2045
  ),
2053
- icon: Icon(Icons.edit_outlined),
2046
+ border: Border.all(color: _border),
2054
2047
  ),
2055
- IconButton(
2056
- onPressed: () => _confirmDelete(
2057
- context,
2058
- title:
2059
- 'Delete core memory entry?',
2060
- message:
2061
- 'Remove "${entry.key}" from core memory.',
2062
- onConfirm: () => controller
2063
- .deleteCoreMemory(
2064
- entry.key,
2048
+ child: Row(
2049
+ crossAxisAlignment:
2050
+ CrossAxisAlignment.start,
2051
+ children: <Widget>[
2052
+ Expanded(
2053
+ child: Column(
2054
+ crossAxisAlignment:
2055
+ CrossAxisAlignment.start,
2056
+ children: <Widget>[
2057
+ Text(
2058
+ entry.key,
2059
+ style: TextStyle(
2060
+ fontWeight:
2061
+ FontWeight.w700,
2062
+ ),
2063
+ ),
2064
+ const SizedBox(height: 6),
2065
+ Text(entry.value.toString()),
2066
+ ],
2067
+ ),
2065
2068
  ),
2066
- ),
2067
- icon: Icon(Icons.delete_outline),
2069
+ IconButton(
2070
+ onPressed: () =>
2071
+ _openCoreMemoryEditor(
2072
+ context,
2073
+ controller,
2074
+ keyValue: entry,
2075
+ ),
2076
+ icon: Icon(Icons.edit_outlined),
2077
+ ),
2078
+ IconButton(
2079
+ onPressed: () => _confirmDelete(
2080
+ context,
2081
+ title:
2082
+ 'Delete core memory entry?',
2083
+ message:
2084
+ 'Remove "${entry.key}" from core memory.',
2085
+ onConfirm: () =>
2086
+ controller.deleteCoreMemory(
2087
+ entry.key,
2088
+ ),
2089
+ ),
2090
+ icon: Icon(Icons.delete_outline),
2091
+ ),
2092
+ ],
2068
2093
  ),
2069
- ],
2070
- ),
2071
- );
2072
- }),
2094
+ );
2095
+ }),
2073
2096
  ],
2074
2097
  ),
2075
2098
  ),
@@ -2092,11 +2115,8 @@ class _MemoryPanelState extends State<MemoryPanel>
2092
2115
  FilledButton.icon(
2093
2116
  onPressed: _llmPromptLoading
2094
2117
  ? null
2095
- : () =>
2096
- _loadLlmPrompt(controller),
2097
- icon: Icon(
2098
- Icons.auto_awesome_outlined,
2099
- ),
2118
+ : () => _loadLlmPrompt(controller),
2119
+ icon: Icon(Icons.auto_awesome_outlined),
2100
2120
  label: Text(
2101
2121
  _llmPromptLoading
2102
2122
  ? 'Generating...'
@@ -2105,11 +2125,9 @@ class _MemoryPanelState extends State<MemoryPanel>
2105
2125
  ),
2106
2126
  OutlinedButton.icon(
2107
2127
  onPressed:
2108
- _llmPromptController.text
2109
- .trim()
2110
- .isEmpty
2111
- ? null
2112
- : _copyLlmPrompt,
2128
+ _llmPromptController.text.trim().isEmpty
2129
+ ? null
2130
+ : _copyLlmPrompt,
2113
2131
  icon: Icon(Icons.copy_all_outlined),
2114
2132
  label: Text('Copy Prompt'),
2115
2133
  ),
@@ -2122,8 +2140,7 @@ class _MemoryPanelState extends State<MemoryPanel>
2122
2140
  maxLines: 8,
2123
2141
  readOnly: true,
2124
2142
  decoration: const InputDecoration(
2125
- labelText:
2126
- 'Prompt to paste into another AI',
2143
+ labelText: 'Prompt to paste into another AI',
2127
2144
  ),
2128
2145
  ),
2129
2146
  const SizedBox(height: 16),
@@ -2133,8 +2150,7 @@ class _MemoryPanelState extends State<MemoryPanel>
2133
2150
  onChanged: _llmImporting
2134
2151
  ? null
2135
2152
  : (value) => setState(
2136
- () =>
2137
- _llmApplyBehaviorNotes = value,
2153
+ () => _llmApplyBehaviorNotes = value,
2138
2154
  ),
2139
2155
  title: Text('Apply behavior notes'),
2140
2156
  subtitle: Text(
@@ -2147,8 +2163,7 @@ class _MemoryPanelState extends State<MemoryPanel>
2147
2163
  onChanged: _llmImporting
2148
2164
  ? null
2149
2165
  : (value) => setState(
2150
- () =>
2151
- _llmApplyCoreMemory = value,
2166
+ () => _llmApplyCoreMemory = value,
2152
2167
  ),
2153
2168
  title: Text('Apply core memory'),
2154
2169
  subtitle: Text(
@@ -2168,13 +2183,10 @@ class _MemoryPanelState extends State<MemoryPanel>
2168
2183
  FilledButton.icon(
2169
2184
  onPressed: _llmImporting
2170
2185
  ? null
2171
- : () =>
2172
- _importLlmMemories(controller),
2186
+ : () => _importLlmMemories(controller),
2173
2187
  icon: Icon(Icons.file_download_outlined),
2174
2188
  label: Text(
2175
- _llmImporting
2176
- ? 'Importing...'
2177
- : 'Import',
2189
+ _llmImporting ? 'Importing...' : 'Import',
2178
2190
  ),
2179
2191
  ),
2180
2192
  ],
@@ -2274,50 +2286,6 @@ class _MemoryPanelState extends State<MemoryPanel>
2274
2286
  );
2275
2287
  }
2276
2288
 
2277
- Future<void> _openBehaviorNotesEditor(
2278
- BuildContext context,
2279
- NeoAgentController controller,
2280
- ) async {
2281
- final contentController = TextEditingController(
2282
- text: controller.memoryOverview.assistantBehaviorNotes,
2283
- );
2284
- await showDialog<void>(
2285
- context: context,
2286
- builder: (context) {
2287
- return AlertDialog(
2288
- backgroundColor: _bgCard,
2289
- title: Text('Edit Assistant Behavior Notes'),
2290
- content: SizedBox(
2291
- width: 720,
2292
- child: TextField(
2293
- controller: contentController,
2294
- minLines: 16,
2295
- maxLines: 24,
2296
- decoration: const InputDecoration(
2297
- labelText: 'assistant_behavior_notes',
2298
- ),
2299
- ),
2300
- ),
2301
- actions: <Widget>[
2302
- TextButton(
2303
- onPressed: () => Navigator.of(context).pop(),
2304
- child: Text('Cancel'),
2305
- ),
2306
- FilledButton(
2307
- onPressed: () async {
2308
- await controller.updateAssistantBehaviorNotes(
2309
- contentController.text,
2310
- );
2311
- if (context.mounted) Navigator.of(context).pop();
2312
- },
2313
- child: Text('Save'),
2314
- ),
2315
- ],
2316
- );
2317
- },
2318
- );
2319
- }
2320
-
2321
2289
  Future<void> _openCoreMemoryEditor(
2322
2290
  BuildContext context,
2323
2291
  NeoAgentController controller, {
@@ -2453,9 +2421,10 @@ class _MemoryConfidenceGaugeState extends State<_MemoryConfidenceGauge>
2453
2421
  vsync: this,
2454
2422
  duration: const Duration(milliseconds: 1200),
2455
2423
  );
2456
- _progress = Tween<double>(begin: 0, end: widget.confidence).animate(
2457
- CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic),
2458
- );
2424
+ _progress = Tween<double>(
2425
+ begin: 0,
2426
+ end: widget.confidence,
2427
+ ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic));
2459
2428
  _controller.forward();
2460
2429
  }
2461
2430
 
@@ -2463,12 +2432,10 @@ class _MemoryConfidenceGaugeState extends State<_MemoryConfidenceGauge>
2463
2432
  void didUpdateWidget(_MemoryConfidenceGauge oldWidget) {
2464
2433
  super.didUpdateWidget(oldWidget);
2465
2434
  if (oldWidget.confidence != widget.confidence) {
2466
- _progress = Tween<double>(
2467
- begin: _progress.value,
2468
- end: widget.confidence,
2469
- ).animate(
2470
- CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic),
2471
- );
2435
+ _progress = Tween<double>(begin: _progress.value, end: widget.confidence)
2436
+ .animate(
2437
+ CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic),
2438
+ );
2472
2439
  _controller
2473
2440
  ..reset()
2474
2441
  ..forward();
@@ -2658,10 +2625,7 @@ class _MemoryRow extends StatelessWidget {
2658
2625
  if (onDelete != null)
2659
2626
  IconButton(
2660
2627
  onPressed: onDelete,
2661
- icon: Icon(
2662
- Icons.delete_outline,
2663
- size: 18,
2664
- ),
2628
+ icon: Icon(Icons.delete_outline, size: 18),
2665
2629
  ),
2666
2630
  ],
2667
2631
  ),
@@ -2686,10 +2650,7 @@ class _MemoryRow extends StatelessWidget {
2686
2650
  const SizedBox(height: 6),
2687
2651
  Text(
2688
2652
  memory.createdAtLabel,
2689
- style: TextStyle(
2690
- fontSize: 11,
2691
- color: _textMuted,
2692
- ),
2653
+ style: TextStyle(fontSize: 11, color: _textMuted),
2693
2654
  ),
2694
2655
  ],
2695
2656
  ),
@@ -2778,27 +2739,31 @@ class _EntityGraphViewState extends State<_EntityGraphView>
2778
2739
  for (int i = 0; i < entities.length; i++) {
2779
2740
  final entity = entities[i];
2780
2741
  final sizeFactor = 0.4 + 0.6 * (entity.mentionCount / maxMention);
2781
- _nodes.add(_GraphNode(
2782
- id: entity.name,
2783
- label: entity.name,
2784
- radius: 18 + 20 * sizeFactor,
2785
- color: _kindColors[entity.kind] ?? _kindColors['concept']!,
2786
- kind: entity.kind,
2787
- isReflection: false,
2788
- offsetPhase: i * 0.7,
2789
- ));
2742
+ _nodes.add(
2743
+ _GraphNode(
2744
+ id: entity.name,
2745
+ label: entity.name,
2746
+ radius: 18 + 20 * sizeFactor,
2747
+ color: _kindColors[entity.kind] ?? _kindColors['concept']!,
2748
+ kind: entity.kind,
2749
+ isReflection: false,
2750
+ offsetPhase: i * 0.7,
2751
+ ),
2752
+ );
2790
2753
  }
2791
2754
 
2792
2755
  for (int i = 0; i < views.length && i < 6; i++) {
2793
- _nodes.add(_GraphNode(
2794
- id: 'kv_${views[i].title}',
2795
- label: views[i].title,
2796
- radius: 14,
2797
- color: const Color(0xFF8B7EC8),
2798
- kind: views[i].viewType,
2799
- isReflection: true,
2800
- offsetPhase: (entities.length + i) * 0.9,
2801
- ));
2756
+ _nodes.add(
2757
+ _GraphNode(
2758
+ id: 'kv_${views[i].title}',
2759
+ label: views[i].title,
2760
+ radius: 14,
2761
+ color: const Color(0xFF8B7EC8),
2762
+ kind: views[i].viewType,
2763
+ isReflection: true,
2764
+ offsetPhase: (entities.length + i) * 0.9,
2765
+ ),
2766
+ );
2802
2767
  }
2803
2768
 
2804
2769
  _layoutDone = false;
@@ -2939,10 +2904,12 @@ class _EntityGraphPainter extends CustomPainter {
2939
2904
  void paint(Canvas canvas, Size size) {
2940
2905
  if (nodes.isEmpty) return;
2941
2906
 
2942
- final entityNodes =
2943
- nodes.where((n) => !n.isReflection).toList(growable: false);
2944
- final reflectionNodes =
2945
- nodes.where((n) => n.isReflection).toList(growable: false);
2907
+ final entityNodes = nodes
2908
+ .where((n) => !n.isReflection)
2909
+ .toList(growable: false);
2910
+ final reflectionNodes = nodes
2911
+ .where((n) => n.isReflection)
2912
+ .toList(growable: false);
2946
2913
 
2947
2914
  // Draw connections between entity nodes (subtle web)
2948
2915
  final linePaint = Paint()
@@ -2974,8 +2941,8 @@ class _EntityGraphPainter extends CustomPainter {
2974
2941
  var closest = entityNodes.first;
2975
2942
  var minDist = double.infinity;
2976
2943
  for (final en in entityNodes) {
2977
- final d = (en.x - rn.x) * (en.x - rn.x) +
2978
- (en.y - rn.y) * (en.y - rn.y);
2944
+ final d =
2945
+ (en.x - rn.x) * (en.x - rn.x) + (en.y - rn.y) * (en.y - rn.y);
2979
2946
  if (d < minDist) {
2980
2947
  minDist = d;
2981
2948
  closest = en;
@@ -3002,8 +2969,9 @@ class _EntityGraphPainter extends CustomPainter {
3002
2969
  // Glow
3003
2970
  if (isSelected || isHovered) {
3004
2971
  final glowPaint = Paint()
3005
- ..color = (isSelected ? accentColor : node.color)
3006
- .withValues(alpha: 0.22)
2972
+ ..color = (isSelected ? accentColor : node.color).withValues(
2973
+ alpha: 0.22,
2974
+ )
3007
2975
  ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 12);
3008
2976
  canvas.drawCircle(Offset(cx, cy), r + 6, glowPaint);
3009
2977
  }
@@ -3023,8 +2991,8 @@ class _EntityGraphPainter extends CustomPainter {
3023
2991
  ..color = isSelected
3024
2992
  ? accentColor
3025
2993
  : (isHovered
3026
- ? node.color.withValues(alpha: 0.8)
3027
- : node.color.withValues(alpha: 0.35))
2994
+ ? node.color.withValues(alpha: 0.8)
2995
+ : node.color.withValues(alpha: 0.35))
3028
2996
  ..style = PaintingStyle.stroke
3029
2997
  ..strokeWidth = isSelected ? 2.5 : 1.5;
3030
2998
  canvas.drawCircle(Offset(cx, cy), r, borderPaint);
@@ -3041,10 +3009,7 @@ class _EntityGraphPainter extends CustomPainter {
3041
3009
  maxLines: 1,
3042
3010
  ellipsis: '…',
3043
3011
  )..layout(maxWidth: r * 3);
3044
- tp.paint(
3045
- canvas,
3046
- Offset(cx - tp.width / 2, cy + r + 5),
3047
- );
3012
+ tp.paint(canvas, Offset(cx - tp.width / 2, cy + r + 5));
3048
3013
  }
3049
3014
  }
3050
3015
 
@@ -5365,6 +5330,7 @@ String _formatTaskWeekdays(Set<int> weekdays) {
5365
5330
  if (sorted.isEmpty) return 'Monday';
5366
5331
  return sorted.map((day) => _taskWeekdayLabels[day - 1]).join(', ');
5367
5332
  }
5333
+
5368
5334
  Future<String?> _pickTaskTriggerType(
5369
5335
  BuildContext context,
5370
5336
  String selectedType,
@@ -6545,9 +6511,7 @@ class _TasksPanelState extends State<TasksPanel> {
6545
6511
  final selectedConnectionId = ValueNotifier<int?>(
6546
6512
  task?.triggerConfig['connectionId'] is int
6547
6513
  ? task!.triggerConfig['connectionId'] as int
6548
- : int.tryParse(
6549
- task?.triggerConfig['connectionId']?.toString() ?? '',
6550
- ),
6514
+ : int.tryParse(task?.triggerConfig['connectionId']?.toString() ?? ''),
6551
6515
  );
6552
6516
  final selectedDeliveryTarget = ValueNotifier<TaskDeliveryTarget?>(
6553
6517
  _taskDeliveryTargetFromTask(task),