neoagent 2.3.1-beta.85 → 2.3.1-beta.87
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/docs/capabilities.md +2 -0
- package/flutter_app/android/app/src/main/AndroidManifest.xml +14 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +84 -0
- package/flutter_app/lib/main_chat.dart +156 -2
- package/flutter_app/lib/main_controller.dart +137 -10
- package/flutter_app/lib/main_models.dart +69 -0
- package/flutter_app/lib/main_operations.dart +248 -0
- package/flutter_app/lib/main_runtime.dart +11 -2
- package/flutter_app/lib/main_settings.dart +173 -176
- package/flutter_app/lib/main_shared.dart +78 -0
- package/flutter_app/lib/src/app_launch_bridge.dart +39 -10
- package/flutter_app/lib/src/backend_client.dart +28 -0
- package/package.json +1 -1
- package/server/guest-agent.android.package.json +13 -0
- package/server/guest-agent.browser.package.json +14 -0
- package/server/guest_agent.js +61 -44
- package/server/http/routes.js +1 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +69936 -69277
- package/server/routes/android.js +2 -11
- package/server/routes/browser.js +2 -2
- package/server/routes/memory.js +90 -0
- package/server/routes/social_video.js +62 -0
- package/server/services/ai/capabilityHealth.js +6 -14
- package/server/services/ai/systemPrompt.js +1 -0
- package/server/services/ai/toolResult.js +20 -0
- package/server/services/ai/tools.js +29 -0
- package/server/services/android/android_bootstrap_worker.js +2 -2
- package/server/services/android/controller.js +528 -132
- package/server/services/browser/controller.js +51 -68
- package/server/services/manager.js +15 -0
- package/server/services/memory/llm_transfer.js +217 -0
- package/server/services/runtime/backends/local-vm.js +16 -3
- package/server/services/runtime/guest_bootstrap.js +224 -56
- package/server/services/runtime/manager.js +53 -15
- package/server/services/runtime/qemu.js +149 -24
- package/server/services/runtime/settings.js +9 -14
- package/server/services/runtime/validation.js +10 -11
- package/server/services/social_video/adapters/base.js +26 -0
- package/server/services/social_video/adapters/index.js +27 -0
- package/server/services/social_video/adapters/instagram.js +17 -0
- package/server/services/social_video/adapters/tiktok.js +17 -0
- package/server/services/social_video/adapters/x.js +17 -0
- package/server/services/social_video/adapters/youtube.js +17 -0
- package/server/services/social_video/captions.js +187 -0
- package/server/services/social_video/frame.js +42 -0
- package/server/services/social_video/index.js +7 -0
- package/server/services/social_video/metadata.js +63 -0
- package/server/services/social_video/result.js +63 -0
- package/server/services/social_video/service.js +576 -0
- package/server/services/social_video/url.js +83 -0
- package/server/utils/deployment.js +4 -4
- package/server/guest-agent.package.json +0 -15
|
@@ -598,10 +598,7 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
598
598
|
'Cloud uses the isolated browser runtime. Extension uses a paired Chrome browser on the remote machine.',
|
|
599
599
|
),
|
|
600
600
|
items: const <DropdownMenuItem<String>>[
|
|
601
|
-
DropdownMenuItem<String>(
|
|
602
|
-
value: 'vm',
|
|
603
|
-
child: Text('Cloud'),
|
|
604
|
-
),
|
|
601
|
+
DropdownMenuItem<String>(value: 'vm', child: Text('Cloud')),
|
|
605
602
|
DropdownMenuItem<String>(
|
|
606
603
|
value: 'extension',
|
|
607
604
|
child: Text('Chrome extension'),
|
|
@@ -1465,194 +1462,194 @@ class _SettingsPanelState extends State<SettingsPanel> {
|
|
|
1465
1462
|
),
|
|
1466
1463
|
const SizedBox(height: 12),
|
|
1467
1464
|
if (!controller.appUpdaterConfigured)
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
labelText: 'App release channel',
|
|
1482
|
-
),
|
|
1483
|
-
items: const <DropdownMenuItem<String>>[
|
|
1484
|
-
DropdownMenuItem<String>(
|
|
1485
|
-
value: 'stable',
|
|
1486
|
-
child: Text('Stable'),
|
|
1465
|
+
if (!kIsWeb)
|
|
1466
|
+
Text(
|
|
1467
|
+
'Client app updates are not configured for this build.',
|
|
1468
|
+
style: TextStyle(color: _textSecondary, height: 1.5),
|
|
1469
|
+
)
|
|
1470
|
+
else ...<Widget>[
|
|
1471
|
+
LayoutBuilder(
|
|
1472
|
+
builder: (context, constraints) {
|
|
1473
|
+
final compact = constraints.maxWidth < 780;
|
|
1474
|
+
final channelPicker = DropdownButtonFormField<String>(
|
|
1475
|
+
initialValue: controller.appUpdateChannel,
|
|
1476
|
+
decoration: const InputDecoration(
|
|
1477
|
+
labelText: 'App release channel',
|
|
1487
1478
|
),
|
|
1488
|
-
DropdownMenuItem<String
|
|
1489
|
-
|
|
1490
|
-
|
|
1479
|
+
items: const <DropdownMenuItem<String>>[
|
|
1480
|
+
DropdownMenuItem<String>(
|
|
1481
|
+
value: 'stable',
|
|
1482
|
+
child: Text('Stable'),
|
|
1483
|
+
),
|
|
1484
|
+
DropdownMenuItem<String>(
|
|
1485
|
+
value: 'beta',
|
|
1486
|
+
child: Text('Beta'),
|
|
1487
|
+
),
|
|
1488
|
+
],
|
|
1489
|
+
onChanged: (value) {
|
|
1490
|
+
if (value != null) {
|
|
1491
|
+
unawaited(controller.setAppUpdateChannel(value));
|
|
1492
|
+
}
|
|
1493
|
+
},
|
|
1494
|
+
);
|
|
1495
|
+
final autoCheck = SwitchListTile.adaptive(
|
|
1496
|
+
value: controller.appUpdateAutoCheckEnabled,
|
|
1497
|
+
contentPadding: EdgeInsets.zero,
|
|
1498
|
+
title: Text('Check automatically on launch'),
|
|
1499
|
+
subtitle: Text(
|
|
1500
|
+
'This only checks GitHub Releases on startup. Installation still requires your confirmation.',
|
|
1501
|
+
style: TextStyle(color: _textSecondary),
|
|
1491
1502
|
),
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
if (value != null) {
|
|
1495
|
-
unawaited(controller.setAppUpdateChannel(value));
|
|
1496
|
-
}
|
|
1497
|
-
},
|
|
1498
|
-
);
|
|
1499
|
-
final autoCheck = SwitchListTile.adaptive(
|
|
1500
|
-
value: controller.appUpdateAutoCheckEnabled,
|
|
1501
|
-
contentPadding: EdgeInsets.zero,
|
|
1502
|
-
title: Text('Check automatically on launch'),
|
|
1503
|
-
subtitle: Text(
|
|
1504
|
-
'This only checks GitHub Releases on startup. Installation still requires your confirmation.',
|
|
1505
|
-
style: TextStyle(color: _textSecondary),
|
|
1506
|
-
),
|
|
1507
|
-
onChanged: controller.setAppUpdateAutoCheckEnabled,
|
|
1508
|
-
);
|
|
1503
|
+
onChanged: controller.setAppUpdateAutoCheckEnabled,
|
|
1504
|
+
);
|
|
1509
1505
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1506
|
+
if (compact) {
|
|
1507
|
+
return Column(
|
|
1508
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
1509
|
+
children: <Widget>[
|
|
1510
|
+
channelPicker,
|
|
1511
|
+
const SizedBox(height: 10),
|
|
1512
|
+
autoCheck,
|
|
1513
|
+
],
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
return Row(
|
|
1512
1518
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
1513
1519
|
children: <Widget>[
|
|
1514
|
-
channelPicker,
|
|
1515
|
-
const SizedBox(
|
|
1516
|
-
autoCheck,
|
|
1520
|
+
Expanded(child: channelPicker),
|
|
1521
|
+
const SizedBox(width: 16),
|
|
1522
|
+
Expanded(child: autoCheck),
|
|
1517
1523
|
],
|
|
1518
1524
|
);
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
)
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
),
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1525
|
+
},
|
|
1526
|
+
),
|
|
1527
|
+
const SizedBox(height: 8),
|
|
1528
|
+
Text(
|
|
1529
|
+
'Installed: ${controller.installedAppVersion ?? 'Unknown'} | Channel: ${controller.appUpdateChannelLabel} | Last checked: ${controller.appUpdateLastCheckedLabel}',
|
|
1530
|
+
style: TextStyle(color: _textSecondary),
|
|
1531
|
+
),
|
|
1532
|
+
const SizedBox(height: 6),
|
|
1533
|
+
Text(
|
|
1534
|
+
'Source: ${app_release_updater.appUpdaterGithubOwner}/${app_release_updater.appUpdaterGithubRepo}${app_release_updater.appUpdaterGithubToken.trim().isNotEmpty ? ' (override active)' : ''}',
|
|
1535
|
+
style: TextStyle(color: _textSecondary),
|
|
1536
|
+
),
|
|
1537
|
+
if (controller.appUpdateErrorMessage
|
|
1538
|
+
case final message?) ...<Widget>[
|
|
1539
|
+
const SizedBox(height: 12),
|
|
1540
|
+
_InlineError(message: message),
|
|
1541
|
+
],
|
|
1542
|
+
if (controller.availableAppUpdate
|
|
1543
|
+
case final release?) ...<Widget>[
|
|
1544
|
+
const SizedBox(height: 16),
|
|
1545
|
+
Container(
|
|
1546
|
+
width: double.infinity,
|
|
1547
|
+
padding: const EdgeInsets.all(16),
|
|
1548
|
+
decoration: BoxDecoration(
|
|
1549
|
+
color: _bgSecondary,
|
|
1550
|
+
borderRadius: BorderRadius.circular(18),
|
|
1551
|
+
border: Border.all(color: _border),
|
|
1552
|
+
),
|
|
1553
|
+
child: Column(
|
|
1554
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
1555
|
+
children: <Widget>[
|
|
1556
|
+
Wrap(
|
|
1557
|
+
spacing: 10,
|
|
1558
|
+
runSpacing: 10,
|
|
1559
|
+
children: <Widget>[
|
|
1560
|
+
_StatusPill(
|
|
1561
|
+
label: 'Update ${release.version}',
|
|
1562
|
+
color: release.channel == 'beta'
|
|
1563
|
+
? _warning
|
|
1564
|
+
: _accent,
|
|
1565
|
+
),
|
|
1566
|
+
_StatusPill(
|
|
1567
|
+
label: release.asset.name,
|
|
1568
|
+
color: _textSecondary,
|
|
1569
|
+
),
|
|
1570
|
+
],
|
|
1571
|
+
),
|
|
1572
|
+
const SizedBox(height: 10),
|
|
1573
|
+
Text(
|
|
1574
|
+
'${release.title} · ${release.publishedLabel} · ${release.asset.sizeLabel}',
|
|
1575
|
+
style: TextStyle(color: _textSecondary),
|
|
1576
|
+
),
|
|
1577
|
+
if (release.body.trim().isNotEmpty) ...<Widget>[
|
|
1578
|
+
const SizedBox(height: 14),
|
|
1579
|
+
ConstrainedBox(
|
|
1580
|
+
constraints: const BoxConstraints(maxHeight: 220),
|
|
1581
|
+
child: SingleChildScrollView(
|
|
1582
|
+
child: MarkdownBody(
|
|
1583
|
+
data: release.body,
|
|
1584
|
+
selectable: true,
|
|
1585
|
+
styleSheet: MarkdownStyleSheet(
|
|
1586
|
+
p: TextStyle(
|
|
1587
|
+
color: _textSecondary,
|
|
1588
|
+
height: 1.45,
|
|
1589
|
+
),
|
|
1590
|
+
),
|
|
1591
|
+
),
|
|
1592
|
+
),
|
|
1573
1593
|
),
|
|
1574
1594
|
],
|
|
1575
|
-
),
|
|
1576
|
-
const SizedBox(height: 10),
|
|
1577
|
-
Text(
|
|
1578
|
-
'${release.title} · ${release.publishedLabel} · ${release.asset.sizeLabel}',
|
|
1579
|
-
style: TextStyle(color: _textSecondary),
|
|
1580
|
-
),
|
|
1581
|
-
if (release.body.trim().isNotEmpty) ...<Widget>[
|
|
1582
1595
|
const SizedBox(height: 14),
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1596
|
+
Wrap(
|
|
1597
|
+
spacing: 10,
|
|
1598
|
+
runSpacing: 10,
|
|
1599
|
+
children: <Widget>[
|
|
1600
|
+
FilledButton.icon(
|
|
1601
|
+
onPressed: controller.isOpeningAppUpdate
|
|
1602
|
+
? null
|
|
1603
|
+
: controller.openAppUpdate,
|
|
1604
|
+
style: FilledButton.styleFrom(
|
|
1605
|
+
backgroundColor: _accent,
|
|
1606
|
+
),
|
|
1607
|
+
icon: controller.isOpeningAppUpdate
|
|
1608
|
+
? const SizedBox.square(
|
|
1609
|
+
dimension: 16,
|
|
1610
|
+
child: CircularProgressIndicator(
|
|
1611
|
+
strokeWidth: 2,
|
|
1612
|
+
color: Colors.white,
|
|
1613
|
+
),
|
|
1614
|
+
)
|
|
1615
|
+
: const Icon(Icons.system_update_alt),
|
|
1616
|
+
label: Text(
|
|
1617
|
+
controller.isOpeningAppUpdate
|
|
1618
|
+
? 'Opening...'
|
|
1619
|
+
: 'Download update',
|
|
1594
1620
|
),
|
|
1595
1621
|
),
|
|
1596
|
-
|
|
1622
|
+
if (release.htmlUrl.trim().isNotEmpty)
|
|
1623
|
+
OutlinedButton.icon(
|
|
1624
|
+
onPressed: () {
|
|
1625
|
+
unawaited(
|
|
1626
|
+
widget.controller._oauthLauncher
|
|
1627
|
+
.openExternal(
|
|
1628
|
+
url: release.htmlUrl,
|
|
1629
|
+
label: 'release_notes',
|
|
1630
|
+
),
|
|
1631
|
+
);
|
|
1632
|
+
},
|
|
1633
|
+
icon: const Icon(Icons.open_in_new),
|
|
1634
|
+
label: Text('View release'),
|
|
1635
|
+
),
|
|
1636
|
+
],
|
|
1597
1637
|
),
|
|
1598
1638
|
],
|
|
1599
|
-
|
|
1600
|
-
Wrap(
|
|
1601
|
-
spacing: 10,
|
|
1602
|
-
runSpacing: 10,
|
|
1603
|
-
children: <Widget>[
|
|
1604
|
-
FilledButton.icon(
|
|
1605
|
-
onPressed: controller.isOpeningAppUpdate
|
|
1606
|
-
? null
|
|
1607
|
-
: controller.openAppUpdate,
|
|
1608
|
-
style: FilledButton.styleFrom(
|
|
1609
|
-
backgroundColor: _accent,
|
|
1610
|
-
),
|
|
1611
|
-
icon: controller.isOpeningAppUpdate
|
|
1612
|
-
? const SizedBox.square(
|
|
1613
|
-
dimension: 16,
|
|
1614
|
-
child: CircularProgressIndicator(
|
|
1615
|
-
strokeWidth: 2,
|
|
1616
|
-
color: Colors.white,
|
|
1617
|
-
),
|
|
1618
|
-
)
|
|
1619
|
-
: const Icon(Icons.system_update_alt),
|
|
1620
|
-
label: Text(
|
|
1621
|
-
controller.isOpeningAppUpdate
|
|
1622
|
-
? 'Opening...'
|
|
1623
|
-
: 'Download update',
|
|
1624
|
-
),
|
|
1625
|
-
),
|
|
1626
|
-
if (release.htmlUrl.trim().isNotEmpty)
|
|
1627
|
-
OutlinedButton.icon(
|
|
1628
|
-
onPressed: () {
|
|
1629
|
-
unawaited(
|
|
1630
|
-
widget.controller._oauthLauncher.openExternal(
|
|
1631
|
-
url: release.htmlUrl,
|
|
1632
|
-
label: 'release_notes',
|
|
1633
|
-
),
|
|
1634
|
-
);
|
|
1635
|
-
},
|
|
1636
|
-
icon: const Icon(Icons.open_in_new),
|
|
1637
|
-
label: Text('View release'),
|
|
1638
|
-
),
|
|
1639
|
-
],
|
|
1640
|
-
),
|
|
1641
|
-
],
|
|
1639
|
+
),
|
|
1642
1640
|
),
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1641
|
+
] else ...<Widget>[
|
|
1642
|
+
const SizedBox(height: 12),
|
|
1643
|
+
Text(
|
|
1644
|
+
controller.isCheckingAppUpdate
|
|
1645
|
+
? 'Checking GitHub releases...'
|
|
1646
|
+
: controller.appUpdateLastCheckedAt == null
|
|
1647
|
+
? 'Choose a channel, then check GitHub releases.'
|
|
1648
|
+
: 'No newer app release is available on the selected channel.',
|
|
1649
|
+
style: TextStyle(color: _textSecondary, height: 1.45),
|
|
1650
|
+
),
|
|
1651
|
+
],
|
|
1654
1652
|
],
|
|
1655
|
-
],
|
|
1656
1653
|
const Divider(height: 32),
|
|
1657
1654
|
if (controller.updateStatus.allowSelfUpdate) ...<Widget>[
|
|
1658
1655
|
LayoutBuilder(
|
|
@@ -1132,6 +1132,13 @@ class _ChatBubble extends StatelessWidget {
|
|
|
1132
1132
|
Widget build(BuildContext context) {
|
|
1133
1133
|
final isUser = entry.role == 'user';
|
|
1134
1134
|
final isTransient = entry.transient;
|
|
1135
|
+
final sharedAttachments = (entry.metadata['sharedAttachments'] is List)
|
|
1136
|
+
? (entry.metadata['sharedAttachments'] as List)
|
|
1137
|
+
.whereType<Map>()
|
|
1138
|
+
.map((item) => SharedChatAttachment.fromJson(item))
|
|
1139
|
+
.where((item) => item.isValid)
|
|
1140
|
+
.toList(growable: false)
|
|
1141
|
+
: const <SharedChatAttachment>[];
|
|
1135
1142
|
|
|
1136
1143
|
if (entry.typing) {
|
|
1137
1144
|
return const _TypingIndicatorBubble();
|
|
@@ -1206,6 +1213,77 @@ class _ChatBubble extends StatelessWidget {
|
|
|
1206
1213
|
),
|
|
1207
1214
|
),
|
|
1208
1215
|
),
|
|
1216
|
+
if (sharedAttachments.isNotEmpty) ...<Widget>[
|
|
1217
|
+
const SizedBox(height: 10),
|
|
1218
|
+
Wrap(
|
|
1219
|
+
spacing: 8,
|
|
1220
|
+
runSpacing: 8,
|
|
1221
|
+
children: sharedAttachments
|
|
1222
|
+
.map((attachment) {
|
|
1223
|
+
final icon =
|
|
1224
|
+
attachment.mimeType.toLowerCase().startsWith(
|
|
1225
|
+
'video/',
|
|
1226
|
+
)
|
|
1227
|
+
? Icons.videocam_outlined
|
|
1228
|
+
: attachment.mimeType.toLowerCase().startsWith(
|
|
1229
|
+
'image/',
|
|
1230
|
+
)
|
|
1231
|
+
? Icons.image_outlined
|
|
1232
|
+
: attachment.mimeType.toLowerCase().startsWith(
|
|
1233
|
+
'audio/',
|
|
1234
|
+
)
|
|
1235
|
+
? Icons.audiotrack_outlined
|
|
1236
|
+
: Icons.attach_file_rounded;
|
|
1237
|
+
return Container(
|
|
1238
|
+
padding: const EdgeInsets.symmetric(
|
|
1239
|
+
horizontal: 10,
|
|
1240
|
+
vertical: 7,
|
|
1241
|
+
),
|
|
1242
|
+
decoration: BoxDecoration(
|
|
1243
|
+
color: isUser
|
|
1244
|
+
? const Color(0x1FFFFFFF)
|
|
1245
|
+
: _bgSecondary,
|
|
1246
|
+
borderRadius: BorderRadius.circular(999),
|
|
1247
|
+
border: Border.all(
|
|
1248
|
+
color: isUser
|
|
1249
|
+
? const Color(0x40FFFFFF)
|
|
1250
|
+
: _border,
|
|
1251
|
+
),
|
|
1252
|
+
),
|
|
1253
|
+
child: Row(
|
|
1254
|
+
mainAxisSize: MainAxisSize.min,
|
|
1255
|
+
children: <Widget>[
|
|
1256
|
+
Icon(
|
|
1257
|
+
icon,
|
|
1258
|
+
size: 14,
|
|
1259
|
+
color: isUser
|
|
1260
|
+
? Colors.white
|
|
1261
|
+
: _textSecondary,
|
|
1262
|
+
),
|
|
1263
|
+
const SizedBox(width: 6),
|
|
1264
|
+
ConstrainedBox(
|
|
1265
|
+
constraints: const BoxConstraints(
|
|
1266
|
+
maxWidth: 180,
|
|
1267
|
+
),
|
|
1268
|
+
child: Text(
|
|
1269
|
+
attachment.name,
|
|
1270
|
+
maxLines: 1,
|
|
1271
|
+
overflow: TextOverflow.ellipsis,
|
|
1272
|
+
style: TextStyle(
|
|
1273
|
+
color: isUser
|
|
1274
|
+
? Colors.white
|
|
1275
|
+
: _textPrimary,
|
|
1276
|
+
fontSize: 12,
|
|
1277
|
+
),
|
|
1278
|
+
),
|
|
1279
|
+
),
|
|
1280
|
+
],
|
|
1281
|
+
),
|
|
1282
|
+
);
|
|
1283
|
+
})
|
|
1284
|
+
.toList(growable: false),
|
|
1285
|
+
),
|
|
1286
|
+
],
|
|
1209
1287
|
if (!isUser &&
|
|
1210
1288
|
entry.runId?.trim().isNotEmpty == true) ...<Widget>[
|
|
1211
1289
|
const SizedBox(height: 12),
|
|
@@ -1,27 +1,56 @@
|
|
|
1
1
|
import 'package:flutter/foundation.dart';
|
|
2
2
|
import 'package:flutter/services.dart';
|
|
3
3
|
|
|
4
|
+
class AppLaunchRequest {
|
|
5
|
+
const AppLaunchRequest({
|
|
6
|
+
required this.action,
|
|
7
|
+
this.text,
|
|
8
|
+
this.subject,
|
|
9
|
+
this.files = const <Map<String, dynamic>>[],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
factory AppLaunchRequest.fromEvent(dynamic event) {
|
|
13
|
+
if (event is Map) {
|
|
14
|
+
final map = Map<String, dynamic>.from(event);
|
|
15
|
+
final files = (map['files'] is List)
|
|
16
|
+
? (map['files'] as List)
|
|
17
|
+
.whereType<Map>()
|
|
18
|
+
.map((item) => Map<String, dynamic>.from(item))
|
|
19
|
+
.toList()
|
|
20
|
+
: const <Map<String, dynamic>>[];
|
|
21
|
+
return AppLaunchRequest(
|
|
22
|
+
action: map['action']?.toString() ?? '',
|
|
23
|
+
text: map['text']?.toString(),
|
|
24
|
+
subject: map['subject']?.toString(),
|
|
25
|
+
files: files,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return AppLaunchRequest(action: event?.toString() ?? '');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
final String action;
|
|
32
|
+
final String? text;
|
|
33
|
+
final String? subject;
|
|
34
|
+
final List<Map<String, dynamic>> files;
|
|
35
|
+
}
|
|
36
|
+
|
|
4
37
|
class AppLaunchBridge {
|
|
5
38
|
static const String voiceAssistantAction = 'voice_assistant';
|
|
39
|
+
static const String shareToChatAction = 'share_to_chat';
|
|
6
40
|
static const EventChannel _events = EventChannel(
|
|
7
41
|
'neoagent/app_launch/events',
|
|
8
42
|
);
|
|
9
43
|
|
|
10
|
-
static Stream<
|
|
44
|
+
static Stream<AppLaunchRequest>? _launchRequests;
|
|
11
45
|
|
|
12
|
-
Stream<
|
|
46
|
+
Stream<AppLaunchRequest> get launchRequests {
|
|
13
47
|
if (!_isAndroid) {
|
|
14
|
-
return const Stream<
|
|
48
|
+
return const Stream<AppLaunchRequest>.empty();
|
|
15
49
|
}
|
|
16
50
|
return _launchRequests ??= _events
|
|
17
51
|
.receiveBroadcastStream()
|
|
18
|
-
.map(
|
|
19
|
-
|
|
20
|
-
return event['action']?.toString() ?? '';
|
|
21
|
-
}
|
|
22
|
-
return event?.toString() ?? '';
|
|
23
|
-
})
|
|
24
|
-
.where((action) => action.trim().isNotEmpty);
|
|
52
|
+
.map(AppLaunchRequest.fromEvent)
|
|
53
|
+
.where((request) => request.action.trim().isNotEmpty);
|
|
25
54
|
}
|
|
26
55
|
|
|
27
56
|
bool get _isAndroid =>
|
|
@@ -1243,6 +1243,34 @@ class BackendClient {
|
|
|
1243
1243
|
return getMap(baseUrl, _withAgentQuery('/api/memory', agentId));
|
|
1244
1244
|
}
|
|
1245
1245
|
|
|
1246
|
+
Future<Map<String, dynamic>> fetchMemoryTransferPrompt(
|
|
1247
|
+
String baseUrl, {
|
|
1248
|
+
String? agentId,
|
|
1249
|
+
}) async {
|
|
1250
|
+
return getMap(
|
|
1251
|
+
baseUrl,
|
|
1252
|
+
_withAgentQuery('/api/memory/transfer-prompt', agentId),
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
Future<Map<String, dynamic>> importMemoryTransfer(
|
|
1257
|
+
String baseUrl, {
|
|
1258
|
+
required String text,
|
|
1259
|
+
bool applyBehaviorNotes = true,
|
|
1260
|
+
bool applyCoreMemory = true,
|
|
1261
|
+
String? agentId,
|
|
1262
|
+
}) async {
|
|
1263
|
+
return postMap(
|
|
1264
|
+
baseUrl,
|
|
1265
|
+
'/api/memory/transfer-import',
|
|
1266
|
+
_withAgentId(<String, dynamic>{
|
|
1267
|
+
'text': text,
|
|
1268
|
+
'applyBehaviorNotes': applyBehaviorNotes,
|
|
1269
|
+
'applyCoreMemory': applyCoreMemory,
|
|
1270
|
+
}, agentId),
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1246
1274
|
Future<List<Map<String, dynamic>>> fetchMemories(
|
|
1247
1275
|
String baseUrl, {
|
|
1248
1276
|
String? category,
|
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "neoagent-guest-agent-android",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Guest runtime for NeoAgent Android and CLI services",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"express": "^4.21.2",
|
|
11
|
+
"proper-lockfile": "^4.1.2"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "neoagent-guest-agent-browser",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Guest runtime for NeoAgent browser and CLI services",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"express": "^4.21.2",
|
|
11
|
+
"playwright-chromium": "^1.59.1",
|
|
12
|
+
"proper-lockfile": "^4.1.2"
|
|
13
|
+
}
|
|
14
|
+
}
|