Skip to content

feat(agent): Node.js agent support for lk agent dev/start/console#868

Open
u9g wants to merge 5 commits into
brian/agent-session-node-supportfrom
jason/agent-console-dev-node
Open

feat(agent): Node.js agent support for lk agent dev/start/console#868
u9g wants to merge 5 commits into
brian/agent-session-node-supportfrom
jason/agent-console-dev-node

Conversation

@u9g

@u9g u9g commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Stacked on #861. Extends Node.js agent support from the session daemon to the full lk agent dev / start / console flow.

Changes

Node agents in dev/start/console (9128955)

  • dev/start spawn the agents-js dev subcommand for Node projects (Python keeps start --dev)
  • Log levels normalized per runtime: agents-js accepts only lowercase, Python expects uppercase
  • --reload-addr is Python-only and no longer passed to Node agents
  • Entrypoint candidate lists per runtime (agent.ts/agent.js + src/ fallbacks), with cwd-relative resolution so monorepo example dirs work
  • resolveCredentials honors IsSet("url") so an explicit --url wins

Env file loading for Node agents (2430a24)

  • Node agents spawned by dev/start/console inherited only the shell environment, so credentials in a project .env were never seen (Python agents conventionally call load_dotenv() themselves; Node ones don't)
  • A known env file discovered in the project dir is now passed to Node's built-in dotenv via --env-file (Node ≥ 20.6; skipped silently on older Nodes). Shell-exported variables still take precedence over file values

Fail fast on pre-connect job crashes (7660aa2)

  • A job that crashes before the console TCP connection (e.g. missing API key in the entrypoint) leaves the worker process alive, so lk agent console previously sat on the spinner for the full 60s connect timeout
  • Agent output is now scanned for crash markers (Python's "job crashed" shutdown reason, agents-js's FATAL console mode failed:) and the connect wait aborts immediately with the recent logs; the session daemon does the same through its ready pipe

Testing

  • Unit tests for buildAgentCommand (Node + Python argv), env-file discovery, and the fail-signal watcher
  • E2E against agents-js (examples/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
  • Crash repro: removing the .env now fails in ~4s with the traceback instead of timing out at 60s

u9g added 3 commits June 9, 2026 16:47
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.
@toubatbrian toubatbrian requested review from rektdeckard, theomonnom and toubatbrian and removed request for rektdeckard June 9, 2026 23:09
Comment thread cmd/lk/simulate_subprocess.go Outdated
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) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rektdeckard What's your thoughts on auto-loading the env file?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++, 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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can drop it, I'll fix this in my branch

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for being explicit, let's just forward everything to agents

u9g added 2 commits June 10, 2026 06:28
…--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.
@theomonnom

Copy link
Copy Markdown
Member

For framework specific "magic strings", let's try to move all of them at one place.

var pythonFatalMarkers = []string{

@theomonnom theomonnom left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!! Node finally has a console mode!

Comment thread cmd/lk/agent_run_test.go

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lot of tests aren't super useful here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants