Skip to content

[WIP] Add documentation for using VSCode Speech API as a consumer#2

Draft
adamhill with Copilot wants to merge 1 commit into
mainfrom
copilot/add-vscode-speech-api-docs
Draft

[WIP] Add documentation for using VSCode Speech API as a consumer#2
adamhill with Copilot wants to merge 1 commit into
mainfrom
copilot/add-vscode-speech-api-docs

Conversation

Copilot AI commented Dec 18, 2025

Copy link
Copy Markdown

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.

Original prompt

I need some reference docs and example code

I need a very thorough explanation of how to use the VSCode Speech API's - NOT as a Speech provider, but as a consumer, ie. use an installed VScode Speech Extension to recognize my speech from ANOTHER Visual Studio Code Extension.

I need all the startup / initialization code, how to initiate it listening to the microphone, geting the stream of words and then turning it off.

The vscode project already has this implemented in the Chat area, there is a Microphone icon that lights up when you install the VS Code Speech Extension - marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-speech allows you to press it and dictate into the chat area.

I require details and code pointers for the flow of the API's that vscode uses.

vscode uses the NPM speech package at - npmjs.com/package/@vscode/node-speech

There is an offficial Provisional Specch API in the .proposed.tx namespace.

Please write out the architecture and docs to an md file

Then give me a plan I can give back to you at a later date when I implement this in a VS Code extension.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@coderabbitai

coderabbitai Bot commented Dec 18, 2025

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI requested a review from adamhill December 19, 2025 05:42
adamhill pushed a commit that referenced this pull request Jun 25, 2026
…ows (microsoft#319595)

* nes: send periodic enhanced telemetry with overlapping recording windows

Adds ContinuousEnhancedTelemetrySender which periodically ships a fixed-length
slice (5 min) of DebugRecorder activity as an enhanced GH telemetry event,
reusing the existing 'copilot-nes/provideInlineEdit' channel and tagging events
with 'continuous: true' so the backend can route them.

Adjacent slices are guaranteed to overlap by >= 30 s. With tick cadence
INTERVAL = WINDOW - OVERLAP - HARD_CAP and a (idle, hard_cap) wait that mirrors
the suggestion-anchored TelemetrySender, the slice always ends at a 'stable'
moment so we don't capture mid-keystroke state. Slices with no actual edits are
skipped.

- DebugRecorder gains getLogInRange(from, to), with framing fast-forwarded so
  the emitted setContent reflects the document state at the slice start.
- New experiment-gated setting chat.advanced.nes.continuousEnhancedTelemetry.enabled
  (default off).
- Wired into InlineEditProviderFeature alongside TelemetrySender.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: address PR review feedback

- Fix config key mismatch: TS used 'chat.advanced.nes...' but package.json
  exposed 'chat.nes...', so user/experiment config was never read. Align the
  TS key with the package.json key.
- Use DebugRecorder.getTimestamp() instead of Date.now() for the window end
  so edits whose recorded instant was bumped past Date.now() for total
  ordering aren't dropped at the boundary.
- Drop unused 'at' parameter from the insertEdit test helper and clean up
  the call sites that were still passing a redundant timestamp.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: drop config gate for continuous enhanced telemetry

Per PR feedback: the existing GH enhanced-telemetry user controls are
sufficient gating; no need for a dedicated setting.

Removes:
- chat.nes.continuousEnhancedTelemetry.enabled setting (package.json,
  package.nls.json, ConfigKey).
- IConfigurationService + IExperimentationService dependencies from the
  sender; the loop now runs unconditionally for the sender's lifetime.
- Two tests that exercised the config toggle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: clarify continuous telemetry semantics + drop misnamed field

Subagent review findings:

- Drop `activeDocumentRepository` for continuous events: a 5-min slice spans
  many docs over time, so there's no meaningful 'active' document. The full
  workspace repo set is reported via `repositories` already.
- Rename `MAX_ENTRIES_BYTES` -> `MAX_ENTRIES_CHARS` (truth in advertising:
  it's `string.length` / UTF-16 code units, matching the existing suggestion-
  anchored recording cap).
- Class-level doc: clarify that the overlap guarantee assumes timely scheduler
  execution; extension-host stalls / machine sleep / skipped empty slices can
  produce gaps. Treat `windowStart`/`windowEnd` as authoritative; don't infer
  contiguity from `sequenceNumber + 1`.
- Doc that `sessionId` is per-sender-lifetime, and that the sender can be
  recreated within one extension session when `InlineEditProviderFeature`'s
  autorun reruns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: don't bump docVersion on selectionChanged in DebugRecorder

Per PR review: `selectionChanged` entries have no `v` field in the schema
(workspaceLog.ts:64), and production `WorkspaceRecorder` only bumps version
on real document content changes via VS Code's model version. The replayer
consumes `changed.v` directly when applying edits.

Previously, `DebugRecorder` synthesized `v` and bumped it on every recorded
event including selections, which produced phantom gaps in the `changed`
version sequence (e.g. 2, 4, 5 instead of 2, 3, 4) that don't match what a
real recording would contain.

Fixed in both `getDocumentLog` and `getDocumentLogInRange`. Snapshot test
updated; added a focused regression test asserting consecutive `changed`
entries get consecutive `v` values regardless of interleaved selection
changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: drop caller reference from DebugRecorder.getLogInRange jsdoc

Per PR review: low-level method docs shouldn't reference specific
callers — they easily go stale.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: clamp slice framing times + dedup upstream-remote helper

Two PR review threads:

1. Slice framing times made misleading. `getDocumentLogInRange` was
   emitting `documentEncountered.time = creationTime` and
   `setContent.time = baseValueTime`, both of which can pre-date the
   requested `[fromTimeMs, toTimeMs]` window (a doc may have been open
   for hours). Now framing times are clamped up to `fromTimeMs` so the
   slice's per-event `time` contract holds. Documented the invariant
   and added a coverage test asserting every emitted time falls in
   range; updated the fast-forward test's expectation accordingly.

2. Upstream-remote extraction was copy-pasted in three places (twice in
   `nextEditProviderTelemetry.ts`, once in the new sender). Extracted
   to `getUpstreamRemote(repository)` in `platform/git/common/utils.ts`
   and reused everywhere. Behaviour preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: extract NES_GH_TELEMETRY_EVENT_NAME constant

Per PR review: the literal 'copilot-nes/provideInlineEdit' was hardcoded
in three call sites in nextEditProviderTelemetry.ts plus the new continuous
sender. Extract into a named export from nextEditProviderTelemetry.ts (the
file that already owns the event) and import it from the continuous sender
so the relationship is explicit. Behaviour unchanged.

Tests intentionally still use the literal string since they assert on the
wire-level event name.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: revert clamp of framing times in getDocumentLogInRange

The clamp I added in b1d795c was wrong on three counts:

1. **Sort ambiguity**: clamping multiple docs' framing to `fromTimeMs`
   creates ties in the sortTime used by the cross-doc merge sort in
   `getLogInRange`. Ordering then depends on insertion order (i.e. map
   iteration order) instead of real time. Stable sort still preserves
   the per-doc framing-before-edits invariant, but the result becomes
   load-bearing on insertion order in a way the old code wasn't.
2. **Inconsistency with production**: `WorkspaceRecorder`
   (workspaceRecorder.ts:254) emits `documentEncountered`/`setContent`/
   `opened` with their actual timestamps, never clamped to a window.
   The DebugRecorder slice should match that semantic.
3. **Worse for stitching**: with clamping, the same logical
   `documentEncountered` event gets a different time in each
   overlapping slice (fromTimeMs of that slice) — harder to dedup than
   the stable true creationTime.

Revert the clamp; document that framing carries true creation/base-value
times even when they pre-date `fromTimeMs`, and that consumers should
treat any entry with `time < fromTimeMs` as framing. Drop the
out-of-range test, restore the original setContent.time expectation in
the fast-forward test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* nes: harden continuous telemetry loop against subagent-found issues

Subagent review (rounds: code-review HIGH + rubber-duck #2,#3,#8) found:

1. **Unhandled throw in _sendNow kills the loop forever.** RunOnceScheduler's
   runner has no try/catch, so an exception from JSON.stringify or the
   telemetry service would propagate out and never let reschedule() run.
   Fix: try/finally around _sendNow() so reschedule() always fires.
   Added regression test.

2. **cleanUpHistory() in getDocumentLogInRange races with fromTimeMs.**
   Cleanup uses getNow() - 5min as its cutoff. Between the caller computing
   windowEnd and the per-doc cleanup running, getNow() can advance enough
   that earliestTime > fromTimeMs, causing an edit at the leading edge of
   the requested range to be rotated into baseValue and dropped from the
   emitted slice. Fix: don't call cleanUpHistory() in this getter at all —
   the fast-forward loop already handles any base state, and the per-edit
   cleanup in handleEdit keeps memory bounded.

3. **Disposed idleStores accumulate in loopStore.** Calling idleStore.dispose()
   doesn't remove it from the parent's tracking Set, so dead inner stores
   leak one per ~4 min for the sender's lifetime. Fix: loopStore.delete(idleStore)
   instead.

4. **_sendNow() duration not in overlap math.** Added a doc caveat — the
   JSON.stringify cost is added to inter-send spacing but is well under 1 %
   of the 30 s overlap budget in practice. No code change.

5. **No test for doc opened after toTimeMs.** Added one.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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