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.
@@ -3778,7 +3778,8 @@ class NeoAgentController extends ChangeNotifier {
3778
3778
  _desktopFloatingToolbarPopupRequested = false;
3779
3779
  unawaited(
3780
3780
  _analytics.trackRecordingStopped(
3781
- kind: recordingRuntime.supportsBackgroundMic &&
3781
+ kind:
3782
+ recordingRuntime.supportsBackgroundMic &&
3782
3783
  !recordingRuntime.supportsScreenAndMic
3783
3784
  ? 'background'
3784
3785
  : 'desktop',
@@ -1,26 +1,34 @@
1
1
  part of 'main.dart';
2
2
 
3
3
  class IntegrationsPanel extends StatelessWidget {
4
- const IntegrationsPanel({super.key, required this.controller});
4
+ const IntegrationsPanel({
5
+ super.key,
6
+ required this.controller,
7
+ this.embedded = false,
8
+ });
5
9
 
6
10
  final NeoAgentController controller;
11
+ final bool embedded;
7
12
 
8
13
  @override
9
14
  Widget build(BuildContext context) {
10
- return Padding(
11
- padding: _pagePadding(context),
12
- child: Column(
13
- children: <Widget>[
15
+ final body = Column(
16
+ children: <Widget>[
17
+ if (!embedded) ...<Widget>[
14
18
  _PageTitle(
15
19
  title: 'Integrations',
16
20
  subtitle:
17
21
  'Connect and manage official integrations separately from reusable skills.',
18
22
  ),
19
23
  const SizedBox(height: 12),
20
- Expanded(child: OfficialIntegrationsTab(controller: controller)),
21
24
  ],
22
- ),
25
+ Expanded(child: OfficialIntegrationsTab(controller: controller)),
26
+ ],
23
27
  );
28
+ if (embedded) {
29
+ return body;
30
+ }
31
+ return Padding(padding: _pagePadding(context), child: body);
24
32
  }
25
33
  }
26
34
 
@@ -832,7 +832,7 @@ class MessagingAccessCapabilities {
832
832
  });
833
833
 
834
834
  factory MessagingAccessCapabilities.fromJson(Map<String, dynamic> json) {
835
- List<String> _stringList(dynamic value) {
835
+ List<String> stringList(dynamic value) {
836
836
  if (value is! List) return const <String>[];
837
837
  return value
838
838
  .map((item) => item.toString())
@@ -845,9 +845,9 @@ class MessagingAccessCapabilities {
845
845
  supportsSharedPolicy: json['supportsSharedPolicy'] != false,
846
846
  supportsMentionGate: json['supportsMentionGate'] == true,
847
847
  supportsDiscovery: json['supportsDiscovery'] == true,
848
- directRuleScopes: _stringList(json['directRuleScopes']),
849
- sharedSpaceRuleScopes: _stringList(json['sharedSpaceRuleScopes']),
850
- sharedActorRuleScopes: _stringList(json['sharedActorRuleScopes']),
848
+ directRuleScopes: stringList(json['directRuleScopes']),
849
+ sharedSpaceRuleScopes: stringList(json['sharedSpaceRuleScopes']),
850
+ sharedActorRuleScopes: stringList(json['sharedActorRuleScopes']),
851
851
  manualEntryHint: json['manualEntryHint']?.toString() ?? '',
852
852
  );
853
853
  }
@@ -932,7 +932,7 @@ class MessagingAccessCatalog {
932
932
  String platform,
933
933
  Map<String, dynamic> json,
934
934
  ) {
935
- List<MessagingAccessTarget> _targets(dynamic raw) {
935
+ List<MessagingAccessTarget> parseTargets(dynamic raw) {
936
936
  if (raw is! List) return const <MessagingAccessTarget>[];
937
937
  return raw
938
938
  .whereType<Map>()
@@ -950,8 +950,8 @@ class MessagingAccessCatalog {
950
950
  capabilities: MessagingAccessCapabilities.fromJson(
951
951
  _jsonMap(json['capabilities']),
952
952
  ),
953
- discoveredTargets: _targets(json['discoveredTargets']),
954
- suggestedTargets: _targets(json['suggestedTargets']),
953
+ discoveredTargets: parseTargets(json['discoveredTargets']),
954
+ suggestedTargets: parseTargets(json['suggestedTargets']),
955
955
  summary: json['summary']?.toString() ?? 'Access policy',
956
956
  );
957
957
  }
@@ -1434,6 +1434,7 @@ class RunDetailSnapshot {
1434
1434
  const RunDetailSnapshot({
1435
1435
  required this.run,
1436
1436
  required this.steps,
1437
+ required this.events,
1437
1438
  required this.response,
1438
1439
  });
1439
1440
 
@@ -1444,12 +1445,17 @@ class RunDetailSnapshot {
1444
1445
  json['steps'],
1445
1446
  fallbackToMapValues: true,
1446
1447
  ).map(RunStepItem.fromJson).toList(),
1448
+ events: _jsonMapList(
1449
+ json['events'],
1450
+ fallbackToMapValues: true,
1451
+ ).map(RunEventItem.fromJson).toList(),
1447
1452
  response: json['response']?.toString() ?? '',
1448
1453
  );
1449
1454
  }
1450
1455
 
1451
1456
  final RunSummary run;
1452
1457
  final List<RunStepItem> steps;
1458
+ final List<RunEventItem> events;
1453
1459
  final String response;
1454
1460
 
1455
1461
  int get completedTools => steps
@@ -1469,6 +1475,95 @@ class RunDetailSnapshot {
1469
1475
  steps.where((step) => step.isPlanningRelated).length;
1470
1476
  }
1471
1477
 
1478
+ class RunEventItem {
1479
+ const RunEventItem({
1480
+ required this.id,
1481
+ required this.eventType,
1482
+ required this.sequenceIndex,
1483
+ required this.requestId,
1484
+ required this.stepId,
1485
+ required this.payload,
1486
+ required this.createdAt,
1487
+ });
1488
+
1489
+ factory RunEventItem.fromJson(Map<dynamic, dynamic> json) {
1490
+ return RunEventItem(
1491
+ id: _asInt(json['id']),
1492
+ eventType:
1493
+ json['eventType']?.toString().ifEmpty(
1494
+ json['event_type']?.toString() ?? 'event',
1495
+ ) ??
1496
+ 'event',
1497
+ sequenceIndex: _asInt(json['sequenceIndex'] ?? json['sequence_index']),
1498
+ requestId:
1499
+ json['requestId']?.toString() ?? json['request_id']?.toString(),
1500
+ stepId: json['stepId']?.toString() ?? json['step_id']?.toString(),
1501
+ payload: json['payload'] is Map
1502
+ ? Map<String, dynamic>.from(json['payload'] as Map)
1503
+ : (json['payload_json'] is Map
1504
+ ? Map<String, dynamic>.from(json['payload_json'] as Map)
1505
+ : const <String, dynamic>{}),
1506
+ createdAt: _parseOptionalTimestamp(
1507
+ json['createdAt']?.toString() ?? json['created_at']?.toString(),
1508
+ ),
1509
+ );
1510
+ }
1511
+
1512
+ final int id;
1513
+ final String eventType;
1514
+ final int sequenceIndex;
1515
+ final String? requestId;
1516
+ final String? stepId;
1517
+ final Map<String, dynamic> payload;
1518
+ final DateTime? createdAt;
1519
+
1520
+ String get title {
1521
+ switch (eventType) {
1522
+ case 'run_started':
1523
+ return 'Run started';
1524
+ case 'memory_injected':
1525
+ return 'Memory injected';
1526
+ case 'model_turn_started':
1527
+ return 'Model turn started';
1528
+ case 'model_turn_completed':
1529
+ return 'Model turn completed';
1530
+ case 'tool_started':
1531
+ return 'Tool started';
1532
+ case 'tool_completed':
1533
+ return 'Tool completed';
1534
+ case 'tool_failed':
1535
+ return 'Tool failed';
1536
+ case 'run_completed':
1537
+ return 'Run completed';
1538
+ case 'run_failed':
1539
+ return 'Run failed';
1540
+ case 'run_stopped':
1541
+ return 'Run stopped';
1542
+ default:
1543
+ return _titleCase(eventType.replaceAll('_', ' '));
1544
+ }
1545
+ }
1546
+
1547
+ String get detail {
1548
+ final toolName = payload['toolName']?.toString() ?? '';
1549
+ if (toolName.trim().isNotEmpty) return toolName;
1550
+ final preview =
1551
+ payload['contentPreview']?.toString() ??
1552
+ payload['recallPreview']?.toString() ??
1553
+ '';
1554
+ if (preview.trim().isNotEmpty) return preview;
1555
+ final error = payload['error']?.toString() ?? '';
1556
+ if (error.trim().isNotEmpty) return error;
1557
+ final titleValue = payload['title']?.toString() ?? '';
1558
+ return titleValue;
1559
+ }
1560
+
1561
+ String get createdAtLabel =>
1562
+ createdAt == null ? '' : _formatTimestamp(createdAt!);
1563
+
1564
+ bool get isFailure => eventType == 'tool_failed' || eventType == 'run_failed';
1565
+ }
1566
+
1472
1567
  class RunStepItem {
1473
1568
  const RunStepItem({
1474
1569
  required this.id,
@@ -2802,6 +2897,9 @@ class AiWidgetItem {
2802
2897
  required this.userId,
2803
2898
  required this.agentId,
2804
2899
  required this.name,
2900
+ required this.widgetKind,
2901
+ required this.systemKey,
2902
+ required this.isSystem,
2805
2903
  required this.template,
2806
2904
  required this.layoutVariant,
2807
2905
  required this.definition,
@@ -2823,6 +2921,14 @@ class AiWidgetItem {
2823
2921
  userId: _asInt(json['userId'] ?? json['user_id']),
2824
2922
  agentId: json['agentId']?.toString() ?? json['agent_id']?.toString(),
2825
2923
  name: json['name']?.toString().ifEmpty('Widget') ?? 'Widget',
2924
+ widgetKind:
2925
+ json['widgetKind']?.toString().ifEmpty(
2926
+ json['widget_kind']?.toString() ?? 'custom',
2927
+ ) ??
2928
+ 'custom',
2929
+ systemKey:
2930
+ json['systemKey']?.toString() ?? json['system_key']?.toString(),
2931
+ isSystem: json['isSystem'] == true || json['is_system'] == true,
2826
2932
  template: json['template']?.toString().ifEmpty('summary') ?? 'summary',
2827
2933
  layoutVariant:
2828
2934
  json['layoutVariant']?.toString().ifEmpty(
@@ -2876,6 +2982,9 @@ class AiWidgetItem {
2876
2982
  final int userId;
2877
2983
  final String? agentId;
2878
2984
  final String name;
2985
+ final String widgetKind;
2986
+ final String? systemKey;
2987
+ final bool isSystem;
2879
2988
  final String template;
2880
2989
  final String layoutVariant;
2881
2990
  final Map<String, dynamic> definition;
@@ -32,7 +32,7 @@ enum AppSection {
32
32
  health,
33
33
  }
34
34
 
35
- enum SidebarGroup { chat, recordings, activity, automation, settings }
35
+ enum SidebarGroup { chat, recordings, automation, settings }
36
36
 
37
37
  extension SidebarGroupX on SidebarGroup {
38
38
  String get label {
@@ -41,8 +41,6 @@ extension SidebarGroupX on SidebarGroup {
41
41
  return 'Chat';
42
42
  case SidebarGroup.recordings:
43
43
  return 'Recordings';
44
- case SidebarGroup.activity:
45
- return 'Activity';
46
44
  case SidebarGroup.automation:
47
45
  return 'Automation';
48
46
  case SidebarGroup.settings:
@@ -56,8 +54,6 @@ extension SidebarGroupX on SidebarGroup {
56
54
  return Icons.chat_bubble_outline;
57
55
  case SidebarGroup.recordings:
58
56
  return Icons.fiber_smart_record_outlined;
59
- case SidebarGroup.activity:
60
- return Icons.insights_outlined;
61
57
  case SidebarGroup.automation:
62
58
  return Icons.auto_awesome_outlined;
63
59
  case SidebarGroup.settings:
@@ -80,7 +76,7 @@ extension AppSectionX on AppSection {
80
76
  case AppSection.messaging:
81
77
  return 'Messaging';
82
78
  case AppSection.runs:
83
- return 'Runs';
79
+ return 'Runs & Logs';
84
80
  case AppSection.settings:
85
81
  return 'Settings';
86
82
  case AppSection.accountSettings:
@@ -92,7 +88,7 @@ extension AppSectionX on AppSection {
92
88
  case AppSection.agents:
93
89
  return 'Agents';
94
90
  case AppSection.integrations:
95
- return 'Integrations';
91
+ return 'Tools';
96
92
  case AppSection.memory:
97
93
  return 'Memory';
98
94
  case AppSection.tasks:
@@ -119,7 +115,7 @@ extension AppSectionX on AppSection {
119
115
  case AppSection.messaging:
120
116
  return Icons.forum_outlined;
121
117
  case AppSection.runs:
122
- return Icons.history;
118
+ return Icons.monitor_heart_outlined;
123
119
  case AppSection.settings:
124
120
  return Icons.tune;
125
121
  case AppSection.accountSettings:
@@ -131,7 +127,7 @@ extension AppSectionX on AppSection {
131
127
  case AppSection.agents:
132
128
  return Icons.smart_toy_outlined;
133
129
  case AppSection.integrations:
134
- return Icons.integration_instructions_outlined;
130
+ return Icons.handyman_outlined;
135
131
  case AppSection.memory:
136
132
  return Icons.psychology_outlined;
137
133
  case AppSection.tasks:
@@ -152,9 +148,6 @@ extension AppSectionX on AppSection {
152
148
  return SidebarGroup.chat;
153
149
  case AppSection.recordings:
154
150
  return SidebarGroup.recordings;
155
- case AppSection.runs:
156
- case AppSection.logs:
157
- return SidebarGroup.activity;
158
151
  case AppSection.devices:
159
152
  case AppSection.skills:
160
153
  case AppSection.integrations:
@@ -164,6 +157,8 @@ extension AppSectionX on AppSection {
164
157
  case AppSection.mcp:
165
158
  case AppSection.health:
166
159
  return SidebarGroup.automation;
160
+ case AppSection.runs:
161
+ case AppSection.logs:
167
162
  case AppSection.settings:
168
163
  case AppSection.accountSettings:
169
164
  case AppSection.messaging:
@@ -172,17 +167,31 @@ extension AppSectionX on AppSection {
172
167
  }
173
168
  }
174
169
 
170
+ AppSection get canonicalSection {
171
+ switch (this) {
172
+ case AppSection.logs:
173
+ return AppSection.runs;
174
+ case AppSection.skills:
175
+ case AppSection.mcp:
176
+ return AppSection.integrations;
177
+ default:
178
+ return this;
179
+ }
180
+ }
181
+
175
182
  String get navigationTitle {
176
- final groupLabel = group.label;
177
- if (this == AppSection.voiceAssistant) {
178
- return label;
183
+ final effectiveSection = canonicalSection;
184
+ final groupLabel = effectiveSection.group.label;
185
+ if (effectiveSection == AppSection.voiceAssistant) {
186
+ return effectiveSection.label;
179
187
  }
180
- if (group == SidebarGroup.chat || group == SidebarGroup.recordings) {
188
+ if (effectiveSection.group == SidebarGroup.chat ||
189
+ effectiveSection.group == SidebarGroup.recordings) {
181
190
  return groupLabel;
182
191
  }
183
- if (groupLabel == label) {
192
+ if (groupLabel == effectiveSection.label) {
184
193
  return groupLabel;
185
194
  }
186
- return '$groupLabel · $label';
195
+ return '$groupLabel · ${effectiveSection.label}';
187
196
  }
188
197
  }