git.iko.soy/opencode-android
on master help sign in
Fix untruncated bulk previews, stale file-search error, switch-server error clobber, and generic send-failure message, and log swallowed SSE parse errors
f2ce9a1iko
app/src/main/java/soy/iko/opencode/data/network/EventStreamClient.kt+1
@@ -104,6 +104,7 @@ class EventStreamClient(
104 val event = try {
104 val event = try {
105 OpencodeJson.decodeFromString(BusEvent.serializer(), data)
105 OpencodeJson.decodeFromString(BusEvent.serializer(), data)
106 } catch (e: kotlinx.serialization.SerializationException) {
106 } catch (e: kotlinx.serialization.SerializationException) {
107+ Log.d("EventStream", "Skipping unparseable SSE event", e)
107 continue
108 continue
108 }
109 }
109 // Any successfully decoded event means the stream is live;
110 // Any successfully decoded event means the stream is live;
app/src/main/java/soy/iko/opencode/ui/chat/ChatViewModel.kt+5−6
@@ -209,24 +209,23 @@ class ChatViewModel(
209 // would be lost forever. The persisted draft is cleared only on success.
209 // would be lost forever. The persisted draft is cleared only on success.
210 _draft.value = ""
210 _draft.value = ""
211 viewModelScope.launch {
211 viewModelScope.launch {
212− val ok = runCatching {
212+ runCatching {
213 conn.repository.sendPrompt(
213 conn.repository.sendPrompt(
214 sessionId,
214 sessionId,
215 trimmed,
215 trimmed,
216 model = _selectedModel.value?.ref,
216 model = _selectedModel.value?.ref,
217 agent = _selectedAgent.value,
217 agent = _selectedAgent.value,
218 )
218 )
219− }.isSuccess
219+ }.onFailure {
220− _running.value = false
221− if (!ok) {
222 _failedDraft.value = trimmed
220 _failedDraft.value = trimmed
223 // Only restore the draft if the user hasn't typed anything new since.
221 // Only restore the draft if the user hasn't typed anything new since.
224 if (_draft.value.isBlank()) updateDraft(trimmed)
222 if (_draft.value.isBlank()) updateDraft(trimmed)
225− _error.value = container.string(R.string.error_failed_to_send)
223+ _error.value = container.friendlyError(it)
226− } else {
224+ }.onSuccess {
227 // Send succeeded — now it's safe to persist the empty draft.
225 // Send succeeded — now it's safe to persist the empty draft.
228 container.draftStore.set(sessionId, "")
226 container.draftStore.set(sessionId, "")
229 }
227 }
228+ _running.value = false
230 }
229 }
231 return true
230 return true
232 }
231 }
app/src/main/java/soy/iko/opencode/ui/file/FileBrowserViewModel.kt+1−1
@@ -88,7 +88,7 @@ class FileBrowserViewModel(private val container: AppContainer) : ViewModel() {
88 }
88 }
89
89
90 fun setQuery(query: String) {
90 fun setQuery(query: String) {
91− _state.value = _state.value.copy(query = query)
91+ _state.value = _state.value.copy(query = query, error = null)
92 searchJob?.cancel()
92 searchJob?.cancel()
93 if (query.isBlank()) {
93 if (query.isBlank()) {
94 _state.value = _state.value.copy(results = emptyList(), searching = false)
94 _state.value = _state.value.copy(results = emptyList(), searching = false)
app/src/main/java/soy/iko/opencode/ui/session/SessionListViewModel.kt+1−2
@@ -216,7 +216,7 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
216 api.listMessages(session.id).lastOrNull()?.let { msg ->
216 api.listMessages(session.id).lastOrNull()?.let { msg ->
217 msg.parts.filterIsInstance<TextPart>().lastOrNull()?.text
217 msg.parts.filterIsInstance<TextPart>().lastOrNull()?.text
218 }
218 }
219− }.getOrNull()?.takeIf { it.isNotBlank() } ?: return@withPermit
219+ }.getOrNull()?.takeIf { it.isNotBlank() }?.take(NetworkConfig.previewTextMaxLength) ?: return@withPermit
220 _state.update { s -> s.copy(previews = s.previews + (session.id to preview)) }
220 _state.update { s -> s.copy(previews = s.previews + (session.id to preview)) }
221 }
221 }
222 }
222 }
@@ -281,7 +281,6 @@ class SessionListViewModel(private val container: AppContainer) : ViewModel() {
281 .onFailure {
281 .onFailure {
282 container.disconnect()
282 container.disconnect()
283 _state.value = SessionListState(loading = false, error = container.friendlyError(it))
283 _state.value = SessionListState(loading = false, error = container.friendlyError(it))
284− refresh()
285 }
284 }
286 }
285 }
287 }
286 }