Conversation history
When enabled, VoiceThere stores final user speech (STT) and agent TTS text for each voice session. You review transcripts in the dashboard Conversation tab on the session detail page. This is for voice turn text only — DataChannel chat messages are not recorded in conversation history.
Where to configure
- Dashboard: Project Settings → Session settings → Conversation history toggle (
conversation_history_enabled). - CLI:
voicethere projects session-settings list/voicethere projects session-settings set conversation_history_enabled <true|false> - API:
PATCH /projects/:projectId/session-settings— see Control plane API.
Default is true. Settings apply on the next Deploy to cloud. Turning history off stops recording new transcripts; existing rows remain until retention policies remove them.
What is stored
- User turns — final STT text after the speech pipeline commits an utterance.
- Agent turns — text sent to TTS for spoken replies.
Partial STT, barge-in events, and data-channel payloads are not listed in the Conversation tab. For runtime errors and agent logs, use Agent logs & session errors.
Dashboard: Conversation tab
Open a session from Project → Sessions → session detail. The Conversation tab shows a chronological transcript when history was enabled for that project at session time. Search and export behavior follows dashboard retention on your plan.
Turn details
Caller and agent rows in the session Timeline and Transcript views have an ⓘ button. It opens a small panel with the details of that one turn. Turns recorded before this feature shipped have no button.
- Caller turns: the speech-to-text vendor and model, the language, how long the caller spoke, how long the pipeline waited after speech ended before it committed the text, and what ended the turn (end of speech, a vendor final, or a timeout).
- Agent turns: the text-to-speech vendor, voice, model and quality tier, the number of characters, the time to first audio, how long after the transcript the reply started, how long it played, and the point where the caller interrupted it. After a voice or language switch, replies show the voice that actually spoke them.
Time to first audio is measured from the moment your agent asked for speech until the first audio came back from the voice. A reply that was queued behind an earlier one includes that wait. A reply served from the phrase cache is marked as cached and is not billed.
Estimated credits
The panel shows an estimate such as ≈ 0.25 credits. We work it out in the dashboard from the stored quantities (billed seconds for speech to text, characters and quality tier for text to speech) and the current rates in Billing & usage credits. The number is never stored and the API does not return it.
- Billing settles per session, so a single turn is an estimate. The session total on the usage statement is exact.
- Turns that ran on a cloud vendor you brought show No speech credits, because those vendors bill you directly.
- Session minutes are billed separately and do not appear on a turn. The wait messages your callers hear while a new language loads are billed too, but they are not transcript rows, so the turn estimates can add up to slightly less than the session.
API field
GET /api/v1/projects/:projectId/sessions/:sessionId/conversation returns an optional utterance object on each turn. Fields that are not known for a turn are left out. The vendor value is voicethere for the built-in speech, or the id of the cloud vendor (for example deepgram).
// caller turn
{ "sttVendor": "voicethere", "language": "en", "audioMs": 2300,
"audioBilledS": 3, "speechEndToFinalMs": 800, "finalReason": "end_of_utterance" }
// agent turn
{ "ttsVendor": "voicethere", "ttsVoice": "en-amy-low", "ttsQuality": "low",
"chars": 84, "cached": false, "timeToFirstAudioMs": 320,
"finalToReplyStartMs": 410, "playedMs": 4200, "interrupted": false }utteranceId links an agent turn to the caller turn it answers. Durations are in milliseconds, except audioBilledS (seconds).
Agent runtime controls
When the project setting is on, VoiceThere stores final STT and TTS text for each session. Call the @voicethere/agent helpers with the session id to stop storing turns while the caller shares a card number, PIN, or password. That is text history only. For voice audio, pause conversation recording instead.
- Sensitive input: call
setConversationHistoryEnabled(sessionId, false)(ordisableConversationHistory) before collecting secrets, thensetConversationHistoryEnabled(sessionId, true)(orenableConversationHistory) when it is safe to store turns again. - Availability: on
onSessionStart, checkconversationHistoryAvailableorisConversationHistoryAvailable(ctx)before you depend on these helpers. If the project setting was off at deploy time, the flag stays false for the whole session. - Project gate: the agent cannot turn project history on. Calling enable when
conversationHistoryAvailableis false resolves with{ ok: false, reason: "disabled" }. Disable still runs, so you can skip storage on a project that otherwise keeps history. - Timing: disable before the caller speaks the secret. A turn already in the pipeline can still land in storage once. Same idea as pausing recording before PII.
Helpers return a promise that resolves when VoiceThere acknowledges the control message. On local verify (no parent process), they resolve immediately with reason: "local_mock".
Minimal example
import {
disableConversationHistory,
enableConversationHistory,
speak,
} from "@voicethere/agent";
await disableConversationHistory(sessionId);
await speak(sessionId, "Please say your PIN. I will not save this part.");
// …caller speaks the secret…
await enableConversationHistory(sessionId);Disable history while collecting credentials
import {
defineAgent,
disableConversationHistory,
enableConversationHistory,
isConversationHistoryAvailable,
speak,
} from "@voicethere/agent";
const collectingSecret = new Set<string>();
export default defineAgent({
async onSessionStart(ctx) {
if (!isConversationHistoryAvailable(ctx)) return;
// History storage is on by default when the project setting is enabled.
},
async onUserSpeechFinal({ sessionId, text }) {
if (collectingSecret.has(sessionId)) {
if (/\bcontinue\b|done|finished/i.test(text)) {
collectingSecret.delete(sessionId);
await enableConversationHistory(sessionId);
await speak(sessionId, "Thanks. I will save the rest of this conversation.");
}
return;
}
if (/verify (my )?(account|card)|enter (your|my )?pin/i.test(text)) {
const off = await disableConversationHistory(sessionId);
if (!off.ok) return;
collectingSecret.add(sessionId);
await speak(
sessionId,
"Go ahead. I will not save this part. Say continue when you are done.",
);
}
},
});Storage caps & overage billing
Each plan includes a maximum number of stored conversations per project. When you exceed the effective cap, the oldest conversations roll off (FIFO). On the project billing settings panel you can toggle conversation overage billing:
- Overage on — storage can grow past the plan cap; overage credits apply for new conversations past your monthly included count. Only retention-day pruning runs (no FIFO cap while overage is on).
- Overage off — FIFO roll-off at your plan cap with no overage credits. If you had overage on, grew above the plan limit, then turn overage off, your current session count is frozen as an elevated rollover ceiling until you delete data or re-enable overage.
See also Billing & usage credits.
CLI examples
# Check whether conversation history is enabled voicethere projects session-settings list # Opt out of new transcripts (existing history kept) voicethere projects session-settings set conversation_history_enabled false voicethere deploy --wait # Re-enable recording voicethere projects session-settings set conversation_history_enabled true voicethere deploy --wait
Related
- Conversation recording — voice audio capture (separate from STT/TTS text history)
- Advanced voice settings
- Agent logs & session errors
- Session idle timeout