neoagent 2.4.1-beta.39 → 2.4.1-beta.41
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/.env.example +11 -0
- package/docs/configuration.md +2 -0
- package/flutter_app/lib/main_model_picker.dart +55 -1
- package/flutter_app/lib/main_models.dart +4 -0
- package/flutter_app/lib/main_settings.dart +643 -348
- package/package.json +1 -1
- 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 +63624 -63424
- package/server/services/ai/models.js +141 -97
- package/server/services/ai/providers/anthropic.js +15 -4
- package/server/services/ai/providers/google.js +34 -7
- package/server/services/ai/providers/grok.js +14 -1
- package/server/services/ai/providers/nvidia.js +12 -0
- package/server/services/ai/providers/openai.js +18 -4
- package/server/services/ai/providers/openrouter.js +139 -0
- package/server/services/ai/settings.js +10 -0
- package/server/services/ai/systemPrompt.js +36 -20
package/.env.example
CHANGED
|
@@ -111,6 +111,17 @@ GOOGLE_AI_KEY=your-google-ai-key-here
|
|
|
111
111
|
# • MiniMax-M2.7 via the Anthropic-compatible MiniMax endpoint
|
|
112
112
|
MINIMAX_API_KEY=your-minimax-api-key-here
|
|
113
113
|
|
|
114
|
+
# NVIDIA NIM API key — used for:
|
|
115
|
+
# • Free-tier and paid models on NVIDIA's hosted inference (Nemotron, Kimi, Llama 4, DeepSeek, etc.)
|
|
116
|
+
# Get your key at: https://build.nvidia.com
|
|
117
|
+
NVIDIA_API_KEY=your-nvidia-nim-api-key-here
|
|
118
|
+
|
|
119
|
+
# OpenRouter API key — used for:
|
|
120
|
+
# • 300+ models from all major providers through a single API
|
|
121
|
+
# • Includes free-tier models (no credit needed for :free variants)
|
|
122
|
+
# Get your key at: https://openrouter.ai/keys
|
|
123
|
+
OPENROUTER_API_KEY=your-openrouter-api-key-here
|
|
124
|
+
|
|
114
125
|
# GitHub Copilot OAuth token — used for:
|
|
115
126
|
# • Copilot-backed chat/coding models (gpt-5.3, gpt-4.1)
|
|
116
127
|
# Set via: neoagent login github-copilot
|
package/docs/configuration.md
CHANGED
|
@@ -40,6 +40,8 @@ At least one key is required unless you only use local Ollama.
|
|
|
40
40
|
| `XAI_BASE_URL` | Optional xAI-compatible base URL override |
|
|
41
41
|
| `GOOGLE_AI_KEY` | Gemini (Google) |
|
|
42
42
|
| `MINIMAX_API_KEY` | MiniMax (including `MiniMax-M2.7`) |
|
|
43
|
+
| `NVIDIA_API_KEY` | NVIDIA NIM (free-tier + paid: Nemotron, Kimi, Llama 4, DeepSeek, etc.) |
|
|
44
|
+
| `OPENROUTER_API_KEY` | OpenRouter — access 300+ models from all providers through one API; free-tier models included |
|
|
43
45
|
| `BRAVE_SEARCH_API_KEY` | Brave Search for the `web_search` tool |
|
|
44
46
|
| `OPENAI_BASE_URL` | Optional OpenAI-compatible base URL override |
|
|
45
47
|
| `ANTHROPIC_BASE_URL` | Optional Anthropic-compatible base URL override |
|
|
@@ -13,6 +13,7 @@ class _ModelPickerOption {
|
|
|
13
13
|
this.color,
|
|
14
14
|
this.icon,
|
|
15
15
|
this.isAuto = false,
|
|
16
|
+
this.priceTier,
|
|
16
17
|
});
|
|
17
18
|
|
|
18
19
|
final String value;
|
|
@@ -22,6 +23,8 @@ class _ModelPickerOption {
|
|
|
22
23
|
final Color? color;
|
|
23
24
|
final IconData? icon;
|
|
24
25
|
final bool isAuto;
|
|
26
|
+
/// 'free' | 'cheap' | 'medium' | 'expensive' | null
|
|
27
|
+
final String? priceTier;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
// ─── Provider helpers ─────────────────────────────────────────────────────────
|
|
@@ -43,6 +46,9 @@ Color _providerPickerColor(String provider) {
|
|
|
43
46
|
if (p.contains('copilot') || p.contains('github')) {
|
|
44
47
|
return const Color(0xFF238636);
|
|
45
48
|
}
|
|
49
|
+
if (p.contains('openrouter')) return const Color(0xFF6366F1);
|
|
50
|
+
if (p.contains('nvidia')) return const Color(0xFF76B900);
|
|
51
|
+
if (p.contains('minimax')) return const Color(0xFF0EA5E9);
|
|
46
52
|
if (p.contains('deepgram')) return const Color(0xFF13D4A0);
|
|
47
53
|
if (p.contains('ollama')) return const Color(0xFF6C8EBF);
|
|
48
54
|
return const Color(0xFF7C8CFF);
|
|
@@ -64,6 +70,9 @@ IconData _providerPickerIcon(String provider) {
|
|
|
64
70
|
}
|
|
65
71
|
if (p.contains('grok') || p.contains('xai')) return Icons.psychology_rounded;
|
|
66
72
|
if (p.contains('copilot') || p.contains('github')) return Icons.code_rounded;
|
|
73
|
+
if (p.contains('openrouter')) return Icons.hub_rounded;
|
|
74
|
+
if (p.contains('nvidia')) return Icons.speed_rounded;
|
|
75
|
+
if (p.contains('minimax')) return Icons.water_rounded;
|
|
67
76
|
if (p.contains('deepgram')) return Icons.hearing_rounded;
|
|
68
77
|
if (p.contains('ollama')) return Icons.device_hub_rounded;
|
|
69
78
|
return Icons.memory_rounded;
|
|
@@ -78,10 +87,15 @@ String _providerPickerLabel(String id) {
|
|
|
78
87
|
'meta': 'Meta',
|
|
79
88
|
'mistral': 'Mistral',
|
|
80
89
|
'grok': 'xAI',
|
|
90
|
+
'grok-oauth': 'xAI (OAuth)',
|
|
81
91
|
'xai': 'xAI',
|
|
82
92
|
'ollama': 'Ollama',
|
|
83
93
|
'github-copilot': 'GitHub Copilot',
|
|
84
|
-
'openai-codex': 'OpenAI',
|
|
94
|
+
'openai-codex': 'OpenAI Codex',
|
|
95
|
+
'claude-code': 'Claude Code',
|
|
96
|
+
'openrouter': 'OpenRouter',
|
|
97
|
+
'nvidia': 'NVIDIA NIM',
|
|
98
|
+
'minimax': 'MiniMax',
|
|
85
99
|
'deepgram': 'Deepgram',
|
|
86
100
|
};
|
|
87
101
|
return labels[id.toLowerCase()] ?? id;
|
|
@@ -113,6 +127,7 @@ List<_ModelPickerOption> _modelPickerOptions(
|
|
|
113
127
|
subtitle: parts.isNotEmpty ? parts.join(' · ') : null,
|
|
114
128
|
color: _providerPickerColor(m.provider),
|
|
115
129
|
icon: _providerPickerIcon(m.provider),
|
|
130
|
+
priceTier: m.priceTier,
|
|
116
131
|
);
|
|
117
132
|
}),
|
|
118
133
|
];
|
|
@@ -500,6 +515,41 @@ class _ModelPickerDialogState extends State<_ModelPickerDialog> {
|
|
|
500
515
|
// Sub-widgets
|
|
501
516
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
502
517
|
|
|
518
|
+
class _PriceTierChip extends StatelessWidget {
|
|
519
|
+
const _PriceTierChip({required this.tier});
|
|
520
|
+
|
|
521
|
+
final String tier;
|
|
522
|
+
|
|
523
|
+
@override
|
|
524
|
+
Widget build(BuildContext context) {
|
|
525
|
+
final (String text, Color color) = switch (tier) {
|
|
526
|
+
'free' => ('FREE', const Color(0xFF22C55E)),
|
|
527
|
+
'cheap' => ('\$', const Color(0xFF4ADE80)),
|
|
528
|
+
'medium' => ('\$\$', const Color(0xFFF59E0B)),
|
|
529
|
+
'expensive' => ('\$\$\$', const Color(0xFFEF4444)),
|
|
530
|
+
_ => ('', Colors.transparent),
|
|
531
|
+
};
|
|
532
|
+
if (text.isEmpty) return const SizedBox.shrink();
|
|
533
|
+
return Container(
|
|
534
|
+
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
|
535
|
+
decoration: BoxDecoration(
|
|
536
|
+
color: color.withValues(alpha: 0.15),
|
|
537
|
+
borderRadius: BorderRadius.circular(5),
|
|
538
|
+
border: Border.all(color: color.withValues(alpha: 0.35), width: 0.8),
|
|
539
|
+
),
|
|
540
|
+
child: Text(
|
|
541
|
+
text,
|
|
542
|
+
style: TextStyle(
|
|
543
|
+
fontSize: 10,
|
|
544
|
+
fontWeight: FontWeight.w700,
|
|
545
|
+
color: color,
|
|
546
|
+
letterSpacing: 0.2,
|
|
547
|
+
),
|
|
548
|
+
),
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
503
553
|
class _PickerGroupHeader extends StatelessWidget {
|
|
504
554
|
const _PickerGroupHeader({required this.label, required this.color});
|
|
505
555
|
|
|
@@ -612,6 +662,10 @@ class _PickerRow extends StatelessWidget {
|
|
|
612
662
|
),
|
|
613
663
|
),
|
|
614
664
|
const SizedBox(width: 8),
|
|
665
|
+
if (option.priceTier != null) ...<Widget>[
|
|
666
|
+
_PriceTierChip(tier: option.priceTier!),
|
|
667
|
+
const SizedBox(width: 6),
|
|
668
|
+
],
|
|
615
669
|
SizedBox(
|
|
616
670
|
width: 20,
|
|
617
671
|
child: selected
|
|
@@ -2015,6 +2015,7 @@ class ModelMeta {
|
|
|
2015
2015
|
this.available = true,
|
|
2016
2016
|
this.providerStatus = '',
|
|
2017
2017
|
this.providerStatusLabel = '',
|
|
2018
|
+
this.priceTier,
|
|
2018
2019
|
});
|
|
2019
2020
|
|
|
2020
2021
|
factory ModelMeta.fromJson(Map<dynamic, dynamic> json) {
|
|
@@ -2026,6 +2027,7 @@ class ModelMeta {
|
|
|
2026
2027
|
available: json['available'] != false,
|
|
2027
2028
|
providerStatus: json['providerStatus']?.toString() ?? '',
|
|
2028
2029
|
providerStatusLabel: json['providerStatusLabel']?.toString() ?? '',
|
|
2030
|
+
priceTier: json['priceTier']?.toString(),
|
|
2029
2031
|
);
|
|
2030
2032
|
}
|
|
2031
2033
|
|
|
@@ -2036,6 +2038,8 @@ class ModelMeta {
|
|
|
2036
2038
|
final bool available;
|
|
2037
2039
|
final String providerStatus;
|
|
2038
2040
|
final String providerStatusLabel;
|
|
2041
|
+
/// Pricing tier: 'free' | 'cheap' | 'medium' | 'expensive' | null (unknown)
|
|
2042
|
+
final String? priceTier;
|
|
2039
2043
|
}
|
|
2040
2044
|
|
|
2041
2045
|
class AiProviderConfig {
|