* feat(#480): pass refresh=true on Models pull-to-refresh to re-probe custom providers * test(#480): assert refresh flag propagation for default vs pull-to-refresh loads * fix(#480): capture refresh arg via slot instead of brittle coVerify in propagation test --------- Co-authored-by: ronia <ronia@m57>
This commit is contained in:
1 parent
7384b51476
commit
bdf566ba3e
4 files changed
+54
-5
No files matched your search
@@ -430,7 +430,9 @@ interface HermesApiService {
|
||||
): Response<Unit>
|
||||
|
||||
@GET("api/model/options")
|
||||
suspend fun getModelOptions(): Response<ModelOptionsResponse>
|
||||
suspend fun getModelOptions(
|
||||
@Query("refresh") refresh: Boolean = false,
|
||||
): Response<ModelOptionsResponse>
|
||||
|
||||
@GET("api/model/auxiliary")
|
||||
suspend fun getAuxiliaryModels(): Response<AuxiliaryModelsResponse>
|
||||
|
||||
@@ -101,7 +101,7 @@ fun ModelScreen(
|
||||
title = { Text(stringResource(R.string.screen_models)) },
|
||||
navigationIcon = onOpenDrawer?.let { NavIcon.Menu(it) },
|
||||
isRefreshing = state.isLoading,
|
||||
onRefresh = { viewModel.loadAll() },
|
||||
onRefresh = { viewModel.loadAll(refresh = true) },
|
||||
) { paddingValues ->
|
||||
when {
|
||||
state.isLoading && state.providers.isEmpty() -> {
|
||||
|
||||
@@ -76,12 +76,12 @@ class ModelViewModel :
|
||||
_uiState.update { it.copy(pinnedModels = AuthManager.getPinnedModels()) }
|
||||
}
|
||||
|
||||
fun loadAll() {
|
||||
fun loadAll(refresh: Boolean = false) {
|
||||
_uiState.update { it.copy(isLoading = true, errorMessage = null) }
|
||||
viewModelScope.launch {
|
||||
val optionsDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
safeApiCall { ApiClient.hermesApi.getModelOptions() }
|
||||
safeApiCall { ApiClient.hermesApi.getModelOptions(refresh = refresh) }
|
||||
}
|
||||
val activeProfileDeferred =
|
||||
async(Dispatchers.IO) {
|
||||
|
||||
@@ -1284,7 +1284,7 @@ class E2eIntegrationTest {
|
||||
val provider = ModelProvider("ollama", "Ollama", false, true, listOf("llama3"), 1, null, true, null, null)
|
||||
val profile = ProfileInfo("default", null, true, "llama3", "ollama", null, null, null, null)
|
||||
|
||||
coEvery { mockApiService.getModelOptions() } returns
|
||||
coEvery { mockApiService.getModelOptions(any()) } returns
|
||||
Response.success(ModelOptionsResponse(listOf(provider)))
|
||||
coEvery { mockApiService.getActiveProfile() } returns
|
||||
Response.success(ActiveProfileResponse("default", null))
|
||||
@@ -1333,6 +1333,53 @@ class E2eIntegrationTest {
|
||||
assertEquals("Successfully set profile model to llama3", viewModel.uiState.value.toastMessage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testModelOptions_refreshFlagPropagation() =
|
||||
runTest {
|
||||
val provider = ModelProvider("ollama", "Ollama", false, true, listOf("llama3"), 1, null, true, null, null)
|
||||
val profile = ProfileInfo("default", null, true, "llama3", "ollama", null, null, null, null)
|
||||
|
||||
coEvery { mockApiService.getModelOptions(any()) } returns
|
||||
Response.success(ModelOptionsResponse(listOf(provider)))
|
||||
coEvery { mockApiService.getActiveProfile() } returns
|
||||
Response.success(ActiveProfileResponse("default", null))
|
||||
coEvery { mockApiService.getProfiles() } returns Response.success(ProfilesResponse(listOf(profile)))
|
||||
coEvery { mockApiService.getAuxiliaryModels() } returns
|
||||
Response.success(
|
||||
AuxiliaryModelsResponse(
|
||||
tasks = emptyList(),
|
||||
main = MainModelAssignment("openai", "gpt-4"),
|
||||
),
|
||||
)
|
||||
coEvery { mockApiService.getMoaModels() } returns
|
||||
Response.success<MoaConfigResponse>(
|
||||
MoaConfigResponse(
|
||||
presets = emptyMap(),
|
||||
default_preset = "",
|
||||
reference_models = emptyList(),
|
||||
aggregator = MoaModelSlot("openai", "gpt-4"),
|
||||
max_tokens = 4096,
|
||||
),
|
||||
)
|
||||
|
||||
val capturedRefresh = mutableListOf<Boolean>()
|
||||
coEvery { mockApiService.getModelOptions(any()) } answers {
|
||||
capturedRefresh.add(firstArg())
|
||||
Response.success(ModelOptionsResponse(listOf(provider)))
|
||||
}
|
||||
|
||||
// Default loadAll() must call getModelOptions with refresh = false
|
||||
val viewModel = ModelViewModel()
|
||||
viewModel.loadAll()
|
||||
advanceUntilIdle()
|
||||
|
||||
// Pull-to-refresh path must call getModelOptions with refresh = true
|
||||
viewModel.loadAll(refresh = true)
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals(listOf(false, true), capturedRefresh)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConnectViewModel_onPairingString_urlFormat() =
|
||||
runTest {
|
||||
|
||||
Reference in new issue
Block a user