From 3cdfc5a192ca91a5344b74a6b322f256ae224944 Mon Sep 17 00:00:00 2001 From: rektdeckard Date: Fri, 23 Jan 2026 11:11:11 -0700 Subject: [PATCH 1/5] migrate to vite/vitest, update tests and docs --- AGENTS.md | 10 ++++++++ package.json | 27 +++++++++++----------- src/agent.test.ts | 59 ++++++++++++++++++++++++++++++++--------------- src/agent.ts | 9 +++++--- tsconfig.json | 2 +- vite.config.ts | 15 ++++++++++++ 6 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 vite.config.ts diff --git a/AGENTS.md b/AGENTS.md index 4ce6802..e9f0dcd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,6 +46,16 @@ If you are another agentic IDE, refer to your own documentation for how to insta Voice AI agents are highly sensitive to excessive latency. For this reason, it's important to design complex agents in a structured manner that minimizes the amount of irrelevant context and unnecessary tools present on requests to the LLM. LiveKit Agents supports handoffs (one agent hands control to another) to support building reliable workflows. You should make use of these features, instead of writing long instruction prompts that cover multiple phases of a conversation. Refer to the [documentation](https://docs.livekit.io/agents/build/workflows/) for more information. +### Submit docs feedback to LiveKit + +If you use the LiveKit Docs MCP Server to search or browse documentation, also submit constructive feedback to LiveKit with the submit_docs_feedback tool. Add this to your to-do list when planning work, to ensure you file feedback after completing your other tasks. Useful feedback includes incomplete documentation, broken examples, missing steps or any other documentation gap or issue. + +## Testing + +When possible, add tests for agent behavior. Read the [documentation](https://docs.livekit.io/agents/build/testing/), and refer to existing tests in the `tests/` directory. Run tests with `uv run pytest`. + +Important: When modifying core agent behavior such as instructions, tool descriptions, and tasks/workflows/handoffs, never just guess what will work. Always use test-driven development (TDD) and begin by writing tests for the desired behavior. For instance, if you're planning to add a new tool, write one or more tests for the tool's behavior, then iterate on the tool until the tests pass correctly. This will ensure you are able to produce a working, reliable agent for the user. + ## Feature parity with Python SDK The Node.js SDK for LiveKit Agents has most, but not all, of the same features available in Python SDK for LiveKit Agents. You should always check the documentation for feature availability, and avoid using features that are not available in the Node.js SDK. diff --git a/package.json b/package.json index f0588a9..1222c77 100644 --- a/package.json +++ b/package.json @@ -4,16 +4,16 @@ "private": true, "type": "module", "scripts": { - "build": "tsc", + "build": "vite build", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", "lint": "eslint \"**/*.{ts,js}\"", "lint:fix": "eslint --fix \"**/*.{ts,js}\"", "format": "prettier --write \"**/*.{ts,js,json,md}\"", "format:check": "prettier --check \"**/*.{ts,js,json,md}\"", - "test": "node --test --import tsx", - "test:watch": "node --test --watch --import tsx", - "dev": "tsx src/agent.ts dev", + "test": "vitest --run", + "test:watch": "vitest", + "dev": "pnpm run build && node dist/agent.js dev", "download-files": "pnpm run build && node dist/agent.js download-files", "start": "node dist/agent.js start" }, @@ -22,20 +22,21 @@ "pnpm": ">=10.0.0" }, "devDependencies": { - "@eslint/js": "^9.38.0", + "@eslint/js": "^9.39.2", "@trivago/prettier-plugin-sort-imports": "^5.2.2", - "@types/node": "^22.18.11", - "eslint": "^9.38.0", - "globals": "^16.4.0", + "@types/node": "^22.19.7", + "eslint": "^9.39.2", + "globals": "^16.5.0", "jiti": "^2.6.1", - "tsx": "^4.20.6", "typescript": "^5.9.3", - "typescript-eslint": "^8.46.2" + "typescript-eslint": "^8.53.1", + "vite": "^7.3.1", + "vitest": "^4.0.18" }, "dependencies": { - "@livekit/agents": "^1.0.21", - "@livekit/agents-plugin-livekit": "^1.0.21", - "@livekit/agents-plugin-silero": "^1.0.21", + "@livekit/agents": "^1.0.38", + "@livekit/agents-plugin-livekit": "^1.0.38", + "@livekit/agents-plugin-silero": "^1.0.38", "@livekit/noise-cancellation-node": "^0.1.9", "dotenv": "^17.2.3", "zod": "^3.25.76" diff --git a/src/agent.test.ts b/src/agent.test.ts index 494aa99..46844ee 100644 --- a/src/agent.test.ts +++ b/src/agent.test.ts @@ -1,24 +1,47 @@ -import assert from 'node:assert'; -import { describe, it } from 'node:test'; - -describe('Agent Configuration', () => { - it('should have Node.js environment available', () => { - // Basic test to ensure Node.js environment is working - assert.ok(typeof process !== 'undefined', 'Process should be available'); - assert.ok(typeof process.env !== 'undefined', 'Environment variables should be accessible'); - }); +import { inference, initializeLogger, voice } from '@livekit/agents'; +import { afterEach, beforeEach, describe, it } from 'vitest'; +import { Assistant } from './agent'; + +type TestableAgentSession = InstanceType & { + run(options: { userInput: string }): voice.testing.RunResult; +}; + +// Initialize logger for testing +initializeLogger({ pretty: false, level: 'debug' }); + +describe('agent evaluation', () => { + let session: TestableAgentSession; + let llmInstance: inference.LLM; - it('should be able to import required modules', async () => { - // Test that core Node.js modules work - const path = await import('node:path'); - const url = await import('node:url'); + beforeEach(async () => { + llmInstance = new inference.LLM({ model: 'openai/gpt-5.1' }); + session = new voice.AgentSession({ llm: llmInstance }) as TestableAgentSession; + await session.start({ agent: new Assistant() }); + }); - assert.ok(typeof path.dirname === 'function', 'Path module should be available'); - assert.ok(typeof url.fileURLToPath === 'function', 'URL module should be available'); + afterEach(async () => { + await session?.close(); }); - it('should have TypeScript compilation working', () => { - // This test file being run means TypeScript compiled successfully - assert.ok(true, 'TypeScript compilation is working'); + it('offers assistance', { timeout: 30000 }, async () => { + // Run an agent turn following the user's greeting + const result = await session.run({ userInput: 'Hello' }).wait(); + + // Evaluate the agent's response for friendliness + await result.expect + .nextEvent() + .isMessage({ role: 'assistant' }) + .judge(llmInstance, { + intent: `\ +Greets the user in a friendly manner. + +Optional context that may or may not be included: +- Offer of assistance with any request the user may have +- Other small talk or chit chat is acceptable, so long as it is friendly and not too intrusive +`, + }); + + // Assert that there are no unexpected further events + result.expect.noMoreEvents(); }); }); diff --git a/src/agent.ts b/src/agent.ts index d68b75d..012316b 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -16,7 +16,7 @@ import { fileURLToPath } from 'node:url'; dotenv.config({ path: '.env.local' }); -class Assistant extends voice.Agent { +export class Assistant extends voice.Agent { constructor() { super({ instructions: `You are a helpful voice AI assistant. The user is interacting with you via voice, even if you perceive the conversation as text. @@ -65,7 +65,7 @@ export default defineAgent({ // A Large Language Model (LLM) is your agent's brain, processing user input and generating a response // See all providers at https://docs.livekit.io/agents/models/llm/ llm: new inference.LLM({ - model: 'openai/gpt-4.1-mini', + model: 'openai/gpt-5.1-mini', }), // Text-to-speech (TTS) is your agent's voice, turning the LLM's text into speech that the user can hear @@ -127,4 +127,7 @@ export default defineAgent({ }, }); -cli.runApp(new ServerOptions({ agent: fileURLToPath(import.meta.url) })); +// Only run the CLI if we're not in a test environment +if (process.env.NODE_ENV !== 'test') { + cli.runApp(new ServerOptions({ agent: fileURLToPath(import.meta.url) })); +} diff --git a/tsconfig.json b/tsconfig.json index 79e44f4..59a1665 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "include": ["./src/**/*"], - "exclude": ["./dist", "./node_modules"], + "exclude": ["./dist", "./node_modules", "**/*.test.ts", "**/*.spec.ts"], "compilerOptions": { "target": "ES2022", "module": "ES2022", diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..88a521d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + ssr: 'src/agent.ts', // marks entry as Node + target: 'node18', + sourcemap: true, + outDir: 'dist', + rollupOptions: { + output: { + entryFileNames: 'agent.js', + }, + }, + }, +}); From e833c189f315f424910069ba57b14e702187aa55 Mon Sep 17 00:00:00 2001 From: rektdeckard Date: Fri, 23 Jan 2026 11:54:25 -0700 Subject: [PATCH 2/5] chore: update workflow to pull gh secrets --- .github/workflows/template-check.yml | 8 ++++---- .github/workflows/tests.yml | 12 ++++++++---- src/agent.ts | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/template-check.yml b/.github/workflows/template-check.yml index eecbd5c..fa89a47 100644 --- a/.github/workflows/template-check.yml +++ b/.github/workflows/template-check.yml @@ -1,6 +1,6 @@ # As this is a starter template project, we don't want to check in the pnpm-lock.yaml and livekit.toml files in its template form # However, once you have cloned this repo for your own use, LiveKit recommends you check them in and delete this github workflow entirely - + name: Template Check on: @@ -12,10 +12,10 @@ on: jobs: check-template-files: runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v4 - + - name: Check template files not tracked in git run: | if git ls-files | grep -q "^pnpm-lock.yaml$"; then @@ -28,4 +28,4 @@ jobs: echo "Disable this test and commit the file once you have cloned this repo for your own use" exit 1 fi - echo "✓ pnpm-lock.yaml and livekit.toml are correctly not tracked in git" \ No newline at end of file + echo "✓ pnpm-lock.yaml and livekit.toml are correctly not tracked in git" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 593ae14..45c6eed 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,11 +14,11 @@ jobs: test: name: Test (Node.js ${{ matrix.node-version }}) runs-on: ubuntu-latest - + strategy: matrix: node-version: [22] - + steps: - name: Checkout code uses: actions/checkout@v4 @@ -40,12 +40,16 @@ jobs: run: pnpm run build - name: Run tests + env: + LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }} + LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }} + LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }} run: pnpm run test - + format: name: Formatting & Linting runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/src/agent.ts b/src/agent.ts index 012316b..32079e2 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -65,7 +65,7 @@ export default defineAgent({ // A Large Language Model (LLM) is your agent's brain, processing user input and generating a response // See all providers at https://docs.livekit.io/agents/models/llm/ llm: new inference.LLM({ - model: 'openai/gpt-5.1-mini', + model: 'openai/gpt-4.1-mini', }), // Text-to-speech (TTS) is your agent's voice, turning the LLM's text into speech that the user can hear From 21dbdd43b1f830a529426ff8308d820f3bb89e7c Mon Sep 17 00:00:00 2001 From: rektdeckard Date: Fri, 23 Jan 2026 12:47:13 -0700 Subject: [PATCH 3/5] chore: add greeting --- src/agent.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/agent.ts b/src/agent.ts index 32079e2..ba709f9 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -124,6 +124,11 @@ export default defineAgent({ // Join the room and connect to the user await ctx.connect(); + + // Greet the user + session.generateReply({ + instructions: 'Greet the user in a helpful and friendly manner.', + }); }, }); From bf04d943e397799e3d73616f8caa6d82916f2e8f Mon Sep 17 00:00:00 2001 From: rektdeckard Date: Fri, 30 Jan 2026 12:56:19 -0700 Subject: [PATCH 4/5] chore: separate agent definition for testing, bump pkgs --- package.json | 14 +++--- src/agent.test.ts | 11 +++-- src/agent.ts | 108 +--------------------------------------------- src/main.ts | 108 ++++++++++++++++++++++++++++++++++++++++++++++ vite.config.ts | 4 +- 5 files changed, 124 insertions(+), 121 deletions(-) create mode 100644 src/main.ts diff --git a/package.json b/package.json index 1222c77..a9140b4 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "format:check": "prettier --check \"**/*.{ts,js,json,md}\"", "test": "vitest --run", "test:watch": "vitest", - "dev": "pnpm run build && node dist/agent.js dev", - "download-files": "pnpm run build && node dist/agent.js download-files", - "start": "node dist/agent.js start" + "dev": "pnpm run build && node dist/main.js dev", + "download-files": "pnpm run build && node dist/main.js download-files", + "start": "node dist/main.js start" }, "engines": { "node": ">=22.0.0", @@ -29,14 +29,14 @@ "globals": "^16.5.0", "jiti": "^2.6.1", "typescript": "^5.9.3", - "typescript-eslint": "^8.53.1", + "typescript-eslint": "^8.54.0", "vite": "^7.3.1", "vitest": "^4.0.18" }, "dependencies": { - "@livekit/agents": "^1.0.38", - "@livekit/agents-plugin-livekit": "^1.0.38", - "@livekit/agents-plugin-silero": "^1.0.38", + "@livekit/agents": "^1.0.40", + "@livekit/agents-plugin-livekit": "^1.0.40", + "@livekit/agents-plugin-silero": "^1.0.40", "@livekit/noise-cancellation-node": "^0.1.9", "dotenv": "^17.2.3", "zod": "^3.25.76" diff --git a/src/agent.test.ts b/src/agent.test.ts index 46844ee..94b2ff1 100644 --- a/src/agent.test.ts +++ b/src/agent.test.ts @@ -1,21 +1,20 @@ import { inference, initializeLogger, voice } from '@livekit/agents'; +import dotenv from 'dotenv'; import { afterEach, beforeEach, describe, it } from 'vitest'; -import { Assistant } from './agent'; +import { Assistant } from './agent.js'; -type TestableAgentSession = InstanceType & { - run(options: { userInput: string }): voice.testing.RunResult; -}; +dotenv.config({ path: '.env.local' }); // Initialize logger for testing initializeLogger({ pretty: false, level: 'debug' }); describe('agent evaluation', () => { - let session: TestableAgentSession; + let session: voice.AgentSession; let llmInstance: inference.LLM; beforeEach(async () => { llmInstance = new inference.LLM({ model: 'openai/gpt-5.1' }); - session = new voice.AgentSession({ llm: llmInstance }) as TestableAgentSession; + session = new voice.AgentSession({ llm: llmInstance }); await session.start({ agent: new Assistant() }); }); diff --git a/src/agent.ts b/src/agent.ts index ba709f9..7c1e095 100644 --- a/src/agent.ts +++ b/src/agent.ts @@ -1,21 +1,6 @@ -import { - type JobContext, - type JobProcess, - ServerOptions, - cli, - defineAgent, - inference, - metrics, - voice, -} from '@livekit/agents'; -import * as livekit from '@livekit/agents-plugin-livekit'; -import * as silero from '@livekit/agents-plugin-silero'; -import { BackgroundVoiceCancellation } from '@livekit/noise-cancellation-node'; -import dotenv from 'dotenv'; -import { fileURLToPath } from 'node:url'; - -dotenv.config({ path: '.env.local' }); +import { voice } from '@livekit/agents'; +// Define a custom voice AI assistant by extending the base Agent class export class Assistant extends voice.Agent { constructor() { super({ @@ -47,92 +32,3 @@ export class Assistant extends voice.Agent { }); } } - -export default defineAgent({ - prewarm: async (proc: JobProcess) => { - proc.userData.vad = await silero.VAD.load(); - }, - entry: async (ctx: JobContext) => { - // Set up a voice AI pipeline using OpenAI, Cartesia, AssemblyAI, and the LiveKit turn detector - const session = new voice.AgentSession({ - // Speech-to-text (STT) is your agent's ears, turning the user's speech into text that the LLM can understand - // See all available models at https://docs.livekit.io/agents/models/stt/ - stt: new inference.STT({ - model: 'assemblyai/universal-streaming', - language: 'en', - }), - - // A Large Language Model (LLM) is your agent's brain, processing user input and generating a response - // See all providers at https://docs.livekit.io/agents/models/llm/ - llm: new inference.LLM({ - model: 'openai/gpt-4.1-mini', - }), - - // Text-to-speech (TTS) is your agent's voice, turning the LLM's text into speech that the user can hear - // See all available models as well as voice selections at https://docs.livekit.io/agents/models/tts/ - tts: new inference.TTS({ - model: 'cartesia/sonic-3', - voice: '9626c31c-bec5-4cca-baa8-f8ba9e84c8bc', - }), - - // VAD and turn detection are used to determine when the user is speaking and when the agent should respond - // See more at https://docs.livekit.io/agents/build/turns - turnDetection: new livekit.turnDetector.MultilingualModel(), - vad: ctx.proc.userData.vad! as silero.VAD, - voiceOptions: { - // Allow the LLM to generate a response while waiting for the end of turn - preemptiveGeneration: true, - }, - }); - - // To use a realtime model instead of a voice pipeline, use the following session setup instead. - // (Note: This is for the OpenAI Realtime API. For other providers, see https://docs.livekit.io/agents/models/realtime/)) - // 1. Install '@livekit/agents-plugin-openai' - // 2. Set OPENAI_API_KEY in .env.local - // 3. Add import `import * as openai from '@livekit/agents-plugin-openai'` to the top of this file - // 4. Use the following session setup instead of the version above - // const session = new voice.AgentSession({ - // llm: new openai.realtime.RealtimeModel({ voice: 'marin' }), - // }); - - // Metrics collection, to measure pipeline performance - // For more information, see https://docs.livekit.io/agents/build/metrics/ - const usageCollector = new metrics.UsageCollector(); - session.on(voice.AgentSessionEventTypes.MetricsCollected, (ev) => { - metrics.logMetrics(ev.metrics); - usageCollector.collect(ev.metrics); - }); - - const logUsage = async () => { - const summary = usageCollector.getSummary(); - console.log(`Usage: ${JSON.stringify(summary)}`); - }; - - ctx.addShutdownCallback(logUsage); - - // Start the session, which initializes the voice pipeline and warms up the models - await session.start({ - agent: new Assistant(), - room: ctx.room, - inputOptions: { - // LiveKit Cloud enhanced noise cancellation - // - If self-hosting, omit this parameter - // - For telephony applications, use `BackgroundVoiceCancellationTelephony` for best results - noiseCancellation: BackgroundVoiceCancellation(), - }, - }); - - // Join the room and connect to the user - await ctx.connect(); - - // Greet the user - session.generateReply({ - instructions: 'Greet the user in a helpful and friendly manner.', - }); - }, -}); - -// Only run the CLI if we're not in a test environment -if (process.env.NODE_ENV !== 'test') { - cli.runApp(new ServerOptions({ agent: fileURLToPath(import.meta.url) })); -} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..d4b7e96 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,108 @@ +import { + type JobContext, + type JobProcess, + ServerOptions, + cli, + defineAgent, + inference, + metrics, + voice, +} from '@livekit/agents'; +import * as livekit from '@livekit/agents-plugin-livekit'; +import * as silero from '@livekit/agents-plugin-silero'; +import { BackgroundVoiceCancellation } from '@livekit/noise-cancellation-node'; +import dotenv from 'dotenv'; +import { fileURLToPath } from 'node:url'; +import { Assistant } from './agent.js'; + +// Load environment variables from a local file. +// Make sure to set LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET +// when running locally or self-hosting your agent server. +dotenv.config({ path: '.env.local' }); + +export default defineAgent({ + prewarm: async (proc: JobProcess) => { + proc.userData.vad = await silero.VAD.load(); + }, + entry: async (ctx: JobContext) => { + // Set up a voice AI pipeline using OpenAI, Cartesia, AssemblyAI, and the LiveKit turn detector + const session = new voice.AgentSession({ + // Speech-to-text (STT) is your agent's ears, turning the user's speech into text that the LLM can understand + // See all available models at https://docs.livekit.io/agents/models/stt/ + stt: new inference.STT({ + model: 'assemblyai/universal-streaming', + language: 'en', + }), + + // A Large Language Model (LLM) is your agent's brain, processing user input and generating a response + // See all providers at https://docs.livekit.io/agents/models/llm/ + llm: new inference.LLM({ + model: 'openai/gpt-4.1-mini', + }), + + // Text-to-speech (TTS) is your agent's voice, turning the LLM's text into speech that the user can hear + // See all available models as well as voice selections at https://docs.livekit.io/agents/models/tts/ + tts: new inference.TTS({ + model: 'cartesia/sonic-3', + voice: '9626c31c-bec5-4cca-baa8-f8ba9e84c8bc', + }), + + // VAD and turn detection are used to determine when the user is speaking and when the agent should respond + // See more at https://docs.livekit.io/agents/build/turns + turnDetection: new livekit.turnDetector.MultilingualModel(), + vad: ctx.proc.userData.vad! as silero.VAD, + voiceOptions: { + // Allow the LLM to generate a response while waiting for the end of turn + preemptiveGeneration: true, + }, + }); + + // To use a realtime model instead of a voice pipeline, use the following session setup instead. + // (Note: This is for the OpenAI Realtime API. For other providers, see https://docs.livekit.io/agents/models/realtime/)) + // 1. Install '@livekit/agents-plugin-openai' + // 2. Set OPENAI_API_KEY in .env.local + // 3. Add import `import * as openai from '@livekit/agents-plugin-openai'` to the top of this file + // 4. Use the following session setup instead of the version above + // const session = new voice.AgentSession({ + // llm: new openai.realtime.RealtimeModel({ voice: 'marin' }), + // }); + + // Metrics collection, to measure pipeline performance + // For more information, see https://docs.livekit.io/agents/build/metrics/ + const usageCollector = new metrics.UsageCollector(); + session.on(voice.AgentSessionEventTypes.MetricsCollected, (ev) => { + metrics.logMetrics(ev.metrics); + usageCollector.collect(ev.metrics); + }); + + const logUsage = async () => { + const summary = usageCollector.getSummary(); + console.log(`Usage: ${JSON.stringify(summary)}`); + }; + + ctx.addShutdownCallback(logUsage); + + // Start the session, which initializes the voice pipeline and warms up the models + await session.start({ + agent: new Assistant(), + room: ctx.room, + inputOptions: { + // LiveKit Cloud enhanced noise cancellation + // - If self-hosting, omit this parameter + // - For telephony applications, use `BackgroundVoiceCancellationTelephony` for best results + noiseCancellation: BackgroundVoiceCancellation(), + }, + }); + + // Join the room and connect to the user + await ctx.connect(); + + // Greet the user on joining + session.generateReply({ + instructions: 'Greet the user in a helpful and friendly manner.', + }); + }, +}); + +// Run the agent server +cli.runApp(new ServerOptions({ agent: fileURLToPath(import.meta.url) })); diff --git a/vite.config.ts b/vite.config.ts index 88a521d..7aa09a0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,13 +2,13 @@ import { defineConfig } from 'vite'; export default defineConfig({ build: { - ssr: 'src/agent.ts', // marks entry as Node + ssr: 'src/main.ts', // marks entry as Node target: 'node18', sourcemap: true, outDir: 'dist', rollupOptions: { output: { - entryFileNames: 'agent.js', + entryFileNames: 'main.js', }, }, }, From 5bfc8d5f9d51665ed30c9e4be8a264c36aaaaa9a Mon Sep 17 00:00:00 2001 From: rektdeckard Date: Fri, 30 Jan 2026 13:01:22 -0700 Subject: [PATCH 5/5] fix: update testing instructions in AGENTS.md --- AGENTS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e9f0dcd..db5fde4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ The following is a guide for working with this project. This Node.js project uses the `pnpm` package manager. You should always use `pnpm` to install dependencies, run the agent, and run tests. -All app-level code is in the `src/` directory. In general, simple agents can be constructed with a single `agent.ts` file. Additional files can be added, but you must retain `agent.ts` as the entrypoint (see the associated Dockerfile for how this is deployed). +All app-level code is in the `src/` directory. In general, simple agents can be constructed with a single `main.ts` file. Additional files can be added, but you must retain `main.ts` as the entrypoint (see the associated Dockerfile for how this is deployed). Be sure to maintain code formatting. You can use the prettier formatter and eslint to format and lint the code. Scripts are available in `package.json`, including `pnpm format` and `pnpm lint`. @@ -52,7 +52,7 @@ If you use the LiveKit Docs MCP Server to search or browse documentation, also s ## Testing -When possible, add tests for agent behavior. Read the [documentation](https://docs.livekit.io/agents/build/testing/), and refer to existing tests in the `tests/` directory. Run tests with `uv run pytest`. +When possible, add tests for agent behavior. Read the [documentation](https://docs.livekit.io/agents/build/testing/), and refer to existing test files with the `.test.ts` extension. Run tests with `pnpm test`. Important: When modifying core agent behavior such as instructions, tool descriptions, and tasks/workflows/handoffs, never just guess what will work. Always use test-driven development (TDD) and begin by writing tests for the desired behavior. For instance, if you're planning to add a new tool, write one or more tests for the tool's behavior, then iterate on the tool until the tests pass correctly. This will ensure you are able to produce a working, reliable agent for the user.