Skip to content

Commit 7b7ddd5

Browse files
committed
session-e2e: add Node echo agent fixture and CI matrix arm
Mirror testdata/echo-agent with a Node sibling (testdata/echo-agent-node) so the agent daemon e2e exercises the node <entry> console launch path in addition to Python. Adds the agents-js echo agent.ts + package.json, gitignores its installed deps (resolved fresh in CI like the uv venv), and adds a lang: [python, node] dimension to both the Linux/macOS and Windows e2e jobs.
1 parent 1b45769 commit 7b7ddd5

4 files changed

Lines changed: 110 additions & 23 deletions

File tree

.github/workflows/session-e2e.yaml

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
name: Session E2E
22

33
# Drives the real `lk agent daemon` start/say/stop lifecycle against the minimal
4-
# one-file echo agent in cmd/lk/testdata/echo-agent, on Linux, macOS, and
5-
# Windows. This exercises the detached daemon, the readiness handshake, the
6-
# console IPC transport, and the model round-trip end to end -- runtime behavior
7-
# that `go test` alone never covers.
4+
# one-file echo agents in cmd/lk/testdata, on Linux, macOS, and Windows. This
5+
# exercises the detached daemon, the readiness handshake, the console IPC
6+
# transport, and the model round-trip end to end -- runtime behavior that
7+
# `go test` alone never covers.
8+
#
9+
# Both agent runtimes are exercised via the `lang` matrix dimension: Python
10+
# (testdata/echo-agent, the test's default) and Node (testdata/echo-agent-node,
11+
# selected with LK_SESSION_E2E_AGENT). The daemon launches each as
12+
# `<python> -m livekit.agents console ...` or `node <entry> console ...`, so a
13+
# pass proves the language-specific launch path as well as the shared transport.
814
#
915
# Runs on manual dispatch and on pushes to any repo branch (forks can't trigger
1016
# `push`, so secrets are only exposed to trusted collaborators). It needs live
1117
# LiveKit credentials -- set these repo secrets first: LIVEKIT_API_KEY,
12-
# LIVEKIT_API_SECRET, LIVEKIT_URL. The echo agent drives its LLM through LiveKit
13-
# Inference, so no other provider keys are needed.
18+
# LIVEKIT_API_SECRET, LIVEKIT_URL. The echo agents drive their LLM through
19+
# LiveKit Inference, so no other provider keys are needed.
1420
#
15-
# The echo agent depends on plain PyPI livekit-agents (synced by `uv sync` from
16-
# its pyproject.toml). Note: on current releases/main, `cli.run_app()` routes
17-
# `console` through the legacy click CLI, which has no --connect-addr (that
18-
# lives behind `python -m livekit.agents`). The fixture's __main__ dispatches
19-
# console mode to the TCP console directly to bridge the daemon's
20-
# `python <entry> console --connect-addr` launch.
21+
# Each agent's deps are resolved fresh in CI (they're gitignored): the Python
22+
# fixture via `uv sync` from its pyproject.toml; the Node fixture via
23+
# `npm install` from its package.json. The Node `.ts` entrypoint runs through
24+
# Node's --experimental-strip-types loader, which needs Node >= 22.6.
2125
#
2226
# Windows is split into two jobs: pkg/apm/webrtc's C++ uses MSVC SEH
2327
# (__try/__except) that the runner's mingw GCC can't compile, so we build with
@@ -26,12 +30,8 @@ name: Session E2E
2630
# ~32KB command-line limit. So `cross-build-windows` cross-compiles lk.exe AND
2731
# the e2e test binary on Linux and uploads them; `e2e-windows` downloads them
2832
# and runs the test natively (LK_SESSION_E2E_BIN points the test at the
29-
# prebuilt lk, so nothing is rebuilt on the Windows runner).
30-
#
31-
# Node is intentionally not in the matrix yet: this branch's session daemon only
32-
# supports Python agents (`detectProject` rejects non-Python), and Node console
33-
# support depends on the brian/agent-session-node-support CLI line (#868/#878)
34-
# plus agents-js #1804. Add a node arm once those land.
33+
# prebuilt lk, so nothing is rebuilt on the Windows runner). The binaries are
34+
# language-agnostic, so that build runs once and feeds every `lang` arm.
3535

3636
on:
3737
workflow_dispatch:
@@ -50,9 +50,10 @@ jobs:
5050
fail-fast: false
5151
matrix:
5252
os: [ubuntu-latest, macos-latest]
53+
lang: [python, node]
5354

5455
runs-on: ${{ matrix.os }}
55-
name: Agent Session with Python Agent on ${{ matrix.os }}
56+
name: Agent Session with ${{ matrix.lang }} Agent on ${{ matrix.os }}
5657

5758
permissions:
5859
contents: read
@@ -76,24 +77,42 @@ jobs:
7677
cache: true
7778

7879
- name: Set up Python
80+
if: matrix.lang == 'python'
7981
uses: actions/setup-python@v5
8082
with:
8183
python-version: "3.12"
8284

8385
- name: Set up uv
86+
if: matrix.lang == 'python'
8487
uses: astral-sh/setup-uv@v5
8588
with:
8689
enable-cache: true
8790

8891
- name: Sync echo agent deps
92+
if: matrix.lang == 'python'
8993
working-directory: cmd/lk/testdata/echo-agent
9094
run: uv sync
9195

96+
- name: Set up Node
97+
if: matrix.lang == 'node'
98+
uses: actions/setup-node@v4
99+
with:
100+
# --experimental-strip-types (used to run the .ts entrypoint) needs >= 22.6.
101+
node-version: "22"
102+
103+
- name: Install Node echo agent deps
104+
if: matrix.lang == 'node'
105+
working-directory: cmd/lk/testdata/echo-agent-node
106+
run: npm install
107+
92108
- name: Run session e2e
93109
env:
94110
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
95111
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
96112
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
113+
# Default (unset) targets the Python fixture; point at the Node one for that arm.
114+
# Resolved relative to cmd/lk, the test binary's working directory.
115+
LK_SESSION_E2E_AGENT: ${{ matrix.lang == 'node' && 'testdata/echo-agent-node/agent.ts' || '' }}
97116
run: go test ./cmd/lk -run TestSessionE2E -count=1 -v -timeout 600s
98117

99118
# Cross-compile the Windows artifacts on Linux with zig, mirroring
@@ -159,7 +178,12 @@ jobs:
159178
e2e-windows:
160179
needs: cross-build-windows
161180
runs-on: windows-latest
162-
name: Agent Session with Python Agent on windows-latest
181+
name: Agent Session with ${{ matrix.lang }} Agent on windows-latest
182+
183+
strategy:
184+
fail-fast: false
185+
matrix:
186+
lang: [python, node]
163187

164188
permissions:
165189
contents: read
@@ -168,7 +192,7 @@ jobs:
168192
- name: Checkout livekit-cli
169193
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
170194
# No submodules: the prebuilt binaries already contain the cgo code;
171-
# only the echo-agent fixture (plain repo files) is needed at runtime.
195+
# only the echo-agent fixtures (plain repo files) are needed at runtime.
172196

173197
- name: Download Windows artifacts
174198
uses: actions/download-artifact@v4
@@ -177,22 +201,37 @@ jobs:
177201
path: dist
178202

179203
- name: Set up Python
204+
if: matrix.lang == 'python'
180205
uses: actions/setup-python@v5
181206
with:
182207
python-version: "3.12"
183208

184209
- name: Set up uv
210+
if: matrix.lang == 'python'
185211
uses: astral-sh/setup-uv@v5
186212
with:
187213
enable-cache: true
188214

189215
- name: Sync echo agent deps
216+
if: matrix.lang == 'python'
190217
working-directory: cmd/lk/testdata/echo-agent
191218
run: uv sync
192219

220+
- name: Set up Node
221+
if: matrix.lang == 'node'
222+
uses: actions/setup-node@v4
223+
with:
224+
# --experimental-strip-types (used to run the .ts entrypoint) needs >= 22.6.
225+
node-version: "22"
226+
227+
- name: Install Node echo agent deps
228+
if: matrix.lang == 'node'
229+
working-directory: cmd/lk/testdata/echo-agent-node
230+
run: npm install
231+
193232
- name: Run session e2e
194-
# Run from cmd/lk so the test's default testdata/echo-agent/agent.py
195-
# path resolves; point it at the cross-built lk.exe so nothing rebuilds.
233+
# Run from cmd/lk so the test's relative testdata/ entrypoint paths
234+
# resolve; point it at the cross-built lk.exe so nothing rebuilds.
196235
shell: bash
197236
working-directory: cmd/lk
198237
env:
@@ -202,6 +241,8 @@ jobs:
202241
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
203242
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
204243
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
244+
# Default (unset) targets the Python fixture; point at the Node one for that arm.
245+
LK_SESSION_E2E_AGENT: ${{ matrix.lang == 'node' && 'testdata/echo-agent-node/agent.ts' || '' }}
205246
run: |
206247
../../dist/session-e2e.test.exe \
207248
-test.run TestSessionE2E -test.count=1 -test.v -test.timeout 600s

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ cmd/lk/testdata/**/.venv
3333

3434
# uv lockfiles for test agent fixtures (resolved fresh in CI)
3535
cmd/lk/testdata/**/uv.lock
36+
37+
# node deps installed for e2e agent fixtures (resolved fresh in CI)
38+
cmd/lk/testdata/**/node_modules
39+
cmd/lk/testdata/**/package-lock.json
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Minimal one-file echo agent for the `lk agent daemon` e2e test -- the Node
3+
* sibling of testdata/echo-agent/agent.py.
4+
*
5+
* Driven in text mode, so an LLM is the only component needed. Echoes the
6+
* user's text verbatim, which the test asserts on.
7+
*/
8+
import { type JobContext, ServerOptions, cli, defineAgent, inference, voice } from '@livekit/agents';
9+
import 'dotenv/config';
10+
import { fileURLToPath } from 'node:url';
11+
12+
export default defineAgent({
13+
entry: async (ctx: JobContext) => {
14+
const session = new voice.AgentSession({
15+
llm: new inference.LLM({ model: 'openai/gpt-4o-mini' }),
16+
});
17+
await session.start({
18+
agent: new voice.Agent({
19+
instructions:
20+
'You are an echo bot. Reply with exactly the text the user sends, verbatim, and nothing else.',
21+
}),
22+
room: ctx.room,
23+
// No TTS, so disable audio output or the turn crashes in the tts node.
24+
outputOptions: { audioEnabled: false },
25+
});
26+
await ctx.connect();
27+
},
28+
});
29+
30+
cli.runApp(new ServerOptions({ agent: fileURLToPath(import.meta.url) }));
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "lk-session-e2e-echo-agent-node",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"dependencies": {
7+
"@livekit/agents": "^1.4.9",
8+
"@livekit/rtc-node": "^0.13.29",
9+
"dotenv": "^16.4.5",
10+
"zod": "^3.25.76"
11+
}
12+
}

0 commit comments

Comments
 (0)