Skip to content

docs(examples): add Voice Agent session recorder - #781

Merged
GregHolmes merged 2 commits into
mainfrom
gh/voice-agent-session-recording-example
Sep 3, 2026
Merged

docs(examples): add Voice Agent session recorder#781
GregHolmes merged 2 commits into
mainfrom
gh/voice-agent-session-recording-example

Conversation

@GregHolmes

@GregHolmes GregHolmes commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an application-owned Voice Agent event recorder example
  • serialize received transcript, function-call, and latency events as JSON
  • document that transcripts and tool data need application consent, redaction, retention, and storage controls

Validation

  • poetry run ruff format --check examples/31-voice-agent-session-recording.py
  • poetry run ruff check examples/31-voice-agent-session-recording.py
  • poetry run mypy --ignore-missing-imports examples/31-voice-agent-session-recording.py
  • poetry run python -m py_compile examples/31-voice-agent-session-recording.py
  • poetry run mypy src/
  • poetry run mypy tests/typecheck
  • poetry run pytest -rP --cov=deepgram --cov-branch --cov-report=xml --cov-report=term-missing .

Closes #775

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Branch Rate Complexity Health
src.deepgram 97% 94% 0
src.deepgram.agent 100% 100% 0
src.deepgram.agent.v1 98% 100% 0
src.deepgram.agent.v1.settings 100% 100% 0
src.deepgram.agent.v1.settings.think 100% 100% 0
src.deepgram.agent.v1.settings.think.models 97% 100% 0
src.deepgram.auth 100% 100% 0
src.deepgram.auth.v1 100% 100% 0
src.deepgram.auth.v1.tokens 97% 100% 0
src.deepgram.core 88% 81% 0
src.deepgram.errors 100% 100% 0
src.deepgram.helpers 100% 95% 0
src.deepgram.listen 100% 100% 0
src.deepgram.listen.v1 98% 93% 0
src.deepgram.listen.v1.media 97% 100% 0
src.deepgram.listen.v2 98% 93% 0
src.deepgram.manage 100% 100% 0
src.deepgram.manage.v1 100% 100% 0
src.deepgram.manage.v1.models 96% 100% 0
src.deepgram.manage.v1.projects 97% 100% 0
src.deepgram.manage.v1.projects.billing 100% 100% 0
src.deepgram.manage.v1.projects.billing.balances 96% 100% 0
src.deepgram.manage.v1.projects.billing.breakdown 97% 100% 0
src.deepgram.manage.v1.projects.billing.fields 97% 100% 0
src.deepgram.manage.v1.projects.billing.purchases 97% 100% 0
src.deepgram.manage.v1.projects.keys 96% 100% 0
src.deepgram.manage.v1.projects.members 97% 100% 0
src.deepgram.manage.v1.projects.members.invites 96% 100% 0
src.deepgram.manage.v1.projects.members.scopes 96% 100% 0
src.deepgram.manage.v1.projects.models 96% 100% 0
src.deepgram.manage.v1.projects.usage 98% 100% 0
src.deepgram.manage.v1.projects.usage.breakdown 97% 100% 0
src.deepgram.manage.v1.projects.usage.fields 97% 100% 0
src.deepgram.read 100% 100% 0
src.deepgram.read.v1 100% 100% 0
src.deepgram.read.v1.text 98% 100% 0
src.deepgram.self_hosted 100% 100% 0
src.deepgram.self_hosted.v1 100% 100% 0
src.deepgram.self_hosted.v1.distribution_credentials 96% 100% 0
src.deepgram.speak 100% 100% 0
src.deepgram.speak.v1 98% 97% 0
src.deepgram.speak.v1.audio 91% 80% 0
src.deepgram.speak.v2 98% 93% 0
src.deepgram.speak.v2.audio 100% 100% 0
src.deepgram.voice_agent 100% 100% 0
src.deepgram.voice_agent.configurations 95% 100% 0
src.deepgram.voice_agent.variables 95% 100% 0
Summary 95% (6498 / 6813) 91% (1419 / 1552) 0

Scope: hand-maintained SDK logic. Fern-generated data models (types/, requests/), package __init__.py files, version.py, and the unused core/http_sse/ scaffolding are excluded — see .coveragerc. Unscoped whole-package coverage is ~70%.

@dg-coreylweathers dg-coreylweathers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What this PR does

Adds example 31: a standalone Voice Agent script that injects one text question, collects the transcript, function-call, and latency events the server sends, and writes them to one JSON file when the session ends. Closes #775. No SDK code changes.

What I checked

  • Does it run end to end? Yes. In a python:3.12 container with a valid key it finished in about 3 seconds and wrote a record with the user question, the assistant reply, and four latency reports (ttt_token_latency, ttt_text_latency, tts_latency, total_latency).
  • Is the temp-file claim true? Yes. The fallback temp file is created mode 0600. A file passed via --output gets the default umask (0644 in my run).
  • Can the API key leak? No. The key is absent from stdout, stderr, and the record; a fake-key run exposes nothing either.
  • Do the event names and imports match the SDK? Yes. All six imported types exist, and ConversationText, FunctionCallRequest, FunctionCallResponse, and LatencyReport are all in the server response union.
  • ruff format, ruff check, mypy, py_compile, and CI on 3.10-3.13 pass. No new runtime dependency.

Should-fix (non-blocking, can follow in a later commit)

  1. A server Error event is silently ignored. on_message (line ~130) handles only SettingsApplied and ConversationText, so if the think provider fails after the question is injected, the script waits the full 30 seconds and exits with "Timed out waiting for the agent to respond" while the real cause is lost. Example 30 prints Error events. Suggest adding, after the ConversationText branch:
            elif getattr(message, "type", None) == "Error":
                print(f"Agent error: {message.code} - {message.description}")
                assistant_response_event.set()

and raising with the server's message after the wait instead of a timeout.

  1. A failed or timed-out session writes no record. Both TimeoutError raises (lines ~151 and ~155) exit the with block before recorder.finish() and the write, so the events already collected are lost and ended_at stays null. The docstring says "after a successful session," so this is documented, but the failed session is the one a developer most wants to inspect. Suggest a try/finally around the with block that always writes the record and lets the exception propagate.

Nits, optional

  • Docstring (lines 1-13): the settings define no functions, so function_calls is always [] in a real run. One sentence saying so would set expectations.
  • Line ~113: a bad or missing key produces a raw traceback ending in InvalidStatus: HTTP 401; examples 18 and 30 print one line. Wrapping main() in except Exception as exc: print(f"Session failed: {type(exc).__name__}: {exc}", file=sys.stderr) would match them. The key is not in the traceback.
  • Line ~57: --output files get default permissions while the temp fallback is 0600 and the docstring stresses sensitive contents. Either open with 0o600 or say in the docstring that --output permissions are the caller's.

@GregHolmes
GregHolmes merged commit 30ad152 into main Sep 3, 2026
10 checks passed
@GregHolmes
GregHolmes deleted the gh/voice-agent-session-recording-example branch September 3, 2026 12:27
GregHolmes added a commit that referenced this pull request Sep 3, 2026
🤖 I have created a release *beep* *boop*
---


##
[7.8.1](v7.8.0...v7.8.1)
(2026-09-03)


### Bug Fixes

* **TextBuilder:** `ssml_to_deepgram()` now preserves a `<phoneme>`
pronunciation when its valid `ph` and `alphabet` attributes appear in
either order.
([#741](#741))
([7fd4b63](7fd4b63))
* **Credentials:** Explicitly passing `api_key=None` continues to
disable ambient `DEEPGRAM_API_KEY` lookup, which is important for
multi-tenant and test environments.
([#778](#778))
([e675990](e675990))
* **Credentials:** `DeepgramClient()` and `AsyncDeepgramClient()` now
resolve `DEEPGRAM_API_KEY` when constructed, so `load_dotenv()` can run
after importing the SDK. Closes
[#734](#734).
([#767](#767))
([ec362ec](ec362ec))
* **Custom transports:** Speak V2 WebSocket connections now honor
`transport_factory`, matching the routing behavior of other WebSocket
APIs for proxies, test doubles, and custom-hosted transports.
([#766](#766))
([0980663](0980663))


### Documentation

* **Transcription:** Clarified that Nova-3 assumes English when
`language` is omitted; non-English and multilingual audio require an
explicit language such as `fr` or `multi`.
([#771](#771))
([4574337](4574337))
* **Examples:** Added Listen V1 live microphone transcription with
optional `sounddevice`, device selection, bounded audio buffering,
transcript output, and clean Ctrl-C shutdown.
([#780](#780))
([08f0471](08f0471))
* **Examples:** Added a resilient Listen V1 live transcription pattern
with exponential backoff, reconnect-aware audio buffering, timestamp
continuity, and clean shutdown.
([#776](#776))
([96b2d11](96b2d11))
* **Examples:** Added an application-owned Voice Agent session recorder
that serializes received transcripts, function calls, and latency
reports as JSON while leaving consent, redaction, retention, and storage
policy to the application. Closes
[#775](#775).
([#781](#781))
([30ad152](30ad152))
* **Text-to-Speech:** Corrected streaming synthesis snippets to iterate
the response byte chunks instead of accessing a nonexistent `.stream`
attribute.
([#749](#749))
([178724e](178724e))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Greg Holmes <greg.holmes@deepgram.com>
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.

Example: Record a Voice Agent session as JSON

2 participants