| ... | @@ -44,6 +44,7 @@ import { | ... | @@ -44,6 +44,7 @@ import { |
| 44 | type PendingApproval, | 44 | type PendingApproval, |
| 45 | deriveWorkLogEntries, | 45 | deriveWorkLogEntries, |
| 46 | hasToolActivityForTurn, | 46 | hasToolActivityForTurn, |
| | 47 | isLatestTurnSettled, |
| 47 | formatElapsed, | 48 | formatElapsed, |
| 48 | formatTimestamp, | 49 | formatTimestamp, |
| 49 | } from "../session-logic"; | 50 | } from "../session-logic"; |
| ... | @@ -382,10 +383,12 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -382,10 +383,12 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 382 | const diffOpen = diffSearch.diff === "1"; | 383 | const diffOpen = diffSearch.diff === "1"; |
| 383 | const activeThreadId = activeThread?.id ?? null; | 384 | const activeThreadId = activeThread?.id ?? null; |
| 384 | const activeLatestTurn = activeThread?.latestTurn ?? null; | 385 | const activeLatestTurn = activeThread?.latestTurn ?? null; |
| | 386 | const latestTurnSettled = isLatestTurnSettled(activeLatestTurn, activeThread?.session ?? null); |
| 385 | const activeProject = state.projects.find((p) => p.id === activeThread?.projectId); | 387 | const activeProject = state.projects.find((p) => p.id === activeThread?.projectId); |
| 386 | | 388 | |
| 387 | useEffect(() => { | 389 | useEffect(() => { |
| 388 | if (!activeThread?.id) return; | 390 | if (!activeThread?.id) return; |
| | 391 | if (!latestTurnSettled) return; |
| 389 | if (!activeLatestTurn?.completedAt) return; | 392 | if (!activeLatestTurn?.completedAt) return; |
| 390 | const turnCompletedAt = Date.parse(activeLatestTurn.completedAt); | 393 | const turnCompletedAt = Date.parse(activeLatestTurn.completedAt); |
| 391 | if (Number.isNaN(turnCompletedAt)) return; | 394 | if (Number.isNaN(turnCompletedAt)) return; |
| ... | @@ -400,6 +403,7 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -400,6 +403,7 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 400 | activeThread?.id, | 403 | activeThread?.id, |
| 401 | activeThread?.lastVisitedAt, | 404 | activeThread?.lastVisitedAt, |
| 402 | activeLatestTurn?.completedAt, | 405 | activeLatestTurn?.completedAt, |
| | 406 | latestTurnSettled, |
| 403 | dispatch, | 407 | dispatch, |
| 404 | ]); | 408 | ]); |
| 405 | | 409 | |
| ... | @@ -483,6 +487,7 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -483,6 +487,7 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 483 | }, [inferredCheckpointTurnCountByTurnId, timelineEntries, turnDiffSummaryByAssistantMessageId]); | 487 | }, [inferredCheckpointTurnCountByTurnId, timelineEntries, turnDiffSummaryByAssistantMessageId]); |
| 484 | | 488 | |
| 485 | const completionSummary = useMemo(() => { | 489 | const completionSummary = useMemo(() => { |
| | 490 | if (!latestTurnSettled) return null; |
| 486 | if (!activeLatestTurn?.startedAt) return null; | 491 | if (!activeLatestTurn?.startedAt) return null; |
| 487 | if (!activeLatestTurn.completedAt) return null; | 492 | if (!activeLatestTurn.completedAt) return null; |
| 488 | if (!latestTurnHasToolActivity) return null; | 493 | if (!latestTurnHasToolActivity) return null; |
| ... | @@ -493,8 +498,10 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -493,8 +498,10 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 493 | activeLatestTurn?.completedAt, | 498 | activeLatestTurn?.completedAt, |
| 494 | activeLatestTurn?.startedAt, | 499 | activeLatestTurn?.startedAt, |
| 495 | latestTurnHasToolActivity, | 500 | latestTurnHasToolActivity, |
| | 501 | latestTurnSettled, |
| 496 | ]); | 502 | ]); |
| 497 | const completionDividerBeforeEntryId = useMemo(() => { | 503 | const completionDividerBeforeEntryId = useMemo(() => { |
| | 504 | if (!latestTurnSettled) return null; |
| 498 | if (!activeLatestTurn?.startedAt) return null; | 505 | if (!activeLatestTurn?.startedAt) return null; |
| 499 | if (!activeLatestTurn.completedAt) return null; | 506 | if (!activeLatestTurn.completedAt) return null; |
| 500 | if (!completionSummary) return null; | 507 | if (!completionSummary) return null; |
| ... | @@ -521,6 +528,7 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -521,6 +528,7 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 521 | activeLatestTurn?.completedAt, | 528 | activeLatestTurn?.completedAt, |
| 522 | activeLatestTurn?.startedAt, | 529 | activeLatestTurn?.startedAt, |
| 523 | completionSummary, | 530 | completionSummary, |
| | 531 | latestTurnSettled, |
| 524 | timelineEntries, | 532 | timelineEntries, |
| 525 | ]); | 533 | ]); |
| 526 | const gitCwd = activeThread?.worktreePath ?? activeProject?.cwd ?? null; | 534 | const gitCwd = activeThread?.worktreePath ?? activeProject?.cwd ?? null; |