# Hamming plugin for LiveKit Agents Post-call monitoring and session export for LiveKit Agents with Hamming. ## Installation Install the plugin from a checked out repository or extracted source archive: ```bash python -m pip install ./livekit-plugins/livekit-plugins-hamming ``` ## Pre-requisites You will need Hamming credentials before configuring the plugin. - `HAMMING_API_KEY` - `HAMMING_EXTERNAL_AGENT_ID` Credentials can be passed directly or through environment variables. ## Usage ```python import os from livekit.agents import AgentSession, JobContext from livekit.plugins import hamming async def entrypoint(ctx: JobContext) -> None: await ctx.connect() hamming.configure_hamming( api_key=os.environ["HAMMING_API_KEY"], external_agent_id=os.environ["HAMMING_EXTERNAL_AGENT_ID"], recording={"mode": "session_audio"}, ) session = AgentSession() hamming.attach_session( session, job_ctx=ctx, customer_metadata={ "deployment": { "environment": "prod", "prompt_version": "v17", }, "experiment": { "variant": "B", }, }, external_links=[ { "label": "CRM Contact", "url": "https://crm.example.com/contact/123", "source": "salesforce", } ], session_mode="testing", ) ``` ## Unified Responsibilities The Hamming plugin is intentionally focused on one responsibility: - post-call session export for Call Review and testing workflows Use `attach_session(...)` for per-call review/testing context: - `customer_metadata` - `external_links` - `session_mode` ## Call Review And Testing Fields ### `customer_metadata` Use `customer_metadata` for filterable customer-owned metadata: ```python hamming.attach_session( session, job_ctx=ctx, customer_metadata={ "deployment": {"environment": "prod"}, "experiment": {"variant": "B"}, }, ) ``` ### `external_links` Use `external_links` for click-through operator links: ```python hamming.attach_session( session, job_ctx=ctx, external_links=[ { "label": "CRM Contact", "url": "https://crm.example.com/contact/123", "source": "salesforce", "description": "Primary customer record", } ], ) ``` ### `session_mode` Use `session_mode="testing"` when the call is part of a testing workflow: ```python hamming.attach_session( session, job_ctx=ctx, session_mode="testing", ) ``` ## Recording Modes The plugin supports explicit recording modes through `configure_hamming(recording=...)`. If `recording` is omitted, the plugin exports monitoring payloads only and does not start or resolve recordings. - `none` - Send monitoring payload only. - `session_audio` - Use LiveKit session recording and inline `recording_capture` on the final `/collect` payload. - `participant_egress` - Start managed LiveKit participant egress and send dual-track recording URLs derived from deterministic output paths. - `room_composite` - Start managed LiveKit room composite egress and send a single `recording_url` derived from a deterministic output path. ### Session Audio (Default Simple Path) ```python hamming.configure_hamming( api_key=os.environ["HAMMING_API_KEY"], external_agent_id=os.environ["HAMMING_EXTERNAL_AGENT_ID"], recording={"mode": "session_audio"}, ) ``` ### Managed Participant Egress ```python hamming.configure_hamming( api_key=os.environ["HAMMING_API_KEY"], external_agent_id=os.environ["HAMMING_EXTERNAL_AGENT_ID"], recording={ "mode": "participant_egress", "livekit": { "url": os.environ["LIVEKIT_URL"], "api_key": os.environ["LIVEKIT_API_KEY"], "api_secret": os.environ["LIVEKIT_API_SECRET"], }, "s3": { # Required for deterministic artifact URL resolution. "public_url_base": os.environ.get("LIVEKIT_RECORDING_PUBLIC_URL_BASE", ""), # Optional. Include upload credentials only if the plugin should write # directly to S3 instead of relying on LiveKit project defaults. "access_key": os.environ.get("LIVEKIT_RECORDING_S3_ACCESS_KEY", ""), "secret": os.environ.get("LIVEKIT_RECORDING_S3_SECRET", ""), "region": os.environ.get("LIVEKIT_RECORDING_S3_REGION", ""), "bucket": os.environ.get("LIVEKIT_RECORDING_S3_BUCKET", ""), }, }, ) ``` ### Managed Room Composite ```python hamming.configure_hamming( api_key=os.environ["HAMMING_API_KEY"], external_agent_id=os.environ["HAMMING_EXTERNAL_AGENT_ID"], recording={ "mode": "room_composite", "livekit": { "url": os.environ["LIVEKIT_URL"], "api_key": os.environ["LIVEKIT_API_KEY"], "api_secret": os.environ["LIVEKIT_API_SECRET"], }, "audio_only": True, "file_type": "ogg", }, ) ``` Notes: - Managed remote recording modes require LiveKit server API credentials. - Managed remote recording modes also require `job_ctx` when calling `hamming.attach_session(...)`. - Managed remote recording modes require deterministic artifact URL resolution via `recording.s3.public_url_base` or `recording.s3.bucket` + `recording.s3.region`. - If you provide full S3 credentials, the plugin uses those upload settings for egress output. - If you omit S3 upload credentials, your LiveKit project must already have default file output storage configured. - The plugin does not poll LiveKit for completed artifact locations; it derives the final public URLs from the configured output path. ## Verify configuration ```python import os from livekit.plugins import hamming report = hamming.doctor(api_key=os.environ["HAMMING_API_KEY"]) print(report.to_dict()) ``` ## Notes - Sessions are exported when attached through `hamming.attach_session(...)`. - Recording is opt-in. Omitting `recording=...` sends monitoring payloads without recording artifacts. - `auto_record_audio=True` is still supported as a backward-compatible alias for `recording={"mode": "session_audio"}`. - Managed remote recording modes stop egress on close and send deterministic artifact URLs through the same `/api/rest/v2/collect` ingestion path. ## Troubleshooting - `RuntimeError: hamming is not configured` - Call `hamming.configure_hamming(...)` before `hamming.attach_session(...)`. - `ValueError: Hamming API key required` - Set `HAMMING_API_KEY` or pass `api_key=...`. - `external_agent_id is required` - Set `HAMMING_EXTERNAL_AGENT_ID` or pass `external_agent_id=...`. - `Unsupported recording mode` - Use `none`, `session_audio`, `participant_egress`, or `room_composite`. - `recording mode 'participant_egress' requires LiveKit server credentials` - Provide `recording.livekit` or set `LIVEKIT_URL`, `LIVEKIT_API_KEY`, and `LIVEKIT_API_SECRET`. - `recording mode 'participant_egress' requires deterministic artifact URL resolution` - Provide `recording.s3.public_url_base` or `recording.s3.bucket` + `recording.s3.region`. - `recording mode 'participant_egress' requires JobContext` - Pass `job_ctx=ctx` to `hamming.attach_session(...)` or call it from inside the active LiveKit job.