@@ -19,6 +19,7 @@ import soy.iko.opencode.data.repo.responseStatusCode
19import soy.iko.opencode.notification.NotificationChannels
19import soy.iko.opencode.notification.NotificationChannels
20import soy.iko.opencode.notification.SessionNotifications
20import soy.iko.opencode.notification.SessionNotifications
21import soy.iko.opencode.R
21import soy.iko.opencode.R
22+import soy.iko.opencode.util.runCatchingCancellable
22import kotlinx.coroutines.CoroutineScope
23import kotlinx.coroutines.CoroutineScope
23import kotlinx.coroutines.Dispatchers
24import kotlinx.coroutines.Dispatchers
24import kotlinx.coroutines.ExperimentalCoroutinesApi
25import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -178,8 +179,10 @@ class AppContainer(context: Context) {
178 // Track sessions actively streaming so we know which idle events
179 // Track sessions actively streaming so we know which idle events
179 // represent a finished run worth notifying about.
180 // represent a finished run worth notifying about.
180 if (event is MessagePartUpdated || event is MessageUpdated) {
181 if (event is MessagePartUpdated || event is MessageUpdated) {
182+ synchronized(activeRuns) {
181− if (activeRuns.size >= activeRunsLimit) activeRuns.clear()
183+ if (activeRuns.size >= activeRunsLimit) activeRuns.clear()
182− activeRuns.add(sid)
184+ activeRuns.add(sid)
@@ -203,7 +206,7 @@ class AppContainer(context: Context) {
203 /** Resolve the title for [sessionId] (best-effort) and post a completion notification. */
206 /** Resolve the title for [sessionId] (best-effort) and post a completion notification. */
204 private suspend fun notifySessionCompleted(sessionId: String) {
207 private suspend fun notifySessionCompleted(sessionId: String) {
205 val conn = activeConnection.value ?: return
208 val conn = activeConnection.value ?: return
206− val title = runCatching {
209+ val title = runCatchingCancellable {
207 conn.repository.listSessions().firstOrNull { it.id == sessionId }?.displayTitle
210 conn.repository.listSessions().firstOrNull { it.id == sessionId }?.displayTitle
208 }.getOrNull() ?: sessionId
211 }.getOrNull() ?: sessionId
209 SessionNotifications.postCompleted(appContext, sessionId, title)
212 SessionNotifications.postCompleted(appContext, sessionId, title)
@@ -221,7 +224,7 @@ class AppContainer(context: Context) {
221 .getOrDefault(emptyList())
224 .getOrDefault(emptyList())
222 .firstOrNull() ?: return
225 .firstOrNull() ?: return
223 _reconnecting.value = true
226 _reconnecting.value = true
224− val ok = runCatching {
227+ val ok = runCatchingCancellable {
225 val conn = connect(recent)
228 val conn = connect(recent)
226 conn.api.ping()
229 conn.api.ping()
227 }.isSuccess
230 }.isSuccess