#2: approval pauses narrate from ApprovalRequestedEvent (carries tool/tier/preview/stage directly) instead of OrchestrationPaused + a pending-approvals map the next event had not yet populated — the narrator always lost that race and produced generic text. #3: NarrationTrigger now carries the triggering event's stageId; the narration status line and RouterNarrationEvent.stageId use it instead of the router projection's currentStageId, which terminal events have already cleared ('Stage: none'). #9: ExecutionPlanLocked -> plan.locked and ArtifactValidated -> artifact.validated mapped to the TUI (Go: feed lines, plan shows the compiled stage chain); ArtifactValidating explicitly dropped. #10: blank router turn guard — a length-finish with empty text now emits an explanatory turn naming the max_tokens budget instead of a silent blank; blank steering responses no longer emit steering notes. #12: resumeAbandoned only auto-resumes sessions whose last event is within orchestration.resume_abandoned_max_age_minutes (default 24h, 0 disables); staler sessions stay parked for POST /resume. Knob is TUI-editable and persisted.
This commit is contained in:
@@ -227,6 +227,15 @@ func (m *Model) applyServer(msg protocol.ServerMessage) {
|
||||
if s := m.session(msg.SessionID); s != nil {
|
||||
s.addEvent(nowMillis(), "ArtifactCreated", msg.ArtifactID)
|
||||
}
|
||||
case protocol.TypeArtifactValid:
|
||||
if s := m.session(msg.SessionID); s != nil {
|
||||
s.addEvent(nowMillis(), "ArtifactValidated", msg.ArtifactID)
|
||||
}
|
||||
case protocol.TypePlanLocked:
|
||||
if s := m.session(msg.SessionID); s != nil {
|
||||
s.addEvent(nowMillis(), "PlanLocked", strings.Join(msg.StageIDs, " → "))
|
||||
s.LastOutput = "plan locked: " + strings.Join(msg.StageIDs, " → ")
|
||||
}
|
||||
case protocol.TypeWorkspaceBound:
|
||||
if s := m.session(msg.SessionID); s != nil {
|
||||
s.WorkspaceRoot = msg.WorkspaceRoot
|
||||
|
||||
@@ -39,6 +39,8 @@ const (
|
||||
TypeProviderStatus = "provider.status_changed"
|
||||
TypeProtocolError = "protocol_error"
|
||||
TypeArtifactCreated = "artifact.created"
|
||||
TypeArtifactValid = "artifact.validated"
|
||||
TypePlanLocked = "plan.locked"
|
||||
TypeRouterResponse = "router.response"
|
||||
TypeSnapshotComplete = "snapshot_complete"
|
||||
TypeWorkflowList = "workflow.list"
|
||||
@@ -81,6 +83,9 @@ type ServerMessage struct {
|
||||
Outcome string `json:"outcome"` // approval.resolved: APPROVED | REJECTED | AUTO_APPROVED
|
||||
WorkspaceRoot string `json:"workspaceRoot"` // session.workspace_bound: the bound cwd
|
||||
|
||||
// plan.locked: the compiled phase-2 stage ids in execution order
|
||||
StageIDs []string `json:"stageIds"`
|
||||
|
||||
// inference.retry
|
||||
AttemptNumber int `json:"attemptNumber"`
|
||||
MaxAttempts int `json:"maxAttempts"`
|
||||
@@ -224,6 +229,7 @@ func (m ServerMessage) IsEventBearing() bool {
|
||||
TypeToolStarted, TypeToolCompleted, TypeToolFailed, TypeToolRejected,
|
||||
TypeToolAssessed,
|
||||
TypeApprovalRequired, TypeApprovalResolved, TypeWorkspaceBound, TypeArtifactCreated,
|
||||
TypeArtifactValid, TypePlanLocked,
|
||||
TypeRouterNarration:
|
||||
return true
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user