Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"vitest": "^4.1.4"
},
"dependencies": {
"@livekit/agents": "^1.4.7",
"@livekit/agents": "0.0.0-next-20260624041820",
"@livekit/plugins-ai-coustics": "^0.2.14",
"dotenv": "^17.4.1",
"zod": "^3.25.76"
Expand Down
4 changes: 2 additions & 2 deletions src/agent.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { dedent, inference, initializeLogger, voice } from '@livekit/agents';
import dotenv from 'dotenv';
import { afterEach, beforeEach, describe, it } from 'vitest';
import { Agent } from './agent';
import { createAgent } from './agent';

dotenv.config({ path: '.env.local' });

Expand All @@ -16,7 +16,7 @@ describe('agent evaluation', () => {
beforeEach(async () => {
judgeLlm = new inference.LLM({ model: 'openai/gpt-4.1-mini' });
session = new voice.AgentSession();
await session.start({ agent: new Agent() });
await session.start({ agent: createAgent() });
});

afterEach(async () => {
Expand Down
114 changes: 72 additions & 42 deletions src/agent.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { dedent, inference, voice } from '@livekit/agents';
import { Agent, dedent, inference } from '@livekit/agents';

// Define a custom voice AI assistant by extending the base Agent class
export class Agent extends voice.Agent {
constructor() {
super({
instructions: dedent`
// Build a custom voice AI assistant with the functional `Agent.create` API
// (introduced in @livekit/agents 1.5.0). You can also subclass `voice.Agent`.

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.

I don't think it's a good idea to say you can also subclass voice.Agent, since they should be equally powerful(?)

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.

are they?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Both are equally powerful just differ in syntax

export function createAgent() {
return Agent.create({
instructions: dedent`
You are a friendly, reliable voice assistant that answers questions, explains topics, and completes tasks with available tools.

# Output rules
Expand Down Expand Up @@ -38,42 +38,72 @@ export class Agent extends voice.Agent {
- Protect privacy and minimize sensitive data.
`,

// A Large Language Model (LLM) is your agent's brain, processing user input and generating a response
// See all available models at https://docs.livekit.io/agents/models/llm/
llm: new inference.LLM({ model: 'openai/gpt-5.2-chat-latest' }),
// A Large Language Model (LLM) is your agent's brain, processing user input and generating a response
// See all available models at https://docs.livekit.io/agents/models/llm/
llm: new inference.LLM({ model: 'openai/gpt-5.2-chat-latest' }),

// To use a realtime model instead of a voice pipeline, replace the LLM
// with a RealtimeModel and remove the STT/TTS from the AgentSession
// (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 * as openai from '@livekit/agents-plugin-openai'` to the top of this file
// 4. Replace the llm option with:
// llm: new openai.realtime.RealtimeModel({ voice: 'marin' }),
// To use a realtime model instead of a voice pipeline, replace the LLM
// with a RealtimeModel and remove the STT/TTS from the AgentSession
// (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 * as openai from '@livekit/agents-plugin-openai'` to the top of this file
// 4. Replace the llm option with:
// llm: new openai.realtime.RealtimeModel({ voice: 'marin' }),

// To add tools, specify `tools` in the constructor.
// Here's an example that adds a simple weather tool.
// You also have to add `import { llm } from '@livekit/agents' and `import { z } from 'zod'` to the top of this file
// tools: {
// getWeather: llm.tool({
// description: dedent`
// Use this tool to look up current weather information in the given location.
//
// If the location is not supported by the weather service, the tool will indicate this.
// You must tell the user the location's weather is unavailable.
// `,
// parameters: z.object({
// location: z
// .string()
// .describe('The location to look up weather information for (e.g. city name)'),
// }),
// execute: async ({ location }) => {
// console.log(`Looking up weather for ${location}`);
//
// return 'sunny with a temperature of 70 degrees.';
// },
// }),
// },
});
}
// To add tools, specify `tools` in the constructor.
// Here's an example that adds a simple weather tool.
// You also have to add `import { tool } from '@livekit/agents'` and `import { z } from 'zod'` to the top of this file
// tools: [
// tool({
// name: 'getWeather',
// description: dedent`
// Use this tool to look up current weather information in the given location.
//
// If the location is not supported by the weather service, the tool will indicate this.
// You must tell the user the location's weather is unavailable.
// `,
// parameters: z.object({
// location: z
// .string()
// .describe('The location to look up weather information for (e.g. city name)'),
// }),
// execute: async ({ location }) => {
// console.log(`Looking up weather for ${location}`);
//
// return 'sunny with a temperature of 70 degrees.';
// },
// }),
// ],

// You can also group long-running async tools behind a shared, scoped lifecycle with an
// `AsyncToolset` (import `AsyncToolset` from '@livekit/agents'). `setup` runs when the agent
// becomes active — connect to a backend and register tools via `updateTools` — and `aclose`
// tears it down. Its tools run on a scoped executor, so non-blocking / cancellable async
// tools keep working across agent handoffs. Add the toolset to this `tools` array like any
// other tool:
//
// let supportClient: SupportClient | undefined;

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.

maybe we should actually have a working example here? what's a simple backend service that we could connect to that requires a long-running connection that we could showcase?

// AsyncToolset.create({
// id: 'support-backend',
// tools: [],
// setup: async ({ updateTools }) => {
// supportClient = await connectToSupportBackend();
// updateTools([
// tool({
// name: 'lookupOrder',
// description: 'Look up the status of a customer order by its ID.',
// parameters: z.object({ orderId: z.string() }),
// execute: async ({ orderId }, { ctx }) => {
// ctx.update('Looking up your order, one moment.');
// return `Order ${orderId} is ${await supportClient!.statusOf(orderId)}.`;
// },
// }),
// ]);
// },
// aclose: async () => {
// await supportClient?.disconnect();
// },
// }),
});
}
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ServerOptions, cli, defineAgent, inference, voice } from '@livekit/agen
import { audioEnhancement } from '@livekit/plugins-ai-coustics';
import dotenv from 'dotenv';
import { fileURLToPath } from 'node:url';
import { Agent } from './agent';
import { createAgent } from './agent';

// Load environment variables from a local file.
// Make sure to set LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET
Expand Down Expand Up @@ -41,7 +41,7 @@ export default defineAgent({

// Start the session, which initializes the voice pipeline and warms up the models
await session.start({
agent: new Agent(),
agent: createAgent(),
room: ctx.room,
inputOptions: {
// ai-coustics QUAIL audio enhancement for noise cancellation
Expand Down
Loading