Module livekit.agents.voice.report
Classes
class SessionReport (job_id: str,
room_id: str,
room: str,
options: AgentSessionOptions,
events: list[AgentEvent],
chat_history: ChatContext,
audio_recording_path: Path | None = None,
audio_recording_started_at: float | None = None,
duration: float | None = None,
started_at: float | None = None,
timestamp: float = <factory>,
model_usage: list[ModelUsage] | None = None,
sdk_version: str = <factory>,
agent_name: str = '',
tags: list[str] = <factory>)-
Expand source code
@dataclass class SessionReport: job_id: str room_id: str room: str options: AgentSessionOptions events: list[AgentEvent] chat_history: ChatContext audio_recording_path: Path | None = None audio_recording_started_at: float | None = None """Timestamp when the audio recording started""" duration: float | None = None started_at: float | None = None """Timestamp when the session started""" timestamp: float = field(default_factory=time.time) """Timestamp when the session report was created, typically at the end of the session""" model_usage: list[ModelUsage] | None = None """Usage summaries for the session, one per model/provider combination""" sdk_version: str = field(default_factory=lambda: __version__) """Version of the agents SDK""" agent_name: str = "" """Name the agent was dispatched with""" tags: list[str] = field(default_factory=list) """Tags set on the job's Tagger, sorted""" def to_dict(self, *, include_chat_history: bool = True, include_events: bool = True) -> dict: """Serialize the report. A ``False`` flag omits that key from the result.""" report: dict = { "job_id": self.job_id, "room_id": self.room_id, "room": self.room, } if include_events: events_dict: list[dict] = [] for event in self.events: if event.type == "metrics_collected": # metrics are too noisy, Cloud is using the chat_history as the source of thruth continue events_dict.append(event.model_dump()) report["events"] = events_dict report["audio_recording_path"] = ( str(self.audio_recording_path.absolute()) if self.audio_recording_path else None ) report["audio_recording_started_at"] = self.audio_recording_started_at report["options"] = { "allow_interruptions": self.options.interruption["enabled"], "discard_audio_if_uninterruptible": self.options.interruption[ "discard_audio_if_uninterruptible" ], "min_interruption_duration": self.options.interruption["min_duration"], "min_interruption_words": self.options.interruption["min_words"], "min_endpointing_delay": self.options.endpointing["min_delay"], "max_endpointing_delay": self.options.endpointing["max_delay"], "max_tool_steps": self.options.max_tool_steps, "user_away_timeout": self.options.user_away_timeout, "min_consecutive_speech_delay": self.options.min_consecutive_speech_delay, "preemptive_generation": dict(self.options.preemptive_generation), "recording_options": dict(self.options.recording_options), } if include_chat_history: report["chat_history"] = self.chat_history.to_dict(exclude_timestamp=False) report["timestamp"] = self.timestamp report["usage"] = self._usage_to_dict() if self.model_usage else None report["sdk_version"] = self.sdk_version report["agent_name"] = self.agent_name report["tags"] = list(self.tags) report["duration_ms"] = int(self.duration * 1000) if self.duration is not None else None report["user_turns"] = self._user_turns() report["errors"] = self._error_counts() report["close_reason"] = self._last_close_reason_name() return report def _user_turns(self) -> int: user_turns = 0 for item in self.chat_history.items: if item.type == "message" and item.role == "user": user_turns += 1 return user_turns def _error_counts(self) -> dict[str, int]: # every key is always present, so readers need no defaults errors = dict.fromkeys(_ERROR_KEYS.values(), 0) for event in self.events: if event.type == "error": key = _ERROR_KEYS.get(getattr(event.error, "type", "")) if key is not None: errors[key] += 1 return errors def _last_close_reason_name(self) -> str | None: """Proto enum name of the last close event's reason, or None without a close event.""" name: str | None = None for event in self.events: if event.type == "close": name = _close_reason_name(event.reason) return name def _usage_to_dict(self) -> list[dict] | None: if self.model_usage is None: return None # exclude_defaults drops ``type``, which tells the usage kinds apart return [ {"type": summary.type, **summary.model_dump(exclude_defaults=True)} for summary in self.model_usage ]SessionReport(job_id: 'str', room_id: 'str', room: 'str', options: 'AgentSessionOptions', events: 'list[AgentEvent]', chat_history: 'ChatContext', audio_recording_path: 'Path | None' = None, audio_recording_started_at: 'float | None' = None, duration: 'float | None' = None, started_at: 'float | None' = None, timestamp: 'float' =
, model_usage: 'list[ModelUsage] | None' = None, sdk_version: 'str' = , agent_name: 'str' = '', tags: 'list[str]' = ) Instance variables
var agent_name : str-
Name the agent was dispatched with
var audio_recording_path : pathlib.Path | Nonevar audio_recording_started_at : float | None-
Timestamp when the audio recording started
var chat_history : livekit.agents.llm.chat_context.ChatContextvar duration : float | Nonevar events : list[livekit.agents.voice.events.UserInputTranscribedEvent | livekit.agents.voice.events.UserTranscriptionTimeoutEvent | livekit.agents.voice.events.UserStateChangedEvent | livekit.agents.voice.events.AgentStateChangedEvent | livekit.agents.voice.events.AgentFalseInterruptionEvent | livekit.agents.voice.events.MetricsCollectedEvent | livekit.agents.voice.events.SessionUsageUpdatedEvent | livekit.agents.voice.events.ConversationItemAddedEvent | livekit.agents.voice.events.FunctionToolsExecutedEvent | livekit.agents.voice.events.SpeechCreatedEvent | livekit.agents.voice.events.ToolExecutionUpdatedEvent | livekit.agents.voice.events.ErrorEvent | livekit.agents.voice.events.CloseEvent | OverlappingSpeechEvent]var job_id : strvar model_usage : list[livekit.agents.metrics.usage.LLMModelUsage | livekit.agents.metrics.usage.TTSModelUsage | livekit.agents.metrics.usage.STTModelUsage | livekit.agents.metrics.usage.InterruptionModelUsage | livekit.agents.metrics.usage.EOTModelUsage] | None-
Usage summaries for the session, one per model/provider combination
var options : livekit.agents.voice.agent_session.AgentSessionOptionsvar room : strvar room_id : strvar sdk_version : str-
Version of the agents SDK
var started_at : float | None-
Timestamp when the session started
-
Tags set on the job's Tagger, sorted
var timestamp : float-
Timestamp when the session report was created, typically at the end of the session
Methods
def to_dict(self, *, include_chat_history: bool = True, include_events: bool = True) ‑> dict-
Expand source code
def to_dict(self, *, include_chat_history: bool = True, include_events: bool = True) -> dict: """Serialize the report. A ``False`` flag omits that key from the result.""" report: dict = { "job_id": self.job_id, "room_id": self.room_id, "room": self.room, } if include_events: events_dict: list[dict] = [] for event in self.events: if event.type == "metrics_collected": # metrics are too noisy, Cloud is using the chat_history as the source of thruth continue events_dict.append(event.model_dump()) report["events"] = events_dict report["audio_recording_path"] = ( str(self.audio_recording_path.absolute()) if self.audio_recording_path else None ) report["audio_recording_started_at"] = self.audio_recording_started_at report["options"] = { "allow_interruptions": self.options.interruption["enabled"], "discard_audio_if_uninterruptible": self.options.interruption[ "discard_audio_if_uninterruptible" ], "min_interruption_duration": self.options.interruption["min_duration"], "min_interruption_words": self.options.interruption["min_words"], "min_endpointing_delay": self.options.endpointing["min_delay"], "max_endpointing_delay": self.options.endpointing["max_delay"], "max_tool_steps": self.options.max_tool_steps, "user_away_timeout": self.options.user_away_timeout, "min_consecutive_speech_delay": self.options.min_consecutive_speech_delay, "preemptive_generation": dict(self.options.preemptive_generation), "recording_options": dict(self.options.recording_options), } if include_chat_history: report["chat_history"] = self.chat_history.to_dict(exclude_timestamp=False) report["timestamp"] = self.timestamp report["usage"] = self._usage_to_dict() if self.model_usage else None report["sdk_version"] = self.sdk_version report["agent_name"] = self.agent_name report["tags"] = list(self.tags) report["duration_ms"] = int(self.duration * 1000) if self.duration is not None else None report["user_turns"] = self._user_turns() report["errors"] = self._error_counts() report["close_reason"] = self._last_close_reason_name() return reportSerialize the report. A
Falseflag omits that key from the result.