feat(agent): Node.js agent support for lk agent dev/start/console#868
feat(agent): Node.js agent support for lk agent dev/start/console#868u9g wants to merge 5 commits into
Conversation
Builds on the Node project detection and spawn helpers from the session daemon work (#861) to wire the remaining agent run commands for Node: - `lk agent dev`/`start`: spawn the agents-js `dev` subcommand (Python keeps `start --dev`), normalize --log-level casing per runtime (agents-js only accepts lowercase, Python expects uppercase), and make the reload-server handshake (--reload-addr) Python-only — Node reloads are a plain kill+respawn since agents-js has no job-restore protocol. - Entrypoint discovery: probe per-runtime candidate lists (agent.ts, agent.js, src/agent.{ts,js} for Node; agent.py, src/agent.py for Python) instead of a single root default, and make the not-found message runtime-aware. - Probe `node --version` before running a TypeScript entrypoint and fail with a clear message on Node < 22.6 (no --experimental-strip-types). - resolveCredentials: ignore the global --url flag's default value so the project config (--project) can supply the URL; previously the spawned agent was always pointed at http://localhost:7880 unless --url or LIVEKIT_URL was set explicitly. `lk agent console` needed no changes beyond #861 — the spawn path was already runtime-agnostic. Tested end to end against agents-js' console CLI branch (#1706): console text mode, audio mode (mic/speaker + playback-finished handshake), ctrl-T mode toggle, --record output, dev worker registration, file-watch reload, and clean shutdown.
Node agents spawned by lk agent dev/start/console inherited only the shell environment, so credentials in a project .env file were never seen (Python agents conventionally load_dotenv() themselves). Discover a known env file in the project dir and pass it to Node's built-in dotenv with --env-file. The flag requires Node >= 20.6, so the type-stripping version check is refactored into a shared nodeVersion probe and the flag is skipped on older Nodes. Shell-exported variables still take precedence over file values.
A pre-connect job crash (e.g. missing API key in the entrypoint) leaves the worker process alive, so lk agent console sat on the spinner for the full 60s connect timeout before surfacing the traceback. Scan agent output for crash markers (Python's "job crashed" shutdown reason, agents-js's FATAL "console mode failed:") via a new FailSignals option on AgentStartConfig, and abort the connect wait immediately with the recent logs. The session daemon's wait gets the same treatment, reporting the log path through the ready pipe. Verified against agents @ a61578853: a missing .env now fails in ~4s with the full traceback instead of timing out at 60s.
| args = append(args, "--experimental-strip-types") | ||
| } | ||
| // --env-file requires Node >= 20.6; skip the flag (old behavior) on older Nodes. | ||
| if envFile := agentfs.FindEnvFile(cfg.Dir); envFile != "" && nodeVersionAtLeast(major, minor, ok, 20, 6) { |
There was a problem hiding this comment.
@rektdeckard What's your thoughts on auto-loading the env file?
There was a problem hiding this comment.
Realistically, agent code should already be doing this itself, no? And if it isn't (user has hardcoded keys or whatever) that's assumed to be intentional?
There was a problem hiding this comment.
true, I added it for ease-of-use for running the examples, but for real users, more than likely they have already implemented the key flow themselves. It might just make more sense to support passing additional node args via an environment variable.
There was a problem hiding this comment.
++, probably allowing arbitrary arguments to be forwarded is smart. Seen it with the -- separator, e.g.
lk agent console src/main.py -- --log-level=DEBUG
There was a problem hiding this comment.
done. we now forward -- --env-file=.env. --log-level is a bad example for this because we explicitly set that within livekit-cli, and this feature's goal is to allow users to set their own node/python interpreter flags.
also, Brian's PR which this PR is based on adds --experimental-strip-types, which I just checked and is no longer required since node 24 (current LTS). Is it worth adding the flag unconditionally as we do now, or given that we now provide a way to pass the flag manually, should we no longer pass it ourselves?
There was a problem hiding this comment.
We can drop it, I'll fix this in my branch
There was a problem hiding this comment.
Maybe anything we have explicit command line parameters for that just normalize and forward to the agent, including all the stuff that maps debug levels and such, can be dropped. We lean into "pass args yourself".
…--env-file" This reverts commit 2430a24. Per PR review, agent code is expected to load its own env; auto-loading a discovered .env file second-guesses that. Arbitrary arg forwarding (e.g. a -- separator) is the preferred ease-of-use mechanism instead.
Per PR review, replace the reverted .env auto-loading with explicit arg forwarding: everything after a -- separator is passed to the runtime interpreter ahead of the entrypoint in lk agent dev/start/console and the session daemon, so `lk agent console agent.ts -- --env-file=.env` runs `node --env-file=.env agent.ts console ...`. urfave/cli strips the -- and folds the trailing args into the positionals, so splitForwardedArgs recovers the split from os.Args; detectProject uses it so a forwarded flag with no entrypoint argument isn't mistaken for one. The detached session daemon receives the args JSON-encoded via LK_SESSION_FWD.
Stacked on #861. Extends Node.js agent support from the session daemon to the full
lk agent dev/start/consoleflow.Changes
Node agents in dev/start/console (9128955)
dev/startspawn the agents-jsdevsubcommand for Node projects (Python keepsstart --dev)--reload-addris Python-only and no longer passed to Node agentsagent.ts/agent.js+src/fallbacks), with cwd-relative resolution so monorepo example dirs workresolveCredentialshonorsIsSet("url")so an explicit--urlwinsEnv file loading for Node agents (2430a24)
.envwere never seen (Python agents conventionally callload_dotenv()themselves; Node ones don't)--env-file(Node ≥ 20.6; skipped silently on older Nodes). Shell-exported variables still take precedence over file valuesFail fast on pre-connect job crashes (7660aa2)
lk agent consolepreviously sat on the spinner for the full 60s connect timeout"job crashed"shutdown reason, agents-js's FATALconsole mode failed:) and the connect wait aborts immediately with the recent logs; the session daemon does the same through its ready pipeTesting
buildAgentCommand(Node + Python argv), env-file discovery, and the fail-signal watcherexamples/src/basic_agent.ts, TS entrypoint via type stripping +--env-file) and Python agents @ a61578853 (voice_agents/basic_agent.py): full voice console session in both.envnow fails in ~4s with the traceback instead of timing out at 60s