diff --git a/agent/app/src/androidTest/java/com/example/appfunctions/agent/data/LlmProviderIntegrationTestBase.kt b/agent/app/src/androidTest/java/com/example/appfunctions/agent/data/LlmProviderIntegrationTestBase.kt index 33e4dd8a..04e0b04d 100644 --- a/agent/app/src/androidTest/java/com/example/appfunctions/agent/data/LlmProviderIntegrationTestBase.kt +++ b/agent/app/src/androidTest/java/com/example/appfunctions/agent/data/LlmProviderIntegrationTestBase.kt @@ -383,4 +383,20 @@ abstract class LlmProviderIntegrationTestBase { assertNotNull(textPart) assertTrue(textPart!!.text.contains("sunny")) } + + @Test + fun getAvailableModels_realTest() = + runBlocking { + val models = provider.getAvailableModels(apiKey) + println("Available Models: $models") + assertTrue(models.isNotEmpty()) + assertTrue(models.any { it.modelName == modelName }) + } + + @Test + fun getAvailableModels_invalidApiKeyTest() = + runBlocking { + val models = provider.getAvailableModels("INVALID_KEY") + assertTrue(models.isEmpty()) + } } diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/data/GeminiProviderImpl.kt b/agent/app/src/main/java/com/example/appfunctions/agent/data/GeminiProviderImpl.kt index 30bb74fe..a6da3257 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/data/GeminiProviderImpl.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/data/GeminiProviderImpl.kt @@ -22,6 +22,7 @@ import com.example.appfunctions.agent.domain.LlmProvider import com.example.appfunctions.agent.domain.LlmResponse import com.example.appfunctions.agent.domain.LlmResponsePart import io.ktor.client.HttpClient +import io.ktor.client.request.get import io.ktor.client.request.header import io.ktor.client.request.post import io.ktor.client.request.setBody @@ -51,6 +52,64 @@ class GeminiProviderImpl private val httpClient: HttpClient, private val toolConverter: GeminiToolConverter, ) : LlmProvider { + override suspend fun getAvailableModels(apiKey: String?): List { + if (apiKey.isNullOrBlank()) { + return emptyList() + } + + val response: HttpResponse = + try { + httpClient.get(GEMINI_MODELS_URL) { + header(HEADER_API_KEY, apiKey) + } + } catch (e: Exception) { + Log.w(TAG, "Failed to fetch Gemini models: ${e.message}") + return emptyList() + } + + val responseBodyText = response.bodyAsText() + if (response.status.value !in 200..299) { + Log.w( + TAG, + "Gemini models API error: ${response.status} - $responseBodyText", + ) + return emptyList() + } + + return try { + val jsonResponse = Json.parseToJsonElement(responseBodyText).jsonObject + val modelsArray = jsonResponse[KEY_MODELS]?.jsonArray ?: return emptyList() + + modelsArray + .mapNotNull { element -> + val modelObj = element.jsonObject + val rawName = + modelObj[KEY_NAME]?.jsonPrimitive?.contentOrNull + ?: return@mapNotNull null + val modelId = rawName.removePrefix(MODEL_NAME_PREFIX) + val supportedMethods = + modelObj[KEY_SUPPORTED_GENERATION_METHODS] + ?.jsonArray + ?.mapNotNull { it.jsonPrimitive.contentOrNull } + + // Require "generateContent" to filter out non-generative models (e.g. embeddings). + val supportsGenerateContent = + supportedMethods == null || + VALUE_GENERATE_CONTENT in supportedMethods + + if (modelId.startsWith(GEMINI_MODEL_PREFIX) && supportsGenerateContent) { + LlmModel(LlmProviderName.GEMINI, modelId) + } else { + null + } + } + .distinct() + } catch (e: Exception) { + Log.w(TAG, "Failed to parse Gemini models response", e) + emptyList() + } + } + override suspend fun generateResponse( previousInteractionId: String?, input: LlmInput, @@ -264,8 +323,16 @@ class GeminiProviderImpl companion object { private const val GEMINI_INTERACTIONS_URL = "https://generativelanguage.googleapis.com/v1beta/interactions" + private const val GEMINI_MODELS_URL = + "https://generativelanguage.googleapis.com/v1beta/models?pageSize=100" private const val TAG = "GeminiProvider" + private const val KEY_MODELS = "models" + private const val KEY_SUPPORTED_GENERATION_METHODS = "supportedGenerationMethods" + private const val VALUE_GENERATE_CONTENT = "generateContent" + private const val MODEL_NAME_PREFIX = "models/" + private const val GEMINI_MODEL_PREFIX = "gemini-" + private const val KEY_MODEL = "model" private const val KEY_SERVICE_TIER = "service_tier" private const val KEY_INPUT = "input" diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/data/LlmProviderName.kt b/agent/app/src/main/java/com/example/appfunctions/agent/data/LlmProviderName.kt index 7d8442bb..498cd8b3 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/data/LlmProviderName.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/data/LlmProviderName.kt @@ -15,24 +15,34 @@ */ package com.example.appfunctions.agent.data +import androidx.room.TypeConverter +import kotlinx.serialization.Serializable +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json + /** Enum representing the supported LLM providers. */ -enum class LlmProviderName { - GEMINI, +@Serializable +enum class LlmProviderName(val displayName: String) { + GEMINI("Gemini"), } -/** Enum representing the supported LLM models. */ -enum class LlmModel private constructor(val providerName: LlmProviderName, val modelName: String) { - // Stable (GA) models: consistent latency and production rate limits. Prefer these. - GEMINI_3_5_FLASH(LlmProviderName.GEMINI, "gemini-3.5-flash"), - GEMINI_3_1_FLASH_LITE(LlmProviderName.GEMINI, "gemini-3.1-flash-lite"), +/** Represents an LLM model offered by a specific [LlmProviderName]. */ +@Serializable +data class LlmModel( + val providerName: LlmProviderName, + val modelName: String, +) + +class LlmModelConverter { + private val dbJson = + Json { + ignoreUnknownKeys = true + encodeDefaults = true + } - // Preview models: newer capabilities but restrictive rate limits and no latency SLA. - GEMINI_3_1_PRO_PREVIEW(LlmProviderName.GEMINI, "gemini-3.1-pro-preview"), - GEMINI_3_FLASH_PREVIEW(LlmProviderName.GEMINI, "gemini-3-flash-preview"), - GEMINI_3_1_FLASH_LITE_PREVIEW(LlmProviderName.GEMINI, "gemini-3.1-flash-lite-preview"), - ; + @TypeConverter + fun fromLlmModel(model: LlmModel): String = dbJson.encodeToString(model) - companion object { - val DEFAULT = GEMINI_3_1_FLASH_LITE - } + @TypeConverter + fun toLlmModel(jsonString: String): LlmModel = dbJson.decodeFromString(jsonString) } diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/data/db/AppDatabase.kt b/agent/app/src/main/java/com/example/appfunctions/agent/data/db/AppDatabase.kt index 46d31c1d..3bffa7fb 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/data/db/AppDatabase.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/data/db/AppDatabase.kt @@ -18,13 +18,14 @@ package com.example.appfunctions.agent.data.db import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters +import com.example.appfunctions.agent.data.LlmModelConverter import com.example.appfunctions.agent.data.db.dao.ChatDao import com.example.appfunctions.agent.data.db.entities.MessageAttachmentConverter import com.example.appfunctions.agent.data.db.entities.MessageEntity import com.example.appfunctions.agent.data.db.entities.ThreadEntity -@Database(entities = [ThreadEntity::class, MessageEntity::class], version = 3, exportSchema = false) -@TypeConverters(MessageAttachmentConverter::class) +@Database(entities = [ThreadEntity::class, MessageEntity::class], version = 4, exportSchema = false) +@TypeConverters(MessageAttachmentConverter::class, LlmModelConverter::class) abstract class AppDatabase : RoomDatabase() { abstract fun chatDao(): ChatDao } diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/domain/LlmProvider.kt b/agent/app/src/main/java/com/example/appfunctions/agent/domain/LlmProvider.kt index 60aa8de4..49a5f315 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/domain/LlmProvider.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/domain/LlmProvider.kt @@ -16,10 +16,19 @@ package com.example.appfunctions.agent.domain import androidx.appfunctions.metadata.AppFunctionMetadata +import com.example.appfunctions.agent.data.LlmModel import com.example.appfunctions.agent.data.ServiceTier /** Interface for LLM providers to generate responses. */ interface LlmProvider { + /** + * Retrieves the list of available models from this LLM provider. + * + * @param apiKey The API key for the LLM provider, or null/blank if not configured. + * @return The list of available [LlmModel]s supported by this provider. + */ + suspend fun getAvailableModels(apiKey: String?): List = emptyList() + /** * Generates a response from the LLM. * diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreen.kt b/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreen.kt index b1c9f3b3..badbadcb 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreen.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreen.kt @@ -251,6 +251,7 @@ fun AgentDemoLoadedScreen( .weight(1f) .padding(horizontal = 8.dp), currentThread = uiState.currentThread, + availableModels = uiState.availableModels, onModelSelected = { onEvent(AgentUiEvent.OnModelSelected(it)) }, onMenuClick = { if (isWideScreen) { @@ -260,10 +261,15 @@ fun AgentDemoLoadedScreen( } }, ) + val defaultModel = + uiState.currentThread?.llmModel ?: uiState.availableModels.firstOrNull() IconButton( onClick = { - onEvent(AgentUiEvent.OnCreateThread(uiState.currentThread.llmModel)) + if (defaultModel != null) { + onEvent(AgentUiEvent.OnCreateThread(defaultModel)) + } }, + enabled = defaultModel != null, modifier = Modifier.padding(horizontal = 8.dp), ) { Icon(imageVector = Icons.Default.Add, contentDescription = "Create Thread") @@ -304,43 +310,63 @@ fun AgentDemoLoadedScreen( .padding(start = 16.dp, end = 16.dp), verticalArrangement = Arrangement.SpaceBetween, ) { - // Messages List - LazyColumn( - modifier = - Modifier - .weight(1f) - .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)), - reverseLayout = true, - ) { - // Status item at the bottom (above input) if not - // idle - if (uiState.status != AgentStatus.Idle) { - item { - StatusIndicator( - status = uiState.status, - packageManager = packageManager, - ) - } + if (uiState.currentThread == null) { + Box( + modifier = + Modifier + .weight(1f) + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + Text( + text = stringResource(R.string.agent_demo_select_model_placeholder), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) } + } else { + // Messages List + LazyColumn( + modifier = + Modifier + .weight(1f) + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)), + reverseLayout = true, + ) { + // Status item at the bottom (above input) if not + // idle + if (uiState.status != AgentStatus.Idle) { + item { + StatusIndicator( + status = uiState.status, + packageManager = packageManager, + ) + } + } - items( - items = uiState.messages.reversed(), - key = { message -> message.messageId }, - ) { message -> - MessageBubble( - message = message, - isValidAction = - message.pendingIntentId in uiState.activePendingActionIds, - installedApps = uiState.installedApps, - onConfirmAction = { onEvent(AgentUiEvent.OnConfirmAction(it)) }, - ) + items( + items = uiState.messages.reversed(), + key = { message -> message.messageId }, + ) { message -> + MessageBubble( + message = message, + isValidAction = + message.pendingIntentId in uiState.activePendingActionIds, + installedApps = uiState.installedApps, + onConfirmAction = { onEvent(AgentUiEvent.OnConfirmAction(it)) }, + ) + } } } val sendMessage = { val textStr = messageText.text - if (textStr.isNotBlank() && uiState.status == AgentStatus.Idle) { + if ( + uiState.currentThread != null && + textStr.isNotBlank() && + uiState.status == AgentStatus.Idle + ) { onEvent(AgentUiEvent.OnSendMessage(textStr, selectedAppPackageName)) messageText = TextFieldValue("") selectedAppPackageName = null @@ -428,7 +454,8 @@ fun AgentDemoLoadedScreen( false } }, - enabled = uiState.status == AgentStatus.Idle, + enabled = + uiState.currentThread != null && uiState.status == AgentStatus.Idle, shape = CircleShape, placeholder = { Text(stringResource(R.string.agent_demo_ask_agent)) }, visualTransformation = visualTransformation, @@ -443,7 +470,8 @@ fun AgentDemoLoadedScreen( IconButton( onClick = sendMessage, enabled = - messageText.text.isNotBlank() && + uiState.currentThread != null && + messageText.text.isNotBlank() && uiState.status == AgentStatus.Idle, ) { Icon( @@ -524,10 +552,15 @@ fun AgentDemoLoadedScreen( fun ModelDropdown( modifier: Modifier = Modifier, currentThread: ThreadEntity?, + availableModels: List = emptyList(), onModelSelected: (LlmModel) -> Unit, onMenuClick: () -> Unit, ) { var expanded by remember { mutableStateOf(false) } + val modelsByProvider = + remember(availableModels) { + availableModels.groupBy { it.providerName } + } ExposedDropdownMenuBox( modifier = modifier, expanded = expanded, @@ -597,31 +630,28 @@ fun ModelDropdown( containerColor = MaterialTheme.colorScheme.surfaceBright, shape = RoundedCornerShape(28.dp), ) { - item { - Text( - "--- Gemini ---", - color = MaterialTheme.colorScheme.secondary, - modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), - style = MaterialTheme.typography.labelLarge, - ) - } - val models = - listOf( - LlmModel.GEMINI_3_5_FLASH, - LlmModel.GEMINI_3_1_FLASH_LITE, - LlmModel.GEMINI_3_1_PRO_PREVIEW, - LlmModel.GEMINI_3_FLASH_PREVIEW, - LlmModel.GEMINI_3_1_FLASH_LITE_PREVIEW, - ) - items(models) { model -> - DropdownMenuItem( - text = { Text(model.modelName) }, - onClick = { - onModelSelected(model) - expanded = false - }, - contentPadding = PaddingValues(horizontal = 24.dp, vertical = 8.dp), - ) + modelsByProvider.forEach { (provider, models) -> + item(key = "header_${provider.name}") { + Text( + "--- ${provider.displayName} ---", + color = MaterialTheme.colorScheme.secondary, + modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), + style = MaterialTheme.typography.labelLarge, + ) + } + items( + items = models, + key = { model -> "${model.providerName.name}:${model.modelName}" }, + ) { model -> + DropdownMenuItem( + text = { Text(model.modelName) }, + onClick = { + onModelSelected(model) + expanded = false + }, + contentPadding = PaddingValues(horizontal = 24.dp, vertical = 8.dp), + ) + } } } } diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModel.kt b/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModel.kt index 2f92660d..e465d2a8 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModel.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModel.kt @@ -27,6 +27,7 @@ import com.example.appfunctions.agent.data.db.entities.MessageRole import com.example.appfunctions.agent.data.db.entities.ThreadEntity import com.example.appfunctions.agent.domain.AgentOrchestrator import com.example.appfunctions.agent.domain.AgentStatus +import com.example.appfunctions.agent.domain.LlmProviderFactory import com.example.appfunctions.agent.domain.appfunction.AppInfo import com.example.appfunctions.agent.domain.appfunction.GetAppFunctionsUseCase import com.example.appfunctions.agent.domain.appfunction.GetInstalledAppsUseCase @@ -59,6 +60,7 @@ class AgentDemoViewModel private val sendMessageUseCase: SendMessageUseCase, private val agentOrchestrator: AgentOrchestrator, private val settingsRepository: SettingsRepository, + private val llmProviderFactory: LlmProviderFactory, private val observeActivePendingIntentsUseCase: ObserveActivePendingIntentsUseCase, private val launchPendingIntentUseCase: LaunchPendingIntentUseCase, private val consumePendingIntentUseCase: ConsumePendingIntentUseCase, @@ -69,10 +71,28 @@ class AgentDemoViewModel val uiState: StateFlow = _uiState.asStateFlow() private val installedApps = MutableStateFlow>(emptyList()) + private val availableModels = MutableStateFlow>(emptyList()) private var observationJob: Job? = null init { + viewModelScope.launch { + settingsRepository.geminiApiKey.collectLatest { geminiApiKey -> + val models = + LlmProviderName.entries.flatMap { providerName -> + val apiKey = + when (providerName) { + LlmProviderName.GEMINI -> geminiApiKey + } + llmProviderFactory.getProvider(providerName).getAvailableModels(apiKey) + } + availableModels.value = models + if (models.isNotEmpty() && manageThreadsUseCase.getThreads().first().isEmpty()) { + createAndSelectThread(models.first()) + } + } + } + viewModelScope.launch { getAppFunctionsUseCase().collect { toolsMap -> val allTools = toolsMap.values.flatten() @@ -95,75 +115,75 @@ class AgentDemoViewModel } } - viewModelScope.launch { - val threads = manageThreadsUseCase.getThreads().first() - if (threads.isEmpty()) { - createAndSelectThread(LlmModel.DEFAULT) - } - } - viewModelScope.launch { combine( - manageThreadsUseCase.getThreads(), - settingsRepository.selectedProvider, - agentOrchestrator.status, + combine( + manageThreadsUseCase.getThreads(), + settingsRepository.selectedProvider, + agentOrchestrator.status, + ) { threads, provider, status -> + Triple(threads, provider, status) + }, savedStateHandle.getStateFlow(MainActivity.ARG_THREAD_ID, null), installedApps, + availableModels, ) { - threads, - provider, - status, + (threads, provider, status), targetThreadId, apps, + models, -> - ThreadConfig(threads, provider, status, targetThreadId, apps) + ThreadConfig(threads, provider, status, targetThreadId, apps, models) } - .collectLatest { (threads, provider, status, targetThreadId, apps) -> + .collectLatest { (threads, _, status, targetThreadId, apps, models) -> val currentThread = threads.find { it.threadId == targetThreadId } ?: threads.firstOrNull() val previousThreadId = (_uiState.value as? AgentUiState.Loaded)?.currentThread?.threadId + val currentLoadedState = _uiState.value as? AgentUiState.Loaded + _uiState.value = + AgentUiState.Loaded( + currentThread = currentThread, + messages = + if (currentThread != null) { + currentLoadedState?.messages ?: emptyList() + } else { + emptyList() + }, + status = status, + threads = threads, + activePendingActionIds = + currentLoadedState?.activePendingActionIds ?: emptySet(), + installedApps = apps, + availableModels = models, + ) + if (currentThread == null) { observationJob?.cancel() observationJob = null - _uiState.value = AgentUiState.Loading - } else { - val currentLoadedState = _uiState.value as? AgentUiState.Loaded - _uiState.value = - AgentUiState.Loaded( - currentThread = currentThread, - messages = currentLoadedState?.messages ?: emptyList(), - status = status, - threads = threads, - activePendingActionIds = - currentLoadedState?.activePendingActionIds ?: emptySet(), - installedApps = apps, - ) - + } else if (observationJob == null || previousThreadId != currentThread.threadId) { // Start observing messages for the current thread if not already doing so - if (observationJob == null || previousThreadId != currentThread.threadId) { - observationJob?.cancel() - observationJob = - viewModelScope.launch { - launch { - getChatHistoryUseCase(currentThread.threadId).collect { - messages -> - val currentState = _uiState.value - if (currentState is AgentUiState.Loaded) { - _uiState.value = - currentState.copy(messages = messages) - } + observationJob?.cancel() + observationJob = + viewModelScope.launch { + launch { + getChatHistoryUseCase(currentThread.threadId).collect { + messages -> + val currentState = _uiState.value + if (currentState is AgentUiState.Loaded) { + _uiState.value = + currentState.copy(messages = messages) } } - launch { - agentOrchestrator.observeAndProcessMessages( - currentThread.threadId, - ) - } } - } + launch { + agentOrchestrator.observeAndProcessMessages( + currentThread.threadId, + ) + } + } } } } @@ -173,10 +193,11 @@ class AgentDemoViewModel val currentState = _uiState.value when (event) { is AgentUiEvent.OnSendMessage -> { - if (currentState is AgentUiState.Loaded) { + val currentThread = (currentState as? AgentUiState.Loaded)?.currentThread + if (currentThread != null) { viewModelScope.launch { sendMessageUseCase( - threadId = currentState.currentThread.threadId, + threadId = currentThread.threadId, role = MessageRole.USER, textContent = event.text, processingStatus = MessageProcessingStatus.PENDING_AGENT_RESPONSE, @@ -188,10 +209,15 @@ class AgentDemoViewModel is AgentUiEvent.OnModelSelected -> { if (currentState is AgentUiState.Loaded) { viewModelScope.launch { - manageThreadsUseCase.updateThreadModel( - currentState.currentThread.threadId, - event.model, - ) + val currentThread = currentState.currentThread + if (currentThread != null) { + manageThreadsUseCase.updateThreadModel( + currentThread.threadId, + event.model, + ) + } else { + createAndSelectThread(event.model) + } } } } @@ -222,4 +248,5 @@ private data class ThreadConfig( val status: AgentStatus, val targetThreadId: String?, val installedApps: List, + val availableModels: List, ) diff --git a/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentUiState.kt b/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentUiState.kt index 4798f798..bd92f973 100644 --- a/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentUiState.kt +++ b/agent/app/src/main/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentUiState.kt @@ -26,12 +26,13 @@ sealed class AgentUiState { object Loading : AgentUiState() data class Loaded( - val currentThread: ThreadEntity, + val currentThread: ThreadEntity? = null, val messages: List = emptyList(), val status: AgentStatus = AgentStatus.Idle, val threads: List = emptyList(), val activePendingActionIds: Set = emptySet(), val installedApps: List = emptyList(), + val availableModels: List = emptyList(), ) : AgentUiState() } diff --git a/agent/app/src/screenshotTest/kotlin/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTest.kt b/agent/app/src/screenshotTest/kotlin/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTest.kt index 26ce6c4c..21b7fccd 100644 --- a/agent/app/src/screenshotTest/kotlin/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTest.kt +++ b/agent/app/src/screenshotTest/kotlin/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTest.kt @@ -19,26 +19,45 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import com.android.tools.screenshot.PreviewTest import com.example.appfunctions.agent.data.LlmModel +import com.example.appfunctions.agent.data.LlmProviderName import com.example.appfunctions.agent.data.db.entities.MessageEntity import com.example.appfunctions.agent.data.db.entities.MessageProcessingStatus import com.example.appfunctions.agent.data.db.entities.MessageRole import com.example.appfunctions.agent.data.db.entities.ThreadEntity import com.example.appfunctions.agent.domain.AgentStatus +private val previewFlashModel = LlmModel(LlmProviderName.GEMINI, "gemini-3-flash-preview") +private val previewProModel = LlmModel(LlmProviderName.GEMINI, "gemini-3.1-pro-preview") + /** Screenshot test for [AgentDemoScreen]. */ @PreviewTest @Preview(showBackground = true) @Composable -fun AgentDemoScreenNoThreadPreview() { +fun AgentDemoScreenLoadingPreview() { AgentDemoContent(uiState = AgentUiState.Loading, onEvent = {}) } +@PreviewTest +@Preview(showBackground = true) +@Composable +fun AgentDemoScreenNoThreadPreview() { + AgentDemoContent( + uiState = + AgentUiState.Loaded( + messages = emptyList(), + status = AgentStatus.Idle, + currentThread = null, + ), + onEvent = {}, + ) +} + @PreviewTest @Preview(showBackground = true) @Composable fun AgentDemoScreenScreenshotPreview() { val thread = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val messages = listOf( MessageEntity( @@ -74,7 +93,7 @@ fun AgentDemoScreenScreenshotPreview() { @Composable fun AgentDemoScreenThinkingPreview() { val thread = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val messages = listOf( MessageEntity( @@ -102,7 +121,7 @@ fun AgentDemoScreenThinkingPreview() { @Composable fun AgentDemoScreenInvokingToolPreview() { val thread = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val messages = listOf( MessageEntity( @@ -130,7 +149,7 @@ fun AgentDemoScreenInvokingToolPreview() { @Composable fun AgentDemoScreenConfirmActionPreview() { val thread = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val messages = listOf( MessageEntity( @@ -168,7 +187,7 @@ fun AgentDemoScreenConfirmActionPreview() { @Composable fun AgentDemoScreenActionExpiredPreview() { val thread = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val messages = listOf( MessageEntity( @@ -206,7 +225,7 @@ fun AgentDemoScreenActionExpiredPreview() { @Composable fun AgentDemoScreenErrorPreview() { val thread = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val messages = listOf( MessageEntity( @@ -242,9 +261,9 @@ fun AgentDemoScreenErrorPreview() { @Composable fun AgentDemoScreenSidePanelPreview() { val thread1 = - ThreadEntity("thread-1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW, null) + ThreadEntity("thread-1", System.currentTimeMillis(), previewFlashModel, null) val thread2 = - ThreadEntity("thread-2", System.currentTimeMillis(), LlmModel.GEMINI_3_1_PRO_PREVIEW, null) + ThreadEntity("thread-2", System.currentTimeMillis(), previewProModel, null) val threads = listOf(thread1, thread2) val messages = diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png new file mode 100644 index 00000000..813b32b7 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png new file mode 100644 index 00000000..17e05cc3 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenLoadingPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenLoadingPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png new file mode 100644 index 00000000..2f60e549 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..fc9bfb69 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..b387c404 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..b387c404 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..b387c404 Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..a0ea6e9c Binary files /dev/null and b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png deleted file mode 100644 index d96208fb..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png deleted file mode 100644 index d36df02c..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png deleted file mode 100644 index aae7ab88..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png deleted file mode 100644 index b8d1cdc8..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png deleted file mode 100644 index 16ea318f..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png deleted file mode 100644 index 114384c0..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png deleted file mode 100644 index 317645a6..00000000 Binary files a/agent/app/src/screenshotTestRetailDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png new file mode 100644 index 00000000..813b32b7 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png new file mode 100644 index 00000000..17e05cc3 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenErrorPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenInvokingToolPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenLoadingPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenLoadingPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png new file mode 100644 index 00000000..2f60e549 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenNoThreadPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenSidePanelPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenThinkingPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/ConnectedAppsScreenScreenshotTestKt/ConnectedAppsScreenScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..fc9bfb69 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..b387c404 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..b387c404 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..b387c404 Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png new file mode 100644 index 00000000..a0ea6e9c Binary files /dev/null and b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenInitialScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/ObjectTypeInputWithInputsScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png similarity index 100% rename from agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png rename to agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctions/agent/ui/screens/debugging/DebuggingScreenScreenshotTestKt/TroubleshootContentScreenshotPreview_748aa731_0.png diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png deleted file mode 100644 index d96208fb..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenActionExpiredPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png deleted file mode 100644 index d36df02c..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/AgentDemoScreenScreenshotTestKt/AgentDemoScreenConfirmActionPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png deleted file mode 100644 index e09e10ff..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/agentdemo/SettingsScreenScreenshotTestKt/SettingsScreenScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png deleted file mode 100644 index b8d1cdc8..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenAppSelectedScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png deleted file mode 100644 index 16ea318f..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png deleted file mode 100644 index 114384c0..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionExpandedWithInputsScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png b/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png deleted file mode 100644 index 317645a6..00000000 Binary files a/agent/app/src/screenshotTestStandardDebug/reference/com/example/appfunctionsstudio/ui/screens/debugging/DebuggingScreenScreenshotTestKt/DebuggingScreenFunctionWithEnumScreenshotPreview_748aa731_0.png and /dev/null differ diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/data/GeminiProviderImplTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/data/GeminiProviderImplTest.kt index 167bea6a..ac214f12 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/data/GeminiProviderImplTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/data/GeminiProviderImplTest.kt @@ -501,4 +501,92 @@ class GeminiProviderImplTest { val textPart = success.parts.first() as LlmResponsePart.Text assertEquals("Served on standard", textPart.text) } + + @Test + fun getAvailableModels_returnsFilteredGeminiModels() = + runBlocking { + val responseJson = + buildJsonObject { + put( + "models", + kotlinx.serialization.json.buildJsonArray { + add( + buildJsonObject { + put("name", "models/gemini-2.5-pro") + put( + "supportedGenerationMethods", + kotlinx.serialization.json.buildJsonArray { + add( + kotlinx.serialization.json.JsonPrimitive( + "generateContent", + ), + ) + }, + ) + }, + ) + add( + buildJsonObject { + put("name", "models/gemini-embedding-001") + put( + "supportedGenerationMethods", + kotlinx.serialization.json.buildJsonArray { + add( + kotlinx.serialization.json.JsonPrimitive( + "embedContent", + ), + ) + }, + ) + }, + ) + add( + buildJsonObject { + put("name", "models/imagen-3.0-generate-002") + put( + "supportedGenerationMethods", + kotlinx.serialization.json.buildJsonArray { + add( + kotlinx.serialization.json.JsonPrimitive( + "predict", + ), + ) + }, + ) + }, + ) + }, + ) + } + .toString() + + val httpClient = createMockHttpClient(HttpStatusCode.OK, responseJson) + val provider = GeminiProviderImpl(httpClient, toolConverter) + + val models = provider.getAvailableModels("test_key") + + assertEquals(listOf(LlmModel(LlmProviderName.GEMINI, "gemini-2.5-pro")), models) + } + + @Test + fun getAvailableModels_blankApiKey_returnsEmptyList() = + runBlocking { + val httpClient = createMockHttpClient(HttpStatusCode.OK, "{}") + val provider = GeminiProviderImpl(httpClient, toolConverter) + + val models = provider.getAvailableModels("") + + assertEquals(emptyList(), models) + } + + @Test + fun getAvailableModels_apiError_returnsEmptyList() = + runBlocking { + val httpClient = createMockHttpClient(HttpStatusCode.InternalServerError, "Error") + val provider = GeminiProviderImpl(httpClient, toolConverter) + + val models = provider.getAvailableModels("test_key") + + assertEquals(emptyList(), models) + } } diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/data/RoomChatRepositoryTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/data/RoomChatRepositoryTest.kt index ad397eda..b38ad8c4 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/data/RoomChatRepositoryTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/data/RoomChatRepositoryTest.kt @@ -96,7 +96,7 @@ class RoomChatRepositoryTest { fun updateThreadModel() = runBlocking { val threadId = "thread_1" - val model = LlmModel.GEMINI_3_FLASH_PREVIEW + val model = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-flash") coEvery { chatDao.updateThreadModel(threadId, model) } returns Unit repository.updateThreadModel(threadId, model) diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/data/db/dao/ChatDaoTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/data/db/dao/ChatDaoTest.kt index 7deaa9ec..29a39a30 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/data/db/dao/ChatDaoTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/data/db/dao/ChatDaoTest.kt @@ -18,6 +18,7 @@ package com.example.appfunctions.agent.data.db.dao import androidx.room.Room import androidx.test.core.app.ApplicationProvider import com.example.appfunctions.agent.data.LlmModel +import com.example.appfunctions.agent.data.LlmProviderName import com.example.appfunctions.agent.data.db.AppDatabase import com.example.appfunctions.agent.data.db.entities.MessageEntity import com.example.appfunctions.agent.data.db.entities.MessageProcessingStatus @@ -36,6 +37,7 @@ import org.robolectric.RobolectricTestRunner class ChatDaoTest { private lateinit var database: AppDatabase private lateinit var chatDao: ChatDao + private val testModel = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-flash") @Before fun setup() { @@ -57,8 +59,7 @@ class ChatDaoTest { @Test fun insertAndGetMessages() = runBlocking { - val thread = - ThreadEntity("thread_1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW) + val thread = ThreadEntity("thread_1", System.currentTimeMillis(), testModel) chatDao.insertThread(thread) val message = @@ -80,8 +81,7 @@ class ChatDaoTest { @Test fun updateMessageStatus() = runBlocking { - val thread = - ThreadEntity("thread_1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW) + val thread = ThreadEntity("thread_1", System.currentTimeMillis(), testModel) chatDao.insertThread(thread) val message = @@ -104,8 +104,7 @@ class ChatDaoTest { @Test fun deleteThreadCascades() = runBlocking { - val thread = - ThreadEntity("thread_1", System.currentTimeMillis(), LlmModel.GEMINI_3_FLASH_PREVIEW) + val thread = ThreadEntity("thread_1", System.currentTimeMillis(), testModel) chatDao.insertThread(thread) val message = @@ -124,4 +123,19 @@ class ChatDaoTest { val messages = chatDao.getMessagesForThread("thread_1").first() assertEquals(0, messages.size) } + + @Test + fun insertAndUpdateThreadWithDynamicLlmModel() = + runBlocking { + val dynamicModel = LlmModel(LlmProviderName.GEMINI, "gemini-4.0-ultra-experimental") + val thread = ThreadEntity("thread_1", System.currentTimeMillis(), dynamicModel) + chatDao.insertThread(thread) + + val retrieved = chatDao.getThread("thread_1").first() + assertEquals(dynamicModel, retrieved?.llmModel) + + val updatedModel = LlmModel(LlmProviderName.GEMINI, "gemini-4.1-flash") + chatDao.updateThreadModel("thread_1", updatedModel) + assertEquals(updatedModel, chatDao.getThread("thread_1").first()?.llmModel) + } } diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/domain/AgentOrchestratorTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/domain/AgentOrchestratorTest.kt index 8c26dbd8..34222363 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/domain/AgentOrchestratorTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/domain/AgentOrchestratorTest.kt @@ -365,7 +365,7 @@ class AgentOrchestratorTest { private fun createThread( threadId: String, - llmModel: LlmModel = LlmModel.GEMINI_3_FLASH_PREVIEW, + llmModel: LlmModel = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-flash"), latestInteractionId: String? = null, ) = ThreadEntity( threadId = threadId, diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/GetChatHistoryUseCaseTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/GetChatHistoryUseCaseTest.kt index 57a371e3..5fabc67f 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/GetChatHistoryUseCaseTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/GetChatHistoryUseCaseTest.kt @@ -19,6 +19,7 @@ import androidx.room.Room import androidx.test.core.app.ApplicationProvider import com.example.appfunctions.agent.data.ChatRepository import com.example.appfunctions.agent.data.LlmModel +import com.example.appfunctions.agent.data.LlmProviderName import com.example.appfunctions.agent.data.RoomChatRepository import com.example.appfunctions.agent.data.db.AppDatabase import com.example.appfunctions.agent.data.db.dao.ChatDao @@ -66,7 +67,11 @@ class GetChatHistoryUseCaseTest { runBlocking { val threadId = "thread_1" val thread = - ThreadEntity(threadId, System.currentTimeMillis(), LlmModel.GEMINI_3_1_PRO_PREVIEW) + ThreadEntity( + threadId, + System.currentTimeMillis(), + LlmModel(LlmProviderName.GEMINI, "gemini-2.5-pro"), + ) chatRepository.createThread(thread) val message = diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/ManageThreadsUseCaseTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/ManageThreadsUseCaseTest.kt index ec470821..a16f4119 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/ManageThreadsUseCaseTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/domain/chat/ManageThreadsUseCaseTest.kt @@ -19,6 +19,7 @@ import androidx.room.Room import androidx.test.core.app.ApplicationProvider import com.example.appfunctions.agent.data.ChatRepository import com.example.appfunctions.agent.data.LlmModel +import com.example.appfunctions.agent.data.LlmProviderName import com.example.appfunctions.agent.data.RoomChatRepository import com.example.appfunctions.agent.data.db.AppDatabase import com.example.appfunctions.agent.data.db.dao.ChatDao @@ -37,6 +38,8 @@ class ManageThreadsUseCaseTest { private lateinit var chatDao: ChatDao private lateinit var chatRepository: ChatRepository private lateinit var useCase: ManageThreadsUseCase + private val testModelPro = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-pro") + private val testModelFlash = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-flash") @Before fun setup() { @@ -60,49 +63,43 @@ class ManageThreadsUseCaseTest { @Test fun getThreads_returnsThreadsFromRepository() = runBlocking { - val llmModel = LlmModel.GEMINI_3_1_PRO_PREVIEW - val threadId = useCase.createThread(llmModel) + val threadId = useCase.createThread(testModelPro) val result = useCase.getThreads().first() assertEquals(1, result.size) assertEquals(threadId, result[0].threadId) - assertEquals(llmModel, result[0].llmModel) + assertEquals(testModelPro, result[0].llmModel) } @Test fun createThread_createsThreadInRepositoryAndReturnsId() = runBlocking { - val llmModel = LlmModel.GEMINI_3_1_PRO_PREVIEW - - val threadId = useCase.createThread(llmModel) + val threadId = useCase.createThread(testModelPro) val threads = useCase.getThreads().first() assertEquals(1, threads.size) assertEquals(threadId, threads[0].threadId) - assertEquals(llmModel, threads[0].llmModel) + assertEquals(testModelPro, threads[0].llmModel) } @Test fun updateThreadModel_updatesThreadInRepository() = runBlocking { - val llmModel = LlmModel.GEMINI_3_1_PRO_PREVIEW - val threadId = useCase.createThread(llmModel) - val newModel = LlmModel.GEMINI_3_FLASH_PREVIEW + val threadId = useCase.createThread(testModelPro) - useCase.updateThreadModel(threadId, newModel) + useCase.updateThreadModel(threadId, testModelFlash) val threads = useCase.getThreads().first() assertEquals(1, threads.size) assertEquals(threadId, threads[0].threadId) - assertEquals(newModel, threads[0].llmModel) + assertEquals(testModelFlash, threads[0].llmModel) } @Test fun deleteThread_removesThreadFromRepository() = runBlocking { - val llmModel = LlmModel.GEMINI_3_1_PRO_PREVIEW - val threadId = useCase.createThread(llmModel) + val threadId = useCase.createThread(testModelPro) useCase.deleteThread(threadId) diff --git a/agent/app/src/test/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModelTest.kt b/agent/app/src/test/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModelTest.kt index 27a48055..ec826834 100644 --- a/agent/app/src/test/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModelTest.kt +++ b/agent/app/src/test/java/com/example/appfunctions/agent/ui/screens/agentdemo/AgentDemoViewModelTest.kt @@ -16,6 +16,7 @@ package com.example.appfunctions.agent.ui.screens.agentdemo import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModelStore import com.example.appfunctions.agent.data.LlmModel import com.example.appfunctions.agent.data.LlmProviderName import com.example.appfunctions.agent.data.SettingsRepository @@ -25,6 +26,8 @@ import com.example.appfunctions.agent.data.db.entities.MessageRole import com.example.appfunctions.agent.data.db.entities.ThreadEntity import com.example.appfunctions.agent.domain.AgentOrchestrator import com.example.appfunctions.agent.domain.AgentStatus +import com.example.appfunctions.agent.domain.LlmProvider +import com.example.appfunctions.agent.domain.LlmProviderFactory import com.example.appfunctions.agent.domain.appfunction.GetAppFunctionsUseCase import com.example.appfunctions.agent.domain.appfunction.GetInstalledAppsUseCase import com.example.appfunctions.agent.domain.chat.GetChatHistoryUseCase @@ -40,7 +43,7 @@ import io.mockk.mockk import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest @@ -53,12 +56,15 @@ import org.junit.Test @OptIn(ExperimentalCoroutinesApi::class) class AgentDemoViewModelTest { private val testDispatcher = UnconfinedTestDispatcher() + private val viewModelStore = ViewModelStore() private lateinit var getChatHistoryUseCase: GetChatHistoryUseCase private lateinit var manageThreadsUseCase: ManageThreadsUseCase private lateinit var sendMessageUseCase: SendMessageUseCase private lateinit var agentOrchestrator: AgentOrchestrator private lateinit var settingsRepository: SettingsRepository + private lateinit var llmProviderFactory: LlmProviderFactory + private lateinit var llmProvider: LlmProvider private lateinit var savedStateHandle: SavedStateHandle private lateinit var observeActivePendingIntentsUseCase: ObserveActivePendingIntentsUseCase private lateinit var launchPendingIntentUseCase: LaunchPendingIntentUseCase @@ -68,8 +74,12 @@ class AgentDemoViewModelTest { private lateinit var viewModel: AgentDemoViewModel + private val testModelFlash = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-flash") + private val testModelPro = LlmModel(LlmProviderName.GEMINI, "gemini-2.5-pro") + private val threadsFlow = MutableStateFlow>(emptyList()) private val selectedProviderFlow = MutableStateFlow(LlmProviderName.GEMINI) + private val geminiApiKeyFlow = MutableStateFlow(null) private val agentStatusFlow = MutableStateFlow(AgentStatus.Idle) private val messagesFlow = MutableStateFlow>(emptyList()) private val activePendingActionIdsFlow = MutableStateFlow>(emptySet()) @@ -83,6 +93,8 @@ class AgentDemoViewModelTest { sendMessageUseCase = mockk() agentOrchestrator = mockk() settingsRepository = mockk() + llmProviderFactory = mockk() + llmProvider = mockk() savedStateHandle = SavedStateHandle() observeActivePendingIntentsUseCase = mockk() launchPendingIntentUseCase = mockk() @@ -91,23 +103,42 @@ class AgentDemoViewModelTest { getAppFunctionsUseCase = mockk() every { getInstalledAppsUseCase() } returns emptyList() - every { getAppFunctionsUseCase() } returns flowOf(emptyMap()) + every { getAppFunctionsUseCase() } returns emptyFlow() every { manageThreadsUseCase.getThreads() } returns threadsFlow every { settingsRepository.selectedProvider } returns selectedProviderFlow + every { settingsRepository.geminiApiKey } returns geminiApiKeyFlow + every { llmProviderFactory.getProvider(any()) } returns llmProvider + coEvery { llmProvider.getAvailableModels(any()) } returns listOf(testModelFlash, testModelPro) every { agentOrchestrator.status } returns agentStatusFlow every { getChatHistoryUseCase(any()) } returns messagesFlow every { observeActivePendingIntentsUseCase() } returns activePendingActionIdsFlow - every { observeActivePendingIntentsUseCase() } returns activePendingActionIdsFlow coEvery { agentOrchestrator.observeAndProcessMessages(any()) } returns Unit } @After fun tearDown() { + viewModelStore.clear() Dispatchers.resetMain() } + private fun createViewModel(): AgentDemoViewModel = + AgentDemoViewModel( + savedStateHandle, + getChatHistoryUseCase, + manageThreadsUseCase, + sendMessageUseCase, + agentOrchestrator, + settingsRepository, + llmProviderFactory, + observeActivePendingIntentsUseCase, + launchPendingIntentUseCase, + consumePendingIntentUseCase, + getInstalledAppsUseCase, + getAppFunctionsUseCase, + ).also { viewModelStore.put("AgentDemoViewModel", it) } + @Test fun `onEvent OnModelSelected updates thread model when thread exists`() = runTest { @@ -115,33 +146,20 @@ class AgentDemoViewModelTest { ThreadEntity( "thread-1", System.currentTimeMillis(), - LlmModel.GEMINI_3_FLASH_PREVIEW, + testModelFlash, null, ) threadsFlow.value = listOf(existingThread) coEvery { - manageThreadsUseCase.updateThreadModel("thread-1", LlmModel.GEMINI_3_1_PRO_PREVIEW) + manageThreadsUseCase.updateThreadModel("thread-1", testModelPro) } returns Unit - viewModel = - AgentDemoViewModel( - savedStateHandle, - getChatHistoryUseCase, - manageThreadsUseCase, - sendMessageUseCase, - agentOrchestrator, - settingsRepository, - observeActivePendingIntentsUseCase, - launchPendingIntentUseCase, - consumePendingIntentUseCase, - getInstalledAppsUseCase, - getAppFunctionsUseCase, - ) + viewModel = createViewModel() - viewModel.onEvent(AgentUiEvent.OnModelSelected(LlmModel.GEMINI_3_1_PRO_PREVIEW)) + viewModel.onEvent(AgentUiEvent.OnModelSelected(testModelPro)) coVerify { - manageThreadsUseCase.updateThreadModel("thread-1", LlmModel.GEMINI_3_1_PRO_PREVIEW) + manageThreadsUseCase.updateThreadModel("thread-1", testModelPro) } } @@ -149,24 +167,11 @@ class AgentDemoViewModelTest { fun `init creates thread when none exists`() = runTest { threadsFlow.value = emptyList() - coEvery { manageThreadsUseCase.createThread(LlmModel.DEFAULT) } returns "thread-new" - - viewModel = - AgentDemoViewModel( - savedStateHandle, - getChatHistoryUseCase, - manageThreadsUseCase, - sendMessageUseCase, - agentOrchestrator, - settingsRepository, - observeActivePendingIntentsUseCase, - launchPendingIntentUseCase, - consumePendingIntentUseCase, - getInstalledAppsUseCase, - getAppFunctionsUseCase, - ) + coEvery { manageThreadsUseCase.createThread(testModelFlash) } returns "thread-new" + + viewModel = createViewModel() - coVerify { manageThreadsUseCase.createThread(LlmModel.DEFAULT) } + coVerify { manageThreadsUseCase.createThread(testModelFlash) } } @Test @@ -176,26 +181,13 @@ class AgentDemoViewModelTest { ThreadEntity( "thread-1", System.currentTimeMillis(), - LlmModel.GEMINI_3_1_PRO_PREVIEW, + testModelPro, null, ) threadsFlow.value = listOf(existingThread) selectedProviderFlow.value = LlmProviderName.GEMINI - viewModel = - AgentDemoViewModel( - savedStateHandle, - getChatHistoryUseCase, - manageThreadsUseCase, - sendMessageUseCase, - agentOrchestrator, - settingsRepository, - observeActivePendingIntentsUseCase, - launchPendingIntentUseCase, - consumePendingIntentUseCase, - getInstalledAppsUseCase, - getAppFunctionsUseCase, - ) + viewModel = createViewModel() coVerify(exactly = 0) { manageThreadsUseCase.createThread(any()) } assertEquals( @@ -211,26 +203,13 @@ class AgentDemoViewModelTest { ThreadEntity( "thread-1", System.currentTimeMillis(), - LlmModel.GEMINI_3_1_PRO_PREVIEW, + testModelPro, null, ) threadsFlow.value = listOf(existingThread) selectedProviderFlow.value = LlmProviderName.GEMINI - viewModel = - AgentDemoViewModel( - savedStateHandle, - getChatHistoryUseCase, - manageThreadsUseCase, - sendMessageUseCase, - agentOrchestrator, - settingsRepository, - observeActivePendingIntentsUseCase, - launchPendingIntentUseCase, - consumePendingIntentUseCase, - getInstalledAppsUseCase, - getAppFunctionsUseCase, - ) + viewModel = createViewModel() coEvery { sendMessageUseCase(any(), any(), any(), any()) } returns Unit @@ -253,26 +232,13 @@ class AgentDemoViewModelTest { ThreadEntity( "thread-1", System.currentTimeMillis(), - LlmModel.GEMINI_3_1_PRO_PREVIEW, + testModelPro, null, ) threadsFlow.value = listOf(existingThread) selectedProviderFlow.value = LlmProviderName.GEMINI - viewModel = - AgentDemoViewModel( - savedStateHandle, - getChatHistoryUseCase, - manageThreadsUseCase, - sendMessageUseCase, - agentOrchestrator, - settingsRepository, - observeActivePendingIntentsUseCase, - launchPendingIntentUseCase, - consumePendingIntentUseCase, - getInstalledAppsUseCase, - getAppFunctionsUseCase, - ) + viewModel = createViewModel() val message = MessageEntity( @@ -295,34 +261,57 @@ class AgentDemoViewModelTest { ThreadEntity( "thread-old", System.currentTimeMillis() - 1000, - LlmModel.GEMINI_3_1_PRO_PREVIEW, + testModelPro, null, ) val newThread = ThreadEntity( "thread-new", System.currentTimeMillis(), - LlmModel.GEMINI_3_1_PRO_PREVIEW, + testModelPro, null, ) threadsFlow.value = listOf(newThread, oldThread) selectedProviderFlow.value = LlmProviderName.GEMINI - viewModel = - AgentDemoViewModel( - savedStateHandle, - getChatHistoryUseCase, - manageThreadsUseCase, - sendMessageUseCase, - agentOrchestrator, - settingsRepository, - observeActivePendingIntentsUseCase, - launchPendingIntentUseCase, - consumePendingIntentUseCase, - getInstalledAppsUseCase, - getAppFunctionsUseCase, - ) + viewModel = createViewModel() assertEquals(newThread, (viewModel.uiState.value as AgentUiState.Loaded).currentThread) } + + @Test + fun `availableModels loads dynamically from provider`() = + runTest { + val dynamicModels = listOf(testModelPro) + coEvery { llmProvider.getAvailableModels("test-api-key") } returns dynamicModels + geminiApiKeyFlow.value = "test-api-key" + val existingThread = + ThreadEntity( + "thread-1", + System.currentTimeMillis(), + testModelFlash, + null, + ) + threadsFlow.value = listOf(existingThread) + + viewModel = createViewModel() + + assertEquals( + dynamicModels, + (viewModel.uiState.value as AgentUiState.Loaded).availableModels, + ) + } + + @Test + fun `init emits Loaded with null currentThread when no threads and no models exist`() = + runTest { + threadsFlow.value = emptyList() + coEvery { llmProvider.getAvailableModels(any()) } returns emptyList() + + viewModel = createViewModel() + + val loadedState = viewModel.uiState.value as AgentUiState.Loaded + assertEquals(null, loadedState.currentThread) + assertEquals(emptyList(), loadedState.availableModels) + } }