From c61a6250eef5b6b9ccbb9dd5f1b820156ad7d1b8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Jun 2026 16:17:11 +0000 Subject: [PATCH 1/4] chore: regenerate examples from updated skills --- .../guardrails/example/app/api/agent/route.ts | 27 +++++++++---------- agents/nextjs/guardrails/example/app/page.tsx | 4 +-- .../nextjs/quickstart/example/app/page.tsx | 2 +- .../example/lib/assistant-constants.ts | 1 - .../quickstart/example/lib/assistant.ts | 2 ++ 5 files changed, 17 insertions(+), 19 deletions(-) delete mode 100644 speech-engine/nextjs/quickstart/example/lib/assistant-constants.ts diff --git a/agents/nextjs/guardrails/example/app/api/agent/route.ts b/agents/nextjs/guardrails/example/app/api/agent/route.ts index a0739156..34447339 100644 --- a/agents/nextjs/guardrails/example/app/api/agent/route.ts +++ b/agents/nextjs/guardrails/example/app/api/agent/route.ts @@ -1,5 +1,4 @@ import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js"; -import type { ConversationConfig } from "@elevenlabs/elevenlabs-js/api/types/ConversationConfig"; import { ClientEvent } from "@elevenlabs/elevenlabs-js/api/types/ClientEvent"; import { NextResponse } from "next/server"; @@ -57,19 +56,6 @@ export async function POST() { const { client, error } = getClient(); if (error) return error; - const clientEvents: NonNullable = [ - ClientEvent.Audio, - ClientEvent.Interruption, - ClientEvent.UserTranscript, - ClientEvent.TentativeUserTranscript, - ClientEvent.AgentResponse, - ClientEvent.AgentResponseCorrection, - ClientEvent.AgentChatResponsePart, - ClientEvent.GuardrailTriggered, - ClientEvent.InternalTentativeAgentResponse, - ClientEvent.ConversationInitiationMetadata, - ]; - try { const created = await client.conversationalAi.agents.create({ name: DEMO_AGENT_NAME, @@ -91,7 +77,18 @@ export async function POST() { }, conversation: { textOnly: false, - clientEvents, + clientEvents: [ + ClientEvent.Audio, + ClientEvent.Interruption, + ClientEvent.UserTranscript, + ClientEvent.TentativeUserTranscript, + ClientEvent.AgentResponse, + ClientEvent.AgentResponseCorrection, + ClientEvent.AgentChatResponsePart, + ClientEvent.GuardrailTriggered, + ClientEvent.InternalTentativeAgentResponse, + ClientEvent.ConversationInitiationMetadata, + ], }, }, platformSettings: { diff --git a/agents/nextjs/guardrails/example/app/page.tsx b/agents/nextjs/guardrails/example/app/page.tsx index 179f71ad..b728e874 100644 --- a/agents/nextjs/guardrails/example/app/page.tsx +++ b/agents/nextjs/guardrails/example/app/page.tsx @@ -195,11 +195,11 @@ function GuardrailsPage({

{lookupError}

) : null} -
+

Try asking for investment advice

-

+

Example questions: "What should I invest ten thousand dollars in right now?" or "Should I buy Bitcoin or index funds this month?" If the agent crosses the line into investment diff --git a/speech-engine/nextjs/quickstart/example/app/page.tsx b/speech-engine/nextjs/quickstart/example/app/page.tsx index e818cae0..965b00b0 100644 --- a/speech-engine/nextjs/quickstart/example/app/page.tsx +++ b/speech-engine/nextjs/quickstart/example/app/page.tsx @@ -11,7 +11,7 @@ import { type KeyboardEvent, } from "react"; -import { VOICE_FIRST_MESSAGE } from "@/lib/assistant-constants"; +import { VOICE_FIRST_MESSAGE } from "@/lib/assistant"; type DemoRole = "user" | "assistant"; type DemoChannel = "chat" | "voice"; diff --git a/speech-engine/nextjs/quickstart/example/lib/assistant-constants.ts b/speech-engine/nextjs/quickstart/example/lib/assistant-constants.ts deleted file mode 100644 index ffda1c93..00000000 --- a/speech-engine/nextjs/quickstart/example/lib/assistant-constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const VOICE_FIRST_MESSAGE = "Hello! How can I help you today?"; diff --git a/speech-engine/nextjs/quickstart/example/lib/assistant.ts b/speech-engine/nextjs/quickstart/example/lib/assistant.ts index 7447aa34..19fa651e 100644 --- a/speech-engine/nextjs/quickstart/example/lib/assistant.ts +++ b/speech-engine/nextjs/quickstart/example/lib/assistant.ts @@ -22,6 +22,8 @@ const ASSISTANT_MODEL = process.env.OPENAI_MODEL ?? "gpt-4o"; export const ASSISTANT_INSTRUCTIONS = "You are a helpful assistant for a voice-and-text chat demo. Keep responses concise, conversational, and easy to speak aloud."; +export const VOICE_FIRST_MESSAGE = "Hello! How can I help you today?"; + function getOpenAIClient() { if (!process.env.OPENAI_API_KEY) { throw new Error("OPENAI_API_KEY is not configured."); From 1e5897b3df203ea6f8bc3321fac62b98476c1270 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 2 Jun 2026 17:42:58 +0000 Subject: [PATCH 2/4] chore: regenerate examples from updated skills --- .../guardrails/example/app/api/agent/route.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/agents/nextjs/guardrails/example/app/api/agent/route.ts b/agents/nextjs/guardrails/example/app/api/agent/route.ts index 34447339..4b5fad06 100644 --- a/agents/nextjs/guardrails/example/app/api/agent/route.ts +++ b/agents/nextjs/guardrails/example/app/api/agent/route.ts @@ -1,5 +1,6 @@ import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js"; import { ClientEvent } from "@elevenlabs/elevenlabs-js/api/types/ClientEvent"; +import type { ConversationConfigInput } from "@elevenlabs/elevenlabs-js/api/types/ConversationConfigInput"; import { NextResponse } from "next/server"; const DEMO_AGENT_NAME = "Guardrails Demo Voice"; @@ -56,6 +57,19 @@ export async function POST() { const { client, error } = getClient(); if (error) return error; + const clientEvents: NonNullable = [ + ClientEvent.Audio, + ClientEvent.Interruption, + ClientEvent.UserTranscript, + ClientEvent.TentativeUserTranscript, + ClientEvent.AgentResponse, + ClientEvent.AgentResponseCorrection, + ClientEvent.AgentChatResponsePart, + ClientEvent.GuardrailTriggered, + ClientEvent.InternalTentativeAgentResponse, + ClientEvent.ConversationInitiationMetadata, + ]; + try { const created = await client.conversationalAi.agents.create({ name: DEMO_AGENT_NAME, @@ -77,18 +91,7 @@ export async function POST() { }, conversation: { textOnly: false, - clientEvents: [ - ClientEvent.Audio, - ClientEvent.Interruption, - ClientEvent.UserTranscript, - ClientEvent.TentativeUserTranscript, - ClientEvent.AgentResponse, - ClientEvent.AgentResponseCorrection, - ClientEvent.AgentChatResponsePart, - ClientEvent.GuardrailTriggered, - ClientEvent.InternalTentativeAgentResponse, - ClientEvent.ConversationInitiationMetadata, - ], + clientEvents, }, }, platformSettings: { From 4b4046f9ed2e4d468ec1d3db96bc34a3c567dca3 Mon Sep 17 00:00:00 2001 From: Tadas Petra <60107328+tadaspetra@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:11:37 -0500 Subject: [PATCH 3/4] update package and use signedURL --- .../app/api/conversation-token/route.ts | 8 ++--- agents/nextjs/guardrails/example/app/page.tsx | 9 ++--- agents/nextjs/guardrails/example/package.json | 34 +++++++++---------- agents/nextjs/guardrails/setup.sh | 2 +- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/agents/nextjs/guardrails/example/app/api/conversation-token/route.ts b/agents/nextjs/guardrails/example/app/api/conversation-token/route.ts index ecd8e313..b027a0e8 100644 --- a/agents/nextjs/guardrails/example/app/api/conversation-token/route.ts +++ b/agents/nextjs/guardrails/example/app/api/conversation-token/route.ts @@ -21,14 +21,14 @@ export async function GET(request: Request) { const client = new ElevenLabsClient({ apiKey }); try { - const { token } = - await client.conversationalAi.conversations.getWebrtcToken({ + const { signedUrl } = + await client.conversationalAi.conversations.getSignedUrl({ agentId, }); - return NextResponse.json({ token }); + return NextResponse.json({ signedUrl }); } catch (e) { const message = - e instanceof Error ? e.message : "Failed to create conversation token."; + e instanceof Error ? e.message : "Failed to create signed URL."; return NextResponse.json({ error: message }, { status: 502 }); } } diff --git a/agents/nextjs/guardrails/example/app/page.tsx b/agents/nextjs/guardrails/example/app/page.tsx index b728e874..d2b747b5 100644 --- a/agents/nextjs/guardrails/example/app/page.tsx +++ b/agents/nextjs/guardrails/example/app/page.tsx @@ -112,14 +112,15 @@ function GuardrailsPage({ const res = await fetch( `/api/conversation-token?agentId=${encodeURIComponent(trimmedId)}` ); - const data: { token?: string; error?: string } = await res.json(); - if (!res.ok || !data.token) { - setSessionError(data.error ?? "Could not get conversation token."); + const data: { signedUrl?: string; error?: string } = await res.json(); + if (!res.ok || !data.signedUrl) { + setSessionError(data.error ?? "Could not get signed URL."); return; } await startSession({ - conversationToken: data.token, + connectionType: "websocket", + signedUrl: data.signedUrl, }); } catch (error) { const nextMessage = diff --git a/agents/nextjs/guardrails/example/package.json b/agents/nextjs/guardrails/example/package.json index c2100a50..07b142e4 100644 --- a/agents/nextjs/guardrails/example/package.json +++ b/agents/nextjs/guardrails/example/package.json @@ -9,32 +9,32 @@ "lint": "eslint" }, "dependencies": { - "@elevenlabs/elevenlabs-js": "^2.43.0", - "@elevenlabs/react": "^1.1.0", + "@elevenlabs/elevenlabs-js": "^2.51.0", + "@elevenlabs/react": "^1.6.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.575.0", - "next": "16.1.6", + "lucide-react": "^1.17.0", + "next": "16.2.7", "radix-ui": "^1.4.3", - "react": "19.2.3", - "react-dom": "19.2.3", - "tailwind-merge": "^3.5.0" + "react": "19.2.7", + "react-dom": "19.2.7", + "tailwind-merge": "^3.6.0" }, "devDependencies": { - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint": "^9", - "eslint-config-next": "16.1.6", - "shadcn": "^3.8.5", - "tailwindcss": "^4", + "@tailwindcss/postcss": "^4.3.0", + "@types/node": "^25.9.1", + "@types/react": "^19.2.16", + "@types/react-dom": "^19.2.3", + "eslint": "^9.39.4", + "eslint-config-next": "16.2.7", + "shadcn": "^4.10.0", + "tailwindcss": "^4.3.0", "tw-animate-css": "^1.4.0", - "typescript": "^5" + "typescript": "^6.0.3" }, "pnpm": { "overrides": { - "livekit-client": "2.16.1" + "livekit-client": "2.19.1" } } } diff --git a/agents/nextjs/guardrails/setup.sh b/agents/nextjs/guardrails/setup.sh index c3c8ea18..786ae1b9 100755 --- a/agents/nextjs/guardrails/setup.sh +++ b/agents/nextjs/guardrails/setup.sh @@ -35,7 +35,7 @@ node -e " delete pkg.dependencies['@elevenlabs/client']; pkg.pnpm = pkg.pnpm || {}; pkg.pnpm.overrides = pkg.pnpm.overrides || {}; - pkg.pnpm.overrides['livekit-client'] = '2.16.1'; + pkg.pnpm.overrides['livekit-client'] = '2.19.1'; require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); " From 417bea9d5badd94c5bd458364488e09148cacb50 Mon Sep 17 00:00:00 2001 From: Tadas Petra <60107328+tadaspetra@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:24:49 -0500 Subject: [PATCH 4/4] Remove unnecessary constant --- speech-engine/nextjs/quickstart/PROMPT.md | 4 ++-- speech-engine/nextjs/quickstart/example/app/page.tsx | 4 +--- speech-engine/nextjs/quickstart/example/lib/assistant.ts | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/speech-engine/nextjs/quickstart/PROMPT.md b/speech-engine/nextjs/quickstart/PROMPT.md index 68f5b711..15cc7a3d 100644 --- a/speech-engine/nextjs/quickstart/PROMPT.md +++ b/speech-engine/nextjs/quickstart/PROMPT.md @@ -27,7 +27,7 @@ Before writing any code, invoke the `/speech-engine` skill to learn the correct ## 6. `lib/assistant.ts` -- Shared OpenAI Responses API helpers: `ASSISTANT_INSTRUCTIONS`, `VOICE_FIRST_MESSAGE`, `isChatRole`, `normalizeChatMessages`, `transcriptToChatMessages`, `createAssistantReply(messages, signal)`, and `createAssistantStream(messages, signal)`. +- Shared OpenAI Responses API helpers: `ASSISTANT_INSTRUCTIONS`, `isChatRole`, `normalizeChatMessages`, `transcriptToChatMessages`, `createAssistantReply(messages, signal)`, and `createAssistantStream(messages, signal)`. - Map Speech Engine `agent` role to OpenAI `assistant`; keep responses concise. - Normalize history before sending it to OpenAI: trim content, drop empty messages, cap message count and per-message length. @@ -74,7 +74,7 @@ Before writing any code, invoke the `/speech-engine` skill to learn the correct - Build a single chat UI that works like a normal assistant chat first, then can switch into voice mode without losing context. - Keep one `messages` state array with `{ id, role: "user" | "assistant", content, channel: "chat" | "voice", pending?, error? }`. - Text submit path: append the user message, POST the full normalized history to `/api/chat`, replace the pending assistant message with the reply, and keep the composer usable. -- Voice start path: request microphone access, POST current non-pending/non-error chat history to `/api/voice-history`, fetch `/api/token`, then `startSession({ conversationToken: token, overrides: { agent: { firstMessage: VOICE_FIRST_MESSAGE } }, onConversationCreated })`. +- Voice start path: request microphone access, POST current non-pending/non-error chat history to `/api/voice-history`, fetch `/api/token`, then start the voice session with an inline `overrides.agent.firstMessage` greeting. - In `onConversationCreated`, link the stored `historyId` to `voiceConversation.getId()` with `/api/voice-history/link`; if useful, also send a contextual update summarizing recent typed chat. - Voice event path: use `useConversation({ onMessage })` to append or update transcript messages in the same `messages` array, mapping SDK role `agent` to local role `assistant`. - While voice is connected, allow typed messages too: append them to the same thread and call `conversation.sendUserMessage(content)`; avoid duplicating echoes from `onMessage`. diff --git a/speech-engine/nextjs/quickstart/example/app/page.tsx b/speech-engine/nextjs/quickstart/example/app/page.tsx index 965b00b0..e3dd9489 100644 --- a/speech-engine/nextjs/quickstart/example/app/page.tsx +++ b/speech-engine/nextjs/quickstart/example/app/page.tsx @@ -11,8 +11,6 @@ import { type KeyboardEvent, } from "react"; -import { VOICE_FIRST_MESSAGE } from "@/lib/assistant"; - type DemoRole = "user" | "assistant"; type DemoChannel = "chat" | "voice"; @@ -379,7 +377,7 @@ function ConversationView() { conversationToken: token, overrides: { agent: { - firstMessage: VOICE_FIRST_MESSAGE, + firstMessage: "Hello! How can I help you today?", }, }, onConversationCreated: voiceConversation => { diff --git a/speech-engine/nextjs/quickstart/example/lib/assistant.ts b/speech-engine/nextjs/quickstart/example/lib/assistant.ts index 19fa651e..7447aa34 100644 --- a/speech-engine/nextjs/quickstart/example/lib/assistant.ts +++ b/speech-engine/nextjs/quickstart/example/lib/assistant.ts @@ -22,8 +22,6 @@ const ASSISTANT_MODEL = process.env.OPENAI_MODEL ?? "gpt-4o"; export const ASSISTANT_INSTRUCTIONS = "You are a helpful assistant for a voice-and-text chat demo. Keep responses concise, conversational, and easy to speak aloud."; -export const VOICE_FIRST_MESSAGE = "Hello! How can I help you today?"; - function getOpenAIClient() { if (!process.env.OPENAI_API_KEY) { throw new Error("OPENAI_API_KEY is not configured.");