bitter-agency-4722
12/27/2025, 7:49 AMtall-airline-16756
12/27/2025, 7:49 AMtall-airline-16756
12/27/2025, 7:49 AMuser_input_transcribed) and append only final transcripts to a local list (ignore interim text).
2. Capture agent responses via conversation_item_added (store final agent items).
3. On session end (session shutdown or agent_shutdown callback), write the accumulated conversation history to a file or upload to storage (JSON, plain text, or your desired format).
Example pseudocode:
conversation_history = []
@session.on("user_input_transcribed")
def on_transcript(t):
if t.is_final:
conversation_history.append({"role":"user","text":t.transcript,"ts":t.timestamp})
@session.on("conversation_item_added")
def on_item(item):
if item.role == "agent" and item.final:
conversation_history.append({"role":"agent","text":item.text,"ts":item.timestamp})
@ctx.on("agent_shutdown")
async def on_shutdown():
with open("full_transcript.json","w") as f:
json.dump(conversation_history,f,indent=2)
You can also call await session.aclose() to force finalization if the user disconnects early, then export.
Option 2 — Use Agent Observability (LiveKit Cloud) If you use LiveKit Cloud’s Agent Observability, the dashboard already records synchronized audio, transcripts, and logs per session. You can view, export, or download the full, timestamped conversation from the Agent insights tab without manual logging.
If you want, tell me:
• Which programming language/platform you’re using (Python, JS, etc.), and
• Whether you want the transcript in JSON, plain text, or uploaded to cloud storage
I’ll give a concrete code snippet or storage/upload steps for your setup.
Sources: Interrupt User | LiveKit docs | Transcriber | LiveKit docs | How to capture real-time agent transcriptions during conversations | Collect recording consent with tasks | LiveKit docs | https://blog.livekit.io/streamline-troubleshooting-with-agent-observability/#/portal/signup|bitter-agency-4722
12/27/2025, 9:01 AMtall-airline-16756
12/27/2025, 9:01 AMimport json
from datetime import datetime
Inside your entrypoint, before await session.start(...), initialize the conversation list:
conversation_history = []
Register handlers after creating session (but before await session.start(...)):
# collect final user STT transcripts (diarized)
@session.on("user_input_transcribed")
def on_user_transcribed(t):
if getattr(t, "is_final", False):
conversation_history.append({
"role": "user",
"text": t.transcript,
"timestamp": getattr(t, "timestamp", datetime.utcnow().isoformat())
})
# collect final agent replies (conversation items)
@session.on("conversation_item_added")
def on_conversation_item(item):
if getattr(item, "role", None) == "agent" and getattr(item, "final", False):
conversation_history.append({
"role": "agent",
"text": getattr(item, "text", ""),
"timestamp": getattr(item, "timestamp", datetime.utcnow().isoformat())
})
Add a shutdown handler to save the file (place after handlers):
@session.on("agent_shutdown")
async def on_shutdown():
# write JSON locally - change filename or upload flow as needed
with open("full_transcript.json", "w", encoding="utf-8") as f:
json.dump(conversation_history, f, ensure_ascii=False, indent=2)
Notes and optional tweaks:
• You can call await session.aclose() somewhere to force finalization before shutdown if needed.
• If your STT object uses different field names for final transcripts or timestamps, replace is_final, transcript, and timestamp with the correct attributes from your runtime events.
• To upload instead of saving locally, replace the file write with your cloud storage API call.
If you’d like, tell me:
• preferred output format (JSON, plain text, CSV), and
• whether you want the file uploaded to S3/GCS so I can add that snippet.