-
Notifications
You must be signed in to change notification settings - Fork 121
feat(proxy): add drop-in proxy middleware #655
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
base: lo/v5-5-regen
Are you sure you want to change the base?
Conversation
Adds a proxy module that keeps Deepgram API keys server-side while providing scoped JWT auth and REST/WebSocket forwarding. Includes adapters for FastAPI, Flask, and Django with 57 tests covering scopes, JWT, engine, and end-to-end FastAPI integration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds a new deepgram.proxy module to provide drop-in REST/WebSocket proxy middleware with scoped JWT auth, while also incorporating substantial Fern regeneration output (types/requests), client base URL refactors, CI/release workflow updates, and an examples overhaul.
Changes:
- Introduces proxy scope matching + JWT management, plus FastAPI end-to-end tests.
- Refactors client environment/base URL handling and updates generated models/requests/types.
- Reworks examples/docs and adjusts GitHub Actions release/publish configuration.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integrations/conftest.py | Removes integration-test shared fixtures |
| tests/integrations/init.py | Removes integration-test package marker |
| tests/custom/test_proxy_scopes.py | Adds unit tests for proxy scope/path matching |
| tests/custom/test_proxy_fastapi.py | Adds FastAPI end-to-end proxy adapter tests |
| src/deepgram/types/speak_v1sample_rate.py | Removes generated type alias |
| src/deepgram/types/speak_v1response.py | Changes TTS response type from str to bytes |
| src/deepgram/types/speak_v1model.py | Removes generated type alias |
| src/deepgram/types/speak_v1mip_opt_out.py | Removes generated type alias |
| src/deepgram/types/speak_v1encoding.py | Removes generated type alias |
| src/deepgram/types/project_request_response.py | Tightens response dict typing |
| src/deepgram/types/listen_v2tag.py | Removes generated type alias |
| src/deepgram/types/listen_v2sample_rate.py | Removes generated type alias |
| src/deepgram/types/listen_v2model.py | Removes generated type alias |
| src/deepgram/types/listen_v2mip_opt_out.py | Removes generated type alias |
| src/deepgram/types/listen_v2keyterm.py | Removes generated type alias |
| src/deepgram/types/listen_v2eot_timeout_ms.py | Removes generated type alias |
| src/deepgram/types/listen_v2eot_threshold.py | Removes generated type alias |
| src/deepgram/types/listen_v2encoding.py | Removes generated type alias |
| src/deepgram/types/listen_v2eager_eot_threshold.py | Removes generated type alias |
| src/deepgram/types/listen_v1version.py | Removes generated type alias |
| src/deepgram/types/listen_v1vad_events.py | Removes generated type alias |
| src/deepgram/types/listen_v1utterance_end_ms.py | Removes generated type alias |
| src/deepgram/types/listen_v1tag.py | Removes generated type alias |
| src/deepgram/types/listen_v1smart_format.py | Removes generated type alias |
| src/deepgram/types/listen_v1search.py | Removes generated type alias |
| src/deepgram/types/listen_v1sample_rate.py | Removes generated type alias |
| src/deepgram/types/listen_v1response_results_channels_item_alternatives_item_entities_item.py | Adds new entities model type |
| src/deepgram/types/listen_v1response_results_channels_item_alternatives_item.py | Wires entities into alternatives model |
| src/deepgram/types/listen_v1response_metadata.py | Tightens model_info typing |
| src/deepgram/types/listen_v1request_file.py | Changes request file type from str to bytes |
| src/deepgram/types/listen_v1replace.py | Removes generated type alias |
| src/deepgram/types/listen_v1redact.py | Removes generated type alias |
| src/deepgram/types/listen_v1punctuate.py | Removes generated type alias |
| src/deepgram/types/listen_v1profanity_filter.py | Removes generated type alias |
| src/deepgram/types/listen_v1numerals.py | Removes generated type alias |
| src/deepgram/types/listen_v1multichannel.py | Removes generated type alias |
| src/deepgram/types/listen_v1model.py | Removes generated model literal union |
| src/deepgram/types/listen_v1mip_opt_out.py | Removes generated type alias |
| src/deepgram/types/listen_v1language.py | Removes generated type alias |
| src/deepgram/types/listen_v1keywords.py | Removes generated type alias |
| src/deepgram/types/listen_v1keyterm.py | Removes generated type alias |
| src/deepgram/types/listen_v1interim_results.py | Removes generated type alias |
| src/deepgram/types/listen_v1extra.py | Removes generated type alias |
| src/deepgram/types/listen_v1endpointing.py | Removes generated type alias |
| src/deepgram/types/listen_v1encoding.py | Removes generated type alias |
| src/deepgram/types/listen_v1dictation.py | Removes generated type alias |
| src/deepgram/types/listen_v1diarize.py | Removes generated type alias |
| src/deepgram/types/listen_v1channels.py | Removes generated type alias |
| src/deepgram/types/listen_v1callback_method.py | Removes generated type alias |
| src/deepgram/types/list_models_v1response_tts_models.py | Makes uuid_ a Field alias explicitly |
| src/deepgram/types/list_models_v1response_stt_models.py | Makes uuid_ a Field alias explicitly |
| src/deepgram/types/get_model_v1response_metadata.py | Makes uuid_ a Field alias explicitly |
| src/deepgram/types/get_model_v1response_batch.py | Makes uuid_ a Field alias explicitly |
| src/deepgram/types/create_key_v1request_one.py | Changes optional payload alias to Any |
| src/deepgram/speak/v1/audio/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/speak/raw_client.py | Removes raw client wrapper |
| src/deepgram/speak/client.py | Removes with_raw_response wrapper |
| src/deepgram/self_hosted/v1/raw_client.py | Removes raw client wrapper |
| src/deepgram/self_hosted/v1/client.py | Removes with_raw_response wrapper |
| src/deepgram/self_hosted/raw_client.py | Removes raw client wrapper |
| src/deepgram/self_hosted/client.py | Removes with_raw_response wrapper |
| src/deepgram/requests/project_request_response.py | Tightens response dict typing |
| src/deepgram/requests/listen_v2keyterm.py | Removes generated param alias |
| src/deepgram/requests/listen_v1response_results_channels_item_alternatives_item_entities_item.py | Adds request TypedDict for entities |
| src/deepgram/requests/listen_v1response_results_channels_item_alternatives_item.py | Wires entities into TypedDict |
| src/deepgram/requests/listen_v1response_metadata.py | Tightens model_info typing |
| src/deepgram/requests/init.py | Exports new entities params, removes ListenV2KeytermParams |
| src/deepgram/read/v1/text/types/text_analyze_request_summarize.py | Removes "v1" summarize option literal |
| src/deepgram/read/v1/text/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/read/v1/text/client.py | Expands docstring examples with more params |
| src/deepgram/read/v1/raw_client.py | Removes raw client wrapper |
| src/deepgram/read/v1/client.py | Removes with_raw_response wrapper |
| src/deepgram/read/raw_client.py | Removes raw client wrapper |
| src/deepgram/read/client.py | Removes with_raw_response wrapper |
| src/deepgram/proxy/scopes.py | Adds scope definitions + path routing |
| src/deepgram/proxy/jwt.py | Adds JWT creation/validation with PyJWT |
| src/deepgram/proxy/errors.py | Adds proxy-specific exceptions |
| src/deepgram/proxy/adapters/init.py | Adds adapters package initializer |
| src/deepgram/proxy/init.py | Exports DeepgramProxy and Scope |
| src/deepgram/manage/v1/raw_client.py | Removes raw client wrapper |
| src/deepgram/manage/v1/projects/usage/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/usage/fields/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/usage/fields/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/usage/breakdown/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/requests/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/requests/client.py | Expands docstring examples (datetime + filters) |
| src/deepgram/manage/v1/projects/models/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/models/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/members/scopes/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/members/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/keys/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/billing/raw_client.py | Removes raw client wrapper |
| src/deepgram/manage/v1/projects/billing/purchases/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/billing/purchases/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/billing/fields/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/billing/fields/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/billing/client.py | Removes with_raw_response wrapper |
| src/deepgram/manage/v1/projects/billing/breakdown/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/projects/billing/breakdown/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/projects/billing/balances/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/models/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/manage/v1/models/client.py | Expands docstring examples with params |
| src/deepgram/manage/v1/client.py | Removes with_raw_response wrapper |
| src/deepgram/manage/raw_client.py | Removes raw client wrapper |
| src/deepgram/manage/client.py | Removes with_raw_response wrapper |
| src/deepgram/listen/v2/init.py | Removes v2 init file |
| src/deepgram/listen/v1/media/types/media_transcribe_request_summarize.py | Removes "v1" summarize option literal |
| src/deepgram/listen/v1/media/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/listen/v1/media/client.py | Expands docstring examples with params |
| src/deepgram/listen/raw_client.py | Removes raw client wrapper |
| src/deepgram/listen/client.py | Removes v2 surface + raw-response wrapper |
| src/deepgram/listen/init.py | Removes lazy import/export of v2 |
| src/deepgram/extensions/types/sockets/speak_v1_warning_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/speak_v1_text_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/speak_v1_metadata_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/speak_v1_control_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/speak_v1_control_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/speak_v1_audio_chunk_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/listen_v2_turn_info_event.py | Removes generated socket event type |
| src/deepgram/extensions/types/sockets/listen_v2_media_message.py | Removes generated socket message type |
| src/deepgram/extensions/types/sockets/listen_v2_fatal_error_event.py | Removes generated socket event type |
| src/deepgram/extensions/types/sockets/listen_v2_control_message.py | Removes generated socket control type |
| src/deepgram/extensions/types/sockets/listen_v2_connected_event.py | Removes generated socket event type |
| src/deepgram/extensions/types/sockets/listen_v1_utterance_end_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/listen_v1_speech_started_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/listen_v1_metadata_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/listen_v1_media_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/listen_v1_control_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_welcome_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_warning_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_user_started_speaking_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_update_speak_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_update_prompt_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_speak_updated_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_settings_applied_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_prompt_updated_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_media_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_injection_refused_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_inject_user_message_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_inject_agent_message_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_function_call_response_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_function_call_request_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_error_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_conversation_text_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_control_message.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_audio_chunk_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_agent_thinking_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_agent_started_speaking_event.py | Removes protected socket type |
| src/deepgram/extensions/types/sockets/agent_v1_agent_audio_done_event.py | Removes protected socket type |
| src/deepgram/extensions/telemetry/handler.py | Removes telemetry handler interface |
| src/deepgram/extensions/telemetry/init.py | Removes telemetry package initializer |
| src/deepgram/errors/bad_request_error.py | Changes BadRequestError body typing to Any |
| src/deepgram/environment.py | Replaces environment class with Enum containing base URLs |
| src/deepgram/core/jsonable_encoder.py | Adds Ellipsis (“OMIT”) filtering rules |
| src/deepgram/core/http_sse/_models.py | Adds SSE event model |
| src/deepgram/core/http_sse/_exceptions.py | Replaces alias with SSEError exception |
| src/deepgram/core/http_sse/_decoders.py | Adds SSE line decoder implementation |
| src/deepgram/core/http_sse/init.py | Adds SSE package lazy exports |
| src/deepgram/base_client.py | Adds base_url parameter + resolves environment to base URL |
| src/deepgram/auth/v1/tokens/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/auth/v1/raw_client.py | Removes raw client wrapper |
| src/deepgram/auth/v1/client.py | Removes with_raw_response wrapper |
| src/deepgram/auth/raw_client.py | Removes raw client wrapper |
| src/deepgram/auth/client.py | Removes with_raw_response wrapper |
| src/deepgram/agent/v1/settings/think/raw_client.py | Removes raw client wrapper |
| src/deepgram/agent/v1/settings/think/models/raw_client.py | Removes explicit base_url arg and adjusts error-body typing |
| src/deepgram/agent/v1/settings/think/client.py | Removes with_raw_response wrapper |
| src/deepgram/agent/v1/settings/raw_client.py | Removes raw client wrapper |
| src/deepgram/agent/v1/settings/client.py | Removes with_raw_response wrapper |
| src/deepgram/agent/raw_client.py | Removes raw client wrapper |
| src/deepgram/agent/client.py | Removes with_raw_response wrapper |
| pyproject.toml | Version bump + Poetry config adjustments + dev deps updates |
| mypy.ini | Removes mypy config file |
| examples/speak/v1/connect/with_raw_response.py | Removes old example |
| examples/speak/v1/connect/with_auth_token.py | Removes old example |
| examples/speak/v1/connect/main.py | Removes old example |
| examples/speak/v1/connect/async.py | Removes old example |
| examples/speak/v1/audio/generate/with_raw_response.py | Removes old example |
| examples/speak/v1/audio/generate/with_auth_token.py | Removes old example |
| examples/speak/v1/audio/generate/main.py | Removes old example |
| examples/speak/v1/audio/generate/async.py | Removes old example |
| examples/read/v1/text/analyze/with_raw_response.py | Removes old example |
| examples/read/v1/text/analyze/with_auth_token.py | Removes old example |
| examples/read/v1/text/analyze/main.py | Removes old example |
| examples/read/v1/text/analyze/async.py | Removes old example |
| examples/listen/v2/connect/with_raw_response.py | Removes old example |
| examples/listen/v2/connect/with_auth_token.py | Removes old example |
| examples/listen/v2/connect/main.py | Removes old example |
| examples/listen/v2/connect/async.py | Removes old example |
| examples/listen/v1/media/transcribe_url/with_raw_response.py | Removes old example |
| examples/listen/v1/media/transcribe_url/with_auth_token.py | Removes old example |
| examples/listen/v1/media/transcribe_url/main.py | Removes old example |
| examples/listen/v1/media/transcribe_url/async.py | Removes old example |
| examples/listen/v1/media/transcribe_file/with_raw_response.py | Removes old example |
| examples/listen/v1/media/transcribe_file/with_auth_token.py | Removes old example |
| examples/listen/v1/media/transcribe_file/main.py | Removes old example |
| examples/listen/v1/media/transcribe_file/async.py | Removes old example |
| examples/listen/v1/connect/with_raw_response.py | Removes old example |
| examples/listen/v1/connect/with_auth_token.py | Removes old example |
| examples/listen/v1/connect/main.py | Removes old example |
| examples/listen/v1/connect/async.py | Removes old example |
| examples/agent/v1/connect/with_raw_response.py | Removes old example |
| examples/agent/v1/connect/with_auth_token.py | Removes old example |
| examples/agent/v1/connect/async.py | Removes old example |
| examples/26-transcription-live-websocket-v2.py | Adds new numbered v2 WebSocket example |
| examples/24-error-handling.py | Adds error-handling example |
| examples/23-request-options.py | Adds request options example |
| examples/22-transcription-advanced-options.py | Adds advanced transcription example |
| examples/20-onprem-credentials.py | Adds self-hosted credentials example |
| examples/19-management-models.py | Adds management models example |
| examples/18-management-billing.py | Adds management billing example |
| examples/17-management-usage.py | Adds management usage example |
| examples/16-management-invites.py | Adds management invites example |
| examples/15-management-members.py | Adds management members example |
| examples/14-management-keys.py | Adds management keys example |
| examples/13-management-projects.py | Adds management projects example |
| examples/12-text-intelligence.py | Adds Read/Text Intelligence example |
| examples/11-text-to-speech-streaming.py | Adds TTS WebSocket example |
| examples/10-text-to-speech-single.py | Adds TTS REST streaming example |
| examples/07-transcription-live-websocket.py | Adds v1 WebSocket example |
| examples/06-transcription-prerecorded-callback.py | Adds callback transcription example |
| examples/05-transcription-prerecorded-file.py | Adds file transcription example |
| examples/04-transcription-prerecorded-url.py | Adds URL transcription example |
| examples/02-authentication-access-token.py | Adds access token example |
| examples/01-authentication-api-key.py | Adds API key example |
| docs/Migrating-v3-to-v5.md | Appends trailing newline |
| docs/Migrating-v2-to-v3.md | Appends trailing newline |
| TODO.md | Adds follow-ups for proxy packaging deps/extras |
| LICENSE | Updates copyright year |
| CONTRIBUTING.md | Removes contributing guide |
| .github/workflows/tests-daily.yml | Adds Docker availability check |
| .github/workflows/release-please.yml | Switches publish method + adds Docker check + id-token |
| .github/workflows/pr-title-check.yml | Appends trailing newline |
| .github/workflows/ci.yml | Adds PATH fix, Docker check, and OIDC publish job |
| .github/workflows/changelog-log.yml | Appends trailing newline |
| .github/ISSUE_TEMPLATE/feature_request.yml | Removes issue template |
| .github/ISSUE_TEMPLATE/docs_improvement.yml | Removes issue template |
| .github/CODEOWNERS | Removes CODEOWNERS |
| .github/.release-please-manifest.json | Adds trailing newline |
| .github/.commitlintrc.json | Adds trailing newline |
| .fernignore | Rewrites ignore list and comments |
| .fern/metadata.json | Adds Fern generator metadata snapshot |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
listen.v2 is removed from lazy imports and __all__, but the PR adds a new v2 WebSocket example (and previously supported v2 usage). Either restore the v2 export here (and corresponding client surface) or update/remove the new v2 example so the public API and examples stay consistent.
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
listen.v2 is removed from lazy imports and __all__, but the PR adds a new v2 WebSocket example (and previously supported v2 usage). Either restore the v2 export here (and corresponding client surface) or update/remove the new v2 example so the public API and examples stay consistent.
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example imports/uses deepgram.listen.v2 and client.listen.v2, but the PR removes listen.v2 exports from src/deepgram/listen/__init__.py and removes the v2 surface from src/deepgram/listen/client.py. Update the example to match the supported API surface, or reintroduce v2 support so this example runs.
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example imports/uses deepgram.listen.v2 and client.listen.v2, but the PR removes listen.v2 exports from src/deepgram/listen/__init__.py and removes the v2 surface from src/deepgram/listen/client.py. Update the example to match the supported API surface, or reintroduce v2 support so this example runs.
| client = DeepgramClient() | |
| try: | |
| with client.listen.connect(model="flux-general-en", encoding="linear16", sample_rate="16000") as connection: | |
| def on_message(message) -> None: | |
| msg_type = getattr(message, "type", "Unknown") | |
| print(f"Received {msg_type} event") | |
| # Extract transcription-like information when available | |
| if hasattr(message, "transcript"): | |
| print(f"Turn transcript: {getattr(message, 'transcript', None)}") | |
| print(f"Turn event: {getattr(message, 'event', None)}") | |
| print(f"Turn index: {getattr(message, 'turn_index', None)}") |
| except ImportError: | ||
| raise ImportError( | ||
| "PyJWT is required for proxy JWT support. " | ||
| "Install it with: pip install 'deepgram-sdk[proxy]' or pip install PyJWT" |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message instructs users to install deepgram-sdk[proxy], but this PR does not add a proxy extra to pyproject.toml (and TODO.md indicates it’s still pending). Either add the Poetry extra and optional dependency now, or adjust this message to only recommend pip install PyJWT until the extra exists.
| "Install it with: pip install 'deepgram-sdk[proxy]' or pip install PyJWT" | |
| "Install it with: pip install PyJWT" |
| ) | ||
|
|
||
| proxy._async_client = httpx.AsyncClient(transport=httpx.MockTransport(mock_handler)) | ||
|
|
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test creates an httpx.AsyncClient but never closes it, which can cause resource warnings and flaky test behavior. Consider closing it via a fixture finalizer (yield fixture) or wiring an app shutdown handler that calls await proxy._async_client.aclose().
| async def close_client() -> None: | |
| async_client = getattr(proxy, "_async_client", None) | |
| if async_client is not None: | |
| await async_client.aclose() | |
| application.add_event_handler("shutdown", close_client) |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says Ellipsis/OMIT values should be excluded, but at the top-level this returns None, which can serialize to JSON null (and still be sent) depending on the caller. Prefer a strategy that truly omits the value (e.g., raising to force callers to filter, or returning a sentinel that upstream serializers drop) to avoid accidentally sending null for omitted fields.
| raise ValueError( | |
| "Top-level Ellipsis/OMIT values cannot be JSON-encoded. " | |
| "Callers should omit these values instead of passing them to jsonable_encoder." | |
| ) |
Summary
deepgram.proxymodule withDeepgramProxyclass that keeps API keys server-side while proxying REST and WebSocket requests to DeepgramUsage
Test plan
pytest tests/custom/test_proxy_*.py— 57 tests passingruff check src/deepgram/proxy/— cleanmypy src/deepgram/proxy/ --ignore-missing-imports— cleanpip install -e ".[proxy]"after pyproject.toml update (documented in TODO.md)🤖 Generated with Claude Code