Skip to content

fix(api): close conversation when dialogue stage reaches ended#126

Merged
howard9199 merged 1 commit into
mainfrom
fix/ended-conversation-not-show
May 12, 2026
Merged

fix(api): close conversation when dialogue stage reaches ended#126
howard9199 merged 1 commit into
mainfrom
fix/ended-conversation-not-show

Conversation

@howard9199
Copy link
Copy Markdown
Collaborator

The bug was in the conversation completion path. Previously, the backend only finalized a conversation when
llmResult.ended === true. In some cases, the dialogue state had already advanced to updatedState.stage ===
'ended', but the ended flag was still false. When that happened, the system failed to submit the linked
submission and failed to mark the conversation as closed. As a result, Firestore could remain in a half-finished
state with the submission still marked in_progress, which prevented the frontend from showing the analysis /
assessment screen because the UI gates that view on conversation.state === 'closed'.

The fix was to unify the completion condition so the backend now closes the conversation whenever either signal
says the dialogue is finished: llmResult.ended || llmResult.updatedState.stage === 'ended'. I also added
regression tests to cover the broken case where the stage is ended but the boolean flag is not, and to confirm
the existing normal completion path still works.

The bug was in the conversation completion path. Previously, the backend only finalized a conversation when
  llmResult.ended === true. In some cases, the dialogue state had already advanced to updatedState.stage ===
  'ended', but the ended flag was still false. When that happened, the system failed to submit the linked
  submission and failed to mark the conversation as closed. As a result, Firestore could remain in a half-finished
  state with the submission still marked in_progress, which prevented the frontend from showing the analysis /
  assessment screen because the UI gates that view on conversation.state === 'closed'.

  The fix was to unify the completion condition so the backend now closes the conversation whenever either signal
  says the dialogue is finished: llmResult.ended || llmResult.updatedState.stage === 'ended'. I also added
  regression tests to cover the broken case where the stage is ended but the boolean flag is not, and to confirm
  the existing normal completion path still works.
Copilot AI review requested due to automatic review settings May 12, 2026 08:51
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 12, 2026

⚠️ No Changeset found

Latest commit: 2aff1a4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@howard9199 howard9199 merged commit 1897b25 into main May 12, 2026
4 of 5 checks passed
@howard9199 howard9199 deleted the fix/ended-conversation-not-show branch May 12, 2026 08:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a backend conversation-finalization bug where conversations could remain open (and submissions remain in_progress) when the dialogue state had reached stage === 'ended' but the ended boolean flag was still false. The change unifies completion detection and adds regression tests to prevent Firestore conversations/submissions from getting stuck in a half-finished state.

Changes:

  • Normalize LLM completion detection to treat either result.ended or an ended dialogue stage as completion.
  • Move conversation closing to ConversationService (explicit updateConversation({ state: 'closed' })) and remove the ended parameter from appendTurns.
  • Add unit tests covering the “stage ended but ended flag false” completion path.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/mentora-api/tests/conversation-service-asr.unit.test.ts Adds regression tests to assert submission + conversation closure when stage is ended even if ended flag is false.
packages/mentora-api/src/lib/server/repositories/ports/conversation-repository.ts Removes ended from the appendTurns repository port.
packages/mentora-api/src/lib/server/repositories/firestore/conversation-repository.ts Stops appendTurns from changing conversation state to closed.
packages/mentora-api/src/lib/server/llm/llm-service.ts Computes a combined ended signal from handler output + orchestrator state.
packages/mentora-api/src/lib/server/application/conversation-service.ts Closes the conversation when either completion signal indicates the dialogue is finished; adds additional logging.
Comments suppressed due to low confidence (1)

packages/mentora-api/src/lib/server/repositories/firestore/conversation-repository.ts:173

  • appendTurns no longer has a way to atomically transition the conversation to closed while appending the final turns (it always writes state: latestConversation.state). Because ConversationService.addTurn closes the conversation later via a separate updateConversation call, there’s now a race window where another addTurn can read an open conversation and append extra turns after the dialogue has effectively ended. Consider reintroducing a shouldClose flag (or a dedicated finalizeTurn/appendTurnsAndClose method) so the final turn append + state transition happen in the same transaction.
			transaction.update(conversationRef, {
				turns: [...latestConversation.turns, ...params.turns],
				state: latestConversation.state,
				lastActionAt: params.finalNow,
				updatedAt: params.finalNow,
				tokenUsage: conversationTokenUsage
			});

Comment on lines 595 to +599
await this.submitSubmission(assignment, user.uid, {
assessment: llmResult.assessment ?? undefined,
assessmentError: llmResult.assessmentError
});
const closeNow = Date.now();
Comment on lines +118 to +121
console.log('[ConversationService:submitSubmission]', {
assignmentId: assignment.id,
userId
});
Comment on lines +541 to +545
dialogueStage: llmResult.updatedState.stage,
stageEndedButNotClosed: llmResult.updatedState.stage === 'ended' && !llmResult.ended
});

const conversationShouldClose = llmResult.ended || llmResult.updatedState.stage === 'ended';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants