Skip to content

feat: implement ambient web component - #49

Merged
Natalia Markitantova (markitosha) merged 52 commits into
mainfrom
implement-ambient-web-component-beta-for-console-integration-dxg-1047
Jun 8, 2026
Merged

feat: implement ambient web component#49
Natalia Markitantova (markitosha) merged 52 commits into
mainfrom
implement-ambient-web-component-beta-for-console-integration-dxg-1047

Conversation

@markitosha

@markitosha Natalia Markitantova (markitosha) commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Ships the Ambient speech web component and the repo split needed to maintain dictation and ambient as separate npm packages without duplicating UI or socket code.

Why: Corti Console’s AI Studio ambient preview (DXG-1047) needs a browser component on the Streams API, not Transcribe. Dictation already had most of the plumbing (auth context, devices, recording UX, WebSocket lifecycle). This PR extracts that into shared core/ and adds an ambient-specific layer on top.

What you get

New: @corti/ambient-web<corti-ambient> and modular <ambient-*> elements. Connects via AmbientController to /streams, requires interactionId, surfaces transcript / facts / audio-event (and the same auth, proxy, and recording-state events dictation already had). Virtual mode mixes display-media audio with the mic and drives multichannel transcription; integrator-supplied participants on ambientConfig are kept when non-empty (defaults only when empty).

Unchanged for dictation users: <corti-dictation> and <dictation-*> keep the same public API. The package is now @corti/dictation-web published from dictation/ with shared internals compiled in.

Same page: Both bundles can load together — safeCustomElement avoids double-registration of shared speech-* tags.

Mixins and inheritance

Shared behavior is composed with Lit context mixins under core/src/contexts/mixins/, then extended per product:

RootContext = DevicesContextMixinRecordingStateContextMixinKeybindingsContextMixinLanguagesContextMixinAuthContextMixinProxyContextMixinLitElement

Each mixin owns one concern (@provide for access token / proxy URL, device list, languages, keybindings, recording state, etc.). Package roots inherit that stack and add only what differs:

  • DictationRoot / AmbientRoot extend RootContext and provide dictationConfig or ambientConfig, interactionId, virtualMode, …
  • <corti-dictation> / <corti-ambient> extend CortiRoot — thin all-in-one shells that render the matching *-root and recording button via refs, forwarding auth/socket props
  • DictationRecordingButton / AmbientRecordingButton extend RecordingButtonBase (media capture, keybindings, socket send queue) with package-specific SocketController subclasses (DictationController vs AmbientController) and connect config types
  • Selectors and settings menus extend *-base classes in core/ (device-selector-base, language-selector-base, settings-menu-base, …); dictation/ambient packages register the public custom element names

Inbound WebSocket message shapes are centralized in core/src/socket-messages.ts so RecordingButtonBase can type the handler once; transcribe vs stream message unions are narrowed in each package.

How the repo is organized

Single pnpm workspace: core/ (not published; @core/* alias), dictation/, ambient/. Publish is tag-driven: one version tags both packages; artifacts are dist/bundle.js per package (jsDelivr-compatible path restored in this branch).

Prerelease on npm tag ambient: 0.7.0-ambient.19.

Elsewhere

Copilot AI review requested due to automatic review settings May 12, 2026 13:11
@linear-code

linear-code Bot commented May 12, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Implements an ambient-capture web component (<corti-ambient>) alongside a supporting ambient context/root, recording button, and stream socket controller, while refactoring shared dictation/ambient plumbing (contexts + sockets) into reusable mixins and a generic SocketController.

Changes:

  • Added ambient components and Storybook stories (corti-ambient, ambient-root, ambient-recording-button) backed by a new AmbientController.
  • Refactored connection lifecycle into a reusable SocketController, and refactored root context responsibilities into composable Lit context mixins.
  • Extended event typing and dispatch to support stream messages (e.g., facts, stream transcript/usage variants) and updated exports/registrations.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
stories/recording-button.stories.ts Updates Storybook imports to use dictation-recording-button.
stories/corti-ambient.stories.ts Adds Storybook coverage for the new <corti-ambient> component.
stories/ambient-root.stories.ts Adds Storybook coverage for the new <ambient-root> provider + composed children.
src/utils/events.ts Expands event detail types to include stream variants; adds facts event helper.
src/types.ts Adds a shared inbound message union type for recording socket messages.
src/index.ts Registers/exports new components (ambient + renamed recording button) and types.
src/controllers/socket-controller.ts Introduces shared socket lifecycle/queueing controller used by dictation + ambient.
src/controllers/languages-controller.ts Stops mutating host dictation config directly; relies on emitted events instead.
src/controllers/dictation-controller.ts Refactors dictation socket logic onto SocketController.
src/controllers/ambient-controller.ts Adds stream/ambient socket controller built on SocketController.
src/contexts/root-context.ts Adds a shared root context base built from new mixins.
src/contexts/mixins/types.ts Adds common mixin constructor typing helper.
src/contexts/mixins/recording-state-context.ts New recording-state context provider + event synchronization.
src/contexts/mixins/proxy-context.ts New socket URL/proxy context provider.
src/contexts/mixins/languages-context.ts New languages context provider with lazy initialization behavior.
src/contexts/mixins/keybindings-context.ts New keybinding contexts + defaults on context request.
src/contexts/mixins/devices-context.ts New devices/selected-device contexts + lazy initialization behavior.
src/contexts/mixins/auth-context.ts New auth contexts + token parsing and authConfig support.
src/contexts/dictation-context.ts Refactors dictation-root to extend RootContext and keeps dictation config contexts.
src/contexts/ambient-context.ts Adds ambient-root and its ambient config + interactionId contexts.
src/constants.ts Adds DEFAULT_STREAM_CONFIG for ambient streaming.
src/components/settings-menu.ts Updates recording state context import to the new mixin location.
src/components/recording-button-base.ts Generalizes recording button logic into RecordingButtonBase usable by dictation + ambient.
src/components/language-selector.ts Updates contexts import locations (languages context now from mixin).
src/components/keybinding-selector.ts Updates keybinding context import location (mixin).
src/components/keybinding-input.ts Updates keybinding context import location (mixin).
src/components/dictation-recording-button.ts Adds a concrete dictation recording button built on RecordingButtonBase.
src/components/device-selector.ts Updates devices context import location (mixin).
src/components/corti-root.ts Adds shared host base class for all-in-one components (corti-dictation, corti-ambient).
src/components/corti-dictation.ts Refactors to extend CortiRoot and use dictation-recording-button.
src/components/corti-ambient.ts Adds the new all-in-one ambient component built on CortiRoot.
src/components/ambient-recording-button.ts Adds ambient recording button built on RecordingButtonBase, validates interactionId.
biome.json Adds Biome overrides for mixin files (allow any and unused private members).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/src/controllers/socket-controller.ts
Comment thread src/index.ts Outdated
Comment thread core/src/components/corti-root.ts
Comment thread core/src/components/corti-root.ts
Comment thread src/components/corti-root.ts Outdated
Comment thread src/components/ambient-recording-button.ts Outdated
Comment thread stories/corti-ambient.stories.ts
…ation-dxg-1047' of https://github.com/corticph/dictation-web-sdk into implement-ambient-web-component-beta-for-console-integration-dxg-1047
Rely on RecordingSocketInboundMessage as the generic bound so switch cases
dispatch events directly from message.
Self-hosted ci runners were blocking workflow jobs from completing reliably.
Add lit, @corti/sdk, and @lit/context to root devDependencies so tsc -p core
resolves on CI; align Biome schema and format recording-button-base imports.
pnpm version at the workspace root does not honor --dir; run it inside each
package folder instead.
tsc output keeps @core imports that are not published; only bundle.js
inlines core. Point main/module and exports.import at bundle.js so Vite
and other bundlers load the correct artifact.
Shared core tags are bundled into both dictation-web and ambient-web.
Guard registration so loading both packages on one page does not throw.
Wire dictation and ambient to @corti/core-web workspace imports, add
core/package.json, and strip the bundled core dep from dist manifests
before publish.
Use @core path alias for shared source only. safeCustomElement on all
custom elements. Ship self-contained .d.ts via dist/core/ rewrite; keep
bundle.js as the runtime entry.
Per-package READMEs for @corti/dictation-web and @corti/ambient-web with
install, quick start, and links to docs.corti.ai. Copy README into dist on
build so npm publish includes them.
Publish from package roots again so dist/bundle.js matches legacy jsdelivr URLs.
Consolidate build scripts, commit per-package LICENSE files, and drop dist/package.json copying.
Move virtual-mode transcription updates into a util; only inject default
doctor/patient channels when participants are empty, and clear auto-injected
defaults on disable via reference equality.
Self-hosted ci runners are not available for this repository.

@juozaspeleckas Juozas (juozaspeleckas) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good!
There is one issue with running storybook or I am doing something wrong 🤦

Comment thread ambient/package.json Outdated
Pin Storybook addons to 10.1.5 to prevent startup crashes from version drift, update package repository URLs to speech-web-components, and fix story paths after the monorepo split.
@markitosha
Natalia Markitantova (markitosha) merged commit 69b2e63 into main Jun 8, 2026
4 checks passed
@markitosha
Natalia Markitantova (markitosha) deleted the implement-ambient-web-component-beta-for-console-integration-dxg-1047 branch June 8, 2026 08:48
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.

3 participants