Skip to content

Conversation

@yujonglee
Copy link
Contributor

@yujonglee yujonglee commented Dec 4, 2025

Summary

Adds a new GladiaAdapter for real-time speech-to-text using Gladia's WebSocket API. This implementation handles Gladia's two-step initialization flow:

  1. POST request to /v2/live with audio config to get a session token
  2. WebSocket connection using the token URL returned from step 1

Key changes:

  • New GladiaAdapter struct implementing RealtimeSttAdapter trait
  • Added build_ws_url_with_api_key optional method to RealtimeSttAdapter trait (with default fallback to build_ws_url)
  • Uses ureq for the blocking POST request (chosen over reqwest::blocking to avoid tokio runtime conflicts)
  • Supports native multichannel audio
  • Parses Gladia's transcript messages with word-level timing and confidence

Updates since last revision

Addressed review feedback:

  • Port preservation: Both live.rs and mod.rs now preserve non-standard ports when constructing URLs from api_base (e.g., http://localhost:8080 or https://api.gladia.io:8443)
  • Session registry for channel count: Added a static session_channels() registry that:
    • Stores channel count when session is initialized (keyed by session ID from POST response)
    • Looks up channel count in parse_transcript for accurate channel_index
    • Looks up and removes channel count in EndSession for TerminalResponse.channels
    • Falls back to inferring from channel_idx if session not found (with warning log)

Review & Testing Checklist for Human

  • Verify session ID consistency: The implementation assumes InitResponse.id matches EndSession.id and TranscriptMessage.session_id. Run with debug logging to confirm these IDs match in real Gladia traffic.
  • Test multichannel scenarios: Verify the session registry correctly tracks and returns channel count for dual-channel sessions. Run GLADIA_API_KEY=<key> cargo test -p owhisper-client gladia -- --ignored --nocapture
  • Verify trait change is backward compatible: The new build_ws_url_with_api_key method has a default implementation. Confirm no regressions in other adapters (Deepgram, AssemblyAI, Soniox).
  • Review ureq dependency addition: A new blocking HTTP client was added. Verify this is acceptable for the project.
  • Review session registry thread safety: The static map uses Mutex<HashMap> - verify this is appropriate for concurrent session handling.

Recommended test plan:

  1. Run the ignored tests with a valid Gladia API key (both single and dual channel)
  2. Verify existing adapters still work after the trait change
  3. Test in the actual desktop app if possible

Notes

  • Tests are marked #[ignore] since they require a real API key
  • The blocking HTTP approach using ureq was necessary because reqwest::blocking creates its own tokio runtime which panics when called from within an async test context
  • Session registry entries are removed on EndSession to prevent unbounded growth

Requested by: @yujonglee ([email protected])
Devin Session: https://app.devin.ai/sessions/f1fae0e50661471abba69597a3ad8b93

@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Dec 4, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit b89d4a1
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/693190c3f08d7c0008adaa5a
😎 Deploy Preview https://deploy-preview-2115--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Dec 4, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit b89d4a1
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/693190c3dd91140008da5630
😎 Deploy Preview https://deploy-preview-2115--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

📝 Walkthrough

Walkthrough

Adds a Gladia realtime STT adapter: WebSocket URL/auth construction (with API-key and proxy support), an HTTP init handshake to obtain a session URL, native multi-channel support, comprehensive serde types for Gladia messages, transcript parsing into internal StreamResponse events, and trait implementations plus tests.

Changes

Cohort / File(s) Summary
Adapter registry
owhisper/owhisper-client/src/adapter/mod.rs
Adds mod gladia; and pub use gladia::*;. Extends RealtimeSttAdapter with default build_ws_url_with_api_key(...).
Gladia adapter core
owhisper/owhisper-client/src/adapter/gladia/mod.rs
New GladiaAdapter struct, host detection helpers, DEFAULT_API_HOST/WS_PATH constants, and build_ws_url_from_base(api_base) that parses base URL, preserves query params, selects scheme (ws/wss), handles proxy; includes unit tests.
Gladia live implementation
owhisper/owhisper-client/src/adapter/gladia/live.rs
Implements RealtimeSttAdapter for GladiaAdapter: provider identity, native multichannel support, WS URL construction (with/without API key), auth header, keep-alive/initial/finalize messages, HTTP POST init handshake to obtain session URL, many serde structs/enums for Gladia messages, parse_transcript and parse_response converting Gladia messages into internal StreamResponse, and ignored integration tests.
Client wiring
owhisper/owhisper-client/src/lib.rs
Uses build_ws_url_with_api_key(...) (falls back to build_ws_url) when constructing the WebSocket URL to allow adapters to embed API keys.
Dependencies
owhisper/owhisper-client/Cargo.toml
Adds ureq = { version = "2", features = ["json"] } for the HTTP init handshake JSON requests.

Sequence Diagram(s)

sequenceDiagram
    participant Local as Local Client
    participant Adapter as GladiaAdapter
    participant InitAPI as Gladia REST Init
    participant WS as Gladia WebSocket
    participant Parser as Adapter Parser

    Local->>Adapter: build_ws_url_with_api_key(api_base, params, channels, api_key)
    Adapter->>InitAPI: HTTP POST /v2/live (GladiaConfig JSON)
    alt init success
        InitAPI-->>Adapter: 200 OK with session_url
        Adapter->>WS: Open WebSocket to session_url (or built URL)
        loop audio frames
            Local->>WS: send audio frames (binary)
            WS-->>Parser: JSON messages (Transcript, SpeechStart, SpeechEnd, Error, EndSession)
            Parser-->>Local: StreamResponse events (partials/finals, metadata)
        end
        WS-->>Local: EndSession
    else init failure
        InitAPI-->>Adapter: error response
        Adapter-->>Local: StreamResponse::Error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect serde types and variant handling for robustness to unknown/partial payloads (GladiaMessage, nested structs).
  • Review the HTTP init handshake (ureq) error handling and extraction of session_url.
  • Validate WebSocket URL construction: proxy handling, query-param preservation, scheme selection, and API-key embedding logic.
  • Verify transcript -> StreamResponse mapping: timestamps, channel assignment, word-level metadata and final/partial flags.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a Gladia adapter for real-time speech-to-text functionality.
Description check ✅ Passed The pull request description clearly relates to the changeset, explaining the new GladiaAdapter implementation, its integration with the RealtimeSttAdapter trait, and specific technical details about the two-step initialization flow.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1764853636-gladia-realtime-stt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
owhisper/owhisper-client/src/adapter/gladia/live.rs (1)

80-81: Consider handling serialization failure gracefully.

While serde_json::to_string rarely fails for simple structs, using .unwrap() could panic in edge cases. Consider logging and returning None on failure for robustness.

-        let json = serde_json::to_string(&cfg).unwrap();
-        Some(Message::Text(json.into()))
+        match serde_json::to_string(&cfg) {
+            Ok(json) => Some(Message::Text(json.into())),
+            Err(e) => {
+                tracing::error!(error = ?e, "gladia_config_serialization_failed");
+                None
+            }
+        }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45a239e and a0fe0a6.

📒 Files selected for processing (3)
  • owhisper/owhisper-client/src/adapter/gladia/live.rs (1 hunks)
  • owhisper/owhisper-client/src/adapter/gladia/mod.rs (1 hunks)
  • owhisper/owhisper-client/src/adapter/mod.rs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
owhisper/owhisper-client/src/adapter/gladia/mod.rs (1)
owhisper/owhisper-client/src/adapter/mod.rs (4)
  • host_matches (102-107)
  • build_proxy_ws_url (117-138)
  • extract_query_params (84-88)
  • is_local_host (80-82)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Redirect rules - hyprnote-storybook
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Header rules - hyprnote-storybook
  • GitHub Check: Pages changed - hyprnote-storybook
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: Devin
🔇 Additional comments (6)
owhisper/owhisper-client/src/adapter/mod.rs (1)

6-6: LGTM!

The module declaration and re-export follow the established pattern for other adapters in this file.

Also applies to: 18-18

owhisper/owhisper-client/src/adapter/gladia/mod.rs (1)

10-12: Verify: is_supported_languages always returns true.

This always returns true regardless of the languages provided. If this is intentional (Gladia supports all languages), consider adding a brief comment. Otherwise, implement actual language validation.

owhisper/owhisper-client/src/adapter/gladia/live.rs (4)

10-30: LGTM!

The provider identity, multichannel support flag, and WebSocket URL construction with query parameter preservation are correctly implemented.


128-157: LGTM!

Configuration structs are well-designed with appropriate skip_serializing_if annotations and the untagged enum for polymorphic language configuration.


159-196: LGTM!

The GladiaMessage enum with tagged discriminant and #[serde(other)] for unknown messages provides robust message parsing with good forward compatibility.


302-339: LGTM!

Tests are appropriately marked as #[ignore] since they require a GLADIA_API_KEY environment variable and make actual API calls. The test structure follows the patterns established by other adapters.

devin-ai-integration bot and others added 2 commits December 4, 2025 13:27
- Add build_ws_url_with_api_key method to RealtimeSttAdapter trait
- Use ureq for blocking POST request to get session token
- Fix language_config format to use object with languages array
- Return None for build_auth_header since token is in URL

Co-Authored-By: yujonglee <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
owhisper/owhisper-client/src/adapter/gladia/live.rs (2)

148-171: Channel count in TerminalResponse is still hardcoded to 1.

StreamResponse::TerminalResponse { channels: 1, .. } doesn’t reflect actual channel count for multichannel sessions; it should ideally come from the same channel configuration used when opening the session (or from session metadata), with a sane fallback.

This has already been flagged in a prior review; reiterating here for visibility.


301-357: channel_index total is hardcoded to 1; doesn’t match multichannel semantics.

channel_index: vec![channel_idx, 1] hardcodes the “total channels” element to 1, even though this adapter advertises native multichannel support and sends a channels value in the init body. Ideally the total should reflect the actual configured number of channels (e.g., from session state or the init config), or this limitation should be explicitly documented.

This is the same issue previously called out in earlier review feedback.

🧹 Nitpick comments (5)
owhisper/owhisper-client/Cargo.toml (1)

16-16: Consider whether you really need both reqwest and ureq.

You now pull in two HTTP clients (reqwest and ureq), which increases binary size and maintenance surface. If you don’t have a strong reason to keep both (e.g., sync vs async constraints), it may be cleaner to standardize on one.

owhisper/owhisper-client/src/adapter/gladia/live.rs (4)

32-125: Be explicit about behavior when api_key is missing or init fails.

Right now, if there’s no api_key or the /v2/live init fails, this method returns None, and the caller silently falls back to build_ws_url, which for Gladia likely won’t work anyway. That makes configuration or network errors harder to diagnose.

Consider either:

  • Treating a missing key as a hard configuration error for direct Gladia usage (e.g., log a clear error and perhaps return Some(fallback_url) only for proxy cases), or
  • Returning a URL only when init succeeds and making the fallback path clearly “best-effort / not supported for Gladia” in comments.

This will make failures easier to reason about when things go wrong in production.


95-121: Blocking ureq call in URL builder may be surprising.

build_ws_url_with_api_key performs a synchronous HTTP request with ureq as part of building the WebSocket URL. If ListenClientBuilder::build_* is called on an async runtime’s main thread, this can block the reactor and add connection latency.

If possible, consider:

  • Moving the /v2/live init into an async path using your existing HTTP client (reqwest) and passing the resulting URL into the builder, or
  • At least documenting that this call is blocking and should be run off the main async task if that’s a concern for your consumers.

306-343: Consider logging hygiene for transcript payloads.

tracing::debug!(transcript = %utterance.text, ...) logs full user transcripts, which may contain sensitive content. For production builds, that can be problematic unless logs are tightly controlled.

You might want to:

  • Redact or truncate transcript text in logs, or
  • Guard this with a feature flag or higher log level used only in local debugging.

361-397: Ignored integration tests are a good start; consider documenting how to run them.

The ignored tests for single and dual Gladia clients look useful for manual verification. It could help future maintainers to:

  • Add a short comment explaining these require GLADIA_API_KEY and real network access, and/or
  • Provide a brief note in your README or dev docs describing how to opt-in to running these tests.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0fe0a6 and 59ea40c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • owhisper/owhisper-client/Cargo.toml (1 hunks)
  • owhisper/owhisper-client/src/adapter/gladia/live.rs (1 hunks)
  • owhisper/owhisper-client/src/adapter/mod.rs (3 hunks)
  • owhisper/owhisper-client/src/lib.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • owhisper/owhisper-client/src/adapter/mod.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: Devin
🔇 Additional comments (1)
owhisper/owhisper-client/src/lib.rs (1)

72-78: URL construction change looks correct and remains backward compatible.

Using build_ws_url_with_api_key(..., api_key) with a fallback to build_ws_url cleanly extends adapters that need an API-key-aware handshake (like Gladia) while keeping existing adapters unaffected.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
owhisper/owhisper-client/Cargo.toml (1)

18-18: Consider pinning to a more specific version.

The current constraint "2" allows any version from 2.0.0 to 2.x.x. For reproducibility and to avoid surprise breaking changes in minor/patch updates, consider pinning to a specific version (e.g., "2.1.0" or the latest stable 2.x release).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 59ea40c and 5a05cc7.

📒 Files selected for processing (1)
  • owhisper/owhisper-client/Cargo.toml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: Devin

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
owhisper/owhisper-client/src/adapter/gladia/live.rs (1)

167-175: Hardcoded channels: 1 in TerminalResponse.

The channels field is hardcoded to 1, which will be incorrect for multichannel sessions. Since the adapter supports native multichannel (line 15-17), the terminal response should reflect the actual channel count.

Consider passing the channel count through the adapter state or session context:

             GladiaMessage::EndSession { id } => {
                 tracing::debug!(session_id = %id, "gladia_session_ended");
+                // TODO: Retrieve actual channel count from session state
                 vec![StreamResponse::TerminalResponse {
                     request_id: id,
                     created: String::new(),
                     duration: 0.0,
-                    channels: 1,
+                    channels: 1, // FIXME: Should be actual channel count from session
                 }]
             }
owhisper/owhisper-client/src/adapter/gladia/mod.rs (1)

22-54: Multiple panic points on invalid input.

The function uses .expect() at lines 27, 36, and 52, which will panic if URLs are malformed. Since api_base comes from user configuration, this could crash the application.

Consider returning a Result or using fallback to default URL:

-    pub(crate) fn build_ws_url_from_base(api_base: &str) -> (url::Url, Vec<(String, String)>) {
+    pub(crate) fn build_ws_url_from_base(api_base: &str) -> Result<(url::Url, Vec<(String, String)>), String> {
         if api_base.is_empty() {
             return (
                 format!("wss://{}{}", DEFAULT_API_HOST, WS_PATH)
-                    .parse()
-                    .expect("invalid_default_ws_url"),
+                    .parse()
+                    .map_err(|e| format!("invalid_default_ws_url: {}", e))?,
                 Vec::new(),
             );
         }

         if let Some(proxy_result) = super::build_proxy_ws_url(api_base) {
-            return proxy_result;
+            return Ok(proxy_result);
         }

-        let parsed: url::Url = api_base.parse().expect("invalid_api_base");
+        let parsed: url::Url = api_base.parse().map_err(|e| format!("invalid_api_base: {}", e))?;
         let existing_params = super::extract_query_params(&parsed);

         let host = parsed.host_str().unwrap_or(DEFAULT_API_HOST);
         let scheme = if super::is_local_host(host) {
             "ws"
         } else {
             "wss"
         };
         let host_with_port = match parsed.port() {
             Some(port) => format!("{host}:{port}"),
             None => host.to_string(),
         };

         let url: url::Url = format!("{scheme}://{host_with_port}{WS_PATH}")
-            .parse()
-            .expect("invalid_ws_url");
-        (url, existing_params)
+            .parse()
+            .map_err(|e| format!("invalid_ws_url: {}", e))?;
+        Ok((url, existing_params))
     }
🧹 Nitpick comments (2)
owhisper/owhisper-client/src/adapter/gladia/mod.rs (2)

18-20: Consider more specific host validation.

The substring check host.contains("gladia.io") could match malicious domains like "gladia.io.attacker.com". Consider checking for exact match or proper domain suffix.

Apply this diff for more secure host matching:

-    pub(crate) fn is_gladia_host(host: &str) -> bool {
-        host.contains("gladia.io")
-    }
+    pub(crate) fn is_gladia_host(host: &str) -> bool {
+        host == "gladia.io" || host == "api.gladia.io" || host.ends_with(".gladia.io")
+    }

10-12: Document the language support assumption or add validation if needed.

Gladia's Live WebSocket API supports 100+ languages, making the unconditional true return reasonable in practice. However, the underscore-prefixed parameter suggests the languages aren't being validated. Consider whether this is intentional (trusting Gladia's broad support) and document it, or add explicit language validation if there are actual restrictions. For context, DeepgramAdapter::is_supported_languages validates against a SUPPORTED_LANGUAGES constant, offering a more defensive approach.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a05cc7 and d337347.

📒 Files selected for processing (2)
  • owhisper/owhisper-client/src/adapter/gladia/live.rs (1 hunks)
  • owhisper/owhisper-client/src/adapter/gladia/mod.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
owhisper/owhisper-client/src/adapter/gladia/mod.rs (1)
owhisper/owhisper-client/src/adapter/mod.rs (4)
  • host_matches (112-117)
  • build_proxy_ws_url (127-148)
  • extract_query_params (94-98)
  • is_local_host (90-92)
owhisper/owhisper-client/src/adapter/gladia/live.rs (1)
owhisper/owhisper-client/src/adapter/gladia/mod.rs (1)
  • build_ws_url_from_base (22-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Redirect rules - hyprnote-storybook
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Header rules - hyprnote-storybook
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: Pages changed - hyprnote-storybook
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: fmt
  • GitHub Check: Devin
🔇 Additional comments (8)
owhisper/owhisper-client/src/adapter/gladia/mod.rs (2)

1-7: LGTM!

The module structure and struct definition are clean and appropriate for the adapter pattern.


57-101: Tests look good but need update if error handling changes.

The test coverage is comprehensive, covering various URL formats including empty, standard, with port, proxy, and localhost. However, if build_ws_url_from_base is changed to return Result (as suggested above), these tests will need to be updated to unwrap the Result.

owhisper/owhisper-client/src/adapter/gladia/live.rs (6)

1-9: LGTM!

Imports are clean and appropriate for the implementation.


19-30: Depends on panic-prone build_ws_url_from_base.

This method calls Self::build_ws_url_from_base which can panic on invalid URLs (flagged in mod.rs). Ensure that issue is resolved to prevent runtime crashes.


32-129: LGTM! Two-step authentication flow correctly implemented.

The function properly implements Gladia's recommended flow: (1) POST to /v2/live with API key to obtain session URL, (2) return the session URL for client connection. Error handling with tracing logs is appropriate.


131-150: LGTM!

The trait methods are correctly implemented for Gladia's protocol. Authentication via session URL (not headers), no keep-alive or initial messages needed, and proper finalization message.


192-303: LGTM!

The data structures are well-designed with appropriate serde attributes for JSON serialization/deserialization. The use of #[serde(default)], tagged enums, and fallback variants demonstrates good API integration practices.


369-406: LGTM!

Tests are properly structured and marked with #[ignore] since they require a real API key. Good coverage of both single and dual-channel scenarios.

@yujonglee yujonglee merged commit 3c913f8 into main Dec 4, 2025
15 checks passed
@yujonglee yujonglee deleted the devin/1764853636-gladia-realtime-stt branch December 4, 2025 13:53
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