Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/next-release/changeset-reload-dir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"livekit-agents": minor
---

Add `--reload-dir` (repeatable) and `LIVEKIT_RELOAD_DIRS` to `dev` so the watcher
restarts the worker on edits inside additional, user-supplied directories.
Auto-discovery of the entrypoint, `livekit.agents`, and editable plugins is
unchanged; the new flag is purely additive.
31 changes: 28 additions & 3 deletions livekit-agents/livekit/agents/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1816,26 +1816,51 @@ def dev(
envvar="LIVEKIT_API_SECRET",
),
] = None,
reload_dir: Annotated[
list[pathlib.Path] | None, # noqa: UP007
typer.Option(
"--reload-dir",
envvar="LIVEKIT_RELOAD_DIRS",
help=(
"Additional directory to watch for .py changes (repeatable). "
"Watched recursively; avoid huge trees. "
"Env var LIVEKIT_RELOAD_DIRS is split on os.pathsep."
),
),
] = None,
) -> None:
c = AgentsConsole.get_instance()
_configure_logger(c, log_level.value)

resolved_reload_dirs: list[pathlib.Path] = []
for p in reload_dir or []:
rp = pathlib.Path(p).expanduser().resolve()
if not rp.exists():
c.print(" ")
c.print(f"[error]--reload-dir path does not exist: {p}")
c.print(" ")
raise typer.Exit(code=1)
resolved_reload_dirs.append(rp)

args = proto.CliArgs(
log_level=log_level.value,
url=url,
api_key=api_key,
api_secret=api_secret,
devmode=True,
reload=reload,
reload_dirs=resolved_reload_dirs,
)

c = AgentsConsole.get_instance()
_configure_logger(c, log_level.value)

term_program = os.environ.get("TERM_PROGRAM")

if term_program == "iTerm.app" and args.reload:
c.print("[error]Auto-reload is not supported on the iTerm2 terminal, disabling...")
args.reload = False

if not args.reload:
if resolved_reload_dirs:
c.print("[error]--reload-dir provided but auto-reload is disabled; ignoring.")
_run_worker(server=server, args=args)
return

Expand Down
5 changes: 5 additions & 0 deletions livekit-agents/livekit/agents/cli/proto.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations # noqa: I001

import io
import pathlib
import socket
from dataclasses import dataclass, field
from typing import ClassVar
Expand All @@ -23,6 +24,10 @@ class CliArgs:
devmode: bool = False
reload: bool = False

# extra directories supplied by the user via `--reload-dir` / LIVEKIT_RELOAD_DIRS;
# unioned with the auto-discovered watch paths inside WatchServer.
reload_dirs: list[pathlib.Path] = field(default_factory=list)

# simulate_job: str | None = None

# internal states
Expand Down
9 changes: 7 additions & 2 deletions livekit-agents/livekit/agents/cli/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,14 @@ def __init__(
self._close_fut = asyncio.Future[None]()

async def run(self) -> None:
watch_paths = _find_watchable_paths(self._main_file)
for pth in watch_paths:
auto_paths = _find_watchable_paths(self._main_file)
user_paths = list(self._cli_args.reload_dirs)
watch_paths = [*auto_paths, *user_paths]

for pth in auto_paths:
logger.log(DEV_LEVEL, f"Watching {pth}")
for pth in user_paths:
logger.log(DEV_LEVEL, f"Watching {pth} (user)")

self._pch = await utils.aio.duplex_unix._AsyncDuplex.open(self._mp_pch)
read_ipc_task = self._loop.create_task(self._read_ipc_task())
Expand Down
Loading