Skip to content

Public API to re-arm the user-away window (user_state stuck "away" while the user waits on a long tool run) #6883

Description

@0xNuru

Use case

Voice agent with a long-running async tool (AsyncToolset): the user asks for something, the tool runs for 30–90s, and the user quite reasonably waits in silence. After user_away_timeout the session flips user_state to "away" and emits user_state_changed once.

The problem: "away" is edge-triggered, and the away timer only re-arms while the user is "listening"_set_user_away_timer() is called from _update_agent_state / _update_user_state under a mutual-listening check (state == "listening" and self._user_state == "listening", agent_session.py, v1.6.10). So once a silent user is marked away, the agent finishing its tool run and speaking the results does not restart the window, and no further user_state_changed events ever fire for that user unless they speak. Any idle etiquette built on that event (check in once, then say goodbye and close the room) is silently disarmed for the rest of the session: results get announced to a silent user and the session hangs open indefinitely, holding a live room on nobody.

What we do today

We call the private method to flip the user back and let the framework re-arm its own timer:

if session.user_state == "away":
    session._update_user_state("listening")

This works well — _update_user_state no-ops on same-state, re-arms the away timer under the mutual-listening check, and emits the event — but it's private surface, so it's pinned-version-only and has to be re-verified on every SDK upgrade.

Feature request

A supported way to tell the session "this user is still here / restart the away window", for example any of:

  • session.reset_user_away_timer() — re-arm the window without touching state; or
  • a public session.set_user_state("listening") (with the same guards _update_user_state already has); or
  • an option like user_away_resets_on_agent_speech: bool so agent speech re-arms the window even when the user is already "away" — which would cover the "user is waiting on the agent" case with no application code at all.

Happy to open a PR for whichever shape you'd prefer.

Environment: livekit-agents 1.6.10, STT-LLM-TTS pipeline, async tools via AsyncToolset.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions