neoagent 2.4.1-beta.33 → 2.4.1-beta.34

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.
@@ -3099,6 +3099,9 @@ class TaskItem {
3099
3099
  required this.model,
3100
3100
  required this.enabled,
3101
3101
  required this.lastRun,
3102
+ required this.lastRunId,
3103
+ required this.lastRunStatus,
3104
+ required this.lastRunError,
3102
3105
  required this.taskType,
3103
3106
  required this.widgetId,
3104
3107
  });
@@ -3144,6 +3147,9 @@ class TaskItem {
3144
3147
  '',
3145
3148
  enabled: json['enabled'] != false,
3146
3149
  lastRun: _parseOptionalTimestamp(json['lastRun']?.toString()),
3150
+ lastRunId: json['lastRunId']?.toString() ?? '',
3151
+ lastRunStatus: json['lastRunStatus']?.toString() ?? '',
3152
+ lastRunError: json['lastRunError']?.toString() ?? '',
3147
3153
  taskType:
3148
3154
  json['taskType']?.toString().ifEmpty(
3149
3155
  json['task_type']?.toString() ?? 'agent_prompt',
@@ -3168,12 +3174,20 @@ class TaskItem {
3168
3174
  final String model;
3169
3175
  final bool enabled;
3170
3176
  final DateTime? lastRun;
3177
+ final String lastRunId;
3178
+ final String lastRunStatus;
3179
+ final String lastRunError;
3171
3180
  final String taskType;
3172
3181
  final String widgetId;
3173
3182
 
3174
3183
  String get scheduleLabel =>
3175
3184
  triggerSummary.trim().isEmpty ? 'Task trigger' : triggerSummary;
3176
3185
  String get lastRunLabel => lastRun == null ? '' : _formatTimestamp(lastRun!);
3186
+ String get lastRunStatusLabel =>
3187
+ _titleCase(lastRunStatus.replaceAll('_', ' '));
3188
+ bool get hasLastRunStatus => lastRunStatus.trim().isNotEmpty;
3189
+ bool get lastRunFailed =>
3190
+ lastRunStatus == 'failed' || lastRunStatus == 'error';
3177
3191
  bool get hasModelOverride => model.trim().isNotEmpty;
3178
3192
  bool get isWidgetRefresh => taskType == 'widget_refresh';
3179
3193
  }
@@ -4555,6 +4555,89 @@ class _TasksPanelState extends State<TasksPanel> {
4555
4555
 
4556
4556
  NeoAgentController get controller => widget.controller;
4557
4557
 
4558
+ Color _taskRunStatusColor(String status) {
4559
+ switch (status) {
4560
+ case 'completed':
4561
+ return _success;
4562
+ case 'failed':
4563
+ case 'error':
4564
+ return _danger;
4565
+ case 'running':
4566
+ case 'retrying':
4567
+ return _warning;
4568
+ default:
4569
+ return _textSecondary;
4570
+ }
4571
+ }
4572
+
4573
+ Future<void> _showLastRun(TaskItem task) async {
4574
+ final runId = task.lastRunId.trim();
4575
+ if (runId.isEmpty) return;
4576
+
4577
+ try {
4578
+ final detail = await controller.fetchRunDetail(runId, force: true);
4579
+ if (!mounted) return;
4580
+ await showDialog<void>(
4581
+ context: context,
4582
+ builder: (dialogContext) => AlertDialog(
4583
+ title: Text(detail.run.title),
4584
+ content: ConstrainedBox(
4585
+ constraints: const BoxConstraints(maxWidth: 620),
4586
+ child: SingleChildScrollView(
4587
+ child: Column(
4588
+ mainAxisSize: MainAxisSize.min,
4589
+ crossAxisAlignment: CrossAxisAlignment.start,
4590
+ children: <Widget>[
4591
+ Wrap(
4592
+ spacing: 8,
4593
+ runSpacing: 8,
4594
+ children: <Widget>[
4595
+ _StatusPill(
4596
+ label: detail.run.statusLabel,
4597
+ color: detail.run.statusColor,
4598
+ ),
4599
+ _StatusPill(
4600
+ label: '${detail.steps.length} steps',
4601
+ color: _textSecondary,
4602
+ ),
4603
+ ],
4604
+ ),
4605
+ if (detail.run.error.trim().isNotEmpty) ...<Widget>[
4606
+ const SizedBox(height: 16),
4607
+ Text(detail.run.error, style: TextStyle(color: _danger)),
4608
+ ],
4609
+ if (detail.response.trim().isNotEmpty) ...<Widget>[
4610
+ const SizedBox(height: 16),
4611
+ SelectableText(detail.response),
4612
+ ],
4613
+ if (detail.response.trim().isEmpty &&
4614
+ detail.run.error.trim().isEmpty) ...<Widget>[
4615
+ const SizedBox(height: 16),
4616
+ Text(
4617
+ 'This run did not produce a user-facing response.',
4618
+ style: TextStyle(color: _textSecondary),
4619
+ ),
4620
+ ],
4621
+ ],
4622
+ ),
4623
+ ),
4624
+ ),
4625
+ actions: <Widget>[
4626
+ TextButton(
4627
+ onPressed: () => Navigator.of(dialogContext).pop(),
4628
+ child: const Text('Close'),
4629
+ ),
4630
+ ],
4631
+ ),
4632
+ );
4633
+ } catch (error) {
4634
+ if (!mounted) return;
4635
+ ScaffoldMessenger.of(context).showSnackBar(
4636
+ SnackBar(content: Text(controller.friendlyErrorMessage(error))),
4637
+ );
4638
+ }
4639
+ }
4640
+
4558
4641
  @override
4559
4642
  void didUpdateWidget(covariant TasksPanel oldWidget) {
4560
4643
  super.didUpdateWidget(oldWidget);
@@ -4703,6 +4786,13 @@ class _TasksPanelState extends State<TasksPanel> {
4703
4786
  label: task.enabled ? 'Active' : 'Paused',
4704
4787
  color: task.enabled ? _success : _textSecondary,
4705
4788
  ),
4789
+ if (task.hasLastRunStatus) ...<Widget>[
4790
+ const SizedBox(width: 8),
4791
+ _StatusPill(
4792
+ label: 'Last: ${task.lastRunStatusLabel}',
4793
+ color: _taskRunStatusColor(task.lastRunStatus),
4794
+ ),
4795
+ ],
4706
4796
  ],
4707
4797
  ),
4708
4798
  const SizedBox(height: 10),
@@ -4734,6 +4824,11 @@ class _TasksPanelState extends State<TasksPanel> {
4734
4824
  style: TextStyle(color: _textSecondary),
4735
4825
  ),
4736
4826
  ],
4827
+ if (task.lastRunFailed &&
4828
+ task.lastRunError.trim().isNotEmpty) ...<Widget>[
4829
+ const SizedBox(height: 8),
4830
+ Text(task.lastRunError, style: TextStyle(color: _danger)),
4831
+ ],
4737
4832
  const SizedBox(height: 14),
4738
4833
  Wrap(
4739
4834
  spacing: 10,
@@ -4753,6 +4848,11 @@ class _TasksPanelState extends State<TasksPanel> {
4753
4848
  : () => controller.runTaskNow(task.id),
4754
4849
  child: Text(_manualRunButtonLabel('Run Now', remaining)),
4755
4850
  ),
4851
+ if (task.lastRunId.trim().isNotEmpty)
4852
+ OutlinedButton(
4853
+ onPressed: () => _showLastRun(task),
4854
+ child: const Text('View last run'),
4855
+ ),
4756
4856
  OutlinedButton(
4757
4857
  onPressed: () => _confirmDelete(
4758
4858
  context,
@@ -4805,6 +4905,13 @@ class _TasksPanelState extends State<TasksPanel> {
4805
4905
  label: task.enabled ? 'Active' : 'Paused',
4806
4906
  color: task.enabled ? _success : _textSecondary,
4807
4907
  ),
4908
+ if (task.hasLastRunStatus) ...<Widget>[
4909
+ const SizedBox(width: 8),
4910
+ _StatusPill(
4911
+ label: 'Last: ${task.lastRunStatusLabel}',
4912
+ color: _taskRunStatusColor(task.lastRunStatus),
4913
+ ),
4914
+ ],
4808
4915
  ],
4809
4916
  ),
4810
4917
  const SizedBox(height: 10),
@@ -4839,6 +4946,11 @@ class _TasksPanelState extends State<TasksPanel> {
4839
4946
  style: TextStyle(color: _textSecondary),
4840
4947
  ),
4841
4948
  ],
4949
+ if (task.lastRunFailed &&
4950
+ task.lastRunError.trim().isNotEmpty) ...<Widget>[
4951
+ const SizedBox(height: 8),
4952
+ Text(task.lastRunError, style: TextStyle(color: _danger)),
4953
+ ],
4842
4954
  const SizedBox(height: 14),
4843
4955
  Wrap(
4844
4956
  spacing: 10,
@@ -4868,6 +4980,11 @@ class _TasksPanelState extends State<TasksPanel> {
4868
4980
  _manualRunButtonLabel('Refresh Now', remaining),
4869
4981
  ),
4870
4982
  ),
4983
+ if (task.lastRunId.trim().isNotEmpty)
4984
+ OutlinedButton(
4985
+ onPressed: () => _showLastRun(task),
4986
+ child: const Text('View last run'),
4987
+ ),
4871
4988
  OutlinedButton(
4872
4989
  onPressed: linkedWidget == null
4873
4990
  ? null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.4.1-beta.33",
3
+ "version": "2.4.1-beta.34",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
@@ -1 +1 @@
1
- 49442e542f5b85df16e4fff2751cb6a3
1
+ 79f8662ed3c8bed9a624d3d498b9e894
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"c416acfeb8126e097f758c664aaa3da929e27d
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "2270904145" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "3692681921" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });