Skip to content

simulate: Node agent support, --view mode, and TUI/start UX fixes#878

Merged
u9g merged 4 commits into
mainfrom
jason/simulate-node-agent-improvements
Jun 25, 2026
Merged

simulate: Node agent support, --view mode, and TUI/start UX fixes#878
u9g merged 4 commits into
mainfrom
jason/simulate-node-agent-improvements

Conversation

@u9g

@u9g u9g commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Ports our simulate work onto the Node-support branch (brian/agent-session-node-support). These changes originated on an older fork of the simulate TUI, so they're re-applied as fresh edits rather than cherry-picks.

Agent start / Node support

  • Use normalizeLogLevel for the agent's --log-level.
  • Only pass --log-format colored for Python (the Node CLI rejects it).
  • Default Node entrypoints main.ts / src/main.js (and src/ fallbacks).
  • Refuse entrypoint auto-discovery when package.json defines a build task and no entrypoint was given (build output paths are nontrivial).
  • Drop the Python-only guard so Node agents can be simulated.

lk agent simulate --view <runID>

  • New --view flag / modeView to open a pre-existing simulation.
  • Print the reopen command (lk agent simulate --view <runID>) when the TUI closes.

TUI UX

  • / enter to open a simulation's detail; / esc / backspace to go back (hints updated).
  • Richer agent-exit errors: include the command used to start the agent and its recent output (or "exited with no output").
  • Quit the TUI when the agent fails to register instead of hanging.

Intentionally not ported (already present in a different form on this branch): the exit()/confirmQuit refactor and the s save-scenario key — this branch has its own save overlay and quit handling.

Builds clean with go build and go vet -tags console.

@u9g u9g force-pushed the jason/simulate-node-agent-improvements branch from 74d461e to 11e7c80 Compare June 24, 2026 20:38
toubatbrian and others added 4 commits June 24, 2026 16:44
The `lk agent session` daemon could previously only spawn Python agents;
Node/JS projects were rejected at detection time. This wires up the Node
path so a JS/TS agent can be driven over the same text-mode console
protocol as Python.

- agent_utils.go: stop gating `detectProject` on Python-only. Accept Node
  projects too (DetectProjectRoot already recognizes them via package.json)
  and update the error to reflect both supported runtimes.
- simulate_subprocess.go: extract interpreter/argv resolution into
  `buildAgentCommand`, branching on project type. Python keeps
  `<python> <entry> <args>` (uv prefixes `run python`); Node runs
  `node [--experimental-strip-types] <entry> <args>`. Add `findNodeBinary`
  (resolves `node` from PATH) and `isTypeScriptEntry` so a `.ts`/`.mts`/
  `.cts` entrypoint runs directly via the type-stripping loader with no
  build step.
- session_daemon.go: drop the stale TODO; the daemon now spawns either
  runtime via `buildConsoleArgs` (`console --connect-addr <addr>`).

Verified end-to-end: `lk agent session start examples/src/console_text_agent.ts`
spawns the JS agent, connects to the Go TCP console server, completes the
text-mode handshake, and round-trips multi-turn `say` requests including a
function-tool call.

Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(agent): support Node.js agents in lk agent dev/start/console

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.

* feat(agent): load discovered .env files into Node agents via --env-file

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.

* feat(console): fail fast when the agent job crashes before connecting

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.

* Revert "feat(agent): load discovered .env files into Node agents via --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.

* feat(agent): forward runtime args after -- to node/python

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.

* test(agent): trim agent run tests to the fail-signal case

Remove the log-level, entrypoint-resolution, arg-splitting, and command-
building unit tests along with the session forwarded-args round-trip test,
keeping TestAgentProcessFailSignal.
Ports our simulate work onto the Node-support branch:
- Node agent start: normalizeLogLevel, --log-format only for Python,
  main.ts/main.js entrypoints, and refuse entrypoint discovery when
  package.json defines a build task; drop the Python-only guard.
- `lk agent simulate --view <runID>`: open a pre-existing simulation and
  print the reopen command on close.
- TUI: ←/→ arrow navigation in/out of simulation detail, richer
  agent-exit errors (start command + recent output), and quit when the
  agent fails to register.
…ately

The local-run version gate ran main's file-based CheckSDKVersion for Node
too, which (a) couldn't find @livekit/agents in monorepo/workspace layouts
where the dep is a `workspace:*` symlink rather than a versioned entry, and
(b) gated on the Python thin-CLI baseline (1.6.0), the wrong floor for the
Node SDK.

Resolve the installed @livekit/agents via Node's own module resolution
(embedded node_resolve_version.js), starting from the entrypoint's directory
so pnpm/workspace symlinks and hoisting resolve exactly as they will at
runtime, and gate Node on its own nodeAgentMinVersion. Python keeps the
existing CheckSDKVersion path. Export IsVersionSatisfied for the reused
comparison.
@u9g u9g force-pushed the jason/simulate-node-agent-improvements branch from 11e7c80 to f321ff9 Compare June 24, 2026 20:53
@u9g u9g changed the base branch from brian/agent-session-node-support to main June 24, 2026 20:58
@u9g u9g merged commit d92b2d7 into main Jun 25, 2026
5 checks passed
@u9g u9g deleted the jason/simulate-node-agent-improvements branch June 25, 2026 02:21
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.

3 participants