UpdateStep updates an existing debug step and emits a step update event. When a terminal status is set without an explicit FinishedAt, the service auto-fills the timestamp so the stale sweep does not leave terminal rows with finished_at = NULL.
( ctx context.Context, params UpdateStepParams, )
| 470 | // service auto-fills the timestamp so the stale sweep does not leave |
| 471 | // terminal rows with finished_at = NULL. |
| 472 | func (s *Service) UpdateStep( |
| 473 | ctx context.Context, |
| 474 | params UpdateStepParams, |
| 475 | ) (database.ChatDebugStep, error) { |
| 476 | if params.Status.IsTerminal() && params.FinishedAt.IsZero() { |
| 477 | params.FinishedAt = s.clock.Now() |
| 478 | } |
| 479 | step, err := s.db.UpdateChatDebugStep(chatdContext(ctx), |
| 480 | database.UpdateChatDebugStepParams{ |
| 481 | Status: nullString(string(params.Status)), |
| 482 | HistoryTipMessageID: sql.NullInt64{}, |
| 483 | AssistantMessageID: nullInt64(params.AssistantMessageID), |
| 484 | NormalizedRequest: pqtype.NullRawMessage{}, |
| 485 | NormalizedResponse: s.nullJSON(ctx, params.NormalizedResponse), |
| 486 | Usage: s.nullJSON(ctx, params.Usage), |
| 487 | Attempts: s.nullJSON(ctx, params.Attempts), |
| 488 | Error: s.nullJSON(ctx, params.Error), |
| 489 | Metadata: s.nullJSON(ctx, params.Metadata), |
| 490 | FinishedAt: nullTime(params.FinishedAt), |
| 491 | Now: s.clock.Now(), |
| 492 | ID: params.ID, |
| 493 | ChatID: params.ChatID, |
| 494 | }) |
| 495 | if err != nil { |
| 496 | return database.ChatDebugStep{}, err |
| 497 | } |
| 498 | |
| 499 | s.publishEvent(ctx, step.ChatID, EventKindStepUpdate, step.RunID, step.ID) |
| 500 | return step, nil |
| 501 | } |
| 502 | |
| 503 | // TouchStep bumps the step's and its parent run's updated_at timestamps |
| 504 | // without changing any other fields. This prevents long-running operations |