Skip to main content

LiveKit client for the saa hosted bridge — consume attention/interrupt/interjection events inside your voice agent.

Project description

saa-livekit-client

LiveKit client for the saa.

Adds attention-aware gating, barge-in, and proactive interjection to any LiveKit voice agent.

Install

pip install saa-livekit-client

Quickstart: existing voice agent

import asyncio
import os

from livekit.agents import Agent, AgentServer, AgentSession, JobContext, cli
from livekit.plugins import openai
from saa_livekit_client import (
    AttentionEngine, attention_agent_token, start_attention_session,
)


class MyAssistant(Agent):
    def __init__(self):
        super().__init__(instructions="You are a helpful assistant")


server = AgentServer()


@server.rtc_session()
async def entrypoint(ctx: JobContext):
    await ctx.connect()
    user = await ctx.wait_for_participant()

    # summon the saa hosted agent into the room
    saa = await start_attention_session(
        api_key=os.environ["SAA_API_KEY"],
        livekit_url=os.environ["LIVEKIT_URL"],
        agent_token=attention_agent_token(
            api_key=os.environ["LIVEKIT_API_KEY"],
            api_secret=os.environ["LIVEKIT_API_SECRET"],
            room_name=ctx.room.name,
        ),
        room_name=ctx.room.name,
        participant_identity=user.identity,
    )
    ctx.add_shutdown_callback(saa.stop)

    # stand up the voice agent, then wire saa on top of the running session
    # (session.input / session.interrupt() are only valid once started)
    voice = AgentSession(llm=openai.realtime.RealtimeModel(voice="alloy"))
    await voice.start(agent=MyAssistant(), room=ctx.room)

    engine = AttentionEngine(ctx.room, agent_identity=saa.agent_identity)
    ctx.add_shutdown_callback(engine.stop)

    @engine.on_prediction
    def _(p):
        # gate the mic, only class 2 (talking-to-device) reaches the model
        voice.input.set_audio_enabled(p.aligned_class == 2)

    @engine.on_interrupt
    def _(ev):
        voice.interrupt()

    @engine.on_interjection
    async def _(ev):
        await voice.generate_reply(instructions="Briefly offer to help")

    # tell saa when the agent is speaking, arms interrupt, suppresses interjection
    @voice.on("agent_state_changed")
    def _(ev):
        if ev.new_state == "speaking":
            asyncio.create_task(engine.responding_start())
        elif ev.old_state == "speaking":
            asyncio.create_task(engine.responding_stop())

    await engine.start()


if __name__ == "__main__":
    cli.run_app(server)

That's the whole integration. Works with any LiveKit pipeline, including RealtimeModel speech-to-speech. Runnable variants are in the examples/livekit/ samples. (WorkerOptions(entrypoint_fnc=...) also works on 1.5.x, the older idiom.)

Greenfield, build_attention_entrypoint

For new voice agents that don't have an existing pipeline:

from livekit.agents import AgentServer, JobContext, cli
from saa_livekit_client import build_attention_entrypoint, TurnReadyEvent

async def handle_turn(event: TurnReadyEvent, ctx: JobContext):
    # event.audio_pcm16 = int16 mono 16 kHz; event.frames = list[TurnFrame]
    response_pcm = await my_llm.respond(event.audio_pcm16, frames=event.frames)
    await publish_response_audio(ctx.room, response_pcm)

entrypoint = build_attention_entrypoint(on_turn=handle_turn)

server = AgentServer()
server.rtc_session()(entrypoint)
# or the older idiom: cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))

if __name__ == "__main__":
    cli.run_app(server)

Environment: SAA_API_KEY, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL.

Event types

Event Fires Payload
PredictionEvent every 250 ms raw_class, aligned_class (0/1/2), confidence, source, num_faces, responding
VADEvent every 250 ms is_speech, probability
warmup model warmed up, predictions begin
listening_start / listening_cancelled state edges
TurnReadyEvent end of user turn audio_pcm16, duration, frames, context
InterruptEvent user barges in during AI playback confidence
InterjectionEvent humans went quiet after side-chat reason, audio_pcm16, duration
ErrorEvent out-of-band errors code, message

Classes: 0=silent, 1=human-to-human, 2=human-to-device. responding is True while the AI is mid-playback.

Each is delivered through an @engine.on_* callback: on_prediction, on_vad, on_warmup, on_listening_start, on_listening_cancelled, on_turn_ready, on_interrupt, on_interjection, on_error.

Upstream actions

await attention.mute()                       # stop feeding mic to processor
await attention.unmute()
await attention.responding_start()           # AI is now speaking
await attention.responding_stop()
await attention.set_threshold(0.65)          # model class-2 confidence threshold

These are routed only to the SAA agent (destination_identities=[...]) so they never leak to other room participants.

Requirements

  • Python 3.10+
  • LiveKit URL must be publicly reachable from our cloud (no private VPC)
  • Audio + video tracks must both be available (the model is multimodal)
  • Customer voice agent and hosted attention agent share the same LiveKit room

License

Apache-2.0. © Attention Labs.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

saa_livekit_client-0.3.0.tar.gz (21.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

saa_livekit_client-0.3.0-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

File details

Details for the file saa_livekit_client-0.3.0.tar.gz.

File metadata

  • Download URL: saa_livekit_client-0.3.0.tar.gz
  • Upload date:
  • Size: 21.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for saa_livekit_client-0.3.0.tar.gz
Algorithm Hash digest
SHA256 427889f17de69a73134f7d2b7158c7f75a3449c9b8307989392c0d9b6b6c599a
MD5 f520aa98b6950451743714f664d8725f
BLAKE2b-256 80f171eebb6f42d36c17810e12cd70264c990a989e4ed7389b13ac6be14adbf8

See more details on using hashes here.

File details

Details for the file saa_livekit_client-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for saa_livekit_client-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 566914d7d26f2823fc21e3ef0cf0bbd7615735468ca42b20e59e7ffdc9835bf1
MD5 59b313b5faad0668e88060026396f8b5
BLAKE2b-256 2fb2a43acf29722e52df1316f9590019f22ffb2de3c5de8fe7008612756dd620

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page