@tduncan / Cortana / commits / 6bfe38e

test(servers): cover Requesty endpoints, model parsing and adapter

Thibault Jaigu committed Sep 24, 2026 at 09:37 UTC 6bfe38e41a1d2b16b0799e54ba4af6abe6869844
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