2 files changed
+122
test/features/chat/tools/chat_service_adapter_selection_test.dart
+5
@@ -206,6 +206,11 @@ void main() {
206
expect(adapter, isA<OpenRouterToolAdapter>());
207
});
208
209
+ test('uses OpenAI adapter for Requesty servers', () {
210
+ final adapter = createAdapterForServerType(ServerType.requesty);
211
+ expect(adapter, isA<OpenAiToolAdapter>());
212
+ });
213
+
214
test('uses Ollama adapter for Ollama servers', () {
215
final adapter = createAdapterForServerType(ServerType.ollama);
216
expect(adapter, isA<OllamaToolAdapter>());
test/features/servers/server_api_service_test.dart
+117
@@ -1124,6 +1124,123 @@ void main() {
1124
});
1125
});
1126
1127
+ group('ServerApiService - Requesty model parsing', () {
1128
+ late Server requestyServer;
1129
+
1130
+ setUp(() {
1131
+ requestyServer = Server(
1132
+ id: 'test-requesty',
1133
+ name: 'Test Requesty',
1134
+ type: ServerType.requesty,
1135
+ host: '',
1136
+ port: 443,
1137
+ apiKey: 'test-key',
1138
+ createdAt: DateTime.now(),
1139
+ lastConnectedAt: DateTime.now(),
1140
+ );
1141
+ });
1142
+
1143
+ test('uses the Requesty router endpoints', () {
1144
+ expect(requestyServer.baseUrl, 'https://router.requesty.ai/v1');
1145
+ expect(
1146
+ requestyServer.chatEndpoint,
1147
+ 'https://router.requesty.ai/v1/chat/completions',
1148
+ );
1149
+ expect(
1150
+ requestyServer.modelsEndpoint,
1151
+ 'https://router.requesty.ai/v1/models',
1152
+ );
1153
+ expect(requestyServer.displayAddress, 'router.requesty.ai');
1154
+ });
1155
+
1156
+ test(
1157
+ 'lists managed policies first, then the catalog without duplicates',
1158
+ () async {
1159
+ final service = ServerApiService(
1160
+ Dio()
1161
+ ..interceptors.add(
1162
+ RoutingInterceptor({
1163
+ 'GET https://router.requesty.ai/v1/models': {
1164
+ 'object': 'list',
1165
+ 'data': [
1166
+ {
1167
+ 'id': 'openai/gpt-4o-mini',
1168
+ 'api': 'chat',
1169
+ 'context_window': 128000,
1170
+ 'input_price': 1.5e-07,
1171
+ 'output_price': 6e-07,
1172
+ 'supports_vision': true,
1173
+ 'supports_tool_calling': true,
1174
+ 'supports_reasoning': false,
1175
+ },
1176
+ {
1177
+ 'id': 'claude-sonnet-4-5',
1178
+ 'api': 'chat',
1179
+ 'context_window': 200000,
1180
+ },
1181
+ {'id': 'openai/text-embedding-3-small', 'api': 'embedding'},
1182
+ ],
1183
+ },
1184
+ 'GET https://router.requesty.ai/v1/models/managed': {
1185
+ 'object': 'list',
1186
+ 'data': [
1187
+ {
1188
+ 'id': 'claude-sonnet-4-5',
1189
+ 'api': 'chat',
1190
+ 'context_window': 1000000,
1191
+ 'input_price': 3e-06,
1192
+ 'output_price': 1.5e-05,
1193
+ 'supports_reasoning': true,
1194
+ 'supports_tool_calling': true,
1195
+ },
1196
+ ],
1197
+ },
1198
+ }),
1199
+ ),
1200
+ );
1201
+ final models = await service.fetchModels(requestyServer);
1202
+
1203
+ expect(models.map((m) => m.id), [
1204
+ 'claude-sonnet-4-5',
1205
+ 'openai/gpt-4o-mini',
1206
+ ]);
1207
+
1208
+ final managed = models.first;
1209
+ expect(managed.contextLength, 1000000);
1210
+ expect(managed.supportsReasoning, isTrue);
1211
+ expect(managed.supportsToolUse, isTrue);
1212
+ expect(managed.inputPricePerMillion, closeTo(3.0, 0.0001));
1213
+ expect(managed.outputPricePerMillion, closeTo(15.0, 0.0001));
1214
+
1215
+ final mini = models.last;
1216
+ expect(mini.serverType, ServerType.requesty);
1217
+ expect(mini.contextLength, 128000);
1218
+ expect(mini.supportsVision, isTrue);
1219
+ expect(mini.supportsReasoning, isFalse);
1220
+ expect(mini.pricingLabel, '\$0.15/\$0.60');
1221
+ },
1222
+ );
1223
+
1224
+ test('falls back to the catalog when managed models fail', () async {
1225
+ final service = ServerApiService(
1226
+ Dio()
1227
+ ..interceptors.add(
1228
+ RoutingInterceptor({
1229
+ 'GET https://router.requesty.ai/v1/models': {
1230
+ 'object': 'list',
1231
+ 'data': [
1232
+ {'id': 'openai/gpt-4o-mini', 'api': 'chat'},
1233
+ ],
1234
+ },
1235
+ }),
1236
+ ),
1237
+ );
1238
+ final models = await service.fetchModels(requestyServer);
1239
+
1240
+ expect(models.map((m) => m.id), ['openai/gpt-4o-mini']);
1241
+ });
1242
+ });
1243
+
1244
group('ServerApiService - LM Studio load model behavior', () {
1245
late Server lmStudioServer;
1246