@@ -195,11 +195,7 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
195 livePreviewJobs[sessionId] = viewModelScope.launch {
195 livePreviewJobs[sessionId] = viewModelScope.launch {
196 val job = coroutineContext[kotlinx.coroutines.Job]
196 val job = coroutineContext[kotlinx.coroutines.Job]
198− val preview = runCatching {
198+ val preview = fetchSessionPreview(api, sessionId) ?: return@launch
199− api.listMessages(sessionId).lastOrNull()?.let { msg ->
200− msg.parts.filterIsInstance<TextPart>().lastOrNull()?.text
202− }.getOrNull()?.takeIf { it.isNotBlank() }?.take(NetworkConfig.previewTextMaxLength) ?: return@launch
203 _state.update { s -> s.copy(previews = s.previews + (sessionId to preview)) }
199 _state.update { s -> s.copy(previews = s.previews + (sessionId to preview)) }
204 } finally {
200 } finally {
205 if (job != null) livePreviewJobs.remove(sessionId, job)
201 if (job != null) livePreviewJobs.remove(sessionId, job)
@@ -218,11 +214,7 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
218 sessions.take(NetworkConfig.maxPreviewSessions).map { session ->
214 sessions.take(NetworkConfig.maxPreviewSessions).map { session ->
220 semaphore.withPermit {
216 semaphore.withPermit {
221− val preview = runCatching {
217+ val preview = fetchSessionPreview(api, session.id) ?: return@withPermit
222− api.listMessages(session.id).lastOrNull()?.let { msg ->
223− msg.parts.filterIsInstance<TextPart>().lastOrNull()?.text
225− }.getOrNull()?.takeIf { it.isNotBlank() }?.take(NetworkConfig.previewTextMaxLength) ?: return@withPermit
226 _state.update { s -> s.copy(previews = s.previews + (session.id to preview)) }
218 _state.update { s -> s.copy(previews = s.previews + (session.id to preview)) }
@@ -291,3 +283,17 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
288+ * Fetch the last text part of a session's most recent message, truncated to
289+ * [NetworkConfig.previewTextMaxLength]. Returns null on failure or when the
290+ * last message has no text part.
292+private suspend fun fetchSessionPreview(
293+ api: soy.iko.opencode.data.network.OpencodeApiClient,
295+): String? = runCatching {
296+ api.listMessages(sessionId).lastOrNull()?.let { msg ->
297+ msg.parts.filterIsInstance<TextPart>().lastOrNull()?.text
299+}.getOrNull()?.takeIf { it.isNotBlank() }?.take(NetworkConfig.previewTextMaxLength)