Add hands-free Spoken Send - #829
Conversation
|
The PR Policy check is blocking this PR because required template information is missing. Please update the PR description with:
Visual files detected:
Screenshots or video are required for UI, UX, settings, onboarding, overlay, menu bar, or visual behavior changes. If this PR has no visual changes, check the no-visual-change box in the template. If this remains incomplete for 48 hours after opening, the PR may be closed. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c7a9e97096
ℹ️ 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".
Greptile SummaryThe PR adds configurable hands-free Spoken Send, including phrase parsing, countdown and overlay state, persisted settings, and guarded text insertion followed by a configurable Return action.
|
FluidVoice PR build readyDownload FluidVoice-PR-829-457cbcad55ee The artifact contains the ad-hoc-signed app ZIP, Xcode archive, build manifest, and installation instructions. It expires 5 days after the build. Install the app
This build has its own app identity, so its permissions are separate from the release version of FluidVoice. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b3201a757
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cb9fe9979
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cbd502ee09
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 626c953bb2
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5fae6f120e
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ffb7df0d08
ℹ️ 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".
| let expectedActionValue: String? = if hasTextToInsert { | ||
| expectedInsertedValue | ||
| } else { | ||
| Self.nonemptyEditableDraftValue(requiredFocusTarget) | ||
| } |
There was a problem hiding this comment.
Snapshot existing drafts before waiting for modifiers
When the utterance is only the send phrase and a physical modifier remains held, the two-second wait occurs before nonemptyEditableDraftValue captures the draft. If the user or destination app changes the composer during that wait, releasing the modifier causes the new value to be accepted as the expected value and immediately submitted. Capture the existing draft before waiting and require that same value to remain present before dispatch.
Useful? React with 👍 / 👎.
|
@codex review |
| guard Self.isExactFocusTargetActive(target), | ||
| self.getElementStringValue(target.element) == expectedValue | ||
| else { | ||
| return false | ||
| } | ||
| keyDown.postToPid(target.pid) |
There was a problem hiding this comment.
When focus moves to another field in the captured application after the final exact-focus check, keyDown.postToPid(target.pid) delivers Return to the newly focused field, causing that field to submit or activate its contents instead of the captured field.
Knowledge Base Used: Dictation Capture Flow
Prompt To Fix With AI
This is a comment left during a code review.
Path: Sources/Fluid/Services/TypingService.swift
Line: 838-843
Comment:
**Return escapes captured focus**
When focus moves to another field in the captured application after the final exact-focus check, `keyDown.postToPid(target.pid)` delivers Return to the newly focused field, causing that field to submit or activate its contents instead of the captured field.
**Knowledge Base Used:** [Dictation Capture Flow](https://app.greptile.com/altic/-/custom-context/knowledge-base/altic-dev/fluidvoice/-/docs/dictation-capture-flow.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b15d5e19a4
ℹ️ 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".
| let targetMatchesRecordingFocus = typingTarget.pid != nil | ||
| && typingTarget.pid == self.recordingFocusTarget?.pid |
There was a problem hiding this comment.
Snapshot the focus target before asynchronous post-processing
If another dictation starts while the previous one is doing AI post-processing, captureRecordingTargetContext() overwrites both recordingFocusTarget and recordingTargetPID; this comparison then sees two matching values from the new session and allows the old transcript to be inserted and submitted in the new session's field. The hotkey start path permits this once asr.stop() has returned, so a slow AI request can send a message to the wrong app or conversation. Preserve the stopped session's target in local state and use that snapshot throughout its delivery checks.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 457cbcad55
ℹ️ 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".
| // Capture the focused target PID BEFORE any overlay/UI changes. | ||
| // Used to restore focus when the user interacts with overlay dropdowns. | ||
| let focusedPID = TypingService.captureSystemFocusedPID() | ||
| self.recordingSessionID = UUID() |
There was a problem hiding this comment.
Rotate the session before starting audio capture
When a new dictation is accepted while the previous one is still doing AI post-processing, the session remains unchanged until onCaptureStarted runs after first PCM. During that startup window, the previous operation passes canDeliverCompletedRecording, restores its old focus target, and can do so before the callback captures the new target; the new recording then captures that restored old field and may later insert or send into the wrong conversation. The fresh evidence in this revision is that the delivery snapshots are isolated, but the identifier is still rotated only here rather than synchronously when beginDictationRecording accepts the new session.
Useful? React with 👍 / 👎.
Description
Adds optional Spoken Send: say a configurable phrase at the end of dictation to remove the command phrase, stop recording, insert the text, and dispatch Enter, Shift+Enter, or Command+Enter. Delivery is suppressed for secure fields, terminal apps, held modifiers, changed focus targets, or unconfirmed insertion.
Type of Change
Related Issue or Discussion
Closes #518
Testing
swiftlint --strict --config .swiftlint.yml Sourcesswiftformat --config .swiftformat SourcesLive dogfood through BlackHole 2ch and macOS speech:
send it, inserted the remaining text, and dispatched Enter.literal send itinserted the phrase without dispatching Enter.send itin the middle of a sentence remained normal dictated text.Screenshots / Video
Spoken Send settings were visually inspected in the installed FluidVoice 1.6.8 app.

Notes
The feature is disabled by default. Audio-level monitoring is active only during the 1.5-second Spoken Send countdown. Text insertion and Enter dispatch remain bound to the exact captured field; Enter is suppressed unless insertion is confirmed.