fix(tui): status bar model, snapshot events, session-start selection
Three fixes: 1. Status bar now shows model/provider from ProviderStatusChanged: - RootReducer sets currentModel and providerType when the message arrives - providerType is LOCAL for llama/local providers, REMOTE otherwise - Removes the stale '(no model) (local)' display 2. SessionSnapshot now carries recent event history: - New EventEntryDto in the protocol with timestamp/type/detail - SessionSnapshot.recentEvents populated by bridge from event store - Bridge reads last 7 display-relevant events per session - TUI processSessionSnapshotMessage maps them to TuiEventEntry - Completed sessions finally show their event history 3. SessionStarted now switches selectedId to the new session: - RootReducer cross-field weave updates selectedId alongside sessionEntered - Previously kept the old selectedId, navigating user into the wrong session - Works whether starting a session from the list or during replay
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.correx.apps.server.bridge
|
||||
|
||||
import com.correx.apps.server.protocol.ApprovalDto
|
||||
import com.correx.apps.server.protocol.EventEntryDto
|
||||
import com.correx.apps.server.protocol.ServerMessage
|
||||
import com.correx.apps.server.protocol.SessionStateDto
|
||||
import com.correx.apps.server.protocol.StageToolDecl
|
||||
@@ -8,6 +9,20 @@ import com.correx.apps.server.protocol.ToolDecl
|
||||
import com.correx.apps.server.registry.WorkflowRegistry
|
||||
import com.correx.core.approvals.DefaultApprovalRepository
|
||||
import com.correx.core.artifactstore.ArtifactStore
|
||||
import com.correx.core.events.events.InferenceCompletedEvent
|
||||
import com.correx.core.events.events.InferenceStartedEvent
|
||||
import com.correx.core.events.events.InferenceTimeoutEvent
|
||||
import com.correx.core.events.events.OrchestrationPausedEvent
|
||||
import com.correx.core.events.events.StageCompletedEvent
|
||||
import com.correx.core.events.events.StageFailedEvent
|
||||
import com.correx.core.events.events.StoredEvent
|
||||
import com.correx.core.events.events.ToolExecutionCompletedEvent
|
||||
import com.correx.core.events.events.ToolExecutionFailedEvent
|
||||
import com.correx.core.events.events.ToolExecutionRejectedEvent
|
||||
import com.correx.core.events.events.ToolInvocationRequestedEvent
|
||||
import com.correx.core.events.events.TransitionExecutedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
import com.correx.core.events.events.WorkflowFailedEvent
|
||||
import com.correx.core.events.orchestration.OrchestrationStatus
|
||||
import com.correx.core.events.stores.EventStore
|
||||
import com.correx.core.events.types.SessionId
|
||||
@@ -48,6 +63,10 @@ class SessionEventBridge(
|
||||
}
|
||||
?: emptyList()
|
||||
|
||||
val recentEvents = eventStore.read(sessionId)
|
||||
.mapNotNull { eventToEntry(it) }
|
||||
.takeLast(7)
|
||||
|
||||
send(ServerMessage.SessionSnapshot(
|
||||
sessionId = sessionId,
|
||||
workflowId = orchState.workflowId,
|
||||
@@ -57,6 +76,7 @@ class SessionEventBridge(
|
||||
pauseReason = orchState.pauseReason,
|
||||
),
|
||||
pendingApprovals = pendingApprovals,
|
||||
recentEvents = recentEvents,
|
||||
lastSequence = lastGlobal,
|
||||
lastSessionSequence = lastSession,
|
||||
))
|
||||
@@ -82,6 +102,26 @@ class SessionEventBridge(
|
||||
send(ServerMessage.SnapshotComplete)
|
||||
}
|
||||
|
||||
private fun eventToEntry(event: StoredEvent): EventEntryDto? {
|
||||
val ts = event.metadata.timestamp.toEpochMilliseconds()
|
||||
return when (val p = event.payload) {
|
||||
is TransitionExecutedEvent -> EventEntryDto(ts, "StageStarted", p.to.value)
|
||||
is StageCompletedEvent -> EventEntryDto(ts, "StageCompleted", p.stageId.value)
|
||||
is StageFailedEvent -> EventEntryDto(ts, "StageFailed", p.stageId.value)
|
||||
is InferenceStartedEvent -> EventEntryDto(ts, "InferenceStarted", p.stageId.value)
|
||||
is InferenceCompletedEvent -> EventEntryDto(ts, "InferenceCompleted", p.stageId.value)
|
||||
is InferenceTimeoutEvent -> EventEntryDto(ts, "InferenceTimeout", p.stageId.value)
|
||||
is ToolInvocationRequestedEvent -> EventEntryDto(ts, "ToolStarted", p.toolName)
|
||||
is ToolExecutionCompletedEvent -> EventEntryDto(ts, "ToolCompleted", p.toolName)
|
||||
is ToolExecutionFailedEvent -> EventEntryDto(ts, "ToolFailed", p.toolName)
|
||||
is ToolExecutionRejectedEvent -> EventEntryDto(ts, "ToolRejected", p.toolName)
|
||||
is OrchestrationPausedEvent -> EventEntryDto(ts, "SessionPaused", p.reason)
|
||||
is WorkflowCompletedEvent -> EventEntryDto(ts, "SessionCompleted", "")
|
||||
is WorkflowFailedEvent -> EventEntryDto(ts, "SessionFailed", p.reason)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun streamLive(sessionId: SessionId) {
|
||||
var sessionSequence = 0L
|
||||
eventStore.subscribe(sessionId).collect { event ->
|
||||
|
||||
@@ -54,3 +54,10 @@ data class ToolDecl(
|
||||
val name: String,
|
||||
val tier: Int,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class EventEntryDto(
|
||||
val timestamp: Long,
|
||||
val type: String,
|
||||
val detail: String,
|
||||
)
|
||||
|
||||
@@ -79,6 +79,7 @@ sealed interface ServerMessage {
|
||||
val workflowId: String,
|
||||
val state: SessionStateDto,
|
||||
val pendingApprovals: List<ApprovalDto>,
|
||||
val recentEvents: List<EventEntryDto> = emptyList(),
|
||||
val lastSequence: Long,
|
||||
val lastSessionSequence: Long,
|
||||
override val sequence: Long? = null,
|
||||
|
||||
Reference in New Issue
Block a user