(ctx context.Context, chatID uuid.UUID, logger slog.Logger, status codersdk.ChatStatus)
| 219 | } |
| 220 | |
| 221 | func (r *Runner) handleStatusEvent(ctx context.Context, chatID uuid.UUID, logger slog.Logger, status codersdk.ChatStatus) (bool, error) { |
| 222 | if status == r.lastStatus { |
| 223 | return false, nil |
| 224 | } |
| 225 | if status == codersdk.ChatStatusWaiting && |
| 226 | !r.sawTurnFirstOutput && |
| 227 | (r.sawTurnRunning || r.result.turnsCompleted > 0) { |
| 228 | return false, nil |
| 229 | } |
| 230 | r.lastStatus = status |
| 231 | |
| 232 | switch status { |
| 233 | case codersdk.ChatStatusRunning: |
| 234 | r.sawTurnRunning = true |
| 235 | r.cfg.Metrics.ChatTimeToRunningSeconds.WithLabelValues(r.currentPhase).Observe(time.Since(r.turnStartTime).Seconds()) |
| 236 | logger.Info(ctx, "chat reached running status", |
| 237 | slog.F("phase", r.currentPhase), |
| 238 | ) |
| 239 | return false, nil |
| 240 | case codersdk.ChatStatusWaiting: |
| 241 | r.result.turnsCompleted++ |
| 242 | turnDuration := time.Since(r.turnStartTime) |
| 243 | r.cfg.Metrics.ChatTimeToTerminalStatusSeconds.WithLabelValues(r.currentPhase).Observe(turnDuration.Seconds()) |
| 244 | r.cfg.Metrics.ChatTerminalStatusTotal.WithLabelValues(string(codersdk.ChatStatusWaiting)).Inc() |
| 245 | r.cfg.Metrics.ChatTurnsCompletedTotal.Inc() |
| 246 | logger.Info(ctx, "chat completed turn", |
| 247 | slog.F("turn", r.result.turnsCompleted), |
| 248 | slog.F("turns", r.cfg.Turns), |
| 249 | slog.F("duration", turnDuration), |
| 250 | ) |
| 251 | if r.result.turnsCompleted >= r.cfg.Turns { |
| 252 | r.result.finalStatus = string(codersdk.ChatStatusWaiting) |
| 253 | conversationDuration := time.Since(r.conversationStart) |
| 254 | logger.Info(ctx, "chat reached terminal status", |
| 255 | slog.F("status", codersdk.ChatStatusWaiting), |
| 256 | slog.F("duration", conversationDuration), |
| 257 | slog.F("turns_completed", r.result.turnsCompleted), |
| 258 | ) |
| 259 | return true, nil |
| 260 | } |
| 261 | |
| 262 | // After the very first turn completes, mark this runner ready |
| 263 | // for the CLI-coordinated turn-start gate. The inter-phase |
| 264 | // delay measures the gap between every chat actually finishing its |
| 265 | // initial turn and the start of the follow-up turns, not the gap |
| 266 | // between CreateChat returning and the next turn. |
| 267 | if r.result.turnsCompleted == 1 { |
| 268 | r.markTurnStartReady() |
| 269 | if r.cfg.StartTurnsChan != nil { |
| 270 | logger.Info(ctx, "chat waiting for turn start release", |
| 271 | slog.F("turn_start_delay", r.cfg.TurnStartDelay), |
| 272 | ) |
| 273 | select { |
| 274 | case <-ctx.Done(): |
| 275 | return false, ctx.Err() |
| 276 | case <-r.cfg.StartTurnsChan: |
| 277 | } |
| 278 | } |
no test coverage detected