Skip to content

Defer update prompts until dictation completes - #746

Open
joeyjooste wants to merge 4 commits into
altic-dev:mainfrom
joeyjooste:fix/fluidvoice-745
Open

Defer update prompts until dictation completes#746
joeyjooste wants to merge 4 commits into
altic-dev:mainfrom
joeyjooste:fix/fluidvoice-745

Conversation

@joeyjooste

Copy link
Copy Markdown

Description

Prevents automatic update prompts from interrupting active dictation and discarding the final transcript. FluidVoice now tracks transcript finalization and defers the modal update prompt until recording startup, capture, and final transcription have all completed.

Manual “Check for Updates…” behavior is unchanged.

Type of Change

  • 🐞 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 🧹 Chore
  • 📝 Documentation update

Related Issue or Discussion

Closes #745

Related: #564

Testing

  • Tested on Intel Mac
  • Tested on Apple Silicon Mac
  • Tested on macOS version:
  • Ran linter locally: swiftlint --strict --config .swiftlint.yml Sources
  • Ran formatter locally: swiftformat --config .swiftformat Sources
  • Ran tests locally
  • Parsed all changed Swift files with swiftc -parse
  • Verified the commit with git diff HEAD^ --check

Full SwiftLint and Xcode tests could not run locally because full Xcode is unavailable in the selected developer environment. GitHub Actions will run the repository’s required lint, build, and test checks.

Screenshots / Video

  • No UI/visual changes; screenshots/video are not applicable.

Notes

The existing update alert is unchanged. Only its automatic presentation timing is deferred while dictation owns recording or transcript-finalization work.

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR defers automatic update prompts until dictation lifecycle work has completed.

  • Tracks recording startup, capture, transcript finalization, and output delivery in shared application state.
  • Waits for asynchronous text insertion and clipboard restoration before marking output delivery complete.
  • Leaves manual update checks unchanged and adds focused lifecycle tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (4): Last reviewed commit: "Keep update deferral across dictation bo..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b05c4908ef

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +71 to +73
var hasActiveDictation: Bool {
self._asr.map { $0.isRunningOrStarting || $0.isFinalizing } ?? false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep update deferral active through output delivery

When dictation uses AI post-processing, ContentView.stopAndProcessTranscription continues refining, saving, and typing after ASRService.stop() returns; this helper flips false as soon as ASR finalization ends. A deferred update alert can therefore wake during that post-stop processing and take focus before the dictated output is delivered, so update prompts can still interrupt the active dictation workflow. Track the higher-level stop/output processing state, or keep the deferral active until callers finish delivering the transcription.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e23a8b000

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


private func stopAndProcessTranscription(route: DictationOutputRoute = .normal) async {
self.appServices.setDictationOutputDeliveryActive(true)
defer { self.appServices.setDictationOutputDeliveryActive(false) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep deferral active until typing finishes

In the external typing route, this defer clears hasActiveDictation as soon as stopAndProcessTranscription returns, but the actual insertion has only been dispatched: ASRService.typeOutputPlanToActiveField calls TypingService.typeOutputPlanInstantly, which queues a background worker and can wait before inserting/pasting. Fresh evidence in this revision is that the new higher-level flag still drops before that worker completes, so a deferred automatic update alert can wake during that window, take focus, and cause the dictated output to miss or target the wrong UI; keep the flag active until the typing/paste operation has actually completed.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 957d43c242

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +72 to +74
var hasActiveDictation: Bool {
self.isDeliveringDictationOutput ||
(self._asr.map { $0.isRunningOrStarting || $0.isFinalizing } ?? false)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mark dictation active before scheduling ASR startup

When a user triggers dictation as the automatic update check completes, startRecording() schedules asr.start() in a new Task, so there is a main-actor scheduling window before isStarting becomes true. During that window this expression reports no active dictation, allowing showUpdateNotification to enter its modal alert even though recording startup has already been requested; track the pending start synchronously or set the activity flag before creating the startup task.

Useful? React with 👍 / 👎.

Comment on lines +351 to +354
"complete totalMs=\(Self.elapsedMs(from: requestedAt, to: completedAt)) textReadyToCompleteMs=\(textReadyAt.map { String(Self.elapsedMs(from: $0, to: completedAt)) } ?? "nil")"
)
self.log("[TypingService] Typing operation completed, isCurrentlyTyping set to false")
completion?()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wait for paste confirmation before firing completion

When reliable-paste mode or the clipboard fallback is used, insertTextInstantly reaches withTemporaryPasteboardString, which queues insertion verification on pasteboardRestoreQueue (for up to five seconds) and returns immediately; this completion therefore clears the update deferral while the paste is still only dispatched, so a modal alert can take focus before a global Cmd+V is consumed. Fresh evidence in this revision is that awaiting the worker still does not await that existing asynchronous verification; invoke completion after verification/restoration finishes instead.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5232e10c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
} else {
Task { await self.asr.start() }
self.appServices.beginDictationStartup()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Track voice-command processing through completion

When recording from CommandModeView, this registers only the startup phase; after asr.stop() finishes, hasActiveDictation becomes false while processUserCommand is still awaiting the generated response. A deferred automatic update alert can therefore appear during a voice-originated command and, if the user installs it, restart the app before the response is produced. Keep output-delivery activity set around the stop-and-command-processing task, as the main ContentView dictation route does.

Useful? React with 👍 / 👎.

Comment on lines +87 to +88
func setDictationOutputDeliveryActive(_ active: Bool) {
self.isDeliveringDictationOutput = active

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Count overlapping output-delivery operations

When two stop triggers queue stopAndProcessTranscription before the first has finished—for example, a recording-control action and the global shortcut—the second call can quickly return empty because the first already cleared isRunning, then set this shared Boolean to false. Once the first asr.stop() returns, isFinalizing is also false even though its AI processing and typing are still active, so the deferred update alert can wake prematurely. Use a balanced counter/token rather than a Boolean so one invocation cannot clear another invocation's deferral.

Useful? React with 👍 / 👎.

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.

[BUG] Automatic update prompt interrupts active dictation and can discard transcript

1 participant