Skip to content

feat: support for agent v1 #520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 5, 2025
Merged

feat: support for agent v1 #520

merged 11 commits into from
May 5, 2025

Conversation

naomi-lgbt
Copy link
Contributor

@naomi-lgbt naomi-lgbt commented Apr 28, 2025

Proposed changes

Types of changes

What types of changes does your code introduce to the community Python SDK?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update or tests (if none of the other choices apply)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • I have read the CONTRIBUTING doc
  • I have lint'ed all of my code using repo standards
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

Summary by CodeRabbit

  • New Features
    • Added a new example script demonstrating how to use the voice agent without microphone input, including audio streaming and event handling.
  • Improvements
    • Enhanced agent configuration options with more detailed settings for listening, thinking, speaking, language preferences, and greetings.
    • Expanded support for custom endpoints, provider models, and voice/language configurations in agent setup.
    • Updated agent WebSocket endpoint to a new versioned path for improved communication.
  • Bug Fixes
    • Updated event and option names for clarity and consistency across the agent interface.
    • Renamed fields and enum members for better alignment with updated naming conventions.
  • Documentation
    • Added detailed instructions for building and installing the package locally.
  • Chores
    • Updated .gitignore to exclude generated audio and chat log files.
    • Added the requests library to example dependencies.

Copy link
Contributor

coderabbitai bot commented Apr 28, 2025

## Walkthrough

This update introduces a comprehensive refactor and enhancement of the agent-related configuration and client code within the Deepgram SDK. Key changes include the renaming and restructuring of configuration classes (e.g., `SettingsConfigurationOptions` to `SettingsOptions`, `UpdateInstructionsOptions` to `UpdatePromptOptions`), the introduction of new provider abstractions (`ListenProvider`, `SpeakProvider`, `ThinkProvider`), and the addition of an `Endpoint` class for custom HTTP endpoints. Enum members and event names are updated to match the new terminology. Example scripts are revised to use the new configuration schema, and a new example demonstrates agent usage without a microphone. Documentation and ignore rules are also updated.

## Changes

| Files/Paths                                                                                   | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
|-----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `.github/CONTRIBUTING.md`                                                                     | Added a "Building Locally" section with step-by-step instructions for building and installing the package using `pipenv`, including running an example script.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `.gitignore`                                                                                  | Added ignore patterns for `chatlog.txt` and `output_*.wav` files generated by examples.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `examples/requirements-examples.txt`                                                          | Added `requests` package to the example requirements.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `deepgram/__init__.py`, `deepgram/client.py`, `deepgram/clients/__init__.py`,<br>`deepgram/clients/agent/__init__.py`, `deepgram/clients/agent/v1/__init__.py`,<br>`deepgram/clients/agent/v1/websocket/__init__.py` | Refactored imports to replace `SettingsConfigurationOptions`/`UpdateInstructionsOptions` with `SettingsOptions`/`UpdatePromptOptions`, removed `Provider`/`Context`, and added new provider classes and `Endpoint`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `deepgram/clients/agent/enums.py`                                                             | Renamed enum members: `SettingsConfiguration``Settings`, `UpdateInstructions``UpdatePrompt` in `AgentWebSocketEvents`. Removed `FunctionCalling` member.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `deepgram/clients/agent/v1/websocket/options.py`                                              | Major refactor: replaced/renamed configuration dataclasses (`SettingsConfigurationOptions``SettingsOptions`, etc.), introduced new provider classes (`ListenProvider`, `SpeakProvider`, `ThinkProvider`), added `Endpoint` and `CartesiaVoice`, restructured `Listen`, `Speak`, `Think`, `Agent`, and `Language` classes, and updated deserialization logic.                                                                                                                                                                                                                                                                                                                                                                   |
| `deepgram/clients/agent/v1/websocket/async_client.py`,<br>`deepgram/clients/agent/v1/websocket/client.py` | Updated all type annotations, method signatures, and settings handling to use `SettingsOptions` instead of `SettingsConfigurationOptions`, changed endpoint to `"v1/agent/converse"`, updated nested attribute access for provider settings, removed `FunctionCalling` handling, and revised logging/error messages to new terminology.                                                                                                                                                                                                                                                                                                                                                                                        |
| `deepgram/clients/agent/client.py`                                                            | Updated import aliases to match new provider and options class names.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `deepgram/clients/agent/v1/websocket/response.py`                                            | Removed `FunctionCalling` dataclass and related comments. Renamed `WelcomeResponse.session_id` to `request_id`. Added note that `AgentThinkingResponse` is only received if `experimental` flag is true.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `examples/agent/simple/main.py`, `examples/agent/async_simple/main.py`                        | Refactored example scripts to use `SettingsOptions` and updated configuration structure to match new schema (e.g., nested `provider`, renamed `instructions` to `prompt`, added `greeting`, `language`, etc.). Removed `FunctionCalling` event handling.                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `examples/agent/no_mic/main.py`                                                               | Added a new example script demonstrating agent usage without microphone input, including detailed agent configuration, event handling, audio file streaming, and chat logging.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant UserScript
    participant DeepgramClient
    participant AgentWebSocketClient
    participant AgentProvider

    UserScript->>DeepgramClient: Initialize with API key and options
    UserScript->>AgentWebSocketClient: Connect with SettingsOptions
    AgentWebSocketClient->>AgentProvider: Send Settings (with nested provider config)
    AgentProvider-->>AgentWebSocketClient: Acknowledge settings
    UserScript->>AgentWebSocketClient: Register event handlers
    UserScript->>AgentWebSocketClient: Stream audio data (if applicable)
    AgentWebSocketClient->>AgentProvider: Transmit audio/data/events
    AgentProvider-->>AgentWebSocketClient: Emit events (audio, text, state)
    AgentWebSocketClient-->>UserScript: Invoke registered handlers with event data
    UserScript->>AgentWebSocketClient: Close connection

Possibly related PRs

Suggested reviewers

  • jpvajda
  • SandraRodgers

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=deepgram/deepgram-python-sdk&utm_content=520):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

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

🔭 Outside diff range comments (1)
deepgram/clients/agent/v1/websocket/client.py (1)

181-189: 🛠️ Refactor suggestion

start() rejects None for options, breaking previous behaviour

options is declared as Optional[SettingsOptions], but the subsequent isinstance / elif chain ends with an unconditional else: raise DeepgramError("Invalid options type").
Passing None – which used to be valid for callers that wanted to send the Settings message later – will now raise an exception and make the call site fail at runtime.

If None is no longer acceptable, the type hint should be changed to SettingsOptions (non-optional) and the docstring updated.
If None should stay legal, add an early guard and skip the type-based conversion instead of raising.

-        options: Optional[SettingsOptions] = None,
+        # `None` means: “I will send the Settings message manually later”.
+        options: Optional[SettingsOptions] = None,
...
-        else:
-            raise DeepgramError("Invalid options type")
+        elif options is None:
+            self._logger.notice("No SettingsOptions supplied – caller will send later")
+            self._settings = None
+        else:
+            raise DeepgramError(
+                f"Invalid options type {type(options).__name__}; "
+                "expected SettingsOptions | dict | str | None"
+            )

Also applies to: 199-204

🧹 Nitpick comments (6)
deepgram/clients/__init__.py (1)

367-382: Provider model refactored with granular provider types

The agent configuration has been refactored from a general-purpose Provider class to specific provider types (ListenProvider, SpeakProvider, ThinkProvider) and a new Endpoint abstraction.

This change provides better separation of concerns and more explicit configuration options for each capability of the agent. The granular provider model allows for more targeted configuration and clearer API boundaries.

deepgram/clients/agent/v1/websocket/client.py (2)

229-231: Safety check can dereference None when model is missing

self._settings.agent.listen.provider is guaranteed by defaults, but model
may still be None if the caller intentionally leaves it unset (e.g. to let
the server decide).
The current condition:

if self._settings.agent.listen.provider.keyterms is not None and \
   self._settings.agent.listen.provider.model is not None and \
   not self._settings.agent.listen.provider.model.startswith("nova-3"):

will raise AttributeError if provider itself is None (possible if a
malformed payload sneaks through from_dict). A defensive guard eliminates the
risk.

-if self._settings.agent.listen.provider.keyterms is not None and \
-   self._settings.agent.listen.provider.model is not None and \
-   not self._settings.agent.listen.provider.model.startswith("nova-3"):
+listen_provider = getattr(self._settings.agent.listen, "provider", None)
+if (
+    listen_provider
+    and listen_provider.keyterms
+    and listen_provider.model
+    and not listen_provider.model.startswith("nova-3")
+):

191-197: Consider redacting sensitive data in INFO logs

self._logger.info("settings: %s", options) prints the entire Settings object,
which may contain organisation-specific prompts, model identifiers or future
secret fields. Moving this to DEBUG, or implementing a redaction helper (e.g.
masking long strings), protects users who run the SDK with verbose logging in
production.

deepgram/clients/agent/v1/websocket/options.py (3)

215-223: SpeakProvider.__getitem__ assumes lists for voice / language, conflicting with schema

voice is a singular CartesiaVoice instance, and language /
language_code are strings, but the getter transforms them into lists. This
breaks symmetry (SpeakProvider.from_dict(...).voice returns list, not
CartesiaVoice) and surprises downstream consumers.

-        if "voice" in _dict:
-            _dict["voice"] = [
-                CartesiaVoice.from_dict(voice) for voice in _dict["voice"]
-            ]
-        if "language" in _dict:
-            _dict["language"] = [str(language) for language in _dict["language"]]
+        if "voice" in _dict and isinstance(_dict["voice"], dict):
+            _dict["voice"] = CartesiaVoice.from_dict(_dict["voice"])

(The same pattern occurs in Think, Listen, and Speak classes and could be
refactored via a helper.)


78-81: Endpoint.method is Optional[str] but default is "POST"

Either drop Optional (preferred) or make the default None. Staying
consistent avoids accidental None assignment later.


364-370: Language dataclass shadows the built-in type keyword

Although legal, using the attribute name type invites confusion with
Python’s built-in. Consider renaming to code or lang for clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e48e415 and 7ad48ea.

📒 Files selected for processing (14)
  • .github/CONTRIBUTING.md (1 hunks)
  • deepgram/__init__.py (1 hunks)
  • deepgram/client.py (1 hunks)
  • deepgram/clients/__init__.py (1 hunks)
  • deepgram/clients/agent/__init__.py (1 hunks)
  • deepgram/clients/agent/client.py (2 hunks)
  • deepgram/clients/agent/enums.py (1 hunks)
  • deepgram/clients/agent/v1/__init__.py (1 hunks)
  • deepgram/clients/agent/v1/websocket/__init__.py (1 hunks)
  • deepgram/clients/agent/v1/websocket/async_client.py (7 hunks)
  • deepgram/clients/agent/v1/websocket/client.py (7 hunks)
  • deepgram/clients/agent/v1/websocket/options.py (7 hunks)
  • examples/agent/async_simple/main.py (2 hunks)
  • examples/agent/simple/main.py (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
deepgram/clients/agent/v1/websocket/__init__.py (2)
Learnt from: dvonthenen
PR: deepgram/deepgram-python-sdk#426
File: deepgram/clients/listen/v1/websocket/__init__.py:8-8
Timestamp: 2024-07-01T19:21:39.778Z
Learning: Unused imports in `deepgram/clients/listen/v1/websocket/__init__.py` are retained to maintain backward compatibility and should not be flagged for removal in reviews.
Learnt from: dvonthenen
PR: deepgram/deepgram-python-sdk#426
File: deepgram/clients/listen/v1/websocket/__init__.py:8-8
Timestamp: 2024-10-09T02:19:46.086Z
Learning: Unused imports in `deepgram/clients/listen/v1/websocket/__init__.py` are retained to maintain backward compatibility and should not be flagged for removal in reviews.
🧬 Code Graph Analysis (7)
deepgram/client.py (1)
deepgram/clients/agent/v1/websocket/options.py (13)
  • SettingsOptions (373-404)
  • UpdatePromptOptions (411-417)
  • Listen (257-270)
  • ListenProvider (145-160)
  • Speak (274-294)
  • SpeakProvider (177-223)
  • Header (21-27)
  • Function (94-127)
  • Think (227-253)
  • ThinkProvider (164-173)
  • Agent (298-318)
  • Audio (346-360)
  • Endpoint (73-90)
deepgram/clients/agent/v1/websocket/__init__.py (1)
deepgram/clients/agent/v1/websocket/options.py (13)
  • SettingsOptions (373-404)
  • UpdatePromptOptions (411-417)
  • Listen (257-270)
  • ListenProvider (145-160)
  • Speak (274-294)
  • SpeakProvider (177-223)
  • Header (21-27)
  • Function (94-127)
  • Think (227-253)
  • ThinkProvider (164-173)
  • Agent (298-318)
  • Audio (346-360)
  • Endpoint (73-90)
deepgram/__init__.py (1)
deepgram/clients/agent/v1/websocket/options.py (22)
  • SettingsOptions (373-404)
  • UpdatePromptOptions (411-417)
  • UpdateSpeakOptions (424-430)
  • InjectAgentMessageOptions (437-443)
  • FunctionCallResponse (450-457)
  • AgentKeepAlive (464-469)
  • Listen (257-270)
  • ListenProvider (145-160)
  • Speak (274-294)
  • SpeakProvider (177-223)
  • Header (21-27)
  • Item (31-37)
  • Properties (41-52)
  • Parameters (56-69)
  • Function (94-127)
  • Think (227-253)
  • ThinkProvider (164-173)
  • Agent (298-318)
  • Input (322-328)
  • Output (332-342)
  • Audio (346-360)
  • Endpoint (73-90)
deepgram/clients/agent/v1/websocket/async_client.py (3)
deepgram/clients/agent/v1/websocket/options.py (3)
  • SettingsOptions (373-404)
  • UpdatePromptOptions (411-417)
  • check (391-404)
deepgram/utils/verboselogs/__init__.py (1)
  • notice (150-153)
deepgram/clients/common/v1/websocket_response.py (1)
  • ErrorResponse (41-51)
deepgram/clients/agent/v1/__init__.py (1)
deepgram/clients/agent/v1/websocket/options.py (13)
  • SettingsOptions (373-404)
  • UpdatePromptOptions (411-417)
  • Listen (257-270)
  • ListenProvider (145-160)
  • Speak (274-294)
  • SpeakProvider (177-223)
  • Header (21-27)
  • Function (94-127)
  • Think (227-253)
  • ThinkProvider (164-173)
  • Agent (298-318)
  • Audio (346-360)
  • Endpoint (73-90)
deepgram/clients/agent/v1/websocket/client.py (3)
deepgram/clients/agent/v1/websocket/options.py (3)
  • SettingsOptions (373-404)
  • UpdatePromptOptions (411-417)
  • check (391-404)
deepgram/utils/verboselogs/__init__.py (1)
  • notice (150-153)
deepgram/clients/common/v1/websocket_response.py (1)
  • ErrorResponse (41-51)
deepgram/clients/agent/v1/websocket/options.py (2)
deepgram/clients/common/v1/shared_response.py (1)
  • BaseResponse (16-44)
deepgram/clients/agent/enums.py (1)
  • AgentWebSocketEvents (10-37)
🪛 GitHub Actions: Check - static
deepgram/clients/agent/v1/websocket/options.py

[error] 136-136: mypy: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]


[error] 139-139: mypy: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]

🔇 Additional comments (24)
.github/CONTRIBUTING.md (1)

51-65: Great addition of building documentation!

The new "Building Locally" section provides clear step-by-step instructions for contributors to build and test the package. This is particularly valuable given the extensive refactoring of agent-related classes and options introduced in this PR.

deepgram/clients/agent/enums.py (1)

32-33: Renamed WebSocket events for consistency with option classes

These enum value renamings align with the broader restructuring of agent configuration classes in this PR:

  • SettingsConfigurationSettings (matches SettingsOptions)
  • UpdateInstructionsUpdatePrompt (matches UpdatePromptOptions)

This is a breaking change as noted in the PR description, but improves API consistency.

deepgram/client.py (1)

350-352: Updated imports to match agent v1 provider architecture

These import changes reflect the significant restructuring of the agent configuration model:

  1. Renamed options classes:

    • SettingsConfigurationOptionsSettingsOptions
    • UpdateInstructionsOptionsUpdatePromptOptions
  2. Replaced generic Provider and Context with specialized provider classes:

    • ListenProvider, SpeakProvider, ThinkProvider
    • Added Endpoint abstraction

The new structure enables more granular configuration of agent capabilities through specialized provider classes.

Also applies to: 358-360, 367-368, 372-373

deepgram/clients/agent/v1/websocket/__init__.py (1)

29-30: Updated imports to expose new agent v1 classes

These import changes are consistent with the broader refactoring in this PR and expose the restructured agent configuration classes to users of this namespace:

  1. Renamed option classes:

    • SettingsConfigurationOptionsSettingsOptions
    • UpdateInstructionsOptionsUpdatePromptOptions
  2. Added specialized provider classes:

    • ListenProvider, SpeakProvider, ThinkProvider
    • Endpoint abstraction

These changes maintain consistency with the new agent v1 architecture throughout the codebase.

Also applies to: 37-39, 46-47, 51-52

deepgram/clients/agent/__init__.py (3)

34-36: Class renames align with restructured agent configuration model

The renaming from SettingsConfigurationOptions to SettingsOptions and UpdateInstructionsOptions to UpdatePromptOptions represents part of a broader restructuring of the agent configuration API.


42-45: Provider-specific classes replace generic Provider

The introduction of specialized provider classes (ListenProvider, SpeakProvider, ThinkProvider) replaces the previous generic Provider class, allowing for more granular configuration options specific to each agent capability.

Also applies to: 51-52


56-57: Added Endpoint abstraction supports custom endpoint configuration

The new Endpoint class provides a formal way to configure custom endpoints for agent interactions.

deepgram/clients/agent/client.py (2)

33-36: Updates to import aliases maintain API consistency

The import aliases from .v1 have been updated to reflect the renamed classes and new provider types, ensuring consistency with the broader API restructuring.

Also applies to: 41-44, 50-51, 55-56


82-84: Export aliases updated to match restructured imports

The export aliases at the bottom of the file have been consistently updated to match the restructured imports from the .v1 module.

Also applies to: 90-92, 99-100, 104-104

examples/agent/async_simple/main.py (2)

14-15: Updated import to use new SettingsOptions class

The import statement has been updated to use the new SettingsOptions class, which replaces SettingsConfigurationOptions.


113-121: Example updated to use new agent configuration structure

The example demonstrates the new provider-based configuration structure:

  1. Uses nested provider properties to access model configuration
  2. Renames instructions to prompt to match the new API terminology
  3. Adds new configurations like greeting, listen.provider.keyterms, and top-level language

These changes showcase how to correctly use the new agent configuration model.

deepgram/__init__.py (3)

336-338: Updated top-level exports for agent configuration options

The exports have been updated to use the new class names SettingsOptions and UpdatePromptOptions, ensuring consistency with the new API structure.


344-347: Added provider-specific classes and endpoint abstraction to exports

The specialized provider classes (ListenProvider, SpeakProvider, ThinkProvider) and the Endpoint abstraction have been added to the exports, making them available through the top-level package.

Also applies to: 353-354, 358-359


334-359: Consider adding migration documentation for this breaking change

While the code changes are consistent and complete, the introduction of provider-based nesting and renamed fields constitutes a breaking change that will require client code updates.

Consider adding migration guides or documentation that explains how to update from the previous API to the new structure, especially highlighting the path changes (e.g., think.modelthink.provider.model) and renamed fields (e.g., instructionsprompt).

examples/agent/simple/main.py (1)

11-11: Import updated to use new SettingsOptions class

The agent configuration class has been renamed from SettingsConfigurationOptions to SettingsOptions.

deepgram/clients/agent/v1/__init__.py (2)

38-40: Core settings classes renamed

The agent settings classes have been renamed for clarity and consistency:

  • SettingsConfigurationOptionsSettingsOptions
  • UpdateInstructionsOptionsUpdatePromptOptions

46-61: Provider model refactored with explicit provider types

The agent architecture has been refactored to use specific provider types instead of a general-purpose Provider:

  • ListenProvider: Manages speech recognition configuration
  • SpeakProvider: Manages speech synthesis configuration
  • ThinkProvider: Manages language model configuration
  • Endpoint: New abstraction for custom API integrations

This refactoring improves code organization and API clarity while allowing for more granular configuration of each agent capability.

deepgram/clients/agent/v1/websocket/async_client.py (7)

34-40: Import statements updated to reflect renamed classes

Imports have been updated to use the new class names:

  • SettingsOptions replaces SettingsConfigurationOptions
  • UpdatePromptOptions replaces UpdateInstructionsOptions

82-82: Class attribute type updated

The _settings attribute type has been updated to SettingsOptions.


182-182: Method signature updated

The start method parameter type has been updated to use SettingsOptions.


198-201: Settings validation using updated class type

The instance check and validation now use SettingsOptions.


216-225: Settings object instantiation updated

The code for instantiating settings objects from different input types has been updated to use SettingsOptions.


228-229: Validation logic updated for nested provider structure

The validation logic for keyterms has been updated to check through the nested provider structure:

  • Now validates using self._settings.agent.listen.provider.keyterms and self._settings.agent.listen.provider.model

This ensures that keyterms validation works with the new nested configuration structure.


280-288: Log message and error message references updated

References to "ConfigurationSettings" have been changed to "Settings" in log messages and error descriptions.

This maintains consistency with the class renaming from SettingsConfigurationOptions to SettingsOptions.

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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ad48ea and a38e670.

⛔ Files ignored due to path filters (1)
  • examples/agent/no_mic/output_0.wav is excluded by !**/*.wav
📒 Files selected for processing (2)
  • examples/agent/no_mic/chatlog.txt (1 hunks)
  • examples/agent/no_mic/main.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • examples/agent/no_mic/chatlog.txt
🔇 Additional comments (4)
examples/agent/no_mic/main.py (4)

10-21: Replace ad-hoc prints & unused imports with structured logging

verboselogs is imported but never used, and a series of print() statements are scattered throughout the file for diagnostic purposes. Prefer the std-lib logging module (or verboselogs if you really need verbose levels) so that:

  • log levels can be configured from the command line / env vars
  • output can be redirected or silenced by downstream users
  • unit tests aren’t polluted with console noise
-import requests
-import wave
-import io
-import time
-from datetime import datetime
-from deepgram.utils import verboselogs
-
-# Add debug prints for imports
-print("Checking imports...")
+import logging
+import requests
+import wave
+import io
+import time
+from datetime import datetime
+
+# Configure once, near the top-level of your application
+logging.basicConfig(level=logging.INFO)
+log = logging.getLogger(__name__)
+
+# Example replacement
+log.debug("Imports successful")

Later print(...) calls can be replaced with log.debug/info/warning/error(...) as appropriate.
[ suggest_optional_refactor ]


57-77: convert_audio_to_linear16 neither re-samples nor is it ever invoked

The helper promises “convert … to linear16” but:

  1. It simply writes/reads the same frames – no resampling or format conversion is done.
  2. The function is never called, leaving dead code in the example.

If you genuinely need resampling, use a DSP library (e.g. pydub, scipy, soundfile) or the Deepgram SDK’s built-in conversion. Otherwise, remove the function to reduce cognitive load.

[ suggest_optional_refactor ]


226-235: Download loop lacks basic robustness

  • response.raise_for_status() is omitted – silent HTTP 4xx/5xx will yield empty audio.
  • The stream is never closed (with requests.get(..., stream=True) as response:).
  • If the file is large, you may want back-pressure or to respect response.iter_content(None) when the WebSocket is paused.
-response = requests.get(url, stream=True)
-for chunk in response.iter_content(chunk_size=8192):
+with requests.get(url, stream=True, timeout=15) as response:
+    response.raise_for_status()
+    for chunk in response.iter_content(chunk_size=8192):
         if chunk:
             dg_connection.send(chunk)

[ suggest_essential_refactor ]


234-241: Arbitrary time.sleep(5) may end the script before the agent finishes

A fixed delay is brittle – network latency and model inference time vary.
Instead, either:

  • Wait for a specific terminating event (AgentAudioDone + Close) before exiting, or
  • Call a (hypothetical) dg_connection.wait_until_closed() if provided by the SDK.

[ suggest_optional_refactor ]

jpvajda
jpvajda previously approved these changes Apr 30, 2025
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: 6

🔭 Outside diff range comments (4)
deepgram/clients/agent/v1/websocket/options.py (4)

312-317: ⚠️ Potential issue

Fix inconsistent item handling in Agent.__getitem__ method

The listen, think, and speak fields are defined as single objects, but the getter treats them as lists, which will cause a TypeError.

-        if "listen" in _dict:
-            _dict["listen"] = [Listen.from_dict(listen) for listen in _dict["listen"]]
-        if "think" in _dict:
-            _dict["think"] = [Think.from_dict(think) for think in _dict["think"]]
-        if "speak" in _dict:
-            _dict["speak"] = [Speak.from_dict(speak) for speak in _dict["speak"]]
+        if "listen" in _dict and isinstance(_dict["listen"], dict):
+            _dict["listen"] = Listen.from_dict(_dict["listen"])
+        if "think" in _dict and isinstance(_dict["think"], dict):
+            _dict["think"] = Think.from_dict(_dict["think"])
+        if "speak" in _dict and isinstance(_dict["speak"], dict):
+            _dict["speak"] = Speak.from_dict(_dict["speak"])

356-359: ⚠️ Potential issue

Fix inconsistent item handling in Audio.__getitem__ method

The input and output fields are defined as single objects, but the getter treats them as lists, which will cause a TypeError.

-        if "input" in _dict:
-            _dict["input"] = [Input.from_dict(input) for input in _dict["input"]]
-        if "output" in _dict:
-            _dict["output"] = [Output.from_dict(output) for output in _dict["output"]]
+        if "input" in _dict and isinstance(_dict["input"], dict):
+            _dict["input"] = Input.from_dict(_dict["input"])
+        if "output" in _dict and isinstance(_dict["output"], dict):
+            _dict["output"] = Output.from_dict(_dict["output"])

116-118: ⚠️ Potential issue

Fix inconsistent item handling in Function.__getitem__ for parameters

The parameters field is defined as Optional[Parameters] (a single object), but the getter treats it as a list, which will cause a TypeError.

-        if "parameters" in _dict:
-            _dict["parameters"] = [
-                Parameters.from_dict(parameters) for parameters in _dict["parameters"]
-            ]
+        if "parameters" in _dict and isinstance(_dict["parameters"], dict):
+            _dict["parameters"] = Parameters.from_dict(_dict["parameters"])

50-52: 💡 Verification agent

🧩 Analysis chain

Fix inconsistent item handling in Properties.__getitem__ method

The item field appears to be a single object of type Item, but the getter treats it as a list. Consider whether this is intentional or if it needs correction.


🏁 Script executed:

#!/bin/bash
# Search for occurrences where Properties.item is used to understand the expected type
rg -A 3 -B 3 "Properties.*item"

# Check if the API serializes the 'item' field as an array or a single object
rg -A 5 -B 5 "\"item\":" --type json

Length of output: 70


🏁 Script executed:

#!/bin/bash
# Confirm the target file exists
ls -l deepgram/clients/agent/v1/websocket/options.py

# Show the Properties class definition in context
rg -n 'class Properties' deepgram/clients/agent/v1/websocket/options.py -A20 -B5

# Show the __getitem__ method implementation and surrounding lines
rg -n 'def __getitem__' deepgram/clients/agent/v1/websocket/options.py -A10 -B5

Length of output: 7668


Align item type with its list handling in Properties

The docstring and __getitem__ implementation treat item as a list, but the dataclass field is declared as a single Item. To resolve this inconsistency:

• In deepgram/clients/agent/v1/websocket/options.py (line 46), change

item: Item

to

from typing import List

item: List[Item]

• Ensure you import List from typing at the top of the file.

♻️ Duplicate comments (2)
deepgram/clients/agent/v1/websocket/options.py (2)

123-127: ⚠️ Potential issue

Fix inconsistent item handling in Function.__getitem__ method

The endpoint field is defined as Optional[Endpoint] but the getter treats it as a list. This will fail with TypeError: 'Endpoint' object is not iterable when deserializing.

-        if "endpoint" in _dict:
-            _dict["endpoint"] = [
-                Endpoint.from_dict(endpoint) for endpoint in _dict["endpoint"]
-            ]
+        if "endpoint" in _dict and isinstance(_dict["endpoint"], dict):
+            _dict["endpoint"] = Endpoint.from_dict(_dict["endpoint"])

136-141: ⚠️ Potential issue

Fix type annotations in CartesiaVoice class

mode and id are typed as str but default to None, causing mypy errors as shown in the pipeline failures.

-    mode: str = field(
+    mode: Optional[str] = field(
        default=None, metadata=dataclass_config(exclude=lambda f: f is None)
    )
-    id: str = field(
+    id: Optional[str] = field(
        default=None, metadata=dataclass_config(exclude=lambda f: f is None)
    )
🧰 Tools
🪛 GitHub Actions: Check - static

[error] 136-136: mypy: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]


[error] 139-139: mypy: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9e77b1 and 0d219ce.

📒 Files selected for processing (1)
  • deepgram/clients/agent/v1/websocket/options.py (7 hunks)
🧰 Additional context used
🪛 GitHub Actions: Check - static
deepgram/clients/agent/v1/websocket/options.py

[error] 136-136: mypy: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]


[error] 139-139: mypy: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]

🔇 Additional comments (1)
deepgram/clients/agent/v1/websocket/options.py (1)

169-170: 💡 Verification agent

🧩 Analysis chain

Consider the appropriate default value for ThinkProvider.type

Based on past review comments, think.provider doesn't have a default value in the API. Consider whether setting the default to None is intentional or if it should be omitted.


🌐 Web query:

What is the default provider for Deepgram Agent's think component?

💡 Result:

The default provider for Deepgram Agent's think component is Anthropic. By default, Deepgram configures the think provider with the following settings:

  • Provider type: anthropic
  • Model: claude-3-haiku-20240307

This can be seen in example agent configuration snippets from Deepgram’s official SDK documentation:

agent.configure({
  // ...
  agent: {
    // ...
    think: {
      provider: { type: "anthropic" },
      model: "claude-3-haiku-20240307",
      instructions: "You are a helpful AI assistant. Keep responses brief and friendly.",
    },
  },
});

You can override these defaults and configure a different provider, model, or instructions as needed, but when not specified, Deepgram’s Agent will use Anthropic as the think provider[5].

Citations:


Update default values for ThinkProvider to match API defaults

The Deepgram Agent’s think component defaults to Anthropic with claude-3-haiku-20240307 if no provider or model is specified. To surface these defaults in the client, update the dataclass fields accordingly.

• deepgram/clients/agent/v1/websocket/options.py

  • Replace the None defaults for type and model with the API’s actual defaults.
--- a/deepgram/clients/agent/v1/websocket/options.py
+++ b/deepgram/clients/agent/v1/websocket/options.py
@@ -169,7 +169,7 @@
     """Configuration for the AI thinking provider."""
-    type: Optional[str] = field(default=None)
+    type: str = field(default="anthropic")
-    model: Optional[str] = field(default=None)
+    model: str = field(default="claude-3-haiku-20240307")

Likely an incorrect or invalid review comment.

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

🔭 Outside diff range comments (1)
deepgram/clients/agent/v1/websocket/client.py (1)

182-188: 🛠️ Refactor suggestion

Widen the options type hint

start() accepts dict and str variants, yet the signature narrows the type to Optional[SettingsOptions]. Static analysis (e.g. mypy) will flag every valid call that passes a dict/str.

-        options: Optional[SettingsOptions] = None,
+        options: Union[SettingsOptions, Dict[str, Any], str, None] = None,

This keeps runtime behaviour unchanged while eliminating false-positive type errors.

♻️ Duplicate comments (5)
deepgram/clients/agent/v1/websocket/options.py (5)

123-127: Function.__getitem__ still treats singular endpoint as a list
This was flagged in a previous review but remains unresolved.

-        if "endpoint" in _dict:
-            _dict["endpoint"] = [
-                Endpoint.from_dict(endpoint) for endpoint in _dict["endpoint"]
-            ]
+        if "endpoint" in _dict and isinstance(_dict["endpoint"], dict):
+            _dict["endpoint"] = Endpoint.from_dict(_dict["endpoint"])

150-160: ListenProvider.keyterms deserialisation is safe, but None guard is missing

Attempting list-comprehension on None raises TypeError.

-        if "keyterms" in _dict:
-            _dict["keyterms"] = [str(keyterm) for keyterm in _dict["keyterms"]]
+        if isinstance(_dict.get("keyterms"), list):
+            _dict["keyterms"] = [str(keyterm) for keyterm in _dict["keyterms"]]

215-223: SpeakProvider.__getitem__ – inconsistent handling of scalar fields

voice and language are optional scalars but are processed as lists, yielding runtime TypeErrors.

-        if "voice" in _dict:
-            _dict["voice"] = [
-                CartesiaVoice.from_dict(voice) for voice in _dict["voice"]
-            ]
-        if "language" in _dict:
-            _dict["language"] = [str(language) for language in _dict["language"]]
+        if "voice" in _dict and isinstance(_dict["voice"], dict):
+            _dict["voice"] = CartesiaVoice.from_dict(_dict["voice"])
+        # 'language' is already a string; no transformation needed.

232-241: Think now embeds endpoint and prompt – update __getitem__ accordingly

provider is singular, yet the method still treats it as a list. Same issue for the new endpoint.

-        if "provider" in _dict:
-            _dict["provider"] = [
-                ThinkProvider.from_dict(provider) for provider in _dict["provider"]
-            ]
+        if "provider" in _dict and isinstance(_dict["provider"], dict):
+            _dict["provider"] = ThinkProvider.from_dict(_dict["provider"])
 ...
-        if "endpoint" in _dict:
-            _dict["endpoint"] = [
-                Endpoint.from_dict(endpoint) for endpoint in _dict["endpoint"]
-            ]
+        if "endpoint" in _dict and isinstance(_dict["endpoint"], dict):
+            _dict["endpoint"] = Endpoint.from_dict(_dict["endpoint"])

136-141: ⚠️ Potential issue

CartesiaVoice.mode/id violate declared type – fixes pipeline failure

Both fields default to None but are typed str, causing the mypy errors reported in CI.

-    mode: str = field(
+    mode: Optional[str] = field(
 ...
-    id: str = field(
+    id: Optional[str] = field(

[mypy now passes]

🧰 Tools
🪛 GitHub Actions: Check - static

[error] 136-136: mypy error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]


[error] 139-139: mypy error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]

🧹 Nitpick comments (2)
deepgram/clients/agent/v1/websocket/client.py (2)

99-104: Update the in-code comment or endpoint path for consistency

The explanatory comment still points to the legacy path "agent", while _endpoint has already been updated to "v1/agent/converse". This is misleading for future maintainers.

-# needs to be "wss://agent.deepgram.com/agent"
+# WebSocket path on `agent.deepgram.com` – keep in sync with server contract.

280-289: Send compact JSON to reduce websocket frame size

str(self._settings) pretty-prints with indentation, increasing payload by ~30-40 %.
Switch to self._settings.to_json() (no indent) for lower latency:

-            ret_send_cs = self.send(str(self._settings))
+            ret_send_cs = self.send(self._settings.to_json())

Minor but measurable for high-frequency reconnects.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d219ce and 4ad9eb7.

📒 Files selected for processing (14)
  • deepgram/__init__.py (1 hunks)
  • deepgram/client.py (1 hunks)
  • deepgram/clients/__init__.py (1 hunks)
  • deepgram/clients/agent/__init__.py (1 hunks)
  • deepgram/clients/agent/client.py (2 hunks)
  • deepgram/clients/agent/enums.py (1 hunks)
  • deepgram/clients/agent/v1/__init__.py (1 hunks)
  • deepgram/clients/agent/v1/websocket/__init__.py (1 hunks)
  • deepgram/clients/agent/v1/websocket/async_client.py (7 hunks)
  • deepgram/clients/agent/v1/websocket/client.py (7 hunks)
  • deepgram/clients/agent/v1/websocket/options.py (8 hunks)
  • deepgram/clients/agent/v1/websocket/response.py (2 hunks)
  • examples/agent/async_simple/main.py (2 hunks)
  • examples/agent/simple/main.py (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • deepgram/clients/agent/client.py
🚧 Files skipped from review as they are similar to previous changes (11)
  • deepgram/clients/agent/v1/websocket/response.py
  • examples/agent/async_simple/main.py
  • deepgram/client.py
  • deepgram/clients/agent/init.py
  • deepgram/clients/agent/v1/websocket/init.py
  • deepgram/clients/agent/enums.py
  • deepgram/init.py
  • deepgram/clients/agent/v1/websocket/async_client.py
  • deepgram/clients/init.py
  • examples/agent/simple/main.py
  • deepgram/clients/agent/v1/init.py
🧰 Additional context used
🧬 Code Graph Analysis (2)
deepgram/clients/agent/v1/websocket/client.py (3)
deepgram/clients/agent/v1/websocket/options.py (2)
  • SettingsOptions (373-404)
  • check (391-404)
deepgram/utils/verboselogs/__init__.py (1)
  • notice (150-153)
deepgram/clients/common/v1/websocket_response.py (1)
  • ErrorResponse (41-51)
deepgram/clients/agent/v1/websocket/options.py (2)
deepgram/clients/common/v1/shared_response.py (1)
  • BaseResponse (16-44)
deepgram/clients/agent/enums.py (1)
  • AgentWebSocketEvents (10-36)
🪛 GitHub Actions: Check - static
deepgram/clients/agent/v1/websocket/options.py

[error] 136-136: mypy error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]


[error] 139-139: mypy error: Incompatible types in assignment (expression has type "None", variable has type "str") [assignment]

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 (1)
deepgram/clients/agent/v1/websocket/options.py (1)

171-213: SpeakProvider getitem correctly handles the voice field but ignores language conversion.

The method handles the conversion of the voice field from a dictionary to a CartesiaVoice object, but there was a past review comment about inconsistent handling of the language field.

Fix inconsistent item handling for language in SpeakProvider.__getitem__

The language field is defined as Optional[str] but the getter might incorrectly handle it. Ensure language is handled correctly.

🧹 Nitpick comments (3)
deepgram/clients/agent/v1/websocket/options.py (3)

72-91: New Endpoint class looks well-structured but could use a safety check for empty headers.

The implementation of the new Endpoint class looks good with appropriate field types and defaults. The getitem method correctly handles the conversion of headers.

Consider adding a check to prevent iterating over None headers:

     def __getitem__(self, key):
         _dict = self.to_dict()
-        if "headers" in _dict:
+        if "headers" in _dict and isinstance(_dict["headers"], list):
             _dict["headers"] = [
                 Header.from_dict(headers) for headers in _dict["headers"]
             ]
         return _dict[key]

124-136: CartesiaVoice class uses empty strings as defaults for fields typed as str.

While using empty strings as defaults helps avoid None values, the API might have specific default values or expect specific formats.

You might consider adding documentation comments explaining the allowed values for each field to help users understand valid values for mode and id.


139-154: The ListenProvider class has a type inconsistency in the keyterms handling.

The type check is correct, but there might be unnecessary string conversion in the list comprehension.

The string conversion in the list comprehension is likely redundant since keyterms is already typed as List[str]:

    def __getitem__(self, key):
        _dict = self.to_dict()
        if "keyterms" in _dict and isinstance(_dict["keyterms"], list):
-            _dict["keyterms"] = [str(keyterm) for keyterm in _dict["keyterms"]]
+            _dict["keyterms"] = _dict["keyterms"]  # No conversion needed
        return _dict[key]
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbbc1b3 and 8e066ce.

📒 Files selected for processing (1)
  • deepgram/clients/agent/v1/websocket/options.py (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
deepgram/clients/agent/v1/websocket/options.py (2)
deepgram/clients/common/v1/shared_response.py (1)
  • BaseResponse (16-44)
deepgram/clients/agent/enums.py (1)
  • AgentWebSocketEvents (10-36)
🔇 Additional comments (10)
deepgram/clients/agent/v1/websocket/options.py (10)

109-121: Good implementation for Function.getitem, follows previous code review suggestions.

The implementation correctly checks the type of each field before converting it, addressing issues noted in previous code reviews where some fields were incorrectly treated as lists.


217-243: The Think class getitem method correctly handles provider, functions, and endpoint fields.

The code now checks if the fields are of the expected type before converting them, addressing issues noted in previous reviews.


247-258: The Listen class getitem method correctly handles the provider field.

The implementation includes the type check before conversion, addressing issues noted in previous reviews.


262-277: The Speak class getitem method correctly handles the provider and endpoint fields.

The implementation includes type checks before conversion, addressing issues noted in previous reviews.


290-301: Agent class adds a new greeting field and properly handles all nested objects.

The getitem method correctly handles the conversion of listen, think, and speak fields with appropriate type checks.


340-343: Audio.getitem now includes type checks for input and output fields.

This properly addresses issues noted in previous reviews by checking field types before conversion.


357-372: SettingsOptions (renamed from SettingsConfigurationOptions) looks good but has type handling inconsistency.

The class adds a new experimental field and changes the event type, which aligns with the changes in the AgentWebSocketEvents enum.


391-401: UpdatePromptOptions (renamed from UpdateInstructionsOptions) renames 'instructions' to 'prompt'.

This name change appears intentional and aligns with the PR's goal of supporting agent v1, though it represents a breaking change for existing code.


414-414: UpdateSpeakOptions now uses the comprehensive Speak class instead of a simple model string.

This enhancement provides more flexibility but represents a breaking change that will require updates to existing code.


348-353:

✅ Verification successful

Language class (renamed from Context) simplifies to just use a type field.

The class has been significantly simplified, which might be a breaking change for code that was using the previous Context class.

Verify that code depending on the previous Context class has been updated to use the new Language class structure:


🏁 Script executed:

#!/bin/bash
# Find code that might be referring to the old Context class
echo "Searching for references to Context class..."
rg "Context\(" 
rg "context\:" 

Length of output: 301


🏁 Script executed:

#!/bin/bash
echo "Searching for Context references in deepgram code (excluding SSLContext and options.py)..."
rg -n "\bContext\b" deepgram --color never | grep -Ev "SSLContext|options.py"

Length of output: 270


No remaining references to the old Context class – renaming to Language is safe

A search across the deepgram/ directory (excluding SSLContext and the updated file itself) found zero occurrences of Context. The library’s internal code no longer relies on the old class name, so consumers will be working with the new Language definition without breaking changes.

Comment on lines +158 to 167
class ThinkProvider(BaseResponse):
"""
This class defines the provider for the Think model.
"""

type: Optional[str] = field(
type: Optional[str] = field(default=None)
model: Optional[str] = field(default=None)
temperature: Optional[float] = field(
default=None, metadata=dataclass_config(exclude=lambda f: f is None)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

ThinkProvider type and model fields are nullable while previously they had default values.

The change from required to optional fields might be a breaking change if code relies on these fields having non-null values.

Verify that making these fields nullable aligns with the API's behavior and that existing code doesn't assume these fields will always have values:


🏁 Script executed:

#!/bin/bash
# Find code that might be affected by nullable ThinkProvider fields
echo "Searching for code that accesses think provider type or model fields..."
rg -A 2 "think.*provider.*\.(type|model)" 

Length of output: 1270


🏁 Script executed:

#!/bin/bash
# Display relevant parts of the options.py file including ThinkProvider definition and serialization
file="deepgram/clients/agent/v1/websocket/options.py"
echo "Showing ThinkProvider class and serialization logic:"
sed -n '1,200p' "$file" | sed -n '150,260p'
echo
echo "Searching for any to_dict or serialization methods in this file:"
rg -n "def .*serialize|def .*to_dict|asdict" "$file"

Length of output: 1945


🏁 Script executed:

#!/bin/bash
# Locate BaseResponse definition and its to_dict method
echo "Searching for BaseResponse class:"
rg -n "class BaseResponse" -A 50

# Locate to_dict/serialization logic in BaseResponse
echo
echo "Searching for to_dict methods or usage of dataclass_config in serialization:"
rg -n "to_dict" -A 20 

# Locate dataclass_config helper
echo
echo "Searching for dataclass_config definition:"
rg -n "def dataclass_config" -A 20

Length of output: 108006


Review ThinkProvider defaults and serialization
The ThinkProvider class now defines type and model as Optional[str] = None without any exclude metadata. Unlike temperature, these fields will be serialized as "type": null and "model": null when unset—potentially breaking API calls that expect valid provider identifiers or previous non-null defaults.

Please address this change by either:

  • Restoring sensible defaults (e.g. default="open_ai" and default="gpt-4o-mini") to match prior behavior, or
  • Adding metadata=dataclass_config(exclude=lambda f: f is None) to both type and model so they’re omitted when not explicitly set.

Examples currently override both fields, but the default Think() instance will send null. Confirm against the API spec and update accordingly.

🤖 Prompt for AI Agents (early access)
In deepgram/clients/agent/v1/websocket/options.py around lines 158 to 167, the ThinkProvider class has type and model fields changed to Optional[str] without exclude metadata, causing them to serialize as null when unset. To fix this, either restore their previous default values (e.g., default="open_ai" for type and default="gpt-4o-mini" for model) or add metadata=dataclass_config(exclude=lambda f: f is None) to both fields to omit them from serialization when None. Verify the API spec to choose the correct approach and ensure default Think instances do not send null values for these fields.

@naomi-lgbt naomi-lgbt merged commit 5945c56 into main May 5, 2025
6 checks passed
@naomi-lgbt naomi-lgbt deleted the feat/agent-v1 branch May 5, 2025 21:13
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