| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
fix(sdks/device): document codec 21 (opusFS320) and map it in every SDK `sdks/device` documented only codec ID 20 (Opus, DevKit) on the audio-codec characteristic, but shipping Omi CV1 firmware reports 21 (`omi/firmware/omi/src/lib/core/config.h:37`, vs 20 in `omi/firmware/devkit/src/config.h:37`). The concrete consequence: the TypeScript SDK's `mapCodecId()` returned the bare number `21` for every CV1 device instead of a named `BleAudioCodec` member, so callers had no way to identify the codec the device is actually streaming. The two Opus IDs are not interchangeable: 20 is 160-sample frames @ 100 fps, 21 is 320-sample frames @ 50 fps (per the app's `BleAudioCodec`, `app/lib/backend/schema/bt_device/bt_device.dart`), so a decoder that assumes 10 ms frames mis-times a CV1 stream. - `PROTOCOL.md`: add the codec-21 row, name the owning firmware per ID, record the frame duration/rate difference, and note that `OPUS_FRAME_SAMPLES = 960` is a decode buffer bound, not a wire frame size. - Go / TypeScript: add the codec-21 constant and handle it in `mapCodecId()`. - Rust / C++: add the codec-ID constants (neither exposed any), so all four thin SDKs carry the same map. Dart needs no change — its device SDK returns the raw codec byte and defers to the app's `BleAudioCodec`, which already has `opusFS320`. Tested (no physical CV1 attached; verified at the byte the characteristic returns, not over the radio): - `go vet ./... && go test ./...` in `sdks/device/go` — ok, incl. new `TestCodecIDs`; fails to build on the parent commit (`undefined: CodecOpusFS320`). - `bun test` in `sdks/device/typescript` — 11 pass / 0 fail, incl. new `src/index.test.ts`; on the parent commit `mapCodecId(21)` returns `21` instead of an enum member and the test fails. - `bunx tsc --noEmit` — clean. - `cargo test` in `sdks/device/rust` — 3 pass, incl. new `codec_ids`. - C++: `clang++ -std=c++17 -Wall -Wextra` against `protocol.hpp` with `static_assert`s on all four codec IDs — compiles and runs clean. Failure-Class: none fixes #11254 | 25 天前 | |
feat(sdks): multi-lang device SDKs (protocol + STT + BLE) (#10227) * feat(sdks): add multi-lang device BLE protocol packages Share Omi GATT UUIDs and audio packet framing across TypeScript, Go, Rust, C++, and Dart under sdks/device. Keep full BLE stacks in the existing Python/Swift/React Native packages; wire Python constants to the same protocol doc. Failure-Class: none * feat(sdks): add multi-engine STT parity across device SDKs Expose deepgram, whisper, and parakeet engines with the same PCM16/16k contract on Python, Swift, React Native, TypeScript, Go, Rust, Dart, and C++ helpers. Feature-gate Whisper runners and optional BLE/STT stacks where native deps are platform-specific. Failure-Class: none * feat(sdks/device-rust): add btleplug-backed BLE feature Failure-Class: none * feat(sdks/device-cpp): add optional SimpleBLE client Failure-Class: none Optional OMI_DEVICE_BLE CMake gate (default OFF) adds scan/listen over SimpleBLE using Omi service/audio UUIDs. FetchContent falls back with a clear warning if SimpleBLE is unavailable. * feat(sdks/device-dart): add flutter_blue_plus BLE client Failure-Class: none Wire OmiBleClient + FlutterBluePlusOmiBle (scan/connect/listenAudio/listenPayload/disconnect) using existing protocol UUIDs and stripPacketHeader. Package now depends on Flutter SDK + flutter_blue_plus; pure protocol/STT unit tests still pass via dart test. Verification: cd sdks/device/dart && flutter pub get && dart test → All tests passed! * feat(sdks/device-go): add feature-gated BLE scan/listen Failure-Class: none * feat(sdks/device-ts): add optional noble BLE transport Failure-Class: none * feat(sdks/device-dart): port app GATT map onto flutter_blue_plus BLE Use main-app UUID constants and Omi audio/codec/battery flows with flutter_blue_plus for third-party Flutter apps. Add Python bleak high-level scan/listen API and document multi-lang BLE backends. Failure-Class: none * style(sdks): format device Dart/Python/Swift for CI Apply dart format (line-length 120), black, gofmt alignment, and swift-format so the Formatting gate passes. Failure-Class: none * chore(sdks): re-trigger CI after PR body invariant citation Failure-Class: none * fix(sdks): format device Dart for CI package-less dart Match dart format without package_config (CI only pub-gets app/). Failure-Class: none * fix(ci): green device SDK PR after main rebase Rebase onto main, restore Codemagic digests, format package-less Dart, black Python examples, and align desktop prod promotion policy with the collapsed Stable workflow from #10241. * fix(ci): match Codemagic digests and Dart line-length 120 Refresh approved Codemagic fixture digests to current codemagic.yaml (main fixture lag) and format device Dart with CI --line-length 120. * fix(sdks/device-ts): send Deepgram API key via token query param Stop assigning headers after WebSocket construction; standard browsers and many Node runtimes ignore it. Pass the key as a Deepgram-supported `token` query parameter so auth actually reaches the server. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks/device-dart): send Deepgram API key via token query param web_socket_channel cannot carry arbitrary Authorization headers on all platforms, so the previous constructor accepted an apiKey but never sent it. Wire the key through the documented `token` query parameter. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs(readme): remove duplicate MCP Server link Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * build(sdks/device-cpp): pin SimpleBLE via FetchContent with vendored override Replace the configure-time `git clone` with CMake FetchContent pinned to SimpleBLE v0.10.3 and add OMI_DEVICE_SIMPLEBLE_SOURCE_DIR so callers can opt into an explicit vendored dependency path. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks): authenticate Deepgram via headers in Dart and RN Use IOWebSocketChannel Authorization headers in the Dart device SDK instead of putting the API key in the WebSocket URL. Require createWebSocket on React Native so the default path cannot connect without auth headers. Failure-Class: none Co-authored-by: Cursor <cursoragent@cursor.com> * fix(sdks/ts): remove apiKey from Deepgram WS URL, add createWebSocket factory The token-in-URL query param leaks into server/proxy logs. Now: - deepgramWsUrl() returns token-free URL (sampleRate only) - deepgramWsUrlWithToken() preserved as deprecated fallback - createDeepgramTranscriber accepts optional createWebSocket factory (preferred path) or apiKey (deprecated, token-in-URL) - Tests cover both paths * fix(sdks/ts): require authenticated Deepgram transport Remove the token-in-URL fallback and require an injected authenticated WebSocket factory. Failure-Class: none * fix(sdks): deliver buffered Whisper transcript on stop Allow the terminal flush to emit its final transcript after stopping while keeping all subsequent PCM input disabled. Failure-Class: none --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 1 个月前 | |
fix(sdks/device): document codec 21 (opusFS320) and map it in every SDK `sdks/device` documented only codec ID 20 (Opus, DevKit) on the audio-codec characteristic, but shipping Omi CV1 firmware reports 21 (`omi/firmware/omi/src/lib/core/config.h:37`, vs 20 in `omi/firmware/devkit/src/config.h:37`). The concrete consequence: the TypeScript SDK's `mapCodecId()` returned the bare number `21` for every CV1 device instead of a named `BleAudioCodec` member, so callers had no way to identify the codec the device is actually streaming. The two Opus IDs are not interchangeable: 20 is 160-sample frames @ 100 fps, 21 is 320-sample frames @ 50 fps (per the app's `BleAudioCodec`, `app/lib/backend/schema/bt_device/bt_device.dart`), so a decoder that assumes 10 ms frames mis-times a CV1 stream. - `PROTOCOL.md`: add the codec-21 row, name the owning firmware per ID, record the frame duration/rate difference, and note that `OPUS_FRAME_SAMPLES = 960` is a decode buffer bound, not a wire frame size. - Go / TypeScript: add the codec-21 constant and handle it in `mapCodecId()`. - Rust / C++: add the codec-ID constants (neither exposed any), so all four thin SDKs carry the same map. Dart needs no change — its device SDK returns the raw codec byte and defers to the app's `BleAudioCodec`, which already has `opusFS320`. Tested (no physical CV1 attached; verified at the byte the characteristic returns, not over the radio): - `go vet ./... && go test ./...` in `sdks/device/go` — ok, incl. new `TestCodecIDs`; fails to build on the parent commit (`undefined: CodecOpusFS320`). - `bun test` in `sdks/device/typescript` — 11 pass / 0 fail, incl. new `src/index.test.ts`; on the parent commit `mapCodecId(21)` returns `21` instead of an enum member and the test fails. - `bunx tsc --noEmit` — clean. - `cargo test` in `sdks/device/rust` — 3 pass, incl. new `codec_ids`. - C++: `clang++ -std=c++17 -Wall -Wextra` against `protocol.hpp` with `static_assert`s on all four codec IDs — compiles and runs clean. Failure-Class: none fixes #11254 | 25 天前 | |
fix(sdks/device): document codec 21 (opusFS320) and map it in every SDK `sdks/device` documented only codec ID 20 (Opus, DevKit) on the audio-codec characteristic, but shipping Omi CV1 firmware reports 21 (`omi/firmware/omi/src/lib/core/config.h:37`, vs 20 in `omi/firmware/devkit/src/config.h:37`). The concrete consequence: the TypeScript SDK's `mapCodecId()` returned the bare number `21` for every CV1 device instead of a named `BleAudioCodec` member, so callers had no way to identify the codec the device is actually streaming. The two Opus IDs are not interchangeable: 20 is 160-sample frames @ 100 fps, 21 is 320-sample frames @ 50 fps (per the app's `BleAudioCodec`, `app/lib/backend/schema/bt_device/bt_device.dart`), so a decoder that assumes 10 ms frames mis-times a CV1 stream. - `PROTOCOL.md`: add the codec-21 row, name the owning firmware per ID, record the frame duration/rate difference, and note that `OPUS_FRAME_SAMPLES = 960` is a decode buffer bound, not a wire frame size. - Go / TypeScript: add the codec-21 constant and handle it in `mapCodecId()`. - Rust / C++: add the codec-ID constants (neither exposed any), so all four thin SDKs carry the same map. Dart needs no change — its device SDK returns the raw codec byte and defers to the app's `BleAudioCodec`, which already has `opusFS320`. Tested (no physical CV1 attached; verified at the byte the characteristic returns, not over the radio): - `go vet ./... && go test ./...` in `sdks/device/go` — ok, incl. new `TestCodecIDs`; fails to build on the parent commit (`undefined: CodecOpusFS320`). - `bun test` in `sdks/device/typescript` — 11 pass / 0 fail, incl. new `src/index.test.ts`; on the parent commit `mapCodecId(21)` returns `21` instead of an enum member and the test fails. - `bunx tsc --noEmit` — clean. - `cargo test` in `sdks/device/rust` — 3 pass, incl. new `codec_ids`. - C++: `clang++ -std=c++17 -Wall -Wextra` against `protocol.hpp` with `static_assert`s on all four codec IDs — compiles and runs clean. Failure-Class: none fixes #11254 | 25 天前 | |
test(sdks/device): assert the codec name binding, not the numeric value Review catch (cubic, PR #11256): TypeScript numeric enum members are plain numbers at runtime, so `expect(mapCodecId(21)).toBe(BleAudioCodec.OpusFs320)` is `21 === 21` — it passes even with the mapping removed. It only failed on the parent commit because the member did not exist yet (`undefined`), which makes it a one-shot assertion rather than a durable guard. Assert the reverse map instead (`BleAudioCodec[21] === 'OpusFs320'`), which is the actual contract this PR adds, and check `mapCodecId` resolves every known id to a *named* member while an unknown id stays unnamed. Two of the three tests now fail against the parent commit's `index.ts` (previously one), and both catch removal of the enum member. Nothing in TS can catch removal of only the `mapCodecId` branch — a bare `21` and `BleAudioCodec.OpusFs320` are the same runtime value. `bun test`: 12 pass / 0 fail. | 25 天前 | |
feat(sdks): multi-lang device SDKs (protocol + STT + BLE) (#10227) * feat(sdks): add multi-lang device BLE protocol packages Share Omi GATT UUIDs and audio packet framing across TypeScript, Go, Rust, C++, and Dart under sdks/device. Keep full BLE stacks in the existing Python/Swift/React Native packages; wire Python constants to the same protocol doc. Failure-Class: none * feat(sdks): add multi-engine STT parity across device SDKs Expose deepgram, whisper, and parakeet engines with the same PCM16/16k contract on Python, Swift, React Native, TypeScript, Go, Rust, Dart, and C++ helpers. Feature-gate Whisper runners and optional BLE/STT stacks where native deps are platform-specific. Failure-Class: none * feat(sdks/device-rust): add btleplug-backed BLE feature Failure-Class: none * feat(sdks/device-cpp): add optional SimpleBLE client Failure-Class: none Optional OMI_DEVICE_BLE CMake gate (default OFF) adds scan/listen over SimpleBLE using Omi service/audio UUIDs. FetchContent falls back with a clear warning if SimpleBLE is unavailable. * feat(sdks/device-dart): add flutter_blue_plus BLE client Failure-Class: none Wire OmiBleClient + FlutterBluePlusOmiBle (scan/connect/listenAudio/listenPayload/disconnect) using existing protocol UUIDs and stripPacketHeader. Package now depends on Flutter SDK + flutter_blue_plus; pure protocol/STT unit tests still pass via dart test. Verification: cd sdks/device/dart && flutter pub get && dart test → All tests passed! * feat(sdks/device-go): add feature-gated BLE scan/listen Failure-Class: none * feat(sdks/device-ts): add optional noble BLE transport Failure-Class: none * feat(sdks/device-dart): port app GATT map onto flutter_blue_plus BLE Use main-app UUID constants and Omi audio/codec/battery flows with flutter_blue_plus for third-party Flutter apps. Add Python bleak high-level scan/listen API and document multi-lang BLE backends. Failure-Class: none * style(sdks): format device Dart/Python/Swift for CI Apply dart format (line-length 120), black, gofmt alignment, and swift-format so the Formatting gate passes. Failure-Class: none * chore(sdks): re-trigger CI after PR body invariant citation Failure-Class: none * fix(sdks): format device Dart for CI package-less dart Match dart format without package_config (CI only pub-gets app/). Failure-Class: none * fix(ci): green device SDK PR after main rebase Rebase onto main, restore Codemagic digests, format package-less Dart, black Python examples, and align desktop prod promotion policy with the collapsed Stable workflow from #10241. * fix(ci): match Codemagic digests and Dart line-length 120 Refresh approved Codemagic fixture digests to current codemagic.yaml (main fixture lag) and format device Dart with CI --line-length 120. * fix(sdks/device-ts): send Deepgram API key via token query param Stop assigning headers after WebSocket construction; standard browsers and many Node runtimes ignore it. Pass the key as a Deepgram-supported `token` query parameter so auth actually reaches the server. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks/device-dart): send Deepgram API key via token query param web_socket_channel cannot carry arbitrary Authorization headers on all platforms, so the previous constructor accepted an apiKey but never sent it. Wire the key through the documented `token` query parameter. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs(readme): remove duplicate MCP Server link Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * build(sdks/device-cpp): pin SimpleBLE via FetchContent with vendored override Replace the configure-time `git clone` with CMake FetchContent pinned to SimpleBLE v0.10.3 and add OMI_DEVICE_SIMPLEBLE_SOURCE_DIR so callers can opt into an explicit vendored dependency path. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks): authenticate Deepgram via headers in Dart and RN Use IOWebSocketChannel Authorization headers in the Dart device SDK instead of putting the API key in the WebSocket URL. Require createWebSocket on React Native so the default path cannot connect without auth headers. Failure-Class: none Co-authored-by: Cursor <cursoragent@cursor.com> * fix(sdks/ts): remove apiKey from Deepgram WS URL, add createWebSocket factory The token-in-URL query param leaks into server/proxy logs. Now: - deepgramWsUrl() returns token-free URL (sampleRate only) - deepgramWsUrlWithToken() preserved as deprecated fallback - createDeepgramTranscriber accepts optional createWebSocket factory (preferred path) or apiKey (deprecated, token-in-URL) - Tests cover both paths * fix(sdks/ts): require authenticated Deepgram transport Remove the token-in-URL fallback and require an injected authenticated WebSocket factory. Failure-Class: none * fix(sdks): deliver buffered Whisper transcript on stop Allow the terminal flush to emit its final transcript after stopping while keeping all subsequent PCM input disabled. Failure-Class: none --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 1 个月前 | |
fix(sdks/device): document codec 21 (opusFS320) and map it in every SDK `sdks/device` documented only codec ID 20 (Opus, DevKit) on the audio-codec characteristic, but shipping Omi CV1 firmware reports 21 (`omi/firmware/omi/src/lib/core/config.h:37`, vs 20 in `omi/firmware/devkit/src/config.h:37`). The concrete consequence: the TypeScript SDK's `mapCodecId()` returned the bare number `21` for every CV1 device instead of a named `BleAudioCodec` member, so callers had no way to identify the codec the device is actually streaming. The two Opus IDs are not interchangeable: 20 is 160-sample frames @ 100 fps, 21 is 320-sample frames @ 50 fps (per the app's `BleAudioCodec`, `app/lib/backend/schema/bt_device/bt_device.dart`), so a decoder that assumes 10 ms frames mis-times a CV1 stream. - `PROTOCOL.md`: add the codec-21 row, name the owning firmware per ID, record the frame duration/rate difference, and note that `OPUS_FRAME_SAMPLES = 960` is a decode buffer bound, not a wire frame size. - Go / TypeScript: add the codec-21 constant and handle it in `mapCodecId()`. - Rust / C++: add the codec-ID constants (neither exposed any), so all four thin SDKs carry the same map. Dart needs no change — its device SDK returns the raw codec byte and defers to the app's `BleAudioCodec`, which already has `opusFS320`. Tested (no physical CV1 attached; verified at the byte the characteristic returns, not over the radio): - `go vet ./... && go test ./...` in `sdks/device/go` — ok, incl. new `TestCodecIDs`; fails to build on the parent commit (`undefined: CodecOpusFS320`). - `bun test` in `sdks/device/typescript` — 11 pass / 0 fail, incl. new `src/index.test.ts`; on the parent commit `mapCodecId(21)` returns `21` instead of an enum member and the test fails. - `bunx tsc --noEmit` — clean. - `cargo test` in `sdks/device/rust` — 3 pass, incl. new `codec_ids`. - C++: `clang++ -std=c++17 -Wall -Wextra` against `protocol.hpp` with `static_assert`s on all four codec IDs — compiles and runs clean. Failure-Class: none fixes #11254 | 25 天前 | |
feat(sdks): multi-lang device SDKs (protocol + STT + BLE) (#10227) * feat(sdks): add multi-lang device BLE protocol packages Share Omi GATT UUIDs and audio packet framing across TypeScript, Go, Rust, C++, and Dart under sdks/device. Keep full BLE stacks in the existing Python/Swift/React Native packages; wire Python constants to the same protocol doc. Failure-Class: none * feat(sdks): add multi-engine STT parity across device SDKs Expose deepgram, whisper, and parakeet engines with the same PCM16/16k contract on Python, Swift, React Native, TypeScript, Go, Rust, Dart, and C++ helpers. Feature-gate Whisper runners and optional BLE/STT stacks where native deps are platform-specific. Failure-Class: none * feat(sdks/device-rust): add btleplug-backed BLE feature Failure-Class: none * feat(sdks/device-cpp): add optional SimpleBLE client Failure-Class: none Optional OMI_DEVICE_BLE CMake gate (default OFF) adds scan/listen over SimpleBLE using Omi service/audio UUIDs. FetchContent falls back with a clear warning if SimpleBLE is unavailable. * feat(sdks/device-dart): add flutter_blue_plus BLE client Failure-Class: none Wire OmiBleClient + FlutterBluePlusOmiBle (scan/connect/listenAudio/listenPayload/disconnect) using existing protocol UUIDs and stripPacketHeader. Package now depends on Flutter SDK + flutter_blue_plus; pure protocol/STT unit tests still pass via dart test. Verification: cd sdks/device/dart && flutter pub get && dart test → All tests passed! * feat(sdks/device-go): add feature-gated BLE scan/listen Failure-Class: none * feat(sdks/device-ts): add optional noble BLE transport Failure-Class: none * feat(sdks/device-dart): port app GATT map onto flutter_blue_plus BLE Use main-app UUID constants and Omi audio/codec/battery flows with flutter_blue_plus for third-party Flutter apps. Add Python bleak high-level scan/listen API and document multi-lang BLE backends. Failure-Class: none * style(sdks): format device Dart/Python/Swift for CI Apply dart format (line-length 120), black, gofmt alignment, and swift-format so the Formatting gate passes. Failure-Class: none * chore(sdks): re-trigger CI after PR body invariant citation Failure-Class: none * fix(sdks): format device Dart for CI package-less dart Match dart format without package_config (CI only pub-gets app/). Failure-Class: none * fix(ci): green device SDK PR after main rebase Rebase onto main, restore Codemagic digests, format package-less Dart, black Python examples, and align desktop prod promotion policy with the collapsed Stable workflow from #10241. * fix(ci): match Codemagic digests and Dart line-length 120 Refresh approved Codemagic fixture digests to current codemagic.yaml (main fixture lag) and format device Dart with CI --line-length 120. * fix(sdks/device-ts): send Deepgram API key via token query param Stop assigning headers after WebSocket construction; standard browsers and many Node runtimes ignore it. Pass the key as a Deepgram-supported `token` query parameter so auth actually reaches the server. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks/device-dart): send Deepgram API key via token query param web_socket_channel cannot carry arbitrary Authorization headers on all platforms, so the previous constructor accepted an apiKey but never sent it. Wire the key through the documented `token` query parameter. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs(readme): remove duplicate MCP Server link Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * build(sdks/device-cpp): pin SimpleBLE via FetchContent with vendored override Replace the configure-time `git clone` with CMake FetchContent pinned to SimpleBLE v0.10.3 and add OMI_DEVICE_SIMPLEBLE_SOURCE_DIR so callers can opt into an explicit vendored dependency path. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks): authenticate Deepgram via headers in Dart and RN Use IOWebSocketChannel Authorization headers in the Dart device SDK instead of putting the API key in the WebSocket URL. Require createWebSocket on React Native so the default path cannot connect without auth headers. Failure-Class: none Co-authored-by: Cursor <cursoragent@cursor.com> * fix(sdks/ts): remove apiKey from Deepgram WS URL, add createWebSocket factory The token-in-URL query param leaks into server/proxy logs. Now: - deepgramWsUrl() returns token-free URL (sampleRate only) - deepgramWsUrlWithToken() preserved as deprecated fallback - createDeepgramTranscriber accepts optional createWebSocket factory (preferred path) or apiKey (deprecated, token-in-URL) - Tests cover both paths * fix(sdks/ts): require authenticated Deepgram transport Remove the token-in-URL fallback and require an injected authenticated WebSocket factory. Failure-Class: none * fix(sdks): deliver buffered Whisper transcript on stop Allow the terminal flush to emit its final transcript after stopping while keeping all subsequent PCM input disabled. Failure-Class: none --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 1 个月前 | |
feat(sdks): multi-lang device SDKs (protocol + STT + BLE) (#10227) * feat(sdks): add multi-lang device BLE protocol packages Share Omi GATT UUIDs and audio packet framing across TypeScript, Go, Rust, C++, and Dart under sdks/device. Keep full BLE stacks in the existing Python/Swift/React Native packages; wire Python constants to the same protocol doc. Failure-Class: none * feat(sdks): add multi-engine STT parity across device SDKs Expose deepgram, whisper, and parakeet engines with the same PCM16/16k contract on Python, Swift, React Native, TypeScript, Go, Rust, Dart, and C++ helpers. Feature-gate Whisper runners and optional BLE/STT stacks where native deps are platform-specific. Failure-Class: none * feat(sdks/device-rust): add btleplug-backed BLE feature Failure-Class: none * feat(sdks/device-cpp): add optional SimpleBLE client Failure-Class: none Optional OMI_DEVICE_BLE CMake gate (default OFF) adds scan/listen over SimpleBLE using Omi service/audio UUIDs. FetchContent falls back with a clear warning if SimpleBLE is unavailable. * feat(sdks/device-dart): add flutter_blue_plus BLE client Failure-Class: none Wire OmiBleClient + FlutterBluePlusOmiBle (scan/connect/listenAudio/listenPayload/disconnect) using existing protocol UUIDs and stripPacketHeader. Package now depends on Flutter SDK + flutter_blue_plus; pure protocol/STT unit tests still pass via dart test. Verification: cd sdks/device/dart && flutter pub get && dart test → All tests passed! * feat(sdks/device-go): add feature-gated BLE scan/listen Failure-Class: none * feat(sdks/device-ts): add optional noble BLE transport Failure-Class: none * feat(sdks/device-dart): port app GATT map onto flutter_blue_plus BLE Use main-app UUID constants and Omi audio/codec/battery flows with flutter_blue_plus for third-party Flutter apps. Add Python bleak high-level scan/listen API and document multi-lang BLE backends. Failure-Class: none * style(sdks): format device Dart/Python/Swift for CI Apply dart format (line-length 120), black, gofmt alignment, and swift-format so the Formatting gate passes. Failure-Class: none * chore(sdks): re-trigger CI after PR body invariant citation Failure-Class: none * fix(sdks): format device Dart for CI package-less dart Match dart format without package_config (CI only pub-gets app/). Failure-Class: none * fix(ci): green device SDK PR after main rebase Rebase onto main, restore Codemagic digests, format package-less Dart, black Python examples, and align desktop prod promotion policy with the collapsed Stable workflow from #10241. * fix(ci): match Codemagic digests and Dart line-length 120 Refresh approved Codemagic fixture digests to current codemagic.yaml (main fixture lag) and format device Dart with CI --line-length 120. * fix(sdks/device-ts): send Deepgram API key via token query param Stop assigning headers after WebSocket construction; standard browsers and many Node runtimes ignore it. Pass the key as a Deepgram-supported `token` query parameter so auth actually reaches the server. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks/device-dart): send Deepgram API key via token query param web_socket_channel cannot carry arbitrary Authorization headers on all platforms, so the previous constructor accepted an apiKey but never sent it. Wire the key through the documented `token` query parameter. Failure-Class: none Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs(readme): remove duplicate MCP Server link Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * build(sdks/device-cpp): pin SimpleBLE via FetchContent with vendored override Replace the configure-time `git clone` with CMake FetchContent pinned to SimpleBLE v0.10.3 and add OMI_DEVICE_SIMPLEBLE_SOURCE_DIR so callers can opt into an explicit vendored dependency path. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(sdks): authenticate Deepgram via headers in Dart and RN Use IOWebSocketChannel Authorization headers in the Dart device SDK instead of putting the API key in the WebSocket URL. Require createWebSocket on React Native so the default path cannot connect without auth headers. Failure-Class: none Co-authored-by: Cursor <cursoragent@cursor.com> * fix(sdks/ts): remove apiKey from Deepgram WS URL, add createWebSocket factory The token-in-URL query param leaks into server/proxy logs. Now: - deepgramWsUrl() returns token-free URL (sampleRate only) - deepgramWsUrlWithToken() preserved as deprecated fallback - createDeepgramTranscriber accepts optional createWebSocket factory (preferred path) or apiKey (deprecated, token-in-URL) - Tests cover both paths * fix(sdks/ts): require authenticated Deepgram transport Remove the token-in-URL fallback and require an injected authenticated WebSocket factory. Failure-Class: none * fix(sdks): deliver buffered Whisper transcript on stop Allow the terminal flush to emit its final transcript after stopping while keeping all subsequent PCM input disabled. Failure-Class: none --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> | 1 个月前 |
Omi Device SDKs (multi-language)
Portable device BLE protocol helpers for languages that do not yet have a full native BLE stack package.
Already-complete full device SDKs
| Path | Platform | Notes |
|---|---|---|
../python |
Desktop Python | bleak scan/listen + Opus decode + Deepgram |
../swift |
iOS/macOS | CoreBluetooth + codecs + Whisper |
../react-native |
iOS/Android | react-native-ble-plx |
New portable protocol packages
| Lang | Path | What you get |
|---|---|---|
| TypeScript | typescript/ |
UUIDs, header strip, transport interface |
| Go | go/ |
UUIDs + StripPacketHeader + optional BLE (-tags ble, tinygo bluetooth) |
| Rust | rust/ |
UUIDs + strip_packet_header |
| C++ | cpp/ |
UUIDs + StripPacketHeader |
| Dart | dart/ |
UUIDs + stripPacketHeader |
Protocol source of truth: PROTOCOL.md.
Why not full BLE clients in every language?
BLE stacks are OS-specific (CoreBluetooth, bluer/btleplug, WinRT, Web Bluetooth, noble). Shipping a production scanner in each language is a large ongoing surface. These packages share the Omi packet/GATT contract so native BLE code stays thin.
Full connect/listen loops remain in Python/Swift/RN (and the Flutter app). Wire your platform BLE library to AUDIO_DATA_UUID and strip headers with these helpers.
Opus decode
Python uses opuslib. Other languages should use the platform Opus decoder (libopus / audiopus / Flutter plugins). Header strip is identical everywhere.
STT engines
All languages expose the same engine names: deepgram, whisper, parakeet.
BLE backends (real libraries)
| Lang | Library | Gate |
|---|---|---|
| Python | bleak | always |
| Swift | CoreBluetooth | always |
| React Native | react-native-ble-plx | peer |
| TypeScript | @stoprocent/noble | optionalDependency |
| Go | tinygo.org/x/bluetooth | -tags ble |
| Rust | btleplug | feature ble |
| Dart | flutter_blue_plus (app UUID map) | Flutter package |
| C++ | SimpleBLE | -DOMI_DEVICE_BLE=ON |